@vgai/engine 0.5.15 → 0.5.17
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/dist/adapter/adapter-module.d.ts +229 -33
- package/dist/adapter/adapter-module.d.ts.map +1 -1
- package/dist/adapter/adapter-module.js +222 -50
- package/dist/adapter/authoring-seam-contract.d.ts +530 -0
- package/dist/adapter/authoring-seam-contract.d.ts.map +1 -0
- package/dist/adapter/authoring-seam-contract.js +162 -0
- package/dist/adapter/authoring.d.ts +237 -50
- package/dist/adapter/authoring.d.ts.map +1 -1
- package/dist/adapter/authoring.js +2 -1
- package/dist/adapter/entrypoint-selection-source.d.ts +35 -0
- package/dist/adapter/entrypoint-selection-source.d.ts.map +1 -0
- package/dist/adapter/entrypoint-selection-source.js +151 -0
- package/dist/adapter/finders/scenes-from-entrypoint-selection.d.ts +7 -3
- package/dist/adapter/finders/scenes-from-entrypoint-selection.d.ts.map +1 -1
- package/dist/adapter/finders/scenes-from-entrypoint-selection.js +145 -27
- package/dist/adapter/first-party-systems.d.ts +13 -3
- package/dist/adapter/first-party-systems.d.ts.map +1 -1
- package/dist/adapter/first-party-systems.js +10 -3
- package/dist/adapter/index.d.ts +7 -2
- package/dist/adapter/index.d.ts.map +1 -1
- package/dist/adapter/index.js +4 -0
- package/dist/adapter/ingest/contract-system-adapters.d.ts +1 -1
- package/dist/adapter/ingest/contract-system-adapters.d.ts.map +1 -1
- package/dist/adapter/ingest/contract-system-adapters.js +13 -25
- package/dist/adapter/ingest/game-contract-seams.d.ts +214 -0
- package/dist/adapter/ingest/game-contract-seams.d.ts.map +1 -0
- package/dist/adapter/ingest/game-contract-seams.js +62 -0
- package/dist/adapter/ingest/game-contract.d.ts +5 -3
- package/dist/adapter/ingest/game-contract.d.ts.map +1 -1
- package/dist/adapter/ingest/game-contract.js +4 -1
- package/dist/adapter/ingest/merge-debug-adapters.d.ts +52 -0
- package/dist/adapter/ingest/merge-debug-adapters.d.ts.map +1 -0
- package/dist/adapter/ingest/merge-debug-adapters.js +141 -0
- package/dist/adapter/ingest/observation-debug-adapter.d.ts +56 -0
- package/dist/adapter/ingest/observation-debug-adapter.d.ts.map +1 -0
- package/dist/adapter/ingest/observation-debug-adapter.js +131 -0
- package/dist/adapter/ingest/scene-capture.d.ts +38 -13
- package/dist/adapter/ingest/scene-capture.d.ts.map +1 -1
- package/dist/adapter/ingest/scene-capture.js +101 -24
- package/dist/adapter/ingest/visible-capture-window.d.ts +22 -5
- package/dist/adapter/ingest/visible-capture-window.d.ts.map +1 -1
- package/dist/adapter/ingest/visible-capture-window.js +46 -7
- package/dist/adapter/native-debug-module.d.ts +43 -0
- package/dist/adapter/native-debug-module.d.ts.map +1 -0
- package/dist/adapter/native-debug-module.js +230 -0
- package/dist/adapter/object3d-authoring-subject.d.ts +32 -0
- package/dist/adapter/object3d-authoring-subject.d.ts.map +1 -0
- package/dist/adapter/object3d-authoring-subject.js +25 -0
- package/dist/adapter/root-adapter.d.ts +25 -56
- package/dist/adapter/root-adapter.d.ts.map +1 -1
- package/dist/adapter/root-adapter.js +4 -20
- package/dist/adapter/root-seam-contract.d.ts +129 -0
- package/dist/adapter/root-seam-contract.d.ts.map +1 -0
- package/dist/adapter/root-seam-contract.js +37 -0
- package/dist/adapter/seam-evidence.d.ts +118 -0
- package/dist/adapter/seam-evidence.d.ts.map +1 -0
- package/dist/adapter/seam-evidence.js +231 -0
- package/dist/adapter/setup-three-root-adapter.d.ts +2 -3
- package/dist/adapter/setup-three-root-adapter.d.ts.map +1 -1
- package/dist/adapter/setup-three-root-adapter.js +11 -12
- package/dist/adapter/system-adapter.d.ts +6 -1
- package/dist/adapter/system-adapter.d.ts.map +1 -1
- package/dist/adapter/system-seam-contract.d.ts +354 -0
- package/dist/adapter/system-seam-contract.d.ts.map +1 -0
- package/dist/adapter/system-seam-contract.js +95 -0
- package/dist/animation/xstate-animation-binding.d.ts +6 -0
- package/dist/animation/xstate-animation-binding.d.ts.map +1 -1
- package/dist/animation/xstate-animation-binding.js +142 -4
- package/dist/asset-formats/collider.d.ts +1 -1
- package/dist/asset-formats/mesh.d.ts +2 -2
- package/dist/asset-formats/particles.d.ts +1 -1
- package/dist/canvas-react/engine-bridge.d.ts +6 -6
- package/dist/canvas-react/engine-bridge.d.ts.map +1 -1
- package/dist/canvas-react/engine-bridge.js +2 -2
- package/dist/canvas-react/index.d.ts +2 -2
- package/dist/canvas-react/index.d.ts.map +1 -1
- package/dist/canvas-react/index.js +1 -1
- package/dist/canvas-react/pixi-react-adapter.d.ts +15 -9
- package/dist/canvas-react/pixi-react-adapter.d.ts.map +1 -1
- package/dist/canvas-react/pixi-react-adapter.js +129 -64
- package/dist/canvas-react/pixi-react-root-factory.d.ts.map +1 -1
- package/dist/canvas-react/pixi-react-root-factory.js +4 -0
- package/dist/canvas-react/world-context.d.ts +22 -12
- package/dist/canvas-react/world-context.d.ts.map +1 -1
- package/dist/canvas-react/world-context.js +12 -51
- package/dist/data/curve.d.ts +1 -1
- package/dist/data/curve.js +2 -2
- package/dist/dev/instruments.d.ts +4 -4
- package/dist/dev/instruments.js +4 -4
- package/dist/dev/register-render-vitals.d.ts +2 -2
- package/dist/dev/register-render-vitals.js +2 -2
- package/dist/dev/static-batch-advisor.d.ts +1 -1
- package/dist/dev/static-batch-advisor.js +2 -2
- package/dist/ecs/user-data.d.ts +5 -0
- package/dist/ecs/user-data.d.ts.map +1 -1
- package/dist/ecs/user-data.js +3 -0
- package/dist/input/input-manager.d.ts +64 -0
- package/dist/input/input-manager.d.ts.map +1 -1
- package/dist/input/input-manager.js +149 -0
- package/dist/manifest/load.d.ts +0 -3
- package/dist/manifest/load.d.ts.map +1 -1
- package/dist/manifest/load.js +0 -4
- package/dist/manifest/schema.d.ts +9 -11
- package/dist/manifest/schema.d.ts.map +1 -1
- package/dist/manifest/schema.js +2 -23
- package/dist/pixi/authoring.d.ts +33 -0
- package/dist/pixi/authoring.d.ts.map +1 -1
- package/dist/pixi/authoring.js +301 -2
- package/dist/pixi/ingest.d.ts +2 -1
- package/dist/pixi/ingest.d.ts.map +1 -1
- package/dist/pixi/ingest.js +4 -2
- package/dist/pixi/scene-capture.d.ts +9 -1
- package/dist/pixi/scene-capture.d.ts.map +1 -1
- package/dist/pixi/scene-capture.js +9 -6
- package/dist/react/world-state.d.ts +12 -0
- package/dist/react/world-state.d.ts.map +1 -1
- package/dist/react/world-state.js +14 -0
- package/dist/render/particles-factory.d.ts +13 -6
- package/dist/render/particles-factory.d.ts.map +1 -1
- package/dist/render/particles-factory.js +6 -3
- package/dist/render/soft-particle-depth.d.ts +3 -3
- package/dist/render/soft-particle-depth.d.ts.map +1 -1
- package/dist/render/soft-particle-depth.js +8 -13
- package/dist/runtime/create-runtime.d.ts +25 -62
- package/dist/runtime/create-runtime.d.ts.map +1 -1
- package/dist/runtime/create-runtime.js +58 -105
- package/dist/runtime/dev-build.d.ts +37 -0
- package/dist/runtime/dev-build.d.ts.map +1 -0
- package/dist/runtime/dev-build.js +49 -0
- package/dist/runtime/game.d.ts +38 -72
- package/dist/runtime/game.d.ts.map +1 -1
- package/dist/runtime/game.js +40 -55
- package/dist/runtime/mount-game.d.ts.map +1 -1
- package/dist/runtime/mount-game.js +12 -1
- package/dist/runtime/mount-manifest.d.ts +0 -13
- package/dist/runtime/mount-manifest.d.ts.map +1 -1
- package/dist/runtime/mount-manifest.js +5 -25
- package/dist/runtime/types.d.ts +18 -0
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/setup/setup-renderer.d.ts +3 -4
- package/dist/setup/setup-renderer.d.ts.map +1 -1
- package/dist/setup/setup-renderer.js +3 -4
- package/dist/world3d-react/engine-bridge.d.ts +1 -1
- package/dist/world3d-react/engine-bridge.d.ts.map +1 -1
- package/dist/world3d-react/engine-bridge.js +29 -4
- package/dist/world3d-react/index.d.ts +1 -1
- package/dist/world3d-react/index.js +1 -1
- package/dist/world3d-react/r3f-adapter.d.ts +7 -0
- package/dist/world3d-react/r3f-adapter.d.ts.map +1 -1
- package/dist/world3d-react/r3f-adapter.js +132 -28
- package/dist/world3d-react/r3f-root-factory.d.ts.map +1 -1
- package/dist/world3d-react/r3f-root-factory.js +14 -0
- package/dist/world3d-react/rapier-physics-bridge.d.ts +4 -4
- package/dist/world3d-react/rapier-physics-bridge.js +3 -3
- package/dist/world3d-react/world-context.d.ts +52 -3
- package/dist/world3d-react/world-context.d.ts.map +1 -1
- package/dist/world3d-react/world-context.js +94 -64
- package/dist-config/config.js.map +1 -1
- package/package.json +1 -1
- package/schemas/engine-capabilities.json +8 -8
- package/schemas/vgai-project.schema.json +1 -6
- package/src/adapter/adapter-module.ts +405 -72
- package/src/adapter/authoring-seam-contract.ts +211 -0
- package/src/adapter/authoring.ts +242 -50
- package/src/adapter/entrypoint-selection-source.ts +159 -0
- package/src/adapter/finders/scenes-from-entrypoint-selection.ts +162 -36
- package/src/adapter/first-party-systems.ts +17 -3
- package/src/adapter/index.ts +51 -1
- package/src/adapter/ingest/contract-system-adapters.ts +26 -30
- package/src/adapter/ingest/game-contract-seams.ts +85 -0
- package/src/adapter/ingest/game-contract.ts +9 -4
- package/src/adapter/ingest/merge-debug-adapters.ts +193 -0
- package/src/adapter/ingest/observation-debug-adapter.ts +158 -0
- package/src/adapter/ingest/scene-capture.ts +126 -23
- package/src/adapter/ingest/visible-capture-window.ts +63 -9
- package/src/adapter/native-debug-module.ts +307 -0
- package/src/adapter/object3d-authoring-subject.ts +50 -0
- package/src/adapter/root-adapter.ts +25 -56
- package/src/adapter/root-seam-contract.ts +57 -0
- package/src/adapter/seam-evidence.ts +336 -0
- package/src/adapter/setup-three-root-adapter.ts +13 -15
- package/src/adapter/system-adapter.ts +6 -1
- package/src/adapter/system-seam-contract.ts +121 -0
- package/src/animation/xstate-animation-binding.ts +151 -4
- package/src/canvas-react/engine-bridge.ts +6 -6
- package/src/canvas-react/index.ts +2 -1
- package/src/canvas-react/pixi-react-adapter.tsx +143 -77
- package/src/canvas-react/pixi-react-root-factory.tsx +4 -0
- package/src/canvas-react/world-context.ts +26 -101
- package/src/data/curve.ts +2 -2
- package/src/dev/instruments.ts +4 -4
- package/src/dev/register-render-vitals.ts +2 -2
- package/src/dev/static-batch-advisor.ts +2 -2
- package/src/ecs/user-data.ts +5 -0
- package/src/input/input-manager.ts +145 -0
- package/src/manifest/load.ts +0 -7
- package/src/manifest/schema.ts +2 -25
- package/src/pixi/authoring.ts +329 -2
- package/src/pixi/ingest.ts +9 -2
- package/src/pixi/scene-capture.ts +20 -5
- package/src/react/world-state.tsx +15 -0
- package/src/render/particles-factory.ts +16 -6
- package/src/render/soft-particle-depth.ts +8 -13
- package/src/runtime/create-runtime.ts +79 -158
- package/src/runtime/dev-build.ts +49 -0
- package/src/runtime/game.ts +72 -113
- package/src/runtime/mount-game.ts +19 -1
- package/src/runtime/mount-manifest.ts +5 -37
- package/src/runtime/types.ts +22 -0
- package/src/setup/setup-renderer.ts +3 -4
- package/src/world3d-react/engine-bridge.ts +29 -4
- package/src/world3d-react/index.ts +1 -1
- package/src/world3d-react/r3f-adapter.tsx +140 -31
- package/src/world3d-react/r3f-root-factory.tsx +14 -0
- package/src/world3d-react/rapier-physics-bridge.tsx +4 -4
- package/src/world3d-react/world-context.ts +111 -87
- package/dist/runtime/dev-layers.d.ts +0 -34
- package/dist/runtime/dev-layers.d.ts.map +0 -1
- package/dist/runtime/dev-layers.js +0 -46
- package/src/runtime/dev-layers.ts +0 -46
|
@@ -62,6 +62,18 @@ export const NATIVE_REGION_BASIS = Object.freeze({
|
|
|
62
62
|
up: 'y',
|
|
63
63
|
groundHeight: 0,
|
|
64
64
|
});
|
|
65
|
+
const AdapterRegionMountSchema = z
|
|
66
|
+
.object({
|
|
67
|
+
surface: z
|
|
68
|
+
.enum(['three', 'canvas', 'dom'])
|
|
69
|
+
.describe('An additional surface this root mounts, beside the manifest root’s own adapter'),
|
|
70
|
+
include: z
|
|
71
|
+
.array(z.string().min(1))
|
|
72
|
+
.min(1)
|
|
73
|
+
.describe('Project-relative globs (`**`, `*`, `?`) naming the source files that render on this ' +
|
|
74
|
+
'additional surface'),
|
|
75
|
+
})
|
|
76
|
+
.strict();
|
|
65
77
|
const AdapterRegionBasisSchema = z
|
|
66
78
|
.object({
|
|
67
79
|
up: z.enum(['y', 'z']).describe('World axis pointing away from the ground'),
|
|
@@ -72,10 +84,6 @@ const AdapterRegionSchema = z
|
|
|
72
84
|
.object({
|
|
73
85
|
id: z.string().min(1).describe('Manifest root id this region grades'),
|
|
74
86
|
surface: z.enum(['three', 'canvas', 'dom']).describe('Render surface the host hands this root'),
|
|
75
|
-
dev: z
|
|
76
|
-
.boolean()
|
|
77
|
-
.describe("true = this region grades the game's own dev layer, not shipped content (the " +
|
|
78
|
-
"manifest root's `dev: true`)"),
|
|
79
87
|
projector: z.enum(PROJECTOR_NAMES).describe('Projection library serving this surface, by name'),
|
|
80
88
|
dialect: z
|
|
81
89
|
.string()
|
|
@@ -93,12 +101,62 @@ const AdapterRegionSchema = z
|
|
|
93
101
|
.optional()
|
|
94
102
|
.describe('Project-relative globs (`**`, `*`, `?`) naming source files this region owns, for files ' +
|
|
95
103
|
'no root entry’s import closure reaches; a declared include wins over reach'),
|
|
104
|
+
mounts: z
|
|
105
|
+
.array(AdapterRegionMountSchema)
|
|
106
|
+
.min(1)
|
|
107
|
+
.optional()
|
|
108
|
+
.describe('Surfaces this root mounts BESIDE its own adapter, each with the files that render on ' +
|
|
109
|
+
'them; with `surface`, the root’s full mounted surface set'),
|
|
96
110
|
})
|
|
97
111
|
.strict();
|
|
98
112
|
const RegionBindingSchema = z.union([
|
|
99
113
|
z.literal('manifest-roots'),
|
|
100
114
|
z.array(AdapterRegionSchema).min(1),
|
|
101
115
|
]);
|
|
116
|
+
const AdapterRegionOverlaySchema = z
|
|
117
|
+
.object({
|
|
118
|
+
include: z
|
|
119
|
+
.array(z.string().min(1))
|
|
120
|
+
.min(1)
|
|
121
|
+
.optional()
|
|
122
|
+
.describe('Project-relative globs (`**`, `*`, `?`) naming source files this derived region owns, ' +
|
|
123
|
+
'for files no root entry’s import closure reaches; a declared include wins over reach'),
|
|
124
|
+
mounts: z
|
|
125
|
+
.array(AdapterRegionMountSchema)
|
|
126
|
+
.min(1)
|
|
127
|
+
.optional()
|
|
128
|
+
.describe('Surfaces this root mounts BESIDE its own adapter, each with the files that render on ' +
|
|
129
|
+
'them; with the derived region’s own surface, the root’s full mounted surface set'),
|
|
130
|
+
})
|
|
131
|
+
.strict()
|
|
132
|
+
.refine((value) => value.include !== undefined || value.mounts !== undefined, {
|
|
133
|
+
message: 'regionIncludes entry declares neither `include` nor `mounts` — an empty overlay states ' +
|
|
134
|
+
'nothing the derivation did not already say. Remove it, or name the files it owns.',
|
|
135
|
+
});
|
|
136
|
+
/**
|
|
137
|
+
* PARAMETERS FOR THE RULE, keyed by manifest root id (decision, 2026-08-17;
|
|
138
|
+
* ARCHITECTURE-CORE §The editor protocol, "Declared includes LAYER onto the
|
|
139
|
+
* manifest-roots rule").
|
|
140
|
+
*
|
|
141
|
+
* The finder-selection shape, one level up: `regions: 'manifest-roots'` SELECTS
|
|
142
|
+
* the mechanical derivation, and this table DECLARES the per-region parameters
|
|
143
|
+
* it cannot derive. The two compose — {@link regionsFromManifestRoots} merges
|
|
144
|
+
* them — so a first-party project states one include without hand-writing its
|
|
145
|
+
* whole region table, and adding a root still grows the table for free.
|
|
146
|
+
*
|
|
147
|
+
* Illegal beside an explicit `regions` LIST, and rejected by name: that form is
|
|
148
|
+
* the full REPLACEMENT, and its entries carry `include`/`mounts` themselves.
|
|
149
|
+
* Two homes for one fact is how a declaration goes stale in one of them.
|
|
150
|
+
*
|
|
151
|
+
* MEASURED BASIS (PR #2281, verified twice): the region binding was
|
|
152
|
+
* replace-only, so no `nativeAdapter()` project could declare a single include
|
|
153
|
+
* without restating every region — which is what blocked the source-text R3F
|
|
154
|
+
* floor's retirement across the five shipped 3D projects.
|
|
155
|
+
*/
|
|
156
|
+
const RegionIncludesSchema = z
|
|
157
|
+
.record(z.string().min(1), AdapterRegionOverlaySchema)
|
|
158
|
+
.describe('Per-region parameters for the `manifest-roots` rule, keyed by manifest root id: the ' +
|
|
159
|
+
'`include` globs and `mounts` surfaces the mechanical derivation cannot produce');
|
|
102
160
|
/**
|
|
103
161
|
* The MECHANICAL derivation behind the `'manifest-roots'` rule: one region per
|
|
104
162
|
* declared root, its surface and adapter identity read straight off the
|
|
@@ -107,13 +165,20 @@ const RegionBindingSchema = z.union([
|
|
|
107
165
|
*
|
|
108
166
|
* The per-surface library table below is an ENGINE fact, stated once:
|
|
109
167
|
*
|
|
110
|
-
* | root `adapter` | projector | dialect | anchors
|
|
111
|
-
*
|
|
112
|
-
* | `three` | `three` | `r3f` | source-prop, construction-literal
|
|
113
|
-
* | `canvas` | `pixi` | `pixi-react` | source-prop, construction-literal
|
|
114
|
-
* | `dom` | `dom` | `jsx` | source-prop |
|
|
115
|
-
* | `{module,surface}` | (surface) | `null` | live-only
|
|
116
|
-
* | `{ingest,surface}` | (surface) | `null` | live-only
|
|
168
|
+
* | root `adapter` | projector | dialect | anchors |
|
|
169
|
+
* |-----------------------|-----------|---------------|------------------------------------------------------|
|
|
170
|
+
* | `three` | `three` | `r3f` | source-prop, source-structure, construction-literal |
|
|
171
|
+
* | `canvas` | `pixi` | `pixi-react` | source-prop, source-structure, construction-literal |
|
|
172
|
+
* | `dom` | `dom` | `jsx` | source-prop, source-structure |
|
|
173
|
+
* | `{module,surface}` | (surface) | `null` | live-only |
|
|
174
|
+
* | `{ingest,surface}` | (surface) | `null` | live-only |
|
|
175
|
+
*
|
|
176
|
+
* `source-structure` rides with every first-party dialect because all three
|
|
177
|
+
* write through the SAME structural door (`/__ui-source/struct`) — a region
|
|
178
|
+
* that can rewrite a JSX attribute in a file can rewrite that file's element
|
|
179
|
+
* tree. It is listed separately rather than folded into `source-prop` because
|
|
180
|
+
* they are different doors: a lane could lose one and keep the other, and the
|
|
181
|
+
* matrix has to be able to say so.
|
|
117
182
|
*
|
|
118
183
|
* A module/ingest root's truth is the game's own source, which no first-party
|
|
119
184
|
* dialect writer authors — so it declares `live-only` rather than implying a
|
|
@@ -123,55 +188,81 @@ const RegionBindingSchema = z.union([
|
|
|
123
188
|
* Every derived region carries {@link NATIVE_REGION_BASIS} outright, so the
|
|
124
189
|
* editor's ground plane READS a declaration on the native path too — the
|
|
125
190
|
* default is published, never assumed at the read site.
|
|
191
|
+
*
|
|
192
|
+
* It DERIVES no {@link AdapterRegion.include} and no {@link AdapterRegion.mounts},
|
|
193
|
+
* and there is no derivation that could: the manifest states ONE adapter per
|
|
194
|
+
* root and names only its entry, so a root's extra owned files and its second
|
|
195
|
+
* mounted surface are facts only the game can state. It states them as
|
|
196
|
+
* `regionIncludes` PARAMETERS, which this function merges onto the region it
|
|
197
|
+
* derives for that root — the rule stays selected, the parameters are declared
|
|
198
|
+
* (ARCHITECTURE-CORE §The editor protocol, "Declared includes LAYER onto the
|
|
199
|
+
* manifest-roots rule"). A key naming no declared root merges onto nothing;
|
|
200
|
+
* the LOADER reports that, because only it can see both sides.
|
|
126
201
|
*/
|
|
127
|
-
export function regionsFromManifestRoots(roots) {
|
|
128
|
-
return roots.map((root) => {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
202
|
+
export function regionsFromManifestRoots(roots, regionIncludes = {}) {
|
|
203
|
+
return roots.map((root) => ({
|
|
204
|
+
...derivedRegion(root),
|
|
205
|
+
...overlayOf(regionIncludes[root.id]),
|
|
206
|
+
}));
|
|
207
|
+
}
|
|
208
|
+
/** The declared half of a merged region — omitted keys leave the derived
|
|
209
|
+
* region untouched, so an overlay can only ADD what the rule cannot derive. */
|
|
210
|
+
function overlayOf(overlay) {
|
|
211
|
+
if (!overlay)
|
|
212
|
+
return {};
|
|
213
|
+
return {
|
|
214
|
+
...(overlay.include ? { include: overlay.include } : {}),
|
|
215
|
+
...(overlay.mounts ? { mounts: overlay.mounts } : {}),
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
/** Region ids an overlay names that no declared root answers to. A typo here
|
|
219
|
+
* would otherwise be a declaration that silently does nothing, which is the
|
|
220
|
+
* failure class the whole declaration lane exists to end. */
|
|
221
|
+
export function unmatchedRegionIncludeIds(roots, regionIncludes) {
|
|
222
|
+
const declared = new Set(roots.map((root) => root.id));
|
|
223
|
+
return Object.keys(regionIncludes).filter((id) => !declared.has(id));
|
|
224
|
+
}
|
|
225
|
+
/** One root's region, before any declared parameters are merged onto it. */
|
|
226
|
+
function derivedRegion(root) {
|
|
227
|
+
const surface = root.surface;
|
|
228
|
+
const firstParty = root.adapter.type === 'builtin';
|
|
229
|
+
const projector = surface === 'canvas' ? 'pixi' : surface;
|
|
230
|
+
const basis = NATIVE_REGION_BASIS;
|
|
231
|
+
if (!firstParty) {
|
|
156
232
|
return {
|
|
157
233
|
id: root.id,
|
|
158
234
|
surface,
|
|
159
|
-
dev,
|
|
160
235
|
projector,
|
|
161
|
-
dialect:
|
|
162
|
-
anchors: ['
|
|
236
|
+
dialect: null,
|
|
237
|
+
anchors: ['live-only'],
|
|
163
238
|
basis,
|
|
164
239
|
};
|
|
165
|
-
}
|
|
240
|
+
}
|
|
241
|
+
if (surface === 'dom') {
|
|
242
|
+
return {
|
|
243
|
+
id: root.id,
|
|
244
|
+
surface,
|
|
245
|
+
projector,
|
|
246
|
+
dialect: 'jsx',
|
|
247
|
+
anchors: ['source-prop', 'source-structure'],
|
|
248
|
+
basis,
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
return {
|
|
252
|
+
id: root.id,
|
|
253
|
+
surface,
|
|
254
|
+
projector,
|
|
255
|
+
dialect: surface === 'three' ? 'r3f' : 'pixi-react',
|
|
256
|
+
anchors: ['source-prop', 'source-structure', 'construction-literal'],
|
|
257
|
+
basis,
|
|
258
|
+
};
|
|
166
259
|
}
|
|
167
260
|
// ---------------------------------------------------------------------------
|
|
168
261
|
// Finder selections
|
|
169
262
|
// ---------------------------------------------------------------------------
|
|
170
263
|
/**
|
|
171
264
|
* The rule form of a finder's region targeting: every region the host mounts
|
|
172
|
-
* from an exported composition
|
|
173
|
-
* DEV layer. A dev root is the game's own dev GUI — the manifest already says
|
|
174
|
-
* so (`dev: true`), so skipping it reads a declaration rather than guessing.
|
|
265
|
+
* from an exported composition — a root with an `entry`.
|
|
175
266
|
*/
|
|
176
267
|
export const EXPORTED_COMPOSITION_REGIONS = 'exported-composition-regions';
|
|
177
268
|
/** The finder names, as a value — what the loader's dispatcher switches on. */
|
|
@@ -207,9 +298,11 @@ const SceneReachSchema = z.union([
|
|
|
207
298
|
kind: z.literal('entrypoint-selection'),
|
|
208
299
|
selection: z.string().min(1),
|
|
209
300
|
key: z.string().min(1),
|
|
301
|
+
active: z.boolean().optional(),
|
|
210
302
|
})
|
|
211
303
|
.strict(),
|
|
212
304
|
z.object({ kind: z.literal('story'), storyId: z.string().min(1) }).strict(),
|
|
305
|
+
z.object({ kind: z.literal('game-contract'), sceneId: z.string().min(1) }).strict(),
|
|
213
306
|
z.object({ kind: z.literal('none'), reason: z.string().min(1) }).strict(),
|
|
214
307
|
]);
|
|
215
308
|
const SceneSourceSchema = z
|
|
@@ -224,6 +317,7 @@ const SceneEntrySchema = z
|
|
|
224
317
|
authorable: z.boolean(),
|
|
225
318
|
reach: SceneReachSchema,
|
|
226
319
|
source: SceneSourceSchema.optional(),
|
|
320
|
+
isolationSetup: SceneSourceSchema.optional(),
|
|
227
321
|
finder: z.enum(FINDER_NAMES).optional(),
|
|
228
322
|
})
|
|
229
323
|
.strict();
|
|
@@ -234,24 +328,100 @@ const AdapterSceneTableSchema = z
|
|
|
234
328
|
default: z.string().min(1).optional(),
|
|
235
329
|
})
|
|
236
330
|
.strict();
|
|
331
|
+
// ---------------------------------------------------------------------------
|
|
332
|
+
// Observation
|
|
333
|
+
// ---------------------------------------------------------------------------
|
|
334
|
+
/**
|
|
335
|
+
* The two faces a declaration projects onto. They are exactly the two
|
|
336
|
+
* `DebugAdapter` halves (`adapter/system-adapter.ts`): `state` becomes a
|
|
337
|
+
* provider (`providers()` / `state(name)`), `command` becomes a verb
|
|
338
|
+
* (`commands()` / `invoke(name, args)`). There is deliberately no third kind —
|
|
339
|
+
* see {@link OBSERVATION_KIND_REFUSAL}.
|
|
340
|
+
*/
|
|
341
|
+
export const OBSERVATION_KINDS = ['command', 'state'];
|
|
342
|
+
/**
|
|
343
|
+
* Why a declaration may not name a `SystemAdapters` slot here.
|
|
344
|
+
*
|
|
345
|
+
* A game's system slots are already declared through the game contract's own
|
|
346
|
+
* `systemAdapters` carrier (`adapter/ingest/game-contract.ts`), which validates
|
|
347
|
+
* each slot per-surface and reports a malformed one BY NAME
|
|
348
|
+
* (`contract-system-adapters.ts`). A second door onto the same slots is exactly
|
|
349
|
+
* the two-declarations-one-slot problem `game-contract.ts` records for `debug`,
|
|
350
|
+
* where it says outright that a second door "would let a game declare two
|
|
351
|
+
* different debug planes with no rule for which wins".
|
|
352
|
+
*/
|
|
353
|
+
const OBSERVATION_KIND_REFUSAL = "observation.kind must be 'command' or 'state' — the two DebugAdapter faces a declaration " +
|
|
354
|
+
'projects onto. A SystemAdapters slot is declared through the game contract’s `systemAdapters` ' +
|
|
355
|
+
'carrier, which validates it per-surface; declaring one here would be a second door onto the ' +
|
|
356
|
+
'same slot with no rule for which wins.';
|
|
237
357
|
const ObservationDeclarationSchema = z
|
|
238
358
|
.object({
|
|
239
359
|
id: z.string().min(1),
|
|
240
|
-
kind: z.enum(
|
|
360
|
+
kind: z.enum(OBSERVATION_KINDS, { error: () => OBSERVATION_KIND_REFUSAL }),
|
|
361
|
+
description: z.string().min(1).optional(),
|
|
362
|
+
locus: z.enum(['client', 'server']).optional(),
|
|
241
363
|
answer: z
|
|
242
364
|
.custom((value) => typeof value === 'function', {
|
|
243
365
|
message: 'observation.answer must be a function evaluated against the mounted game',
|
|
244
366
|
})
|
|
245
367
|
.optional(),
|
|
368
|
+
})
|
|
369
|
+
.strict()
|
|
370
|
+
.refine((value) => value.kind === 'command' || value.locus === undefined, {
|
|
371
|
+
path: ['locus'],
|
|
372
|
+
message: 'observation.locus is valid only for a command declaration',
|
|
373
|
+
});
|
|
374
|
+
// ---------------------------------------------------------------------------
|
|
375
|
+
// Native input
|
|
376
|
+
// ---------------------------------------------------------------------------
|
|
377
|
+
/** The action value shapes the session input door already speaks. */
|
|
378
|
+
export const ADAPTER_INPUT_VALUE_TYPES = [
|
|
379
|
+
'digital',
|
|
380
|
+
'scalar',
|
|
381
|
+
'vector2',
|
|
382
|
+
'pointerDelta',
|
|
383
|
+
'pointerPosition',
|
|
384
|
+
];
|
|
385
|
+
const AdapterInputBindingSchema = z
|
|
386
|
+
.object({
|
|
387
|
+
root: z.string().min(1),
|
|
388
|
+
actions: z.custom((value) => typeof value === 'function', {
|
|
389
|
+
message: 'input.actions must be a function returning the app-owned action vocabulary',
|
|
390
|
+
}),
|
|
391
|
+
set: z.custom((value) => typeof value === 'function', {
|
|
392
|
+
message: 'input.set must be a function writing the app-owned input store',
|
|
393
|
+
}),
|
|
394
|
+
clear: z.custom((value) => typeof value === 'function', {
|
|
395
|
+
message: 'input.clear must be a function releasing app-owned virtual actions',
|
|
396
|
+
}),
|
|
246
397
|
})
|
|
247
398
|
.strict();
|
|
399
|
+
/**
|
|
400
|
+
* Why the two forms may not be combined, said in the error a game's author
|
|
401
|
+
* reads. An explicit region list REPLACES the derivation and its entries carry
|
|
402
|
+
* `include`/`mounts` themselves; layering a second table over it would put one
|
|
403
|
+
* fact in two homes, with no rule for which wins.
|
|
404
|
+
*/
|
|
405
|
+
const REGION_INCLUDES_WITH_LIST_REFUSAL = '`regionIncludes` states parameters for the `manifest-roots` RULE, so it cannot be paired ' +
|
|
406
|
+
'with an explicit `regions` list — that form is the full replacement, and each entry carries ' +
|
|
407
|
+
'its own `include`/`mounts`. Move these globs onto the matching `regions[]` entry, or drop the ' +
|
|
408
|
+
'list and let the derivation run.';
|
|
248
409
|
export const AdapterDefinitionSchema = z
|
|
249
410
|
.object({
|
|
250
411
|
regions: RegionBindingSchema.optional(),
|
|
412
|
+
regionIncludes: RegionIncludesSchema.optional(),
|
|
251
413
|
scenes: AdapterSceneTableSchema.optional(),
|
|
252
414
|
observation: z.array(ObservationDeclarationSchema).optional(),
|
|
415
|
+
input: AdapterInputBindingSchema.optional(),
|
|
253
416
|
})
|
|
254
|
-
.strict()
|
|
417
|
+
.strict()
|
|
418
|
+
// An EMPTY table beside a list is fine and must stay fine: `defineAdapter`
|
|
419
|
+
// publishes `regionIncludes: {}` on every definition, and its output is
|
|
420
|
+
// parsed a second time by the host's loader — a refusal on the key's mere
|
|
421
|
+
// presence would reject the module's own valid output on the round trip.
|
|
422
|
+
.refine((value) => value.regionIncludes === undefined ||
|
|
423
|
+
Object.keys(value.regionIncludes).length === 0 ||
|
|
424
|
+
!Array.isArray(value.regions), { message: REGION_INCLUDES_WITH_LIST_REFUSAL });
|
|
255
425
|
/**
|
|
256
426
|
* Validate and freeze a game's binding table.
|
|
257
427
|
*
|
|
@@ -270,8 +440,10 @@ export function defineAdapter(input = {}) {
|
|
|
270
440
|
}
|
|
271
441
|
return Object.freeze({
|
|
272
442
|
regions: input.regions ?? 'manifest-roots',
|
|
443
|
+
regionIncludes: Object.freeze({ ...(input.regionIncludes ?? {}) }),
|
|
273
444
|
scenes: Object.freeze({ ...(input.scenes ?? {}) }),
|
|
274
445
|
observation: Object.freeze([...(input.observation ?? [])]),
|
|
446
|
+
...(input.input ? { input: input.input } : {}),
|
|
275
447
|
});
|
|
276
448
|
}
|
|
277
449
|
/**
|
|
@@ -284,6 +456,7 @@ export function defineAdapter(input = {}) {
|
|
|
284
456
|
export function nativeAdapter(options = {}) {
|
|
285
457
|
return defineAdapter({
|
|
286
458
|
regions: 'manifest-roots',
|
|
459
|
+
...(options.regionIncludes ? { regionIncludes: options.regionIncludes } : {}),
|
|
287
460
|
scenes: {
|
|
288
461
|
...(options.scenes ? { entries: options.scenes } : {}),
|
|
289
462
|
find: [
|
|
@@ -291,7 +464,6 @@ export function nativeAdapter(options = {}) {
|
|
|
291
464
|
{ finder: 'prefabsFromStories' },
|
|
292
465
|
],
|
|
293
466
|
},
|
|
294
|
-
...(options.observation ? { observation: options.observation } : {}),
|
|
295
467
|
});
|
|
296
468
|
}
|
|
297
469
|
/**
|