Spatial UI Document
UIKitDocument wraps the interpreted UIKit component tree in a THREE.Group and exposes DOM‑like query helpers and sizing utilities.
- DOM‑like queries:
getElementById(id)getElementsByClassName(name)querySelector(selector) / querySelectorAll(selector)- Simple selectors supported:
#id, .class, and descendant combinators like #parent .child.
- Physical sizing in meters:
setTargetDimensions(widthMeters, heightMeters) computes a uniform scale from the component’s intrinsic cm size.- Keeps aspect ratio stable; ideal for XR where 1 unit = 1 meter.
- Lifecycle:
- A
dispose() method cleans up signals and components.
PanelUISystem loads JSON, interprets it, creates UIKitDocument, and attaches it to your entity’s object3D.ScreenSpaceUISystem re‑parents the document under the camera with CSS‑like positioning when XR is not presenting.- Pointer events are forwarded (configurable) so UI elements receive hover/active/focus state.
Querying by ID and class:
// Access the document from the entity’s PanelDocument component
const doc = entity.getValue(PanelDocument, 'document'); // UIKitDocument
const button = doc.getElementById('start');
const rows = doc.getElementsByClassName('row');
// Descendant query
const label = doc.querySelector('#menu .title');
Setting a physical target size (meters):
doc.setTargetDimensions(1.0, 0.6); // ~1m wide panel, height constrained to aspect
- UIKit components report an intrinsic size in centimeters (via their
size signal). UIKitDocument converts target meters to a uniform scale:
uiWidthMeters = intrinsicWidthCm / 100scale = min(targetWidth / uiWidthMeters, targetHeight / uiHeightMeters)
- The scale is applied to the
Group (document), not individual components, preserving internal layout.
Selectors and Limitations
- Supported:
#id, .class, descendant combinators (e.g., #menu .row .button). - Not supported: attribute selectors, pseudo‑classes beyond UIKit state (
hover, active, focus). - Performance: cache query results you reuse in systems; avoid repeated deep queries inside per‑frame loops.
- Pointer events forwarded by IWSDK will toggle
hover/active/focus state on elements, which in turn applies conditional styles. - For custom behavior, subscribe to your ECS input/pointer systems and call methods or set properties on matched components.
const start = doc.getElementById('start');
// Example: toggle a class on app state change
if (isLocked) start?.classList.add('disabled');
else start?.classList.remove('disabled');
- When removing a panel, call
dispose() (done by PanelUISystem.cleanupPanel) to detach listeners and release resources. - After disposal, references to components are invalid; re‑query after re‑creating the document.
- Log
doc.toString() to see element/class counts and computed sizes. - Use IDs and class names consistently in
.uikitml so selectors remain stable during iteration.