@vgai/engine 0.5.21 → 0.5.23
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/README.md +6 -3
- package/dist/adapter/adapter-module.d.ts.map +1 -1
- package/dist/adapter/adapter-module.js +2 -4
- package/dist/adapter/adapter-surface.d.ts +1 -1
- package/dist/adapter/adapter-surface.js +1 -1
- package/dist/adapter/authoring.d.ts +19 -21
- package/dist/adapter/authoring.d.ts.map +1 -1
- package/dist/adapter/authoring.js +2 -2
- package/dist/adapter/binding.d.ts +341 -0
- package/dist/adapter/binding.d.ts.map +1 -0
- package/dist/adapter/binding.js +148 -0
- package/dist/adapter/colyseus-networking-adapter.d.ts.map +1 -1
- package/dist/adapter/colyseus-networking-adapter.js +23 -4
- package/dist/adapter/entrypoint-selection-readers.d.ts +24 -0
- package/dist/adapter/entrypoint-selection-readers.d.ts.map +1 -0
- package/dist/adapter/entrypoint-selection-readers.js +63 -0
- package/dist/adapter/entrypoint-selection-source.d.ts.map +1 -1
- package/dist/adapter/entrypoint-selection-source.js +1 -44
- package/dist/adapter/finders/scenes-from-entrypoint-selection.d.ts.map +1 -1
- package/dist/adapter/finders/scenes-from-entrypoint-selection.js +1 -52
- package/dist/adapter/host-context.d.ts +46 -15
- package/dist/adapter/host-context.d.ts.map +1 -1
- package/dist/adapter/host-context.js +2 -9
- package/dist/adapter/index.d.ts +11 -12
- package/dist/adapter/index.d.ts.map +1 -1
- package/dist/adapter/index.js +9 -10
- package/dist/adapter/ingest/game-contract.d.ts +0 -3
- package/dist/adapter/ingest/game-contract.d.ts.map +1 -1
- package/dist/adapter/ingest/game-contract.js +0 -3
- package/dist/adapter/ingest/scene-capture.d.ts +19 -23
- package/dist/adapter/ingest/scene-capture.d.ts.map +1 -1
- package/dist/adapter/ingest/scene-capture.js +143 -17
- package/dist/adapter/ingest/visible-capture-window.d.ts +34 -0
- package/dist/adapter/ingest/visible-capture-window.d.ts.map +1 -1
- package/dist/adapter/manifest-interpreter.d.ts +59 -0
- package/dist/adapter/manifest-interpreter.d.ts.map +1 -0
- package/dist/adapter/manifest-interpreter.js +50 -0
- package/dist/adapter/native-debug-module.d.ts +71 -3
- package/dist/adapter/native-debug-module.d.ts.map +1 -1
- package/dist/adapter/native-debug-module.js +146 -10
- package/dist/adapter/rapier-physics-adapter.d.ts +31 -1
- package/dist/adapter/rapier-physics-adapter.d.ts.map +1 -1
- package/dist/adapter/rapier-physics-adapter.js +50 -36
- package/dist/adapter/renderer-config.d.ts +3 -3
- package/dist/adapter/renderer-config.js +3 -3
- package/dist/adapter/root-adapter.d.ts +7 -7
- package/dist/adapter/root-adapter.js +4 -4
- package/dist/adapter/system-adapter.d.ts +45 -7
- package/dist/adapter/system-adapter.d.ts.map +1 -1
- package/dist/adapter/system-seam-contract.d.ts +3 -3
- package/dist/adapter/system-seam-contract.js +3 -3
- package/dist/adapter/system-slot.d.ts +168 -0
- package/dist/adapter/system-slot.d.ts.map +1 -0
- package/dist/adapter/system-slot.js +229 -0
- package/dist/adapter/transform.d.ts +11 -1
- package/dist/adapter/transform.d.ts.map +1 -1
- package/dist/ai/navigation.d.ts +17 -1
- package/dist/ai/navigation.d.ts.map +1 -1
- package/dist/ai/navigation.js +26 -5
- package/dist/animation/anim-graph-types.d.ts +11 -3
- package/dist/animation/anim-graph-types.d.ts.map +1 -1
- package/dist/animation/theatre-clock-binding.d.ts +4 -4
- package/dist/animation/theatre-clock-binding.js +4 -4
- package/dist/animation/xstate-animation-binding.d.ts.map +1 -1
- package/dist/animation/xstate-animation-binding.js +2 -2
- package/dist/animation/xstate-animation-meta.d.ts +13 -0
- package/dist/animation/xstate-animation-meta.d.ts.map +1 -1
- package/dist/animation/xstate-animation-meta.js +14 -0
- package/dist/asset-formats/index.d.ts +4 -7
- package/dist/asset-formats/index.d.ts.map +1 -1
- package/dist/asset-formats/index.js +4 -7
- package/dist/asset-formats/render-env.d.ts +5 -8
- package/dist/asset-formats/render-env.d.ts.map +1 -1
- package/dist/asset-formats/render-env.js +3 -6
- package/dist/asset-parse-error.d.ts +2 -5
- package/dist/asset-parse-error.d.ts.map +1 -1
- package/dist/asset-parse-error.js +2 -5
- package/dist/audio/bus-mixer.d.ts +101 -0
- package/dist/audio/bus-mixer.d.ts.map +1 -0
- package/dist/audio/bus-mixer.js +115 -0
- package/dist/canvas-react/index.d.ts +5 -12
- package/dist/canvas-react/index.d.ts.map +1 -1
- package/dist/canvas-react/index.js +5 -12
- package/dist/canvas-react/pixi-react-root-factory.d.ts +34 -21
- package/dist/canvas-react/pixi-react-root-factory.d.ts.map +1 -1
- package/dist/canvas-react/pixi-react-root-factory.js +274 -36
- package/dist/core/countdown-timer.d.ts +118 -0
- package/dist/core/countdown-timer.d.ts.map +1 -0
- package/dist/core/countdown-timer.js +137 -0
- package/dist/core/deferred-commands.d.ts +127 -0
- package/dist/core/deferred-commands.d.ts.map +1 -0
- package/dist/core/deferred-commands.js +132 -0
- package/dist/core/frame-pacing.d.ts +1 -1
- package/dist/core/frame-pacing.js +2 -2
- package/dist/core/game-loop.d.ts +1 -3
- package/dist/core/game-loop.d.ts.map +1 -1
- package/dist/core/game-loop.js +1 -3
- package/dist/core/seeded-random.d.ts +1 -1
- package/dist/core/sim-clock.d.ts +19 -8
- package/dist/core/sim-clock.d.ts.map +1 -1
- package/dist/core/sim-clock.js +18 -7
- package/dist/core/types.d.ts +1 -3
- package/dist/core/types.d.ts.map +1 -1
- package/dist/defaults.d.ts +6 -14
- package/dist/defaults.d.ts.map +1 -1
- package/dist/defaults.js +6 -14
- package/dist/dev/instruments.d.ts +38 -11
- package/dist/dev/instruments.d.ts.map +1 -1
- package/dist/dev/instruments.js +81 -11
- package/dist/dev/register-render-vitals.d.ts +1 -4
- package/dist/dev/register-render-vitals.d.ts.map +1 -1
- package/dist/dev/register-render-vitals.js +1 -4
- package/dist/dev/render-debug-adapter.d.ts +2 -3
- package/dist/dev/render-debug-adapter.d.ts.map +1 -1
- package/dist/dev/render-debug-adapter.js +2 -3
- package/dist/dev/render-vitals.d.ts +3 -3
- package/dist/dev/render-vitals.js +3 -3
- package/dist/dev/webgl-frame-capture.d.ts +1 -1
- package/dist/dev/webgl-frame-capture.js +1 -1
- package/dist/index.d.ts +2 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -4
- package/dist/input/host-pointer.d.ts +122 -0
- package/dist/input/host-pointer.d.ts.map +1 -0
- package/dist/input/host-pointer.js +160 -0
- package/dist/input/input-manager.d.ts +33 -5
- package/dist/input/input-manager.d.ts.map +1 -1
- package/dist/input/input-manager.js +48 -13
- package/dist/input/rebind-controller.d.ts.map +1 -1
- package/dist/input/rebind-controller.js +6 -8
- package/dist/input/schema.d.ts.map +1 -1
- package/dist/input/schema.js +56 -28
- package/dist/manifest/filename.d.ts.map +1 -1
- package/dist/manifest/filename.js +8 -12
- package/dist/manifest/load.d.ts +10 -10
- package/dist/manifest/load.d.ts.map +1 -1
- package/dist/manifest/load.js +9 -6
- package/dist/manifest/schema.d.ts +17 -21
- package/dist/manifest/schema.d.ts.map +1 -1
- package/dist/manifest/schema.js +45 -35
- package/dist/physics/collider-dimensions.d.ts +8 -12
- package/dist/physics/collider-dimensions.d.ts.map +1 -1
- package/dist/physics/collider-dimensions.js +8 -12
- package/dist/pixi/scene-capture.d.ts +11 -13
- package/dist/pixi/scene-capture.d.ts.map +1 -1
- package/dist/react/world-state.d.ts +1 -1
- package/dist/react/world-state.d.ts.map +1 -1
- package/dist/render/directional-shadow-fit.d.ts +88 -0
- package/dist/render/directional-shadow-fit.d.ts.map +1 -0
- package/dist/render/directional-shadow-fit.js +133 -0
- package/dist/render/environment-capture.d.ts +68 -0
- package/dist/render/environment-capture.d.ts.map +1 -0
- package/dist/render/environment-capture.js +90 -0
- package/dist/render/ibl-override-material.d.ts +97 -0
- package/dist/render/ibl-override-material.d.ts.map +1 -0
- package/dist/render/ibl-override-material.js +114 -0
- package/dist/render/light-camera-factory.d.ts +5 -7
- package/dist/render/light-camera-factory.d.ts.map +1 -1
- package/dist/render/light-camera-factory.js +8 -11
- package/dist/render/material-factory.js +1 -1
- package/dist/render/render-batch-system.d.ts.map +1 -1
- package/dist/render/render-features.d.ts +17 -6
- package/dist/render/render-features.d.ts.map +1 -1
- package/dist/render/render-features.js +0 -28
- package/dist/runtime/create-runtime.d.ts +34 -25
- package/dist/runtime/create-runtime.d.ts.map +1 -1
- package/dist/runtime/create-runtime.js +218 -93
- package/dist/runtime/debug-registry.d.ts +77 -8
- package/dist/runtime/debug-registry.d.ts.map +1 -1
- package/dist/runtime/debug-registry.js +3 -3
- package/dist/runtime/dev-build.d.ts +2 -2
- package/dist/runtime/dev-build.js +2 -2
- package/dist/runtime/game-input-seams.d.ts +51 -0
- package/dist/runtime/game-input-seams.d.ts.map +1 -0
- package/dist/runtime/game-input-seams.js +86 -0
- package/dist/runtime/game.d.ts +104 -40
- package/dist/runtime/game.d.ts.map +1 -1
- package/dist/runtime/game.js +119 -61
- package/dist/runtime/mount-game.d.ts +0 -16
- package/dist/runtime/mount-game.d.ts.map +1 -1
- package/dist/runtime/mount-game.js +26 -41
- package/dist/runtime/mount-manifest.d.ts +22 -14
- package/dist/runtime/mount-manifest.d.ts.map +1 -1
- package/dist/runtime/mount-manifest.js +22 -20
- package/dist/runtime/playtest.d.ts +22 -0
- package/dist/runtime/playtest.d.ts.map +1 -0
- package/dist/runtime/playtest.js +12 -0
- package/dist/runtime/state-bridge.d.ts +2 -3
- package/dist/runtime/state-bridge.d.ts.map +1 -1
- package/dist/runtime/state-bridge.js +1 -0
- package/dist/setup/setup-audio.d.ts +12 -0
- package/dist/setup/setup-audio.d.ts.map +1 -1
- package/dist/setup/setup-audio.js +9 -10
- package/dist/setup/setup-renderer.d.ts +2 -25
- package/dist/setup/setup-renderer.d.ts.map +1 -1
- package/dist/setup/setup-renderer.js +2 -31
- package/dist/world3d-react/index.d.ts +15 -25
- package/dist/world3d-react/index.d.ts.map +1 -1
- package/dist/world3d-react/index.js +15 -25
- package/dist/world3d-react/r3f-root-factory.d.ts +28 -34
- package/dist/world3d-react/r3f-root-factory.d.ts.map +1 -1
- package/dist/world3d-react/r3f-root-factory.js +403 -57
- package/dist/world3d-react/rapier-physics-bridge.d.ts +30 -17
- package/dist/world3d-react/rapier-physics-bridge.d.ts.map +1 -1
- package/dist/world3d-react/rapier-physics-bridge.js +143 -58
- package/package.json +1 -1
- package/schemas/engine-capabilities.json +16 -14
- package/schemas/vgai-project.schema.json +35 -26
- package/src/adapter/adapter-module.ts +2 -4
- package/src/adapter/adapter-surface.ts +1 -1
- package/src/adapter/authoring.ts +19 -21
- package/src/adapter/binding.ts +468 -0
- package/src/adapter/colyseus-networking-adapter.ts +20 -5
- package/src/adapter/entrypoint-selection-readers.ts +66 -0
- package/src/adapter/entrypoint-selection-source.ts +1 -40
- package/src/adapter/finders/scenes-from-entrypoint-selection.ts +1 -48
- package/src/adapter/host-context.ts +45 -15
- package/src/adapter/index.ts +23 -11
- package/src/adapter/ingest/game-contract.ts +0 -3
- package/src/adapter/ingest/scene-capture.ts +190 -39
- package/src/adapter/ingest/visible-capture-window.ts +35 -0
- package/src/adapter/manifest-interpreter.ts +64 -0
- package/src/adapter/native-debug-module.ts +248 -15
- package/src/adapter/rapier-physics-adapter.ts +76 -20
- package/src/adapter/renderer-config.ts +3 -3
- package/src/adapter/root-adapter.ts +7 -7
- package/src/adapter/system-adapter.ts +43 -8
- package/src/adapter/system-seam-contract.ts +3 -3
- package/src/adapter/system-slot.ts +291 -0
- package/src/adapter/transform.ts +18 -1
- package/src/ai/navigation.ts +30 -3
- package/src/animation/anim-graph-types.ts +11 -3
- package/src/animation/theatre-clock-binding.ts +4 -4
- package/src/animation/xstate-animation-binding.ts +2 -2
- package/src/animation/xstate-animation-meta.ts +16 -0
- package/src/asset-formats/index.ts +4 -7
- package/src/asset-formats/render-env.ts +3 -6
- package/src/asset-parse-error.ts +2 -5
- package/src/audio/bus-mixer.ts +161 -0
- package/src/canvas-react/index.ts +5 -21
- package/src/canvas-react/pixi-react-root-factory.tsx +301 -39
- package/src/core/countdown-timer.ts +188 -0
- package/src/core/deferred-commands.ts +174 -0
- package/src/core/frame-pacing.ts +2 -2
- package/src/core/game-loop.ts +1 -3
- package/src/core/seeded-random.ts +1 -1
- package/src/core/sim-clock.ts +19 -8
- package/src/core/types.ts +1 -3
- package/src/defaults.ts +6 -14
- package/src/dev/instruments.ts +108 -11
- package/src/dev/register-render-vitals.ts +1 -4
- package/src/dev/render-debug-adapter.ts +2 -3
- package/src/dev/render-vitals.ts +3 -3
- package/src/dev/webgl-frame-capture.ts +1 -1
- package/src/index.ts +2 -5
- package/src/input/host-pointer.ts +230 -0
- package/src/input/input-manager.ts +49 -13
- package/src/input/input-types.ts +1 -1
- package/src/input/rebind-controller.ts +6 -8
- package/src/input/schema.ts +216 -188
- package/src/manifest/filename.ts +8 -12
- package/src/manifest/load.ts +17 -13
- package/src/manifest/schema.ts +55 -47
- package/src/physics/collider-dimensions.ts +8 -12
- package/src/pixi/scene-capture.ts +12 -15
- package/src/react/world-state.tsx +1 -1
- package/src/render/directional-shadow-fit.ts +156 -0
- package/src/render/environment-capture.ts +102 -0
- package/src/render/ibl-override-material.ts +170 -0
- package/src/render/light-camera-factory.ts +8 -11
- package/src/render/material-factory.ts +1 -1
- package/src/render/render-batch-system.ts +14 -6
- package/src/render/render-features.ts +17 -35
- package/src/runtime/create-runtime.ts +270 -108
- package/src/runtime/debug-registry.ts +84 -8
- package/src/runtime/dev-build.ts +2 -2
- package/src/runtime/game-input-seams.ts +108 -0
- package/src/runtime/game.ts +231 -85
- package/src/runtime/mount-game.ts +31 -57
- package/src/runtime/mount-manifest.ts +47 -36
- package/src/runtime/playtest.ts +22 -0
- package/src/runtime/state-bridge.ts +3 -3
- package/src/setup/setup-audio.ts +21 -11
- package/src/setup/setup-renderer.ts +2 -61
- package/src/world3d-react/index.ts +15 -31
- package/src/world3d-react/r3f-root-factory.tsx +451 -60
- package/src/world3d-react/rapier-physics-bridge.tsx +154 -58
- package/dist/adapter/setup-three-root-adapter.d.ts +0 -86
- package/dist/adapter/setup-three-root-adapter.d.ts.map +0 -1
- package/dist/adapter/setup-three-root-adapter.js +0 -908
- package/dist/animation/clip-map.d.ts +0 -12
- package/dist/animation/clip-map.d.ts.map +0 -1
- package/dist/animation/clip-map.js +0 -31
- package/dist/asset-registry.d.ts +0 -38
- package/dist/asset-registry.d.ts.map +0 -1
- package/dist/asset-registry.js +0 -66
- package/dist/canvas-react/engine-bridge.d.ts +0 -45
- package/dist/canvas-react/engine-bridge.d.ts.map +0 -1
- package/dist/canvas-react/engine-bridge.js +0 -45
- package/dist/canvas-react/pixi-react-adapter.d.ts +0 -77
- package/dist/canvas-react/pixi-react-adapter.d.ts.map +0 -1
- package/dist/canvas-react/pixi-react-adapter.js +0 -294
- package/dist/canvas-react/world-context.d.ts +0 -98
- package/dist/canvas-react/world-context.d.ts.map +0 -1
- package/dist/canvas-react/world-context.js +0 -173
- package/dist/dev/debug-draw.d.ts +0 -24
- package/dist/dev/debug-draw.d.ts.map +0 -1
- package/dist/dev/debug-draw.js +0 -73
- package/dist/render/auto-batcher.d.ts +0 -34
- package/dist/render/auto-batcher.d.ts.map +0 -1
- package/dist/render/auto-batcher.js +0 -140
- package/dist/render/lod.d.ts +0 -13
- package/dist/render/lod.d.ts.map +0 -1
- package/dist/render/lod.js +0 -16
- package/dist/runtime/types.d.ts +0 -303
- package/dist/runtime/types.d.ts.map +0 -1
- package/dist/runtime/types.js +0 -1
- package/dist/world3d-react/engine-bridge.d.ts +0 -47
- package/dist/world3d-react/engine-bridge.d.ts.map +0 -1
- package/dist/world3d-react/engine-bridge.js +0 -73
- package/dist/world3d-react/r3f-adapter.d.ts +0 -58
- package/dist/world3d-react/r3f-adapter.d.ts.map +0 -1
- package/dist/world3d-react/r3f-adapter.js +0 -634
- package/dist/world3d-react/world-context.d.ts +0 -182
- package/dist/world3d-react/world-context.d.ts.map +0 -1
- package/dist/world3d-react/world-context.js +0 -235
- package/src/adapter/setup-three-root-adapter.ts +0 -1032
- package/src/animation/clip-map.ts +0 -34
- package/src/asset-registry.ts +0 -89
- package/src/canvas-react/engine-bridge.ts +0 -59
- package/src/canvas-react/pixi-react-adapter.tsx +0 -356
- package/src/canvas-react/world-context.ts +0 -253
- package/src/dev/debug-draw.ts +0 -80
- package/src/render/auto-batcher.ts +0 -168
- package/src/render/lod.ts +0 -17
- package/src/runtime/types.ts +0 -328
- package/src/world3d-react/engine-bridge.ts +0 -86
- package/src/world3d-react/r3f-adapter.tsx +0 -717
- package/src/world3d-react/world-context.ts +0 -358
package/src/adapter/authoring.ts
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* AuthoringAdapter — the editor's authoring contract. The editor talks to THIS,
|
|
3
3
|
* keyed by opaque string node ids, instead of to a concrete document format.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* An implementer's document model is its own private business; an ingested
|
|
6
|
+
* game's adapter implements the same
|
|
7
7
|
* providers directly over its live `Object3D` tree. The editor sees only the
|
|
8
8
|
* interface and the advertised `capabilities` — it never branches on which
|
|
9
9
|
* implementer it is talking to.
|
|
@@ -29,8 +29,7 @@ import type { Transform } from './transform';
|
|
|
29
29
|
* Deliberately SMALL: a capability flag earns its place only when the shell
|
|
30
30
|
* actually branches on it. Structural affordances (create/delete/reparent) are
|
|
31
31
|
* gated by `structure` PROVIDER PRESENCE instead — the flag and the provider
|
|
32
|
-
* cannot disagree that way.
|
|
33
|
-
* `reparent`/`layout`, which no shell code ever read.)
|
|
32
|
+
* cannot disagree that way.
|
|
34
33
|
*/
|
|
35
34
|
export interface AuthoringCapabilities {
|
|
36
35
|
transform: boolean;
|
|
@@ -89,7 +88,7 @@ export type EditorNodeRole =
|
|
|
89
88
|
| 'entity'
|
|
90
89
|
| 'boundary';
|
|
91
90
|
|
|
92
|
-
/** A node in the authoring hierarchy — format-neutral
|
|
91
|
+
/** A node in the authoring hierarchy — format-neutral. */
|
|
93
92
|
export interface EditorNode {
|
|
94
93
|
/** STABLE id — survives reload (see ingest structural-path ids). */
|
|
95
94
|
id: string;
|
|
@@ -202,9 +201,9 @@ export interface SelectionProvider {
|
|
|
202
201
|
}
|
|
203
202
|
|
|
204
203
|
/** Adapter-owned result of semantic selection resolution: the raw native/render
|
|
205
|
-
* hit mapped to the node the author actually means.
|
|
206
|
-
*
|
|
207
|
-
* shell
|
|
204
|
+
* hit mapped to the node the author actually means. ONE id, deliberately:
|
|
205
|
+
* separate inspector/transform/boundary aliases would have to agree, and
|
|
206
|
+
* nothing in the shell can enforce that. */
|
|
208
207
|
export interface SelectionResolution {
|
|
209
208
|
/** Hierarchy selection and Inspector subject. */
|
|
210
209
|
id: string;
|
|
@@ -316,7 +315,7 @@ export interface TransformObservation {
|
|
|
316
315
|
}
|
|
317
316
|
|
|
318
317
|
export interface InspectorProvider {
|
|
319
|
-
/** Schema-driven —
|
|
318
|
+
/** Schema-driven — fixed to no document format. */
|
|
320
319
|
properties(id: string): PropertyDescriptor[];
|
|
321
320
|
get(id: string, path: string): unknown;
|
|
322
321
|
/**
|
|
@@ -620,24 +619,24 @@ export interface PersistenceProvider {
|
|
|
620
619
|
* subsequent persistence clears it. Auto-saving source adapters use this to
|
|
621
620
|
* report a rolled-back source write without inventing a dirty document. */
|
|
622
621
|
lastError?(): string | null;
|
|
623
|
-
/** Save to the adapter's OWN source of truth (
|
|
622
|
+
/** Save to the adapter's OWN source of truth (its source file, its own
|
|
623
|
+
* data, …) — whatever that adapter defines it to be. */
|
|
624
624
|
save(): Promise<void>;
|
|
625
625
|
/**
|
|
626
626
|
* Human/agent-readable destination this provider persists to — e.g.
|
|
627
|
-
* `"
|
|
627
|
+
* `"src/world.tsx"`, `"live-only (not saved)"`, or `"ephemeral
|
|
628
628
|
* (discarded on stop)"`. Drives the save-status UI and makes routing
|
|
629
629
|
* inspectable (design §2). Implementers whose destination can change during
|
|
630
|
-
* the session (
|
|
630
|
+
* the session (a provider that tracks the currently focused document, say)
|
|
631
631
|
* should expose this as a live getter rather than a value captured once.
|
|
632
632
|
*/
|
|
633
633
|
readonly destination: string;
|
|
634
634
|
/**
|
|
635
635
|
* The reload contract (design §5): apply an external change to this
|
|
636
636
|
* provider's persisted artifact into the RUNNING session (e.g. a file-watcher
|
|
637
|
-
* update to the
|
|
638
|
-
* pick up external changes
|
|
639
|
-
*
|
|
640
|
-
* provider (`applyOverlay`); absent (correctly) on the ephemeral provider.
|
|
637
|
+
* update to the artifact). Absent ⇒ the host must remount to
|
|
638
|
+
* pick up external changes — the honest floor, and correctly what the
|
|
639
|
+
* ephemeral provider reports.
|
|
641
640
|
*
|
|
642
641
|
* `rawContent`, when the host has it (the file-watcher SSE payload carries the
|
|
643
642
|
* artifact's exact bytes), is an OPTIONAL second parameter enabling own-echo
|
|
@@ -823,7 +822,7 @@ export interface ColorSampleProvider {
|
|
|
823
822
|
}
|
|
824
823
|
|
|
825
824
|
/**
|
|
826
|
-
*
|
|
825
|
+
* Where a node's live object CAME FROM in the game's own truth.
|
|
827
826
|
*
|
|
828
827
|
* `display` is the string the editor shows verbatim. The unanchored shape
|
|
829
828
|
* carries a `reason` rather than a blank, because "we don't know" and "a
|
|
@@ -1172,10 +1171,9 @@ export interface AuthoringAdapter {
|
|
|
1172
1171
|
* Observe transform GESTURES on this adapter's nodes — the one seam the
|
|
1173
1172
|
* animation sequencer needs to record a drag as keyframes and to refresh its
|
|
1174
1173
|
* design baselines. Deliberately narrow (one event shape, one consumer, no
|
|
1175
|
-
* general event bus):
|
|
1176
|
-
*
|
|
1177
|
-
*
|
|
1178
|
-
* adapter reports no gestures.
|
|
1174
|
+
* general event bus): without it the sequencer can only observe the store's
|
|
1175
|
+
* own transform path, so a live or source-backed world's gestures are
|
|
1176
|
+
* invisible to it. Absent ⇒ this adapter reports no gestures.
|
|
1179
1177
|
*/
|
|
1180
1178
|
observeTransforms?(listener: (event: TransformObservation) => void): () => void;
|
|
1181
1179
|
}
|
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE ROOT BINDING — a game's declaration of itself, bound, as ONE host-side
|
|
3
|
+
* value.
|
|
4
|
+
*
|
|
5
|
+
* A game is a native program plus a declaration of itself; the editor is a
|
|
6
|
+
* universal client of that declaration; the host must not know what it is
|
|
7
|
+
* hosting. Today that declaration arrives at the host as a scatter — a
|
|
8
|
+
* `RootInstance`, a `MountedRoot`, an `AuthoringAdapter` provider bag, a
|
|
9
|
+
* `SystemAdapters` slot map, a `ResolvedAdapterRoot`, a parsed
|
|
10
|
+
* `AdapterDefinition` — and every consumer re-assembles its own subset by
|
|
11
|
+
* hand. `RootBinding` is that same material REGROUPED under one name, by the
|
|
12
|
+
* FIVE protocol families a host actually talks in.
|
|
13
|
+
*
|
|
14
|
+
* ## This file declares the vocabulary AND performs the regrouping
|
|
15
|
+
*
|
|
16
|
+
* {@link createRootBinding} is the one place the five families are assembled,
|
|
17
|
+
* and it is a pure re-address of values it is HANDED — it loads nothing,
|
|
18
|
+
* fetches nothing, and constructs no provider. The editor's
|
|
19
|
+
* `binding-resolver.ts` (`resolveRootBinding(root, realm, adapterDef)`) is what
|
|
20
|
+
* gathers those values per realm and calls this; `RootInstance.binding`
|
|
21
|
+
* (`runtime/game.ts`) is where the result lives for the life of the mount.
|
|
22
|
+
* Keeping the assembly here rather than in the resolver is what makes the
|
|
23
|
+
* reference-equality rule below checkable in ONE function instead of once per
|
|
24
|
+
* realm.
|
|
25
|
+
*
|
|
26
|
+
* ## The one rule that makes this a regrouping and not an abstraction
|
|
27
|
+
*
|
|
28
|
+
* **Every member is a REFERENCE to the thing that already exists — never a
|
|
29
|
+
* facade, never a copy, never a wrapper.** `substrate.mounted` IS the
|
|
30
|
+
* `MountedRoot` the adapter returned. `observation.debugRegistry` IS the ONE
|
|
31
|
+
* game-scoped registry every root of that game shares (this binding neither
|
|
32
|
+
* owns it nor tears it down). And the providers that are read AND written
|
|
33
|
+
* through — `selection`, `transforms`, `inspector`, `instances`,
|
|
34
|
+
* `spatialHandles`, `boxEdit`, `text` — appear in BOTH
|
|
35
|
+
* {@link ProjectionBinding} and {@link TruthBinding} as literally the same
|
|
36
|
+
* object, so `binding.projection.selection === binding.truth.selection`. A
|
|
37
|
+
* facade at either address would make the two views disagree the first time
|
|
38
|
+
* anything stateful moved through one of them; reference equality is what
|
|
39
|
+
* makes "regrouping" a checkable claim instead of a promise.
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
import type { ResolvedAdapterRoot } from '../manifest/load';
|
|
43
|
+
import type { DebugRegistry } from '../runtime/debug-registry';
|
|
44
|
+
import type { AdapterDefinition } from './adapter-module';
|
|
45
|
+
import type {
|
|
46
|
+
AssetDropProvider,
|
|
47
|
+
AssetSubjectProvider,
|
|
48
|
+
AuthoringCapabilities,
|
|
49
|
+
AuthoringProvenance,
|
|
50
|
+
BoxEditProvider,
|
|
51
|
+
ColorSampleProvider,
|
|
52
|
+
ComponentInstancesProvider,
|
|
53
|
+
HierarchyProvider,
|
|
54
|
+
InspectorProvider,
|
|
55
|
+
PersistenceProvider,
|
|
56
|
+
PickProvider,
|
|
57
|
+
RectProvider,
|
|
58
|
+
RelatedSubjectsProvider,
|
|
59
|
+
SelectionProvider,
|
|
60
|
+
SpatialHandlesProvider,
|
|
61
|
+
StoriesProvider,
|
|
62
|
+
StructureProvider,
|
|
63
|
+
TextProvider,
|
|
64
|
+
TransformObservation,
|
|
65
|
+
TransformProvider,
|
|
66
|
+
TruthProvider,
|
|
67
|
+
} from './authoring';
|
|
68
|
+
import type { NativeDebugBinding, NativeSystemsBinding } from './native-debug-module';
|
|
69
|
+
import type { MountedRoot, RootStateObserver, SurfaceAdapter } from './root-adapter';
|
|
70
|
+
import type { SystemAdapters } from './system-adapter';
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* THE PROTOCOL VOCABULARY — the five families a host talks to a root in, and
|
|
74
|
+
* the ONLY place they are enumerated.
|
|
75
|
+
*
|
|
76
|
+
* This union is the single enumeration on purpose: `RootBinding`'s keys are
|
|
77
|
+
* pinned to it by {@link RootBindingKeysAreExactlyTheProtocolFamilies} below,
|
|
78
|
+
* so a sixth family cannot be added at one address and forgotten at the
|
|
79
|
+
* other, and no second list of these names may exist anywhere in the repo
|
|
80
|
+
* (`adapter-binding-protocol-families.test.ts` is the tripwire).
|
|
81
|
+
*/
|
|
82
|
+
export type ProtocolFamily = 'substrate' | 'projection' | 'truth' | 'observation' | 'project';
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* WHAT MOUNTED, AND HOW IT RUNS.
|
|
86
|
+
*
|
|
87
|
+
* The adapter that produced the mount, the mount itself, and the two
|
|
88
|
+
* lifecycle facts that are properties of the ROOT rather than of the mounted
|
|
89
|
+
* handle (`pausable` is the manifest's per-world play/pause semantics;
|
|
90
|
+
* `loop` is the declared loop model the loop gate reports against). Every
|
|
91
|
+
* other lifecycle member — `update`, `fixedUpdate`, `setPaused`, `step`,
|
|
92
|
+
* `resize`, `dispose`, `disposeComplete`, `drivesOwnLoop` — is reached
|
|
93
|
+
* through `mounted`, unrepeated, because repeating them here would be the
|
|
94
|
+
* facade this binding exists not to be.
|
|
95
|
+
*/
|
|
96
|
+
export interface SubstrateBinding {
|
|
97
|
+
/** The surface-tagged adapter the resolver produced for this root. */
|
|
98
|
+
readonly adapter: SurfaceAdapter;
|
|
99
|
+
/** The handle the adapter's `mount` returned — the same object, not a view. */
|
|
100
|
+
readonly mounted: MountedRoot;
|
|
101
|
+
/** Per-world play/pause semantics (D10's per-world default is `true`). */
|
|
102
|
+
readonly pausable: boolean;
|
|
103
|
+
/** The declared loop model: host-ticked, or the game owns its own rAF. */
|
|
104
|
+
readonly loop: ResolvedAdapterRoot['loop'];
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* READ VIEWS of the provider set — what the editor's panels ASK this root.
|
|
109
|
+
*
|
|
110
|
+
* `capabilities` and `hierarchy` are required because an `AuthoringAdapter`
|
|
111
|
+
* cannot exist without them; every other member is optional and absent means
|
|
112
|
+
* "this root does not support that", never a fabricated empty.
|
|
113
|
+
*
|
|
114
|
+
* The seven members marked STRADDLER also appear on {@link TruthBinding}, as
|
|
115
|
+
* the same object (see this module's header).
|
|
116
|
+
*/
|
|
117
|
+
export interface ProjectionBinding {
|
|
118
|
+
readonly capabilities: AuthoringCapabilities;
|
|
119
|
+
readonly hierarchy: HierarchyProvider;
|
|
120
|
+
readonly provenance?: AuthoringProvenance | undefined;
|
|
121
|
+
/** STRADDLER. */
|
|
122
|
+
readonly selection?: SelectionProvider | undefined;
|
|
123
|
+
/** STRADDLER. */
|
|
124
|
+
readonly transforms?: TransformProvider | undefined;
|
|
125
|
+
/** STRADDLER. */
|
|
126
|
+
readonly inspector?: InspectorProvider | undefined;
|
|
127
|
+
/** STRADDLER. */
|
|
128
|
+
readonly instances?: ComponentInstancesProvider | undefined;
|
|
129
|
+
/** STRADDLER. */
|
|
130
|
+
readonly spatialHandles?: SpatialHandlesProvider | undefined;
|
|
131
|
+
/** STRADDLER. */
|
|
132
|
+
readonly boxEdit?: BoxEditProvider | undefined;
|
|
133
|
+
/** STRADDLER. */
|
|
134
|
+
readonly text?: TextProvider | undefined;
|
|
135
|
+
readonly assetSubject?: AssetSubjectProvider | undefined;
|
|
136
|
+
readonly related?: RelatedSubjectsProvider | undefined;
|
|
137
|
+
readonly rects?: RectProvider | undefined;
|
|
138
|
+
readonly pickable?: PickProvider | undefined;
|
|
139
|
+
readonly stories?: StoriesProvider | undefined;
|
|
140
|
+
readonly colorSample?: ColorSampleProvider | undefined;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* WRITE VIEWS of the provider set — what an authored edit goes THROUGH.
|
|
145
|
+
*
|
|
146
|
+
* The write-only members (`structure`, `persistence`, `truth`, `assetDrop`)
|
|
147
|
+
* plus the seven straddlers, which are the same objects the projection holds.
|
|
148
|
+
*/
|
|
149
|
+
export interface TruthBinding {
|
|
150
|
+
readonly structure?: StructureProvider | undefined;
|
|
151
|
+
readonly persistence?: PersistenceProvider | undefined;
|
|
152
|
+
/** Projection subject → source/data anchor and write lane, resolved together. */
|
|
153
|
+
readonly truth?: TruthProvider | undefined;
|
|
154
|
+
readonly assetDrop?: AssetDropProvider | undefined;
|
|
155
|
+
/** STRADDLER. */
|
|
156
|
+
readonly selection?: SelectionProvider | undefined;
|
|
157
|
+
/** STRADDLER. */
|
|
158
|
+
readonly transforms?: TransformProvider | undefined;
|
|
159
|
+
/** STRADDLER. */
|
|
160
|
+
readonly inspector?: InspectorProvider | undefined;
|
|
161
|
+
/** STRADDLER. */
|
|
162
|
+
readonly instances?: ComponentInstancesProvider | undefined;
|
|
163
|
+
/** STRADDLER. */
|
|
164
|
+
readonly spatialHandles?: SpatialHandlesProvider | undefined;
|
|
165
|
+
/** STRADDLER. */
|
|
166
|
+
readonly boxEdit?: BoxEditProvider | undefined;
|
|
167
|
+
/** STRADDLER. */
|
|
168
|
+
readonly text?: TextProvider | undefined;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* WHAT THIS ROOT LETS ANYONE WATCH — references only.
|
|
173
|
+
*
|
|
174
|
+
* `debugRegistry` is the ONE registry the whole Game shares. This binding
|
|
175
|
+
* holds a reference to it and nothing more: it never creates it, never
|
|
176
|
+
* disposes it, and per-root teardown must not end it (a game-scoped resource
|
|
177
|
+
* destroyed by a root-scoped teardown is a bug this repo has already paid
|
|
178
|
+
* for once).
|
|
179
|
+
*
|
|
180
|
+
* `entryDebug`/`entrySystems` are the entry module's own statically declared
|
|
181
|
+
* bindings, harvested at resolve time and INSTALLED post-mount by
|
|
182
|
+
* `adapter-runtime-bindings` — they ride here rather than being re-read from
|
|
183
|
+
* the module a second time.
|
|
184
|
+
*/
|
|
185
|
+
export interface ObservationBinding {
|
|
186
|
+
/** The root's system-adapter slots (physics/networking/navigation/audio/debug). */
|
|
187
|
+
readonly systems?: SystemAdapters | undefined;
|
|
188
|
+
/** Reference to the game-scoped registry. Never owned, never disposed here. */
|
|
189
|
+
readonly debugRegistry: DebugRegistry | null;
|
|
190
|
+
/** The ingested-world observation contract, when the adapter has one. */
|
|
191
|
+
readonly observe?: RootStateObserver | undefined;
|
|
192
|
+
/** Change notification → UI refresh. */
|
|
193
|
+
readonly subscribe?: ((listener: () => void) => () => void) | undefined;
|
|
194
|
+
/** Transform GESTURE observation — the animation sequencer's one seam. */
|
|
195
|
+
readonly observeTransforms?:
|
|
196
|
+
| ((listener: (event: TransformObservation) => void) => () => void)
|
|
197
|
+
| undefined;
|
|
198
|
+
/** The entry module's `debug` export, already validated. */
|
|
199
|
+
readonly entryDebug?: NativeDebugBinding | undefined;
|
|
200
|
+
/** The entry module's `systems` export, already validated. */
|
|
201
|
+
readonly entrySystems?: NativeSystemsBinding | undefined;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* The entry module's static surface, WITH the realm's reduction stated.
|
|
206
|
+
*
|
|
207
|
+
* In dev, browser-storage and packaged realms the host holds the entry
|
|
208
|
+
* module's whole namespace. On the hosted deployment there is no `/@fs`, so
|
|
209
|
+
* what exists is a build-time bundle map and the host holds only the four
|
|
210
|
+
* keys that map carries. Saying so in the type is the point: a
|
|
211
|
+
* `Record<string, unknown>` at both addresses would let a consumer reach for
|
|
212
|
+
* an export that CANNOT be there on the hosted lane and only find out at
|
|
213
|
+
* runtime, on the deployment, in someone else's browser.
|
|
214
|
+
*/
|
|
215
|
+
export type EntryStaticSurface =
|
|
216
|
+
| {
|
|
217
|
+
readonly reach: 'full';
|
|
218
|
+
/** The entry module's own namespace object. */
|
|
219
|
+
readonly module: Record<string, unknown>;
|
|
220
|
+
}
|
|
221
|
+
| {
|
|
222
|
+
readonly reach: 'bundleSubset';
|
|
223
|
+
readonly module: BundledEntrySubset;
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
/** Everything the hosted build's bundle map carries for one root. */
|
|
227
|
+
export interface BundledEntrySubset {
|
|
228
|
+
/** The entry's default-exported world component. */
|
|
229
|
+
readonly default: unknown;
|
|
230
|
+
readonly debug?: unknown;
|
|
231
|
+
readonly systems?: unknown;
|
|
232
|
+
readonly components?: unknown;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* WHAT THE PROJECT DECLARED — the manifest root, the parsed `vgai.adapter.ts`
|
|
237
|
+
* definition, and the entry's static surface.
|
|
238
|
+
*
|
|
239
|
+
* `vgai.adapter.ts` LOADING stays where it is (`project-adapter.ts`); its
|
|
240
|
+
* parsed result is an INPUT to `resolveRootBinding`, not something this
|
|
241
|
+
* binding goes and fetches. That is deliberate: the binding is the hand-off's
|
|
242
|
+
* shape, never a second loader.
|
|
243
|
+
*/
|
|
244
|
+
export interface ProjectBinding {
|
|
245
|
+
/** The manifest's own resolved root record. */
|
|
246
|
+
readonly root: ResolvedAdapterRoot;
|
|
247
|
+
/**
|
|
248
|
+
* The project's parsed `vgai.adapter.ts`, or `null` when it declares none.
|
|
249
|
+
*
|
|
250
|
+
* `project-adapter.ts` is still the only thing that LOADS it; the editor's
|
|
251
|
+
* `resolveComposition` asks that owner once per composition — waiting on the
|
|
252
|
+
* load in flight rather than reading past it — and hands the answer to
|
|
253
|
+
* `resolveRootBinding`, so every root of one game carries the same
|
|
254
|
+
* declaration. `null` is therefore a fact about the PROJECT: it shipped no
|
|
255
|
+
* declaration file and runs on the declared native default. Which table
|
|
256
|
+
* stood in (project, registry, or native) is a separate question, answered
|
|
257
|
+
* by `ProjectAdapterFacet.source`.
|
|
258
|
+
*/
|
|
259
|
+
readonly definition: AdapterDefinition | null;
|
|
260
|
+
/** The entry module's static surface, realm-honest about its reach. */
|
|
261
|
+
readonly entry: EntryStaticSurface;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* One root's whole declaration, bound.
|
|
266
|
+
*
|
|
267
|
+
* The keys ARE {@link ProtocolFamily} — pinned below, so the vocabulary and
|
|
268
|
+
* the value can never drift apart.
|
|
269
|
+
*/
|
|
270
|
+
export interface RootBinding {
|
|
271
|
+
readonly substrate: SubstrateBinding;
|
|
272
|
+
/**
|
|
273
|
+
* Present only when this root's mount exposes an `AuthoringAdapter`.
|
|
274
|
+
*
|
|
275
|
+
* A `ProjectionBinding` cannot be fabricated — `capabilities`/`hierarchy`
|
|
276
|
+
* are required — so a mount with no authoring gets no projection. It gets
|
|
277
|
+
* the other four families, which are constructible from the declaration and
|
|
278
|
+
* the mount alone, because withholding those too would answer "what root is
|
|
279
|
+
* this, what did the project declare, what can be watched" with silence for
|
|
280
|
+
* a question the mount's authoring has nothing to do with.
|
|
281
|
+
*
|
|
282
|
+
* Absent is a REAL state, not a rare one: the editor supplies live authoring
|
|
283
|
+
* for native TSX roots itself (`play-mode.ts`'s per-root live adapters,
|
|
284
|
+
* composed into one `CompositeAuthoringAdapter`) rather than through the
|
|
285
|
+
* mount, so today every first-party three/canvas/dom root lands here. Moving
|
|
286
|
+
* that projection into the mount is its own program item; until it does, the
|
|
287
|
+
* absence is the honest report of where authoring lives.
|
|
288
|
+
*/
|
|
289
|
+
readonly projection?: ProjectionBinding | undefined;
|
|
290
|
+
/** Present exactly when {@link projection} is — same authoring adapter, same
|
|
291
|
+
* condition; see there. */
|
|
292
|
+
readonly truth?: TruthBinding | undefined;
|
|
293
|
+
readonly observation: ObservationBinding;
|
|
294
|
+
readonly project: ProjectBinding;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Compile-time pin: `keyof RootBinding` and `ProtocolFamily` are the same set
|
|
299
|
+
* of names, in both directions. Adding a family to one address and not the
|
|
300
|
+
* other is a type error HERE, at the vocabulary, rather than a silent
|
|
301
|
+
* asymmetry every consumer inherits.
|
|
302
|
+
*/
|
|
303
|
+
type MutuallyAssignable<A, B> = [A] extends [B] ? ([B] extends [A] ? true : false) : false;
|
|
304
|
+
type AssertTrue<T extends true> = T;
|
|
305
|
+
export type RootBindingKeysAreExactlyTheProtocolFamilies = AssertTrue<
|
|
306
|
+
MutuallyAssignable<keyof RootBinding, ProtocolFamily>
|
|
307
|
+
>;
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Everything {@link createRootBinding} needs, and nothing it could go and get
|
|
311
|
+
* for itself.
|
|
312
|
+
*
|
|
313
|
+
* Each member is a value some OTHER owner already produced: the resolver
|
|
314
|
+
* mounted the adapter, the manifest loader resolved the root, `project-adapter`
|
|
315
|
+
* parsed the definition, the realm loaded the entry namespace, `createGame`
|
|
316
|
+
* owns the debug registry. This shape exists so that list is stated once, at
|
|
317
|
+
* the seam, instead of being re-derived per realm.
|
|
318
|
+
*/
|
|
319
|
+
export interface RootBindingParts extends RootDeclaration {
|
|
320
|
+
readonly adapter: SurfaceAdapter;
|
|
321
|
+
readonly mounted: MountedRoot;
|
|
322
|
+
readonly pausable: boolean;
|
|
323
|
+
/** The GAME-scoped registry, borrowed. Never created or disposed here. */
|
|
324
|
+
readonly debugRegistry: DebugRegistry | null;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* The DECLARATION half — everything a resolver knows BEFORE anything mounts.
|
|
329
|
+
*
|
|
330
|
+
* This is the half that travels: `binding-resolver.ts` produces one per root
|
|
331
|
+
* while it is resolving adapters, hands it to the host on the root's mount
|
|
332
|
+
* spec, and the host completes the binding at REGISTRATION — the first moment
|
|
333
|
+
* `mounted` exists at all. Splitting it here is what keeps the resolver from
|
|
334
|
+
* having to be present at mount time, and the host from having to know how an
|
|
335
|
+
* entry module was loaded.
|
|
336
|
+
*/
|
|
337
|
+
export interface RootDeclaration {
|
|
338
|
+
/** The manifest's own resolved root record. `loop` rides on it. */
|
|
339
|
+
readonly root: ResolvedAdapterRoot;
|
|
340
|
+
/** The project's parsed `vgai.adapter.ts`, or `null` when it declares none —
|
|
341
|
+
* see {@link ProjectBinding.definition} for the current wiring truth. */
|
|
342
|
+
readonly definition: AdapterDefinition | null;
|
|
343
|
+
/** The entry module's static surface, realm-honest about its reach. */
|
|
344
|
+
readonly entry: EntryStaticSurface;
|
|
345
|
+
/** The entry module's validated `debug` export, harvested at resolve. */
|
|
346
|
+
readonly entryDebug?: NativeDebugBinding | undefined;
|
|
347
|
+
/** The entry module's validated `systems` export, harvested at resolve. */
|
|
348
|
+
readonly entrySystems?: NativeSystemsBinding | undefined;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* REGROUP the parts into the five families. No loading, no defaulting, no
|
|
353
|
+
* fabrication: every member of the result is one of `parts`' own values or one
|
|
354
|
+
* of `parts.mounted.authoring`'s own provider objects, read straight off it.
|
|
355
|
+
*
|
|
356
|
+
* The straddlers are read ONCE into locals and written to both bindings, which
|
|
357
|
+
* is what makes `binding.projection.selection === binding.truth.selection` true
|
|
358
|
+
* by construction rather than by care —
|
|
359
|
+
* `adapter-binding-protocol-families.test.ts` asserts it over a value this
|
|
360
|
+
* function built.
|
|
361
|
+
*
|
|
362
|
+
* The two callback members are the one exception to "the same reference", and
|
|
363
|
+
* deliberately: `subscribe`/`observeTransforms` are METHODS on their adapter
|
|
364
|
+
* (`live-three-authoring-adapter` reads `this.store` inside `subscribe`), so a
|
|
365
|
+
* bare property read would hand the caller a function whose `this` is the
|
|
366
|
+
* observation binding. They are bound to the authoring adapter that owns them —
|
|
367
|
+
* the same function over the same receiver, with nothing interposed. They are
|
|
368
|
+
* not straddlers and carry no equality claim.
|
|
369
|
+
*
|
|
370
|
+
* An absent `mounted.authoring` costs this root its `projection` and `truth`
|
|
371
|
+
* and NOTHING ELSE. There is no such thing as an empty `ProjectionBinding` —
|
|
372
|
+
* `capabilities`/`hierarchy` are required — so those two families are simply
|
|
373
|
+
* not there, which is the honest report. The other three are built from the
|
|
374
|
+
* declaration and the mount, neither of which the authoring adapter has
|
|
375
|
+
* anything to do with; refusing them as well would answer "which root is
|
|
376
|
+
* this, what did the project declare, what can be watched" with silence, and
|
|
377
|
+
* that is what made `binding` unreadable for every native TSX root the editor
|
|
378
|
+
* plays (the editor supplies their authoring itself — see
|
|
379
|
+
* {@link RootBinding.projection}).
|
|
380
|
+
*/
|
|
381
|
+
export function createRootBinding(parts: RootBindingParts): RootBinding {
|
|
382
|
+
const authoring = parts.mounted.authoring;
|
|
383
|
+
|
|
384
|
+
// Read each straddler ONCE — the two bindings below then hold these exact
|
|
385
|
+
// objects, not two reads of the same key.
|
|
386
|
+
const { selection, transforms, inspector, instances, spatialHandles, boxEdit, text } =
|
|
387
|
+
authoring ?? {};
|
|
388
|
+
|
|
389
|
+
return {
|
|
390
|
+
substrate: {
|
|
391
|
+
adapter: parts.adapter,
|
|
392
|
+
mounted: parts.mounted,
|
|
393
|
+
pausable: parts.pausable,
|
|
394
|
+
loop: parts.root.loop,
|
|
395
|
+
},
|
|
396
|
+
...(authoring === undefined
|
|
397
|
+
? {}
|
|
398
|
+
: projectionAndTruth(authoring, {
|
|
399
|
+
selection,
|
|
400
|
+
transforms,
|
|
401
|
+
inspector,
|
|
402
|
+
instances,
|
|
403
|
+
spatialHandles,
|
|
404
|
+
boxEdit,
|
|
405
|
+
text,
|
|
406
|
+
})),
|
|
407
|
+
observation: {
|
|
408
|
+
systems: parts.mounted.systems,
|
|
409
|
+
debugRegistry: parts.debugRegistry,
|
|
410
|
+
observe: parts.mounted.observe,
|
|
411
|
+
subscribe: authoring?.subscribe?.bind(authoring),
|
|
412
|
+
observeTransforms: authoring?.observeTransforms?.bind(authoring),
|
|
413
|
+
entryDebug: parts.entryDebug,
|
|
414
|
+
entrySystems: parts.entrySystems,
|
|
415
|
+
},
|
|
416
|
+
project: {
|
|
417
|
+
root: parts.root,
|
|
418
|
+
definition: parts.definition,
|
|
419
|
+
entry: parts.entry,
|
|
420
|
+
},
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/** The two authoring-dependent families, built together from the ONE adapter
|
|
425
|
+
* and the straddlers already read off it — so the reference-equality rule is
|
|
426
|
+
* still decided in a single place. */
|
|
427
|
+
function projectionAndTruth(
|
|
428
|
+
authoring: NonNullable<MountedRoot['authoring']>,
|
|
429
|
+
straddlers: Pick<
|
|
430
|
+
ProjectionBinding,
|
|
431
|
+
'selection' | 'transforms' | 'inspector' | 'instances' | 'spatialHandles' | 'boxEdit' | 'text'
|
|
432
|
+
>,
|
|
433
|
+
): { projection: ProjectionBinding; truth: TruthBinding } {
|
|
434
|
+
const { selection, transforms, inspector, instances, spatialHandles, boxEdit, text } = straddlers;
|
|
435
|
+
return {
|
|
436
|
+
projection: {
|
|
437
|
+
capabilities: authoring.capabilities,
|
|
438
|
+
hierarchy: authoring.hierarchy,
|
|
439
|
+
provenance: authoring.provenance,
|
|
440
|
+
selection,
|
|
441
|
+
transforms,
|
|
442
|
+
inspector,
|
|
443
|
+
instances,
|
|
444
|
+
spatialHandles,
|
|
445
|
+
boxEdit,
|
|
446
|
+
text,
|
|
447
|
+
assetSubject: authoring.assetSubject,
|
|
448
|
+
related: authoring.related,
|
|
449
|
+
rects: authoring.rects,
|
|
450
|
+
pickable: authoring.pickable,
|
|
451
|
+
stories: authoring.stories,
|
|
452
|
+
colorSample: authoring.colorSample,
|
|
453
|
+
},
|
|
454
|
+
truth: {
|
|
455
|
+
structure: authoring.structure,
|
|
456
|
+
persistence: authoring.persistence,
|
|
457
|
+
truth: authoring.truth,
|
|
458
|
+
assetDrop: authoring.assetDrop,
|
|
459
|
+
selection,
|
|
460
|
+
transforms,
|
|
461
|
+
inspector,
|
|
462
|
+
instances,
|
|
463
|
+
spatialHandles,
|
|
464
|
+
boxEdit,
|
|
465
|
+
text,
|
|
466
|
+
},
|
|
467
|
+
};
|
|
468
|
+
}
|
|
@@ -109,12 +109,23 @@ export function createColyseusNetworkingAdapter(cfg: ColyseusNetworkingConfig):
|
|
|
109
109
|
if (cfg.serverAuthoritative?.(o)) return false; // server owns it → inspect-only
|
|
110
110
|
return cfg.ownerId(o) === cfg.localSessionId(); // only your own peer's objects
|
|
111
111
|
},
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
112
|
+
// `subscribe` is the one member that still defaults, and honestly: an
|
|
113
|
+
// adapter with nothing to notify about has a real no-op subscription, and
|
|
114
|
+
// the caller's contract ("you will hear about changes") is kept — there are
|
|
115
|
+
// none. Every accessor below ANSWERS A QUESTION, and a default answer to a
|
|
116
|
+
// question nobody implemented is a fabricated measurement.
|
|
116
117
|
subscribe: (cb) => cfg.subscribe?.(cb) ?? (() => {}),
|
|
117
118
|
};
|
|
119
|
+
// The link-state accessors attach ONLY when supplied, exactly like the W3b
|
|
120
|
+
// capabilities below. They used to default — `'disconnected'`, `null`, and
|
|
121
|
+
// all-zero stats — which read as "we looked, and the game is idle and
|
|
122
|
+
// unconnected" for a config that had simply never been taught to look.
|
|
123
|
+
const connectionState = cfg.connectionState?.bind(cfg);
|
|
124
|
+
if (connectionState) adapter.getConnectionState = () => connectionState();
|
|
125
|
+
const roomInfo = cfg.roomInfo?.bind(cfg);
|
|
126
|
+
if (roomInfo) adapter.getRoomInfo = () => roomInfo();
|
|
127
|
+
const replicationStats = cfg.replicationStats?.bind(cfg);
|
|
128
|
+
if (replicationStats) adapter.getReplicationStats = () => replicationStats();
|
|
118
129
|
// The W3b inspector capabilities attach ONLY when supplied: their absence
|
|
119
130
|
// is the editor's degradation signal (`getStateSnapshot` in adapter ⇒ tree,
|
|
120
131
|
// missing ⇒ "not provided by this adapter" — never a fabricated empty).
|
|
@@ -135,7 +146,11 @@ export function createColyseusNetworkingAdapter(cfg: ColyseusNetworkingConfig):
|
|
|
135
146
|
// editor shows an editable field only when `setPlayerIdentity` is present.
|
|
136
147
|
const playerIdentity = cfg.playerIdentity?.bind(cfg);
|
|
137
148
|
if (playerIdentity) {
|
|
138
|
-
|
|
149
|
+
// `cfg.playerIdentity` may answer `undefined` — "I read the game's state
|
|
150
|
+
// and it has no seat for this client yet". That is not `{}`, an identity
|
|
151
|
+
// that exists and happens to be blank; it is the reader's real answer, and
|
|
152
|
+
// the seam passes it through.
|
|
153
|
+
adapter.getPlayerIdentity = () => playerIdentity();
|
|
139
154
|
}
|
|
140
155
|
const setPlayerIdentity = cfg.setPlayerIdentity?.bind(cfg);
|
|
141
156
|
if (setPlayerIdentity) {
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure TS-AST readers over an entrypoint's SELECTION TABLE — shared by the
|
|
3
|
+
* write side (`entrypoint-selection-source.ts`) and the read side
|
|
4
|
+
* (`finders/scenes-from-entrypoint-selection.ts`). These two must agree on
|
|
5
|
+
* what a selection table IS, or play remounts a key the finder never
|
|
6
|
+
* discovered; one spelling here is what makes that agreement structural.
|
|
7
|
+
* (The finder-import boundary bans importing from `finders/` — this sibling
|
|
8
|
+
* sits outside that directory precisely so both sides can share it.)
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import ts from 'typescript';
|
|
12
|
+
|
|
13
|
+
/** The object literal a module-level `const <name> = { … }` binds. */
|
|
14
|
+
export function selectionTable(
|
|
15
|
+
sf: ts.SourceFile,
|
|
16
|
+
name: string,
|
|
17
|
+
): ts.ObjectLiteralExpression | undefined {
|
|
18
|
+
for (const statement of sf.statements) {
|
|
19
|
+
if (!ts.isVariableStatement(statement)) continue;
|
|
20
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
21
|
+
if (!ts.isIdentifier(declaration.name) || declaration.name.text !== name) continue;
|
|
22
|
+
const initializer = declaration.initializer;
|
|
23
|
+
if (initializer && ts.isObjectLiteralExpression(initializer)) return initializer;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** A property's key when it is a plain identifier or string literal. */
|
|
30
|
+
export function propertyKey(property: ts.ObjectLiteralElementLike): string | undefined {
|
|
31
|
+
const name = property.name;
|
|
32
|
+
if (!name) return undefined;
|
|
33
|
+
if (ts.isIdentifier(name) || ts.isStringLiteral(name)) return name.text;
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The identifier the entrypoint INDEXES the selection table with — the
|
|
39
|
+
* `activeScene` in `scenes[activeScene]`.
|
|
40
|
+
*
|
|
41
|
+
* `undefined` when the module never indexes the table; `null` when it does
|
|
42
|
+
* but not readably (several identifiers, or a non-identifier index). Both
|
|
43
|
+
* are honest "cannot be read" answers the callers turn into their own notes.
|
|
44
|
+
*/
|
|
45
|
+
export function indexingIdentifier(
|
|
46
|
+
sf: ts.SourceFile,
|
|
47
|
+
selection: string,
|
|
48
|
+
): string | undefined | null {
|
|
49
|
+
const names = new Set<string>();
|
|
50
|
+
let unreadable = false;
|
|
51
|
+
const visit = (node: ts.Node): void => {
|
|
52
|
+
if (
|
|
53
|
+
ts.isElementAccessExpression(node) &&
|
|
54
|
+
ts.isIdentifier(node.expression) &&
|
|
55
|
+
node.expression.text === selection
|
|
56
|
+
) {
|
|
57
|
+
if (ts.isIdentifier(node.argumentExpression)) names.add(node.argumentExpression.text);
|
|
58
|
+
else unreadable = true;
|
|
59
|
+
}
|
|
60
|
+
ts.forEachChild(node, visit);
|
|
61
|
+
};
|
|
62
|
+
ts.forEachChild(sf, visit);
|
|
63
|
+
if (names.size === 0 && !unreadable) return undefined;
|
|
64
|
+
if (names.size !== 1 || unreadable) return null;
|
|
65
|
+
return [...names][0];
|
|
66
|
+
}
|