@realitycollective/webxr-uiextensions 0.1.0-preview.1 → 0.1.0-preview.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -14,6 +14,11 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
14
14
  - `@realitycollective/uix-devtools` - dev-only tooling: edit-session launch gate, runtime UIKitML compilation, and the `uix-dev` CLI (Cloudflare quick tunnel, QR onboarding, environment doctor).
15
15
  - Demo clients: the IWSDK showcase, the devtools playground, and the multiplatform lab that picks its pipeline from the hardware.
16
16
  - `uixComponentSet`, exported from `@realitycollective/iwsdk-uiextensions`. Pass it to `spatialUI.componentSets` so the IWSDK 0.5 parser accepts the `<uix-*>` control elements. Without it a panel using any control fails to parse and never attaches. No equivalent is needed on the three.js or XR Blocks adapters.
17
+ - `WindowHandle` and `WindowOptionsBase` in `@realitycollective/webxr-uiextensions`. `WindowHandle` is what every adapter's `createWindow` hands back: an `id`, a `panel` that is `undefined` until the adapter has attached the document, and `onReady(listener)`, which runs once and fires immediately if the panel is already there. `WindowOptionsBase` holds the options every adapter understands, and both adapters' option types now extend it, so an option name means the same thing on each. `createWindow` itself stays adapter-specific, because the `config` payload differs per engine.
18
+ - `WindowHost.supportsStandalonePanels`. It says whether `createPanel` works on a host, rather than leaving callers to find out by catching. `false` on the IWSDK host, where the ECS owns panel lifecycles and `createPanel` throws; `true` on the three.js / XR Blocks host.
19
+ - `PanelReadyEvent.kind`, either `window` or `panel`. `window` means the panel came from the adapter's window factory and is managed by the window manager. `panel` means a bare panel the adapter noticed, whose `id` is then the adapter's best stable identifier for it - the config path on IWSDK. The field is optional, so existing listeners keep compiling.
20
+ - `createWindow` on the IWSDK scene host, returning an `IwsdkWindowHandle`: a `WindowHandle` plus the ECS `entity`. It spawns through `createUIWindow`, names the window `uix-window-<n>` when no id is given, and resolves `panel` and `onReady` once the document attaches, so wiring one window needs neither an ECS query nor a filtered `onPanelReady`. `createUIWindow` is unchanged and still returns the entity.
21
+ - `getPanelHandle(entity)` in `@realitycollective/iwsdk-uiextensions`: the panel handle for an entity you already hold, or `undefined` while IWSDK is still loading its document.
17
22
 
18
23
  ### Changed
19
24
 
@@ -25,5 +30,9 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
25
30
  - Example and demo markup uses `rgba()` or eight-digit hex rather than `background-opacity`, which the 0.5 parser removed. Both parsers accept the replacement, so one stylesheet serves every adapter.
26
31
  - The IWSDK component kit is selected by name, `spatialUI: { kit: 'horizon' }`, rather than by passing an imported kit module. The kits now live inside the parser.
27
32
  - `@types/three` is pinned to `0.184.0` across the workspace. IWSDK 0.5.3 and xrblocks resolved different copies, and two copies of the three typings make structurally identical `Object3D` types mutually unassignable, which surfaces as spurious errors far from their cause.
33
+ - `onPanelReady` on the IWSDK host announces bare panels as well as managed windows. A `PanelUI` entity with no `UIWindow`, or with an empty `windowId`, used to be dropped silently; it is now announced with `kind: 'panel'` and its config path as the id. Listeners that only want managed windows should check `kind`.
34
+ - `id` is optional in the XR Blocks host's `CreateWindowOptions`; a window created without one is named `uix-window-<n>`, as on IWSDK. The options also accept `movable` for parity, but this host has no title-bar drag of its own yet, so the flag is recorded and not acted on.
35
+ - The XR Blocks window handle gains `panel` - the document, which already implements `PanelHandle` - and `onReady`, which fires synchronously because uikitml interprets the markup during `createWindow`. The interface is now named `XrBlocksWindowHandle`, with `WindowHandle` kept as an alias, because the core exports a `WindowHandle` of its own.
36
+ - Coverage gates `packages/iwsdk-uiextensions/src/factory.ts` and `src/scene-host.ts` at the same 100% as the core. `new World()` from `@iwsdk/core` constructs headlessly - no renderer, no WebGL, no XR session - so the factories, the scene host and its ECS query all run for real in a node test. The per-frame ECS systems still need a live world and stay outside the gate.
28
37
 
