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