@realitycollective/xrblocks-uiextensions 0.1.0-preview.0 → 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 +21 -0
- package/README.md +22 -1
- package/dist/host.d.ts +45 -23
- package/dist/host.js +48 -13
- package/dist/host.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -13,5 +13,26 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
|
|
|
13
13
|
- `@realitycollective/xrblocks-uiextensions` - EXPERIMENTAL Google XR Blocks / plain three.js adapter: panel document, window host, follow and scale maths, desktop controls and locomotion, pointer forwarding.
|
|
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
|
+
- `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.
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
|
|
25
|
+
- **Controls are declared as custom elements rather than attributes.** `<uix-stepper>` replaces `<div data-uix="stepper">`, and each part is its own element: `<uix-value>`, `<uix-line>`, `<uix-label>` and so on, replacing `data-uix-role`. Parameters are unchanged and stay `data-uix-*`. This is what makes one markup file portable: IWSDK 0.5 parses with `@drawcall/uikitml`, which rejects every `data-*` attribute on a built-in tag but accepts custom tags declared in a component set, while the three.js and XR Blocks parser accepts custom tags with no registration at all. Both expose the declared tag on `userData.customElement.componentName`, so the engine-free upgraders read one contract on every adapter.
|
|
26
|
+
- The expandable label's `toggle` part is now `<uix-more>`. As an element the old name would have collided with the `<uix-toggle>` control.
|
|
27
|
+
- `@realitycollective/iwsdk-uiextensions` targets **IWSDK 0.5.x**: peer range `>=0.5.0 <0.6.0`, developed against `@iwsdk/core` 0.5.3. `PanelUI` in 0.5 declares a single field, `config`, holding the URL of the UIKitML **source**; the compiled JSON it took on 0.4.x, and the `@iwsdk/vite-plugin-uikitml` step that produced it, are both gone. `maxWidth` and `maxHeight` were removed from the component schema, and ECS ignores unknown fields silently, so a panel that still writes them is mis-sized with no error. Size through `createUIWindow`, which routes to `UIWindow.targetWidth/Height`.
|
|
28
|
+
- `UixWindowHost` resolves a window's `config` by fetching the `.uikitml` source and parsing it, where it previously fetched compiled JSON. Supplying `loadConfig` is no longer necessary for an ordinary panel; override it only for an unusual transport.
|
|
29
|
+
- `compilePanelSource` in `@realitycollective/uix-devtools` serves the **source** on its `blob:` URL rather than compiled JSON, matching what 0.5 fetches. `CompiledPanel.json` is now `CompiledPanel.source`, and the `resolveFile` option is gone because the 0.5 parser has no `<link ref>` stylesheet resolution; put shared rules in a `<style>` block, of which several are allowed and merge. Validation now runs on `@drawcall/uikitml`, pinned to the version `@iwsdk/core` depends on, so a source that passes here is one `PanelUISystem` will accept and no second parser enters the tree.
|
|
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.
|
|
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.
|
|
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.
|
|
16
37
|
|
|
17
38
|
[0.1.0]: https://github.com/realitycollective/WebXR-UIExtensions/commits/main
|
package/README.md
CHANGED
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
| Desktop mouse input (hover, click, drag-to-look) | ✅ | ✅ via `@pmndrs/pointer-events` |
|
|
18
18
|
| Desktop locomotion (WASD, jump, crouch, sprint) | n/a | ✅ `DesktopControls` |
|
|
19
19
|
| XR select-ray click forwarding | ✅ | ✅ minimal (`forwardClick`) |
|
|
20
|
-
|
|
|
20
|
+
| Bare panels (`createPanel`) | ⬜ ECS owns the lifecycle | ✅ `supportsStandalonePanels` is `true` |
|
|
21
|
+
| Title-bar ray drag (`@pmndrs/handle`) | ✅ | ⬜ roadmap (`movable` is accepted and ignored) |
|
|
21
22
|
| Drop-to-dock by dragging | ✅ | ⬜ roadmap (needs drag) |
|
|
22
23
|
| System keyboard text input | ✅ | ⬜ untested on Android XR |
|
|
23
24
|
|
|
@@ -72,6 +73,26 @@ await xb.init();
|
|
|
72
73
|
|
|
73
74
|
Nothing here imports `xrblocks` - the glue binds to plain three.js shapes (`scene: Object3D`, `camera`), so the same host works in a hand-rolled three.js WebXR app.
|
|
74
75
|
|
|
76
|
+
### Window options and handles
|
|
77
|
+
|
|
78
|
+
`createWindow` takes the portable `WindowOptionsBase` fields plus `config`, so an option means here what it means on the IWSDK adapter. Two notes specific to this host:
|
|
79
|
+
|
|
80
|
+
- `id` is optional. Omit it and the window is named `uix-window-<n>`.
|
|
81
|
+
- `movable` is accepted and recorded, but nothing acts on it yet: this host has no title-bar drag of its own, so there is no gate to close. It is in the options so a scene descriptor written for IWSDK loads here unchanged.
|
|
82
|
+
|
|
83
|
+
The handle it returns satisfies the core `WindowHandle` and adds the three.js specifics:
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
const handle = host.createWindow({ title: 'Status', config });
|
|
87
|
+
handle.id; // 'uix-window-1'
|
|
88
|
+
handle.group; // the scene-graph node - position and rotate freely
|
|
89
|
+
handle.document; // the UixPanelDocument
|
|
90
|
+
handle.panel; // the same document, under the portable name
|
|
91
|
+
handle.onReady((panel) => wire(panel)); // fires straight away here
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
`onReady` fires synchronously because uikitml interprets the markup during `createWindow`; only LAYOUT is async. It still returns an unsubscribe function, so code that runs on both adapters has one shape. `supportsStandalonePanels` is `true`: `createPanel(config)` gives an unmanaged panel with no chrome and no window record.
|
|
95
|
+
|
|
75
96
|
## Known constraint: three versions
|
|
76
97
|
|
|
77
98
|
`xrblocks@0.19` declares a peer of `three@^0.184`, while IWSDK mandates the `super-three@0.181` fork used workspace-wide. Vite resolves a single `three` per bundle so the pairing works in practice, but npm's peer check cannot express it - this workspace uses `legacy-peer-deps` (see the root `.npmrc`). Revisit when IWSDK's three catches up.
|
package/dist/host.d.ts
CHANGED
|
@@ -12,26 +12,23 @@
|
|
|
12
12
|
* portable `SceneDescriptor` builds the same playground here as on IWSDK).
|
|
13
13
|
*/
|
|
14
14
|
import { Group, type Object3D } from 'three';
|
|
15
|
-
import type
|
|
16
|
-
import { RegionRegistry, WindowManager, type
|
|
15
|
+
import { type Kit } from '@pmndrs/uikitml';
|
|
16
|
+
import { RegionRegistry, WindowManager, type HeadPoseSource, type PanelHandle, type PanelReadyEvent, type RegionDefinition, type SceneRegion, type SceneTarget, type SceneWindow, type Vec3Tuple, type WindowHandle as CoreWindowHandle, type WindowHost, type WindowOptionsBase } from '@realitycollective/webxr-uiextensions';
|
|
17
17
|
import { UixPanelDocument } from './panel-document.js';
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Options for {@link UixWindowHost.createWindow}.
|
|
20
|
+
*
|
|
21
|
+
* Everything but `config` comes from the portable {@link WindowOptionsBase},
|
|
22
|
+
* so an option means the same thing here as on the IWSDK adapter. `id` is
|
|
23
|
+
* optional: leave it out and the host names the window `uix-window-<n>`.
|
|
24
|
+
*
|
|
25
|
+
* One option is accepted but not acted on: `movable`. This host has no
|
|
26
|
+
* title-bar drag of its own yet - dragging comes from the XR Blocks / desktop
|
|
27
|
+
* input layer above it - so the flag is recorded and otherwise ignored.
|
|
28
|
+
*/
|
|
29
|
+
export interface CreateWindowOptions extends WindowOptionsBase {
|
|
20
30
|
/** Compiled UIKitML JSON (the `{ element, classes }` shape). */
|
|
21
31
|
config: unknown;
|
|
22
|
-
title?: string;
|
|
23
|
-
dockMode?: DockModeValue;
|
|
24
|
-
position?: Vec3Tuple;
|
|
25
|
-
maxWidth?: number;
|
|
26
|
-
maxHeight?: number;
|
|
27
|
-
closable?: boolean;
|
|
28
|
-
minimizable?: boolean;
|
|
29
|
-
pinnable?: boolean;
|
|
30
|
-
followOffset?: Vec3Tuple;
|
|
31
|
-
followSpeed?: number;
|
|
32
|
-
followTolerance?: number;
|
|
33
|
-
/** Dock straight into this region on spawn. */
|
|
34
|
-
region?: string;
|
|
35
32
|
}
|
|
36
33
|
export interface CreateRegionOptions extends Partial<RegionDefinition> {
|
|
37
34
|
id: string;
|
|
@@ -40,12 +37,25 @@ export interface CreateRegionOptions extends Partial<RegionDefinition> {
|
|
|
40
37
|
follow?: boolean;
|
|
41
38
|
followOffset?: Vec3Tuple;
|
|
42
39
|
}
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
/**
|
|
41
|
+
* A window spawned by {@link UixWindowHost.createWindow}.
|
|
42
|
+
*
|
|
43
|
+
* Satisfies the core {@link CoreWindowHandle} and adds the three.js specifics.
|
|
44
|
+
* `panel` is the document itself, which already implements `PanelHandle`, and
|
|
45
|
+
* is never `undefined` here: uikitml interprets the markup synchronously, so
|
|
46
|
+
* the panel exists the moment `createWindow` returns.
|
|
47
|
+
*/
|
|
48
|
+
export interface XrBlocksWindowHandle extends CoreWindowHandle {
|
|
49
|
+
readonly id: string;
|
|
45
50
|
/** The scene-graph node - position/rotate freely. */
|
|
46
51
|
group: Group;
|
|
47
52
|
document: UixPanelDocument;
|
|
53
|
+
/** Same object as {@link document}, under the portable name. */
|
|
54
|
+
readonly panel: UixPanelDocument;
|
|
55
|
+
onReady(listener: (panel: PanelHandle) => void): () => void;
|
|
48
56
|
}
|
|
57
|
+
/** Back-compatible name for {@link XrBlocksWindowHandle}. */
|
|
58
|
+
export type WindowHandle = XrBlocksWindowHandle;
|
|
49
59
|
export interface RegionHandle {
|
|
50
60
|
id: string;
|
|
51
61
|
group: Group;
|
|
@@ -59,11 +69,18 @@ export interface UixWindowHostOptions {
|
|
|
59
69
|
kit?: Kit;
|
|
60
70
|
/**
|
|
61
71
|
* Resolver for a window's `config` when it arrives as a string path (as
|
|
62
|
-
* portable `SceneDescriptor`s carry it).
|
|
72
|
+
* portable `SceneDescriptor`s carry it).
|
|
73
|
+
*
|
|
74
|
+
* Defaults to fetching the `.uikitml` source and parsing it, which is the
|
|
75
|
+
* same artefact IWSDK loads - so one markup file serves every adapter and
|
|
76
|
+
* no build step is required. Override only for an unusual transport; you do
|
|
77
|
+
* not need to supply this to load a normal panel.
|
|
63
78
|
*/
|
|
64
79
|
loadConfig?: (path: string) => Promise<unknown>;
|
|
65
80
|
}
|
|
66
81
|
export declare class UixWindowHost implements WindowHost, SceneTarget {
|
|
82
|
+
/** Bare panels work here - the host does not own a panel lifecycle. */
|
|
83
|
+
readonly supportsStandalonePanels: boolean;
|
|
67
84
|
readonly manager: WindowManager;
|
|
68
85
|
readonly regions: RegionRegistry;
|
|
69
86
|
private readonly scene;
|
|
@@ -75,8 +92,13 @@ export declare class UixWindowHost implements WindowHost, SceneTarget {
|
|
|
75
92
|
private readonly readyListeners;
|
|
76
93
|
/** Panels already live - replayed to late `onPanelReady` subscribers. */
|
|
77
94
|
private readonly ready;
|
|
95
|
+
/** Feeds `uix-window-<n>` ids to windows created without one. */
|
|
96
|
+
private windowSequence;
|
|
78
97
|
constructor(options: UixWindowHostOptions);
|
|
79
|
-
/**
|
|
98
|
+
/**
|
|
99
|
+
* PanelHost - bare panel, unmanaged (used by devtools and tests). Always
|
|
100
|
+
* available here, which is what `supportsStandalonePanels` reports.
|
|
101
|
+
*/
|
|
80
102
|
createPanel(configJson: unknown): UixPanelDocument;
|
|
81
103
|
/**
|
|
82
104
|
* Observe panel readiness. Windows already live are replayed immediately,
|
|
@@ -96,8 +118,8 @@ export declare class UixWindowHost implements WindowHost, SceneTarget {
|
|
|
96
118
|
/** Dock a window into a region (or undock it with `undefined`). */
|
|
97
119
|
dock(windowId: string, regionId: string | undefined): void;
|
|
98
120
|
/** Spawn a managed window from compiled UIKitML JSON. */
|
|
99
|
-
createWindow(options: CreateWindowOptions):
|
|
100
|
-
window(id: string):
|
|
121
|
+
createWindow(options: CreateWindowOptions): XrBlocksWindowHandle;
|
|
122
|
+
window(id: string): XrBlocksWindowHandle | undefined;
|
|
101
123
|
/** Drive per-frame from the engine loop (delta in SECONDS). */
|
|
102
124
|
update(deltaSeconds: number): void;
|
|
103
125
|
private applyFollow;
|
package/dist/host.js
CHANGED
|
@@ -12,12 +12,29 @@
|
|
|
12
12
|
* portable `SceneDescriptor` builds the same playground here as on IWSDK).
|
|
13
13
|
*/
|
|
14
14
|
import { Group } from 'three';
|
|
15
|
+
import { parse } from '@pmndrs/uikitml';
|
|
16
|
+
/**
|
|
17
|
+
* Default `config` resolver: fetch UIKitML source and parse it.
|
|
18
|
+
*
|
|
19
|
+
* IWSDK 0.5 dropped the build-time compile step and parses `PanelUI.config`
|
|
20
|
+
* as source at runtime, so descriptors carry `.uikitml` paths. This parses the
|
|
21
|
+
* same file for the three.js and XR Blocks hosts, which interpret an AST.
|
|
22
|
+
*/
|
|
23
|
+
async function loadUikitmlSource(path) {
|
|
24
|
+
const response = await fetch(path);
|
|
25
|
+
if (!response.ok) {
|
|
26
|
+
throw new Error(`UIKitML source ${path} -> HTTP ${response.status}`);
|
|
27
|
+
}
|
|
28
|
+
return parse(await response.text());
|
|
29
|
+
}
|
|
15
30
|
import { DockMode, RegionRegistry, WINDOW_CHROME_IDS, WindowManager, minimizeLabelFor, pinLabelFor, slotOffset, } from '@realitycollective/webxr-uiextensions';
|
|
16
31
|
import { approach, approachAlpha, distanceSquared, followTarget, } from './follow-math.js';
|
|
17
32
|
import { UixPanelDocument } from './panel-document.js';
|
|
18
33
|
const DEFAULT_FOLLOW_OFFSET = [0, -0.15, -1.2];
|
|
19
34
|
const DEFAULT_REGION_FOLLOW_OFFSET = [0, -0.2, -1.4];
|
|
20
35
|
export class UixWindowHost {
|
|
36
|
+
/** Bare panels work here - the host does not own a panel lifecycle. */
|
|
37
|
+
supportsStandalonePanels = true;
|
|
21
38
|
manager = new WindowManager();
|
|
22
39
|
regions = new RegionRegistry();
|
|
23
40
|
scene;
|
|
@@ -29,13 +46,13 @@ export class UixWindowHost {
|
|
|
29
46
|
readyListeners = new Set();
|
|
30
47
|
/** Panels already live - replayed to late `onPanelReady` subscribers. */
|
|
31
48
|
ready = new Map();
|
|
49
|
+
/** Feeds `uix-window-<n>` ids to windows created without one. */
|
|
50
|
+
windowSequence = 0;
|
|
32
51
|
constructor(options) {
|
|
33
52
|
this.scene = options.scene;
|
|
34
53
|
this.headPose = options.headPose;
|
|
35
54
|
this.kit = options.kit;
|
|
36
|
-
this.loadConfig =
|
|
37
|
-
options.loadConfig ??
|
|
38
|
-
((path) => fetch(path).then((response) => response.json()));
|
|
55
|
+
this.loadConfig = options.loadConfig ?? loadUikitmlSource;
|
|
39
56
|
this.manager.events.on('closed', (record) => {
|
|
40
57
|
const state = this.states.get(record.id);
|
|
41
58
|
if (state) {
|
|
@@ -60,7 +77,10 @@ export class UixWindowHost {
|
|
|
60
77
|
});
|
|
61
78
|
}
|
|
62
79
|
// --- WindowHost -----------------------------------------------------------
|
|
63
|
-
/**
|
|
80
|
+
/**
|
|
81
|
+
* PanelHost - bare panel, unmanaged (used by devtools and tests). Always
|
|
82
|
+
* available here, which is what `supportsStandalonePanels` reports.
|
|
83
|
+
*/
|
|
64
84
|
createPanel(configJson) {
|
|
65
85
|
return new UixPanelDocument(configJson, this.kit);
|
|
66
86
|
}
|
|
@@ -121,6 +141,7 @@ export class UixWindowHost {
|
|
|
121
141
|
...(window.followTolerance !== undefined
|
|
122
142
|
? { followTolerance: window.followTolerance }
|
|
123
143
|
: {}),
|
|
144
|
+
...(window.movable !== undefined ? { movable: window.movable } : {}),
|
|
124
145
|
...(window.closable !== undefined ? { closable: window.closable } : {}),
|
|
125
146
|
...(window.minimizable !== undefined
|
|
126
147
|
? { minimizable: window.minimizable }
|
|
@@ -168,18 +189,32 @@ export class UixWindowHost {
|
|
|
168
189
|
// --- Windows --------------------------------------------------------------
|
|
169
190
|
/** Spawn a managed window from compiled UIKitML JSON. */
|
|
170
191
|
createWindow(options) {
|
|
192
|
+
const id = options.id ?? `uix-window-${(this.windowSequence += 1)}`;
|
|
171
193
|
const document = new UixPanelDocument(options.config, this.kit);
|
|
172
194
|
document.setTargetDimensions(options.maxWidth ?? 1, options.maxHeight ?? 1);
|
|
173
195
|
const group = new Group();
|
|
174
|
-
group.name = `uix-window:${
|
|
196
|
+
group.name = `uix-window:${id}`;
|
|
175
197
|
group.add(document);
|
|
176
198
|
if (options.position) {
|
|
177
199
|
group.position.set(...options.position);
|
|
178
200
|
}
|
|
179
201
|
this.scene.add(group);
|
|
180
|
-
const handle = {
|
|
181
|
-
|
|
202
|
+
const handle = {
|
|
203
|
+
id,
|
|
204
|
+
group,
|
|
205
|
+
document,
|
|
206
|
+
panel: document,
|
|
207
|
+
// The panel exists already, so readiness is immediate. The unsubscribe
|
|
208
|
+
// is returned anyway, so callers can write one shape of code for both
|
|
209
|
+
// adapters.
|
|
210
|
+
onReady(listener) {
|
|
211
|
+
listener(document);
|
|
212
|
+
return () => { };
|
|
213
|
+
},
|
|
214
|
+
};
|
|
215
|
+
this.states.set(id, {
|
|
182
216
|
handle,
|
|
217
|
+
movable: options.movable ?? true,
|
|
183
218
|
options: {
|
|
184
219
|
followOffset: options.followOffset ?? DEFAULT_FOLLOW_OFFSET,
|
|
185
220
|
followSpeed: options.followSpeed ?? 3,
|
|
@@ -189,25 +224,25 @@ export class UixWindowHost {
|
|
|
189
224
|
pin: undefined,
|
|
190
225
|
minimize: undefined,
|
|
191
226
|
});
|
|
192
|
-
this.manager.open(
|
|
227
|
+
this.manager.open(id, {
|
|
193
228
|
title: options.title ?? '',
|
|
194
229
|
dockMode: options.dockMode ?? DockMode.WorldLocked,
|
|
195
230
|
});
|
|
196
231
|
this.wireChrome(options, handle);
|
|
197
232
|
if (options.region !== undefined) {
|
|
198
|
-
this.dock(
|
|
233
|
+
this.dock(id, options.region);
|
|
199
234
|
}
|
|
200
235
|
// The panel's element tree exists synchronously (uikitml interprets on
|
|
201
236
|
// construction); only its LAYOUT is async. Announce readiness now so
|
|
202
237
|
// wiring can attach handlers immediately.
|
|
203
|
-
const event = { id
|
|
204
|
-
this.ready.set(
|
|
238
|
+
const event = { id, panel: document, kind: 'window' };
|
|
239
|
+
this.ready.set(id, event);
|
|
205
240
|
for (const listener of this.readyListeners) {
|
|
206
241
|
try {
|
|
207
242
|
listener(event);
|
|
208
243
|
}
|
|
209
244
|
catch (error) {
|
|
210
|
-
console.error(`[uix] panel-ready listener failed for "${
|
|
245
|
+
console.error(`[uix] panel-ready listener failed for "${id}":`, error);
|
|
211
246
|
}
|
|
212
247
|
}
|
|
213
248
|
return handle;
|
|
@@ -279,7 +314,7 @@ export class UixWindowHost {
|
|
|
279
314
|
}
|
|
280
315
|
wireChrome(options, handle) {
|
|
281
316
|
const element = (id) => handle.document.getElementById(id);
|
|
282
|
-
const id =
|
|
317
|
+
const id = handle.id;
|
|
283
318
|
const title = element(WINDOW_CHROME_IDS.title);
|
|
284
319
|
if (title && options.title) {
|
|
285
320
|
title.setProperties({ text: options.title });
|
package/dist/host.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host.js","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * UixWindowHost - the engine binding for plain three.js / XR Blocks scenes.\n *\n * Owns a core `WindowManager` + `RegionRegistry` and applies their decisions\n * to the scene graph: spawn UIKitML windows and dock regions, wire chrome\n * buttons (focus / PIN / MIN / X), collapse content while minimized, place\n * docked windows into their region's slots, and ease `body-follow` windows\n * (and body-locked regions) toward the viewer each frame.\n *\n * It implements the core's `WindowHost` (so app code can wire behaviour\n * through `onPanelReady` with no engine knowledge) and `SceneTarget` (so a\n * portable `SceneDescriptor` builds the same playground here as on IWSDK).\n */\nimport { Group, type Object3D } from 'three';\nimport type { Kit } from '@pmndrs/uikitml';\nimport {\n DockMode,\n RegionRegistry,\n WINDOW_CHROME_IDS,\n WindowManager,\n minimizeLabelFor,\n pinLabelFor,\n slotOffset,\n type DockModeValue,\n type HeadPoseSource,\n type PanelReadyEvent,\n type RegionDefinition,\n type SceneRegion,\n type SceneTarget,\n type SceneWindow,\n type UixElement,\n type Vec3Tuple,\n type WindowHost,\n} from '@realitycollective/webxr-uiextensions';\nimport {\n approach,\n approachAlpha,\n distanceSquared,\n followTarget,\n} from './follow-math.js';\nimport { UixPanelDocument } from './panel-document.js';\n\nexport interface CreateWindowOptions {\n id: string;\n /** Compiled UIKitML JSON (the `{ element, classes }` shape). */\n config: unknown;\n title?: string;\n dockMode?: DockModeValue;\n position?: Vec3Tuple;\n maxWidth?: number;\n maxHeight?: number;\n closable?: boolean;\n minimizable?: boolean;\n pinnable?: boolean;\n followOffset?: Vec3Tuple;\n followSpeed?: number;\n followTolerance?: number;\n /** Dock straight into this region on spawn. */\n region?: string;\n}\n\nexport interface CreateRegionOptions extends Partial<RegionDefinition> {\n id: string;\n position?: Vec3Tuple;\n /** Body-lock the region so it follows the viewer. */\n follow?: boolean;\n followOffset?: Vec3Tuple;\n}\n\nexport interface WindowHandle {\n id: string;\n /** The scene-graph node - position/rotate freely. */\n group: Group;\n document: UixPanelDocument;\n}\n\nexport interface RegionHandle {\n id: string;\n group: Group;\n}\n\nexport interface UixWindowHostOptions {\n /** Parent for spawned windows (the scene, or any group inside it). */\n scene: Object3D;\n /** Viewer pose provider - camera on desktop, HMD pose in XR. */\n headPose: HeadPoseSource;\n /** Optional UIKitML component kit(s) (e.g. horizon kit). */\n kit?: Kit;\n /**\n * Resolver for a window's `config` when it arrives as a string path (as\n * portable `SceneDescriptor`s carry it). Defaults to `fetch(path).json()`.\n */\n loadConfig?: (path: string) => Promise<unknown>;\n}\n\ninterface FollowOptions {\n followOffset: Vec3Tuple;\n followSpeed: number;\n followTolerance: number;\n}\n\ninterface WindowState {\n handle: WindowHandle;\n options: FollowOptions;\n content: UixElement | undefined;\n pin: UixElement | undefined;\n minimize: UixElement | undefined;\n}\n\ninterface RegionState {\n handle: RegionHandle;\n follow: boolean;\n followOffset: Vec3Tuple;\n}\n\nconst DEFAULT_FOLLOW_OFFSET: Vec3Tuple = [0, -0.15, -1.2];\nconst DEFAULT_REGION_FOLLOW_OFFSET: Vec3Tuple = [0, -0.2, -1.4];\n\nexport class UixWindowHost implements WindowHost, SceneTarget {\n readonly manager = new WindowManager();\n readonly regions = new RegionRegistry();\n private readonly scene: Object3D;\n private readonly headPose: HeadPoseSource;\n private readonly kit: Kit | undefined;\n private readonly loadConfig: (path: string) => Promise<unknown>;\n private readonly states = new Map<string, WindowState>();\n private readonly regionStates = new Map<string, RegionState>();\n private readonly readyListeners = new Set<(event: PanelReadyEvent) => void>();\n /** Panels already live - replayed to late `onPanelReady` subscribers. */\n private readonly ready = new Map<string, PanelReadyEvent>();\n\n constructor(options: UixWindowHostOptions) {\n this.scene = options.scene;\n this.headPose = options.headPose;\n this.kit = options.kit;\n this.loadConfig =\n options.loadConfig ??\n ((path: string) => fetch(path).then((response) => response.json()));\n\n this.manager.events.on('closed', (record) => {\n const state = this.states.get(record.id);\n if (state) {\n this.states.delete(record.id);\n this.ready.delete(record.id);\n this.regions.undock(record.id);\n state.handle.document.dispose();\n state.handle.group.removeFromParent();\n this.layoutRegions();\n }\n });\n this.manager.events.on('minimized', (record) => {\n this.setContentCollapsed(record.id, true);\n this.syncMinimizeLabel(record.id);\n });\n this.manager.events.on('restored', (record) => {\n this.setContentCollapsed(record.id, false);\n this.syncMinimizeLabel(record.id);\n });\n this.manager.events.on('dockChanged', ({ window }) => {\n this.syncPinLabel(window.id);\n });\n }\n\n // --- WindowHost -----------------------------------------------------------\n\n /** PanelHost - bare panel, unmanaged (used by devtools and tests). */\n createPanel(configJson: unknown): UixPanelDocument {\n return new UixPanelDocument(configJson, this.kit);\n }\n\n /**\n * Observe panel readiness. Windows already live are replayed immediately,\n * so wiring code never races window creation.\n */\n onPanelReady(listener: (event: PanelReadyEvent) => void): () => void {\n this.readyListeners.add(listener);\n for (const event of this.ready.values()) {\n listener(event);\n }\n return () => void this.readyListeners.delete(listener);\n }\n\n // --- SceneTarget (portable scene descriptors) -----------------------------\n\n spawnRegion(region: SceneRegion): void {\n this.createRegion({\n id: region.id,\n ...(region.flow !== undefined ? { flow: region.flow } : {}),\n ...(region.pitch !== undefined ? { pitch: region.pitch } : {}),\n ...(region.columns !== undefined ? { columns: region.columns } : {}),\n ...(region.capacity !== undefined ? { capacity: region.capacity } : {}),\n ...(region.snapRadius !== undefined ? { snapRadius: region.snapRadius } : {}),\n ...(region.position !== undefined\n ? { position: [...region.position] as Vec3Tuple }\n : {}),\n ...(region.follow !== undefined ? { follow: region.follow } : {}),\n ...(region.followOffset !== undefined\n ? { followOffset: [...region.followOffset] as Vec3Tuple }\n : {}),\n });\n }\n\n /**\n * Scene descriptors carry config PATHS; this resolves the path and spawns\n * the window when it arrives. Fire-and-forget by design - subscribe with\n * {@link onPanelReady} to wire behaviour once the panel exists.\n */\n spawnWindow(window: SceneWindow): void {\n void this.loadConfig(window.config)\n .then((config) => {\n this.createWindow({\n id: window.id,\n config,\n title: window.title,\n ...(window.position !== undefined\n ? { position: [...window.position] as Vec3Tuple }\n : {}),\n ...(window.maxWidth !== undefined ? { maxWidth: window.maxWidth } : {}),\n ...(window.maxHeight !== undefined ? { maxHeight: window.maxHeight } : {}),\n ...(window.dockMode !== undefined ? { dockMode: window.dockMode } : {}),\n ...(window.region !== undefined ? { region: window.region } : {}),\n ...(window.followOffset !== undefined\n ? { followOffset: [...window.followOffset] as Vec3Tuple }\n : {}),\n ...(window.followSpeed !== undefined\n ? { followSpeed: window.followSpeed }\n : {}),\n ...(window.followTolerance !== undefined\n ? { followTolerance: window.followTolerance }\n : {}),\n ...(window.closable !== undefined ? { closable: window.closable } : {}),\n ...(window.minimizable !== undefined\n ? { minimizable: window.minimizable }\n : {}),\n ...(window.pinnable !== undefined ? { pinnable: window.pinnable } : {}),\n });\n })\n .catch((error) => {\n console.error(`[uix] failed to load panel \"${window.id}\":`, error);\n });\n }\n\n // --- Regions --------------------------------------------------------------\n\n /** Create a dock region anchored in the scene. */\n createRegion(options: CreateRegionOptions): RegionHandle {\n const { id, position, follow, followOffset, ...definition } = options;\n this.regions.register(id, definition);\n\n const group = new Group();\n group.name = `uix-region:${id}`;\n if (position) {\n group.position.set(...position);\n }\n this.scene.add(group);\n\n const handle: RegionHandle = { id, group };\n this.regionStates.set(id, {\n handle,\n follow: follow ?? false,\n followOffset: followOffset ?? DEFAULT_REGION_FOLLOW_OFFSET,\n });\n return handle;\n }\n\n region(id: string): RegionHandle | undefined {\n return this.regionStates.get(id)?.handle;\n }\n\n /** Dock a window into a region (or undock it with `undefined`). */\n dock(windowId: string, regionId: string | undefined): void {\n if (regionId === undefined) {\n this.regions.undock(windowId);\n } else {\n this.regions.dock(windowId, regionId);\n this.manager.setDockMode(windowId, DockMode.WorldLocked);\n }\n this.layoutRegions();\n }\n\n // --- Windows --------------------------------------------------------------\n\n /** Spawn a managed window from compiled UIKitML JSON. */\n createWindow(options: CreateWindowOptions): WindowHandle {\n const document = new UixPanelDocument(options.config, this.kit);\n document.setTargetDimensions(options.maxWidth ?? 1, options.maxHeight ?? 1);\n\n const group = new Group();\n group.name = `uix-window:${options.id}`;\n group.add(document);\n if (options.position) {\n group.position.set(...options.position);\n }\n this.scene.add(group);\n\n const handle: WindowHandle = { id: options.id, group, document };\n this.states.set(options.id, {\n handle,\n options: {\n followOffset: options.followOffset ?? DEFAULT_FOLLOW_OFFSET,\n followSpeed: options.followSpeed ?? 3,\n followTolerance: options.followTolerance ?? 0.35,\n },\n content: undefined,\n pin: undefined,\n minimize: undefined,\n });\n\n this.manager.open(options.id, {\n title: options.title ?? '',\n dockMode: options.dockMode ?? DockMode.WorldLocked,\n });\n this.wireChrome(options, handle);\n\n if (options.region !== undefined) {\n this.dock(options.id, options.region);\n }\n\n // The panel's element tree exists synchronously (uikitml interprets on\n // construction); only its LAYOUT is async. Announce readiness now so\n // wiring can attach handlers immediately.\n const event: PanelReadyEvent = { id: options.id, panel: handle.document };\n this.ready.set(options.id, event);\n for (const listener of this.readyListeners) {\n try {\n listener(event);\n } catch (error) {\n console.error(`[uix] panel-ready listener failed for \"${options.id}\":`, error);\n }\n }\n\n return handle;\n }\n\n window(id: string): WindowHandle | undefined {\n return this.states.get(id)?.handle;\n }\n\n /** Drive per-frame from the engine loop (delta in SECONDS). */\n update(deltaSeconds: number): void {\n for (const [id, state] of this.states) {\n state.handle.document.update(deltaSeconds);\n const record = this.manager.get(id);\n const docked = this.regions.regionOf(id) !== undefined;\n if (\n record &&\n record.dockMode === DockMode.BodyFollow &&\n !record.dragging &&\n !docked\n ) {\n this.applyFollow(state.handle.group, state.options, deltaSeconds, true);\n }\n }\n for (const state of this.regionStates.values()) {\n if (state.follow) {\n this.applyFollow(\n state.handle.group,\n {\n followOffset: state.followOffset,\n followSpeed: 3,\n followTolerance: 0.2,\n },\n deltaSeconds,\n false,\n );\n this.layoutRegion(state.handle.id);\n }\n }\n }\n\n private applyFollow(\n group: Group,\n options: FollowOptions,\n deltaSeconds: number,\n faceViewer: boolean,\n ): void {\n const pose = this.headPose.getHeadPose();\n const target = followTarget(pose, options.followOffset);\n const position = group.position;\n const current: Vec3Tuple = [position.x, position.y, position.z];\n const tolerance = options.followTolerance;\n if (distanceSquared(current, target) <= tolerance * tolerance) {\n return;\n }\n const next = approach(\n current,\n target,\n approachAlpha(options.followSpeed, deltaSeconds),\n );\n position.set(...next);\n if (faceViewer) {\n group.lookAt(pose.position[0], position.y, pose.position[2]);\n }\n }\n\n /** Re-place every docked window into its region's slot. */\n private layoutRegions(): void {\n for (const id of this.regionStates.keys()) {\n this.layoutRegion(id);\n }\n }\n\n private layoutRegion(regionId: string): void {\n const regionState = this.regionStates.get(regionId);\n const registered = this.regions.get(regionId);\n if (!regionState || !registered) {\n return;\n }\n const origin = regionState.handle.group.position;\n registered.members.forEach((windowId, index) => {\n const windowState = this.states.get(windowId);\n if (!windowState) {\n return;\n }\n const [dx, dy, dz] = slotOffset(registered.definition, index);\n windowState.handle.group.position.set(\n origin.x + dx,\n origin.y + dy,\n origin.z + dz,\n );\n windowState.handle.group.quaternion.copy(regionState.handle.group.quaternion);\n });\n }\n\n private wireChrome(options: CreateWindowOptions, handle: WindowHandle): void {\n const element = (id: string) => handle.document.getElementById(id);\n const id = options.id;\n\n const title = element(WINDOW_CHROME_IDS.title);\n if (title && options.title) {\n title.setProperties({ text: options.title });\n }\n\n // Chrome presses must not bubble to the window root's focus handler:\n // a press on CLOSE would otherwise focus a window that is about to be\n // destroyed, and `focus()` on a removed window throws. (Same guard the\n // IWSDK adapter applies.)\n const swallowPress = (button: UixElement | undefined): void => {\n button?.addEventListener('pointerdown', (event) => {\n (event as { stopPropagation?: () => void } | undefined)?.stopPropagation?.();\n });\n };\n swallowPress(element(WINDOW_CHROME_IDS.pin));\n swallowPress(element(WINDOW_CHROME_IDS.dock));\n swallowPress(element(WINDOW_CHROME_IDS.minimize));\n swallowPress(element(WINDOW_CHROME_IDS.close));\n\n // Any press anywhere on the window brings it to the front. Guarded:\n // events can still arrive for a window that was just closed.\n element(WINDOW_CHROME_IDS.window)?.addEventListener('pointerdown', () => {\n if (this.manager.has(id)) {\n this.manager.focus(id);\n }\n });\n\n const close = element(WINDOW_CHROME_IDS.close);\n if (options.closable === false) {\n close?.setProperties({ display: 'none' });\n } else {\n close?.addEventListener('click', () => {\n if (this.manager.has(id)) {\n this.manager.close(id);\n }\n });\n }\n\n const minimize = element(WINDOW_CHROME_IDS.minimize);\n if (options.minimizable === false) {\n minimize?.setProperties({ display: 'none' });\n } else {\n minimize?.addEventListener('click', () => {\n if (this.manager.has(id)) {\n this.manager.toggleMinimized(id);\n }\n });\n this.syncMinimizeLabel(id);\n }\n\n const pin = element(WINDOW_CHROME_IDS.pin);\n const state = this.states.get(id);\n if (state) {\n state.content = element(WINDOW_CHROME_IDS.content);\n state.pin = pin;\n state.minimize = element(WINDOW_CHROME_IDS.minimize);\n }\n if (options.pinnable === false) {\n pin?.setProperties({ display: 'none' });\n } else {\n pin?.addEventListener('click', () => {\n if (!this.manager.has(id)) {\n return;\n }\n // Pinning a docked window pops it out of its region first.\n if (this.regions.regionOf(id) !== undefined) {\n this.regions.undock(id);\n }\n this.manager.togglePin(id);\n });\n this.syncPinLabel(id);\n }\n }\n\n private setContentCollapsed(id: string, collapsed: boolean): void {\n this.states\n .get(id)\n ?.content?.setProperties({ display: collapsed ? 'none' : 'flex' });\n }\n\n /** MIN when open, MAX when minimized - the label names the next action. */\n private syncMinimizeLabel(id: string): void {\n const record = this.manager.get(id);\n const minimize = this.states.get(id)?.minimize;\n if (record && minimize) {\n minimize.setProperties({ text: minimizeLabelFor(record) });\n }\n }\n\n private syncPinLabel(id: string): void {\n const record = this.manager.get(id);\n const pin = this.states.get(id)?.pin;\n if (record && pin) {\n pin.setProperties({ text: pinLabelFor(record) });\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"host.js","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * UixWindowHost - the engine binding for plain three.js / XR Blocks scenes.\n *\n * Owns a core `WindowManager` + `RegionRegistry` and applies their decisions\n * to the scene graph: spawn UIKitML windows and dock regions, wire chrome\n * buttons (focus / PIN / MIN / X), collapse content while minimized, place\n * docked windows into their region's slots, and ease `body-follow` windows\n * (and body-locked regions) toward the viewer each frame.\n *\n * It implements the core's `WindowHost` (so app code can wire behaviour\n * through `onPanelReady` with no engine knowledge) and `SceneTarget` (so a\n * portable `SceneDescriptor` builds the same playground here as on IWSDK).\n */\nimport { Group, type Object3D } from 'three';\nimport { parse, type Kit } from '@pmndrs/uikitml';\n\n/**\n * Default `config` resolver: fetch UIKitML source and parse it.\n *\n * IWSDK 0.5 dropped the build-time compile step and parses `PanelUI.config`\n * as source at runtime, so descriptors carry `.uikitml` paths. This parses the\n * same file for the three.js and XR Blocks hosts, which interpret an AST.\n */\nasync function loadUikitmlSource(path: string): Promise<unknown> {\n const response = await fetch(path);\n if (!response.ok) {\n throw new Error(`UIKitML source ${path} -> HTTP ${response.status}`);\n }\n return parse(await response.text());\n}\nimport {\n DockMode,\n RegionRegistry,\n WINDOW_CHROME_IDS,\n WindowManager,\n minimizeLabelFor,\n pinLabelFor,\n slotOffset,\n type HeadPoseSource,\n type PanelHandle,\n type PanelReadyEvent,\n type RegionDefinition,\n type SceneRegion,\n type SceneTarget,\n type SceneWindow,\n type UixElement,\n type Vec3Tuple,\n type WindowHandle as CoreWindowHandle,\n type WindowHost,\n type WindowOptionsBase,\n} from '@realitycollective/webxr-uiextensions';\nimport {\n approach,\n approachAlpha,\n distanceSquared,\n followTarget,\n} from './follow-math.js';\nimport { UixPanelDocument } from './panel-document.js';\n\n/**\n * Options for {@link UixWindowHost.createWindow}.\n *\n * Everything but `config` comes from the portable {@link WindowOptionsBase},\n * so an option means the same thing here as on the IWSDK adapter. `id` is\n * optional: leave it out and the host names the window `uix-window-<n>`.\n *\n * One option is accepted but not acted on: `movable`. This host has no\n * title-bar drag of its own yet - dragging comes from the XR Blocks / desktop\n * input layer above it - so the flag is recorded and otherwise ignored.\n */\nexport interface CreateWindowOptions extends WindowOptionsBase {\n /** Compiled UIKitML JSON (the `{ element, classes }` shape). */\n config: unknown;\n}\n\nexport interface CreateRegionOptions extends Partial<RegionDefinition> {\n id: string;\n position?: Vec3Tuple;\n /** Body-lock the region so it follows the viewer. */\n follow?: boolean;\n followOffset?: Vec3Tuple;\n}\n\n/**\n * A window spawned by {@link UixWindowHost.createWindow}.\n *\n * Satisfies the core {@link CoreWindowHandle} and adds the three.js specifics.\n * `panel` is the document itself, which already implements `PanelHandle`, and\n * is never `undefined` here: uikitml interprets the markup synchronously, so\n * the panel exists the moment `createWindow` returns.\n */\nexport interface XrBlocksWindowHandle extends CoreWindowHandle {\n readonly id: string;\n /** The scene-graph node - position/rotate freely. */\n group: Group;\n document: UixPanelDocument;\n /** Same object as {@link document}, under the portable name. */\n readonly panel: UixPanelDocument;\n onReady(listener: (panel: PanelHandle) => void): () => void;\n}\n\n/** Back-compatible name for {@link XrBlocksWindowHandle}. */\nexport type WindowHandle = XrBlocksWindowHandle;\n\nexport interface RegionHandle {\n id: string;\n group: Group;\n}\n\nexport interface UixWindowHostOptions {\n /** Parent for spawned windows (the scene, or any group inside it). */\n scene: Object3D;\n /** Viewer pose provider - camera on desktop, HMD pose in XR. */\n headPose: HeadPoseSource;\n /** Optional UIKitML component kit(s) (e.g. horizon kit). */\n kit?: Kit;\n /**\n * Resolver for a window's `config` when it arrives as a string path (as\n * portable `SceneDescriptor`s carry it).\n *\n * Defaults to fetching the `.uikitml` source and parsing it, which is the\n * same artefact IWSDK loads - so one markup file serves every adapter and\n * no build step is required. Override only for an unusual transport; you do\n * not need to supply this to load a normal panel.\n */\n loadConfig?: (path: string) => Promise<unknown>;\n}\n\ninterface FollowOptions {\n followOffset: Vec3Tuple;\n followSpeed: number;\n followTolerance: number;\n}\n\ninterface WindowState {\n handle: XrBlocksWindowHandle;\n /**\n * Recorded from the create options and not acted on - see\n * {@link CreateWindowOptions}. Kept so a future drag path here, or a caller\n * inspecting the host, reads the value the scene descriptor asked for.\n */\n movable: boolean;\n options: FollowOptions;\n content: UixElement | undefined;\n pin: UixElement | undefined;\n minimize: UixElement | undefined;\n}\n\ninterface RegionState {\n handle: RegionHandle;\n follow: boolean;\n followOffset: Vec3Tuple;\n}\n\nconst DEFAULT_FOLLOW_OFFSET: Vec3Tuple = [0, -0.15, -1.2];\nconst DEFAULT_REGION_FOLLOW_OFFSET: Vec3Tuple = [0, -0.2, -1.4];\n\nexport class UixWindowHost implements WindowHost, SceneTarget {\n /** Bare panels work here - the host does not own a panel lifecycle. */\n readonly supportsStandalonePanels: boolean = true;\n readonly manager = new WindowManager();\n readonly regions = new RegionRegistry();\n private readonly scene: Object3D;\n private readonly headPose: HeadPoseSource;\n private readonly kit: Kit | undefined;\n private readonly loadConfig: (path: string) => Promise<unknown>;\n private readonly states = new Map<string, WindowState>();\n private readonly regionStates = new Map<string, RegionState>();\n private readonly readyListeners = new Set<(event: PanelReadyEvent) => void>();\n /** Panels already live - replayed to late `onPanelReady` subscribers. */\n private readonly ready = new Map<string, PanelReadyEvent>();\n /** Feeds `uix-window-<n>` ids to windows created without one. */\n private windowSequence = 0;\n\n constructor(options: UixWindowHostOptions) {\n this.scene = options.scene;\n this.headPose = options.headPose;\n this.kit = options.kit;\n this.loadConfig = options.loadConfig ?? loadUikitmlSource;\n\n this.manager.events.on('closed', (record) => {\n const state = this.states.get(record.id);\n if (state) {\n this.states.delete(record.id);\n this.ready.delete(record.id);\n this.regions.undock(record.id);\n state.handle.document.dispose();\n state.handle.group.removeFromParent();\n this.layoutRegions();\n }\n });\n this.manager.events.on('minimized', (record) => {\n this.setContentCollapsed(record.id, true);\n this.syncMinimizeLabel(record.id);\n });\n this.manager.events.on('restored', (record) => {\n this.setContentCollapsed(record.id, false);\n this.syncMinimizeLabel(record.id);\n });\n this.manager.events.on('dockChanged', ({ window }) => {\n this.syncPinLabel(window.id);\n });\n }\n\n // --- WindowHost -----------------------------------------------------------\n\n /**\n * PanelHost - bare panel, unmanaged (used by devtools and tests). Always\n * available here, which is what `supportsStandalonePanels` reports.\n */\n createPanel(configJson: unknown): UixPanelDocument {\n return new UixPanelDocument(configJson, this.kit);\n }\n\n /**\n * Observe panel readiness. Windows already live are replayed immediately,\n * so wiring code never races window creation.\n */\n onPanelReady(listener: (event: PanelReadyEvent) => void): () => void {\n this.readyListeners.add(listener);\n for (const event of this.ready.values()) {\n listener(event);\n }\n return () => void this.readyListeners.delete(listener);\n }\n\n // --- SceneTarget (portable scene descriptors) -----------------------------\n\n spawnRegion(region: SceneRegion): void {\n this.createRegion({\n id: region.id,\n ...(region.flow !== undefined ? { flow: region.flow } : {}),\n ...(region.pitch !== undefined ? { pitch: region.pitch } : {}),\n ...(region.columns !== undefined ? { columns: region.columns } : {}),\n ...(region.capacity !== undefined ? { capacity: region.capacity } : {}),\n ...(region.snapRadius !== undefined ? { snapRadius: region.snapRadius } : {}),\n ...(region.position !== undefined\n ? { position: [...region.position] as Vec3Tuple }\n : {}),\n ...(region.follow !== undefined ? { follow: region.follow } : {}),\n ...(region.followOffset !== undefined\n ? { followOffset: [...region.followOffset] as Vec3Tuple }\n : {}),\n });\n }\n\n /**\n * Scene descriptors carry config PATHS; this resolves the path and spawns\n * the window when it arrives. Fire-and-forget by design - subscribe with\n * {@link onPanelReady} to wire behaviour once the panel exists.\n */\n spawnWindow(window: SceneWindow): void {\n void this.loadConfig(window.config)\n .then((config) => {\n this.createWindow({\n id: window.id,\n config,\n title: window.title,\n ...(window.position !== undefined\n ? { position: [...window.position] as Vec3Tuple }\n : {}),\n ...(window.maxWidth !== undefined ? { maxWidth: window.maxWidth } : {}),\n ...(window.maxHeight !== undefined ? { maxHeight: window.maxHeight } : {}),\n ...(window.dockMode !== undefined ? { dockMode: window.dockMode } : {}),\n ...(window.region !== undefined ? { region: window.region } : {}),\n ...(window.followOffset !== undefined\n ? { followOffset: [...window.followOffset] as Vec3Tuple }\n : {}),\n ...(window.followSpeed !== undefined\n ? { followSpeed: window.followSpeed }\n : {}),\n ...(window.followTolerance !== undefined\n ? { followTolerance: window.followTolerance }\n : {}),\n ...(window.movable !== undefined ? { movable: window.movable } : {}),\n ...(window.closable !== undefined ? { closable: window.closable } : {}),\n ...(window.minimizable !== undefined\n ? { minimizable: window.minimizable }\n : {}),\n ...(window.pinnable !== undefined ? { pinnable: window.pinnable } : {}),\n });\n })\n .catch((error) => {\n console.error(`[uix] failed to load panel \"${window.id}\":`, error);\n });\n }\n\n // --- Regions --------------------------------------------------------------\n\n /** Create a dock region anchored in the scene. */\n createRegion(options: CreateRegionOptions): RegionHandle {\n const { id, position, follow, followOffset, ...definition } = options;\n this.regions.register(id, definition);\n\n const group = new Group();\n group.name = `uix-region:${id}`;\n if (position) {\n group.position.set(...position);\n }\n this.scene.add(group);\n\n const handle: RegionHandle = { id, group };\n this.regionStates.set(id, {\n handle,\n follow: follow ?? false,\n followOffset: followOffset ?? DEFAULT_REGION_FOLLOW_OFFSET,\n });\n return handle;\n }\n\n region(id: string): RegionHandle | undefined {\n return this.regionStates.get(id)?.handle;\n }\n\n /** Dock a window into a region (or undock it with `undefined`). */\n dock(windowId: string, regionId: string | undefined): void {\n if (regionId === undefined) {\n this.regions.undock(windowId);\n } else {\n this.regions.dock(windowId, regionId);\n this.manager.setDockMode(windowId, DockMode.WorldLocked);\n }\n this.layoutRegions();\n }\n\n // --- Windows --------------------------------------------------------------\n\n /** Spawn a managed window from compiled UIKitML JSON. */\n createWindow(options: CreateWindowOptions): XrBlocksWindowHandle {\n const id = options.id ?? `uix-window-${(this.windowSequence += 1)}`;\n const document = new UixPanelDocument(options.config, this.kit);\n document.setTargetDimensions(options.maxWidth ?? 1, options.maxHeight ?? 1);\n\n const group = new Group();\n group.name = `uix-window:${id}`;\n group.add(document);\n if (options.position) {\n group.position.set(...options.position);\n }\n this.scene.add(group);\n\n const handle: XrBlocksWindowHandle = {\n id,\n group,\n document,\n panel: document,\n // The panel exists already, so readiness is immediate. The unsubscribe\n // is returned anyway, so callers can write one shape of code for both\n // adapters.\n onReady(listener: (panel: PanelHandle) => void): () => void {\n listener(document);\n return () => {};\n },\n };\n this.states.set(id, {\n handle,\n movable: options.movable ?? true,\n options: {\n followOffset: options.followOffset ?? DEFAULT_FOLLOW_OFFSET,\n followSpeed: options.followSpeed ?? 3,\n followTolerance: options.followTolerance ?? 0.35,\n },\n content: undefined,\n pin: undefined,\n minimize: undefined,\n });\n\n this.manager.open(id, {\n title: options.title ?? '',\n dockMode: options.dockMode ?? DockMode.WorldLocked,\n });\n this.wireChrome(options, handle);\n\n if (options.region !== undefined) {\n this.dock(id, options.region);\n }\n\n // The panel's element tree exists synchronously (uikitml interprets on\n // construction); only its LAYOUT is async. Announce readiness now so\n // wiring can attach handlers immediately.\n const event: PanelReadyEvent = { id, panel: document, kind: 'window' };\n this.ready.set(id, event);\n for (const listener of this.readyListeners) {\n try {\n listener(event);\n } catch (error) {\n console.error(`[uix] panel-ready listener failed for \"${id}\":`, error);\n }\n }\n\n return handle;\n }\n\n window(id: string): XrBlocksWindowHandle | undefined {\n return this.states.get(id)?.handle;\n }\n\n /** Drive per-frame from the engine loop (delta in SECONDS). */\n update(deltaSeconds: number): void {\n for (const [id, state] of this.states) {\n state.handle.document.update(deltaSeconds);\n const record = this.manager.get(id);\n const docked = this.regions.regionOf(id) !== undefined;\n if (\n record &&\n record.dockMode === DockMode.BodyFollow &&\n !record.dragging &&\n !docked\n ) {\n this.applyFollow(state.handle.group, state.options, deltaSeconds, true);\n }\n }\n for (const state of this.regionStates.values()) {\n if (state.follow) {\n this.applyFollow(\n state.handle.group,\n {\n followOffset: state.followOffset,\n followSpeed: 3,\n followTolerance: 0.2,\n },\n deltaSeconds,\n false,\n );\n this.layoutRegion(state.handle.id);\n }\n }\n }\n\n private applyFollow(\n group: Group,\n options: FollowOptions,\n deltaSeconds: number,\n faceViewer: boolean,\n ): void {\n const pose = this.headPose.getHeadPose();\n const target = followTarget(pose, options.followOffset);\n const position = group.position;\n const current: Vec3Tuple = [position.x, position.y, position.z];\n const tolerance = options.followTolerance;\n if (distanceSquared(current, target) <= tolerance * tolerance) {\n return;\n }\n const next = approach(\n current,\n target,\n approachAlpha(options.followSpeed, deltaSeconds),\n );\n position.set(...next);\n if (faceViewer) {\n group.lookAt(pose.position[0], position.y, pose.position[2]);\n }\n }\n\n /** Re-place every docked window into its region's slot. */\n private layoutRegions(): void {\n for (const id of this.regionStates.keys()) {\n this.layoutRegion(id);\n }\n }\n\n private layoutRegion(regionId: string): void {\n const regionState = this.regionStates.get(regionId);\n const registered = this.regions.get(regionId);\n if (!regionState || !registered) {\n return;\n }\n const origin = regionState.handle.group.position;\n registered.members.forEach((windowId, index) => {\n const windowState = this.states.get(windowId);\n if (!windowState) {\n return;\n }\n const [dx, dy, dz] = slotOffset(registered.definition, index);\n windowState.handle.group.position.set(\n origin.x + dx,\n origin.y + dy,\n origin.z + dz,\n );\n windowState.handle.group.quaternion.copy(regionState.handle.group.quaternion);\n });\n }\n\n private wireChrome(\n options: CreateWindowOptions,\n handle: XrBlocksWindowHandle,\n ): void {\n const element = (id: string) => handle.document.getElementById(id);\n const id = handle.id;\n\n const title = element(WINDOW_CHROME_IDS.title);\n if (title && options.title) {\n title.setProperties({ text: options.title });\n }\n\n // Chrome presses must not bubble to the window root's focus handler:\n // a press on CLOSE would otherwise focus a window that is about to be\n // destroyed, and `focus()` on a removed window throws. (Same guard the\n // IWSDK adapter applies.)\n const swallowPress = (button: UixElement | undefined): void => {\n button?.addEventListener('pointerdown', (event) => {\n (event as { stopPropagation?: () => void } | undefined)?.stopPropagation?.();\n });\n };\n swallowPress(element(WINDOW_CHROME_IDS.pin));\n swallowPress(element(WINDOW_CHROME_IDS.dock));\n swallowPress(element(WINDOW_CHROME_IDS.minimize));\n swallowPress(element(WINDOW_CHROME_IDS.close));\n\n // Any press anywhere on the window brings it to the front. Guarded:\n // events can still arrive for a window that was just closed.\n element(WINDOW_CHROME_IDS.window)?.addEventListener('pointerdown', () => {\n if (this.manager.has(id)) {\n this.manager.focus(id);\n }\n });\n\n const close = element(WINDOW_CHROME_IDS.close);\n if (options.closable === false) {\n close?.setProperties({ display: 'none' });\n } else {\n close?.addEventListener('click', () => {\n if (this.manager.has(id)) {\n this.manager.close(id);\n }\n });\n }\n\n const minimize = element(WINDOW_CHROME_IDS.minimize);\n if (options.minimizable === false) {\n minimize?.setProperties({ display: 'none' });\n } else {\n minimize?.addEventListener('click', () => {\n if (this.manager.has(id)) {\n this.manager.toggleMinimized(id);\n }\n });\n this.syncMinimizeLabel(id);\n }\n\n const pin = element(WINDOW_CHROME_IDS.pin);\n const state = this.states.get(id);\n if (state) {\n state.content = element(WINDOW_CHROME_IDS.content);\n state.pin = pin;\n state.minimize = element(WINDOW_CHROME_IDS.minimize);\n }\n if (options.pinnable === false) {\n pin?.setProperties({ display: 'none' });\n } else {\n pin?.addEventListener('click', () => {\n if (!this.manager.has(id)) {\n return;\n }\n // Pinning a docked window pops it out of its region first.\n if (this.regions.regionOf(id) !== undefined) {\n this.regions.undock(id);\n }\n this.manager.togglePin(id);\n });\n this.syncPinLabel(id);\n }\n }\n\n private setContentCollapsed(id: string, collapsed: boolean): void {\n this.states\n .get(id)\n ?.content?.setProperties({ display: collapsed ? 'none' : 'flex' });\n }\n\n /** MIN when open, MAX when minimized - the label names the next action. */\n private syncMinimizeLabel(id: string): void {\n const record = this.manager.get(id);\n const minimize = this.states.get(id)?.minimize;\n if (record && minimize) {\n minimize.setProperties({ text: minimizeLabelFor(record) });\n }\n }\n\n private syncPinLabel(id: string): void {\n const record = this.manager.get(id);\n const pin = this.states.get(id)?.pin;\n if (record && pin) {\n pin.setProperties({ text: pinLabelFor(record) });\n }\n }\n}\n"]}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,sEAAsE;AACtE,cAAc,uCAAuC,CAAC;AAEtD,+BAA+B;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,WAAW,CAAC;AAC1B,cAAc,sBAAsB,CAAC;AACrC,cAAc,eAAe,CAAC;AAE9B,qCAAqC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC","sourcesContent":["/**\n * @realitycollective/xrblocks-uiextensions - EXPERIMENTAL Google XR Blocks /\n * plain three.js adapter for the Reality Collective UI Extensions.\n *\n * Binds the engine-free `@realitycollective/webxr-uiextensions` core to any\n * three.js WebXR scene graph - which is exactly what an XR Blocks Script\n * provides. See the README for the current feature matrix versus the IWSDK\n * adapter.\n */\n// The portable core - re-exported for a single-dependency experience.\nexport * from '@realitycollective/webxr-uiextensions';\n\n// three.js / XR Blocks binding\nexport * from './renderer-setup.js';\nexport * from './scale-math.js';\nexport * from './follow-math.js';\nexport * from './panel-document.js';\nexport * from './host.js';\nexport * from './pointer-forward.js';\nexport * from './xrblocks.js';\n\n// Desktop (mouse + keyboard) support\nexport * from './desktop-locomotion.js';\nexport * from './desktop-controls.js';\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,sEAAsE;AACtE,cAAc,uCAAuC,CAAC;AAEtD,+BAA+B;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,WAAW,CAAC;AAC1B,cAAc,sBAAsB,CAAC;AACrC,cAAc,eAAe,CAAC;AAE9B,qCAAqC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC","sourcesContent":["/**\n * @realitycollective/xrblocks-uiextensions - EXPERIMENTAL Google XR Blocks /\n * plain three.js adapter for the Reality Collective UI Extensions.\n *\n * Binds the engine-free `@realitycollective/webxr-uiextensions` core to any\n * three.js WebXR scene graph - which is exactly what an XR Blocks Script\n * provides. See the README for the current feature matrix versus the IWSDK\n * adapter.\n */\n// The portable core - re-exported for a single-dependency experience.\nexport * from '@realitycollective/webxr-uiextensions';\n\n// three.js / XR Blocks binding\nexport * from './renderer-setup.js';\nexport * from './scale-math.js';\nexport * from './follow-math.js';\nexport * from './panel-document.js';\nexport * from './host.js';\nexport * from './pointer-forward.js';\nexport * from './xrblocks.js';\n\n// Desktop (mouse + keyboard) support\nexport * from './desktop-locomotion.js';\nexport * from './desktop-controls.js';\n\n// `WindowHandle` is declared twice above - once as the core's portable\n// interface, once as this host's richer handle. Name the winner explicitly,\n// or both star exports drop it. The host's handle satisfies the core one, so\n// code written against either keeps compiling.\nexport type { XrBlocksWindowHandle as WindowHandle } from './host.js';\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@realitycollective/xrblocks-uiextensions",
|
|
3
|
-
"version": "0.1.0-preview.
|
|
3
|
+
"version": "0.1.0-preview.2",
|
|
4
4
|
"description": "EXPERIMENTAL Google XR Blocks / plain three.js adapter for the Reality Collective UI Extensions - hosts the engine-free @realitycollective/webxr-uiextensions windowing core (UIKitML panels, window chrome, follow mode) in any three.js WebXR scene, including XR Blocks Scripts.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"realitycollective",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@pmndrs/uikitml": "^0.1.12",
|
|
39
|
-
"@realitycollective/webxr-uiextensions": "^0.1.0-preview.
|
|
39
|
+
"@realitycollective/webxr-uiextensions": "^0.1.0-preview.2"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
42
|
"three": ">=0.170.0"
|