29
38
  [0.1.0]: https://github.com/realitycollective/WebXR-UIExtensions/commits/main
package/README.md CHANGED
@@ -32,7 +32,8 @@ src/controls/ data-uix markup upgraders, driven through the structural
32
32
  src/chrome/ window chrome conventions: contractual element ids
33
33
  (uix-titlebar, uix-pin, ...) + reference UIKitML snippet
34
34
  src/adapter.ts the platform-adapter contract: PanelHost, PanelHandle,
35
- HeadPoseSource, PointerInputSource (plain tuples, no engine)
35
+ WindowHost, WindowHandle, WindowOptionsBase, HeadPoseSource,
36
+ PointerInputSource (plain tuples, no engine)
36
37
  ```
37
38
 
38
39
  ## Writing an adapter
@@ -45,6 +46,18 @@ An adapter supplies three capabilities and drives the core from its frame loop:
45
46
 
46
47
  The IWSDK adapter is the reference implementation; the XR Blocks adapter shows the same contract bound without an ECS.
47
48
 
49
+ ### The window surface
50
+
51
+ `WindowHost` is what app code writes against once panels exist. Four members carry the whole contract, and both shipped adapters honour all four:
52
+
53
+ - `supportsStandalonePanels: boolean` - whether `createPanel` works here. IWSDK reports `false` because the ECS owns panel lifecycles and `createPanel` throws; the three.js host reports `true`. Check it rather than guessing, and spawn a window when it is `false`.
54
+ - `onPanelReady(listener)` - fires as each panel becomes wireable and replays the ones already live, so wiring order never matters. The event's `kind` says what became ready: `window` for one created through the window factory, `panel` for a bare panel the adapter noticed. A bare panel's `id` is the adapter's best stable identifier for it, which on IWSDK is the config path. Only a host that discovers panels the app created outside the window factory ever reports `panel`; the three.js and XR Blocks host reports `window` only, because a standalone `createPanel` document is handed back to the caller and never announced.
55
+ - `createWindow(options)` - adapter-specific, because the `config` payload differs per engine, but it always returns a `WindowHandle`.
56
+ - `WindowHandle` - `id`, `panel` (`undefined` until the document is attached) and `onReady(listener)`, which runs once and fires immediately if the panel is already there. It is the per-window form of `onPanelReady`, for when you hold a handle and want only that window.
57
+ - Getting the panel later, when you did not keep the handle - on IWSDK call `getPanelHandle(entity)` with the window's entity; on the three.js and XR Blocks host call `host.window(id)?.panel`. Both return the same `PanelHandle`.
58
+
59
+ Options are shared even though `createWindow` is not: every adapter's option type extends `WindowOptionsBase` (`id`, `title`, `dockMode`, `position`, `maxWidth`/`maxHeight`, `movable`, `closable`, `minimizable`, `pinnable`, `followOffset`/`followSpeed`/`followTolerance`, `region`). An option means the same thing everywhere, so one `SceneWindow` maps onto every adapter with no translation table.
60
+
48
61
  ## Testing
49
62
 
50
63
  ```bash
package/dist/adapter.d.ts CHANGED
@@ -10,6 +10,15 @@
10
10
  * - {@link PointerInputSource}: deliver ray/pointer press-move-release
11
11
  * - {@link HeadPoseSource}: the viewer pose, for follow mode & body-lock
12
12
  *
13
+ * On top of those, {@link WindowHost} adds the portable window surface:
14
+ * {@link WindowHost.onPanelReady} for readiness, {@link PanelReadyEvent.kind}
15
+ * to tell a managed window from a bare panel, and
16
+ * {@link WindowHost.supportsStandalonePanels} to say whether `createPanel` is
17
+ * usable at all. Each adapter's own `createWindow` returns a
18
+ * {@link WindowHandle} and takes options extending {@link WindowOptionsBase},
19
+ * so window code reads the same on every engine even though the `config`
20
+ * payload does not.
21
+ *
13
22
  * Known adapters:
14
23
  * - `@realitycollective/iwsdk-uiextensions` - Meta IWSDK (ECS systems bind
15
24
  * these capabilities to `@iwsdk/core` components)
@@ -18,6 +27,7 @@
18
27
  *
19
28
  * The interfaces use plain tuples/records only - no engine, no three.js.
20
29
  */
30
+ import type { DockModeValue } from './core/dock-state.js';
21
31
  import type { UixElement } from './controls/element.js';
22
32
  /** Position as [x, y, z] in meters, world space unless stated otherwise. */
23
33
  export type Vec3Tuple = [number, number, number];
@@ -66,6 +76,18 @@ export interface PanelReadyEvent {
66
76
  id: string;
67
77
  /** The live panel - traverse it, or look elements up by markup id. */
68
78
  panel: PanelHandle;
79
+ /**
80
+ * What became ready.
81
+ *
82
+ * - `window` - created through the adapter's window factory and managed by
83
+ * the window manager, so `id` is the id the caller asked for.
84
+ * - `panel` - a bare panel the adapter noticed. `id` is then the adapter's
85
+ * best stable identifier for it, which on IWSDK is the panel's config
86
+ * path.
87
+ *
88
+ * Left optional so existing listeners keep compiling; adapters set it.
89
+ */
90
+ kind?: 'window' | 'panel';
69
91
  }
70
92
  /**
71
93
  * The engine-agnostic surface an app needs to build a UI: spawn windows and
@@ -80,12 +102,74 @@ export interface PanelReadyEvent {
80
102
  * ready before the listener was registered, so wiring order never matters.
81
103
  */
82
104
  export interface WindowHost extends PanelHost {
105
+ /**
106
+ * Whether {@link PanelHost.createPanel} works on this host. When `false`
107
+ * the method is not available and throws; spawn a window instead, so the
108
+ * engine owns the panel lifecycle. IWSDK is `false`, three.js/XR Blocks is
109
+ * `true`.
110
+ */
111
+ readonly supportsStandalonePanels: boolean;
83
112
  /**
84
113
  * Subscribe to panel readiness. Late subscribers are replayed the windows
85
114
  * that are already live. Returns an unsubscribe function.
86
115
  */
87
116
  onPanelReady(listener: (event: PanelReadyEvent) => void): () => void;
88
117
  }
118
+ /**
119
+ * A window an adapter spawned, before its panel necessarily exists.
120
+ *
121
+ * `createWindow` itself stays adapter-specific because the `config` payload
122
+ * differs per engine, but what it hands back is the same everywhere: an id, a
123
+ * panel once there is one, and a one-shot readiness callback.
124
+ */
125
+ export interface WindowHandle {
126
+ /** The window's id - the one passed in, or one the adapter generated. */
127
+ readonly id: string;
128
+ /**
129
+ * The live panel, or `undefined` until the adapter has attached the
130
+ * document. IWSDK loads and parses the markup over later frames; the
131
+ * three.js host interprets it during `createWindow`, so there it is set
132
+ * straight away.
133
+ */
134
+ readonly panel: PanelHandle | undefined;
135
+ /**
136
+ * Run `listener` once, when the panel is attached. Fires immediately if it
137
+ * already is, so wiring order never matters. Returns an unsubscribe
138
+ * function for the case where the caller gives up first.
139
+ */
140
+ onReady(listener: (panel: PanelHandle) => void): () => void;
141
+ }
142
+ /**
143
+ * The window options every adapter understands.
144
+ *
145
+ * An adapter's own `CreateWindowOptions` extends this and adds only what its
146
+ * engine needs - chiefly `config`, whose type differs (IWSDK takes a source
147
+ * path, the three.js host takes parsed markup). Keeping the rest here is what
148
+ * lets one `SceneWindow` map onto every adapter without a translation table.
149
+ */
150
+ export interface WindowOptionsBase {
151
+ /** Stable window id. Adapters generate one when it is absent. */
152
+ id?: string;
153
+ /** Title text written into the window chrome's title element. */
154
+ title?: string;
155
+ dockMode?: DockModeValue;
156
+ /** World position for world-locked windows. */
157
+ position?: Vec3Tuple;
158
+ /** Fit the panel into this box in meters, preserving aspect ratio. */
159
+ maxWidth?: number;
160
+ maxHeight?: number;
161
+ /** Whether the title bar drags the window. */
162
+ movable?: boolean;
163
+ closable?: boolean;
164
+ minimizable?: boolean;
165
+ pinnable?: boolean;
166
+ /** Head-relative offset used in body-follow mode (meters). */
167
+ followOffset?: Vec3Tuple;
168
+ followSpeed?: number;
169
+ followTolerance?: number;
170
+ /** Dock straight into this region on spawn. */
171
+ region?: string;
172
+ }
89
173
  /** One pointer/ray interaction stream, engine-normalised. */
90
174
  export interface PointerSample {
91
175
  /** Pointer world position (ray origin or touch point). */
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Platform-adapter contract.\n *\n * The core package owns every UX decision - window lifecycle, dock state,\n * region slot math, drag math, control models - and knows nothing about any\n * engine. An engine adapter supplies the three capabilities the core cannot\n * provide for itself, and drives the core from its own frame loop:\n *\n * - {@link PanelHost}: turn compiled UIKitML JSON into a live spatial panel\n * - {@link PointerInputSource}: deliver ray/pointer press-move-release\n * - {@link HeadPoseSource}: the viewer pose, for follow mode & body-lock\n *\n * Known adapters:\n * - `@realitycollective/iwsdk-uiextensions` - Meta IWSDK (ECS systems bind\n * these capabilities to `@iwsdk/core` components)\n * - `@realitycollective/xrblocks-uiextensions` - Google XR Blocks / plain\n * three.js (experimental)\n *\n * The interfaces use plain tuples/records only - no engine, no three.js.\n */\nimport type { UixElement } from './controls/element.js';\n\n/** Position as [x, y, z] in meters, world space unless stated otherwise. */\nexport type Vec3Tuple = [number, number, number];\n\n/** Orientation quaternion as [x, y, z, w]. */\nexport type QuatTuple = [number, number, number, number];\n\n/** A viewer (head) pose sample. */\nexport interface HeadPose {\n position: Vec3Tuple;\n quaternion: QuatTuple;\n}\n\n/** Supplies the viewer pose each frame - camera on desktop, HMD in XR. */\nexport interface HeadPoseSource {\n getHeadPose(): HeadPose;\n}\n\n/**\n * A live spatial panel created from compiled UIKitML JSON.\n * The `root` is traversable with the core's `walk`/`findRole` helpers and\n * the `data-uix` control upgraders - identical markup works on every\n * adapter.\n */\nexport interface PanelHandle {\n /** Root element of the interpreted panel (UixElement-conformant). */\n readonly root: UixElement;\n /** Look up an element by its markup `id`. */\n getElementById(id: string): UixElement | undefined;\n /** Constrain the panel to fit within width × height meters. */\n setTargetDimensions(width: number, height: number): void;\n /** Release panel resources. */\n dispose(): void;\n}\n\n/** Creates spatial panels - the engine-specific half of UIKitML rendering. */\nexport interface PanelHost {\n /**\n * Create a panel from compiled UIKitML JSON (the `{ element, classes }`\n * shape produced by the build plugin or by\n * `@realitycollective/uix-devtools`' `compilePanelSource`).\n */\n createPanel(configJson: unknown): PanelHandle;\n}\n\n/**\n * A window whose panel has finished loading and is ready to be wired.\n * Delivered by {@link WindowHost.onPanelReady}.\n */\nexport interface PanelReadyEvent {\n /** The window's id, as given to the scene descriptor / create call. */\n id: string;\n /** The live panel - traverse it, or look elements up by markup id. */\n panel: PanelHandle;\n}\n\n/**\n * The engine-agnostic surface an app needs to build a UI: spawn windows and\n * regions from portable data, observe when panels become wireable, and reach\n * the shared `WindowManager`.\n *\n * Panels load asynchronously on every adapter (IWSDK fetches the config;\n * uikit lays out over following frames), so app code must never assume a\n * panel exists immediately after creating its window. {@link onPanelReady}\n * is the portable answer - it replaces engine-specific discovery (ECS\n * queries on IWSDK, polling anywhere else) and fires for panels that became\n * ready before the listener was registered, so wiring order never matters.\n */\nexport interface WindowHost extends PanelHost {\n /**\n * Subscribe to panel readiness. Late subscribers are replayed the windows\n * that are already live. Returns an unsubscribe function.\n */\n onPanelReady(listener: (event: PanelReadyEvent) => void): () => void;\n}\n\n/** One pointer/ray interaction stream, engine-normalised. */\nexport interface PointerSample {\n /** Pointer world position (ray origin or touch point). */\n origin: Vec3Tuple;\n /** Normalised pointing direction. */\n direction: Vec3Tuple;\n}\n\n/**\n * Delivers press-move-release for one interaction source (a controller ray,\n * a hand pinch, a mouse). The core's `hold-to-drag` and `drag-math` consume\n * these; the adapter decides what constitutes press/release.\n */\nexport interface PointerInputSource {\n onPress(listener: (sample: PointerSample) => void): () => void;\n onMove(listener: (sample: PointerSample) => void): () => void;\n onRelease(listener: (sample: PointerSample) => void): () => void;\n}\n"]}
1
+ {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Platform-adapter contract.\n *\n * The core package owns every UX decision - window lifecycle, dock state,\n * region slot math, drag math, control models - and knows nothing about any\n * engine. An engine adapter supplies the three capabilities the core cannot\n * provide for itself, and drives the core from its own frame loop:\n *\n * - {@link PanelHost}: turn compiled UIKitML JSON into a live spatial panel\n * - {@link PointerInputSource}: deliver ray/pointer press-move-release\n * - {@link HeadPoseSource}: the viewer pose, for follow mode & body-lock\n *\n * On top of those, {@link WindowHost} adds the portable window surface:\n * {@link WindowHost.onPanelReady} for readiness, {@link PanelReadyEvent.kind}\n * to tell a managed window from a bare panel, and\n * {@link WindowHost.supportsStandalonePanels} to say whether `createPanel` is\n * usable at all. Each adapter's own `createWindow` returns a\n * {@link WindowHandle} and takes options extending {@link WindowOptionsBase},\n * so window code reads the same on every engine even though the `config`\n * payload does not.\n *\n * Known adapters:\n * - `@realitycollective/iwsdk-uiextensions` - Meta IWSDK (ECS systems bind\n * these capabilities to `@iwsdk/core` components)\n * - `@realitycollective/xrblocks-uiextensions` - Google XR Blocks / plain\n * three.js (experimental)\n *\n * The interfaces use plain tuples/records only - no engine, no three.js.\n */\nimport type { DockModeValue } from './core/dock-state.js';\nimport type { UixElement } from './controls/element.js';\n\n/** Position as [x, y, z] in meters, world space unless stated otherwise. */\nexport type Vec3Tuple = [number, number, number];\n\n/** Orientation quaternion as [x, y, z, w]. */\nexport type QuatTuple = [number, number, number, number];\n\n/** A viewer (head) pose sample. */\nexport interface HeadPose {\n position: Vec3Tuple;\n quaternion: QuatTuple;\n}\n\n/** Supplies the viewer pose each frame - camera on desktop, HMD in XR. */\nexport interface HeadPoseSource {\n getHeadPose(): HeadPose;\n}\n\n/**\n * A live spatial panel created from compiled UIKitML JSON.\n * The `root` is traversable with the core's `walk`/`findRole` helpers and\n * the `data-uix` control upgraders - identical markup works on every\n * adapter.\n */\nexport interface PanelHandle {\n /** Root element of the interpreted panel (UixElement-conformant). */\n readonly root: UixElement;\n /** Look up an element by its markup `id`. */\n getElementById(id: string): UixElement | undefined;\n /** Constrain the panel to fit within width × height meters. */\n setTargetDimensions(width: number, height: number): void;\n /** Release panel resources. */\n dispose(): void;\n}\n\n/** Creates spatial panels - the engine-specific half of UIKitML rendering. */\nexport interface PanelHost {\n /**\n * Create a panel from compiled UIKitML JSON (the `{ element, classes }`\n * shape produced by the build plugin or by\n * `@realitycollective/uix-devtools`' `compilePanelSource`).\n */\n createPanel(configJson: unknown): PanelHandle;\n}\n\n/**\n * A window whose panel has finished loading and is ready to be wired.\n * Delivered by {@link WindowHost.onPanelReady}.\n */\nexport interface PanelReadyEvent {\n /** The window's id, as given to the scene descriptor / create call. */\n id: string;\n /** The live panel - traverse it, or look elements up by markup id. */\n panel: PanelHandle;\n /**\n * What became ready.\n *\n * - `window` - created through the adapter's window factory and managed by\n * the window manager, so `id` is the id the caller asked for.\n * - `panel` - a bare panel the adapter noticed. `id` is then the adapter's\n * best stable identifier for it, which on IWSDK is the panel's config\n * path.\n *\n * Left optional so existing listeners keep compiling; adapters set it.\n */\n kind?: 'window' | 'panel';\n}\n\n/**\n * The engine-agnostic surface an app needs to build a UI: spawn windows and\n * regions from portable data, observe when panels become wireable, and reach\n * the shared `WindowManager`.\n *\n * Panels load asynchronously on every adapter (IWSDK fetches the config;\n * uikit lays out over following frames), so app code must never assume a\n * panel exists immediately after creating its window. {@link onPanelReady}\n * is the portable answer - it replaces engine-specific discovery (ECS\n * queries on IWSDK, polling anywhere else) and fires for panels that became\n * ready before the listener was registered, so wiring order never matters.\n */\nexport interface WindowHost extends PanelHost {\n /**\n * Whether {@link PanelHost.createPanel} works on this host. When `false`\n * the method is not available and throws; spawn a window instead, so the\n * engine owns the panel lifecycle. IWSDK is `false`, three.js/XR Blocks is\n * `true`.\n */\n readonly supportsStandalonePanels: boolean;\n /**\n * Subscribe to panel readiness. Late subscribers are replayed the windows\n * that are already live. Returns an unsubscribe function.\n */\n onPanelReady(listener: (event: PanelReadyEvent) => void): () => void;\n}\n\n/**\n * A window an adapter spawned, before its panel necessarily exists.\n *\n * `createWindow` itself stays adapter-specific because the `config` payload\n * differs per engine, but what it hands back is the same everywhere: an id, a\n * panel once there is one, and a one-shot readiness callback.\n */\nexport interface WindowHandle {\n /** The window's id - the one passed in, or one the adapter generated. */\n readonly id: string;\n /**\n * The live panel, or `undefined` until the adapter has attached the\n * document. IWSDK loads and parses the markup over later frames; the\n * three.js host interprets it during `createWindow`, so there it is set\n * straight away.\n */\n readonly panel: PanelHandle | undefined;\n /**\n * Run `listener` once, when the panel is attached. Fires immediately if it\n * already is, so wiring order never matters. Returns an unsubscribe\n * function for the case where the caller gives up first.\n */\n onReady(listener: (panel: PanelHandle) => void): () => void;\n}\n\n/**\n * The window options every adapter understands.\n *\n * An adapter's own `CreateWindowOptions` extends this and adds only what its\n * engine needs - chiefly `config`, whose type differs (IWSDK takes a source\n * path, the three.js host takes parsed markup). Keeping the rest here is what\n * lets one `SceneWindow` map onto every adapter without a translation table.\n */\nexport interface WindowOptionsBase {\n /** Stable window id. Adapters generate one when it is absent. */\n id?: string;\n /** Title text written into the window chrome's title element. */\n title?: string;\n dockMode?: DockModeValue;\n /** World position for world-locked windows. */\n position?: Vec3Tuple;\n /** Fit the panel into this box in meters, preserving aspect ratio. */\n maxWidth?: number;\n maxHeight?: number;\n /** Whether the title bar drags the window. */\n movable?: boolean;\n closable?: boolean;\n minimizable?: boolean;\n pinnable?: boolean;\n /** Head-relative offset used in body-follow mode (meters). */\n followOffset?: Vec3Tuple;\n followSpeed?: number;\n followTolerance?: number;\n /** Dock straight into this region on spawn. */\n region?: string;\n}\n\n/** One pointer/ray interaction stream, engine-normalised. */\nexport interface PointerSample {\n /** Pointer world position (ray origin or touch point). */\n origin: Vec3Tuple;\n /** Normalised pointing direction. */\n direction: Vec3Tuple;\n}\n\n/**\n * Delivers press-move-release for one interaction source (a controller ray,\n * a hand pinch, a mouse). The core's `hold-to-drag` and `drag-math` consume\n * these; the adapter decides what constitutes press/release.\n */\nexport interface PointerInputSource {\n onPress(listener: (sample: PointerSample) => void): () => void;\n onMove(listener: (sample: PointerSample) => void): () => void;\n onRelease(listener: (sample: PointerSample) => void): () => void;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@realitycollective/webxr-uiextensions",
3
- "version": "0.1.0-preview.1",
3
+ "version": "0.1.0-preview.2",
4
4
  "description": "Engine-free core of the Reality Collective UI Extensions: windowing, docking, layout regions and control models for WebXR spatial UI, driven through platform-adapter interfaces. Pair with an engine adapter - @realitycollective/iwsdk-uiextensions (Meta IWSDK) or @realitycollective/xrblocks-uiextensions (Google XR Blocks).",
5
5
  "keywords": [
6
6
  "realitycollective",