@vgai/engine 0.5.11 → 0.5.13
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 -5
- package/dist/adapter/authoring.d.ts +51 -28
- package/dist/adapter/authoring.d.ts.map +1 -1
- package/dist/adapter/body-marks.d.ts +59 -0
- package/dist/adapter/body-marks.d.ts.map +1 -0
- package/dist/adapter/body-marks.js +62 -0
- package/dist/adapter/constraint.d.ts +41 -0
- package/dist/adapter/constraint.d.ts.map +1 -0
- package/dist/adapter/constraint.js +27 -0
- package/dist/adapter/hierarchy-marks.d.ts +138 -0
- package/dist/adapter/hierarchy-marks.d.ts.map +1 -0
- package/dist/adapter/hierarchy-marks.js +148 -0
- package/dist/adapter/index.d.ts +1 -1
- package/dist/adapter/index.d.ts.map +1 -1
- package/dist/adapter/ingest/contract-system-adapters.d.ts +64 -0
- package/dist/adapter/ingest/contract-system-adapters.d.ts.map +1 -0
- package/dist/adapter/ingest/contract-system-adapters.js +134 -0
- package/dist/adapter/ingest/game-contract.d.ts +87 -9
- package/dist/adapter/ingest/game-contract.d.ts.map +1 -1
- package/dist/adapter/ingest/game-contract.js +7 -6
- package/dist/adapter/ingest/scene-capture.d.ts +31 -4
- package/dist/adapter/ingest/scene-capture.d.ts.map +1 -1
- package/dist/adapter/ingest/scene-capture.js +29 -7
- package/dist/adapter/ingest/structural-ids.d.ts +1 -1
- package/dist/adapter/ingest/structural-ids.js +2 -2
- package/dist/adapter/reflection-probe.d.ts +53 -0
- package/dist/adapter/reflection-probe.d.ts.map +1 -0
- package/dist/adapter/reflection-probe.js +18 -0
- package/dist/asset-formats/index.d.ts +4 -10
- package/dist/asset-formats/index.d.ts.map +1 -1
- package/dist/asset-formats/index.js +3 -8
- package/dist/asset-formats/material.d.ts +0 -66
- package/dist/asset-formats/material.d.ts.map +1 -1
- package/dist/asset-formats/material.js +0 -8
- package/dist/asset-formats/mesh.d.ts +1 -2
- package/dist/asset-formats/mesh.d.ts.map +1 -1
- package/dist/asset-formats/mesh.js +3 -13
- package/dist/asset-formats/render-env.d.ts +2 -2
- package/dist/asset-parse-error.d.ts +4 -5
- package/dist/asset-parse-error.d.ts.map +1 -1
- package/dist/asset-parse-error.js +4 -5
- package/dist/config.d.ts +7 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +7 -0
- package/dist/data/curve.d.ts +116 -0
- package/dist/data/curve.d.ts.map +1 -0
- package/dist/data/curve.js +230 -0
- package/dist/data/vite-plugin-data.d.ts +2 -2
- package/dist/data/vite-plugin-data.d.ts.map +1 -1
- package/dist/data/vite-plugin-data.js +24 -15
- package/dist/dev/performance-profiler.d.ts +1 -0
- package/dist/dev/performance-profiler.d.ts.map +1 -1
- package/dist/dev/performance-profiler.js +25 -2
- package/dist/ecs/user-data.d.ts +49 -1
- package/dist/ecs/user-data.d.ts.map +1 -1
- package/dist/ecs/user-data.js +34 -0
- package/dist/index.d.ts +2 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -3
- package/dist/manifest/index.d.ts +3 -3
- package/dist/manifest/index.d.ts.map +1 -1
- package/dist/manifest/index.js +2 -2
- package/dist/manifest/load.d.ts +15 -67
- package/dist/manifest/load.d.ts.map +1 -1
- package/dist/manifest/load.js +11 -103
- package/dist/manifest/schema.d.ts +18 -103
- package/dist/manifest/schema.d.ts.map +1 -1
- package/dist/manifest/schema.js +59 -179
- package/dist/pixi/index.d.ts +2 -3
- package/dist/pixi/index.d.ts.map +1 -1
- package/dist/pixi/index.js +2 -3
- package/dist/pixi/ingest.d.ts +7 -75
- package/dist/pixi/ingest.d.ts.map +1 -1
- package/dist/pixi/ingest.js +6 -14
- package/dist/pixi/scene-capture.d.ts +2 -2
- package/dist/pixi/scene-capture.js +2 -2
- package/dist/react/use-data.d.ts +10 -5
- package/dist/react/use-data.d.ts.map +1 -1
- package/dist/react/use-data.js +15 -15
- package/dist/render/viewport-shading.d.ts +1 -1
- package/dist/render/viewport-shading.d.ts.map +1 -1
- package/dist/render/viewport-shading.js +14 -0
- package/dist/runtime/create-runtime.d.ts +12 -0
- package/dist/runtime/create-runtime.d.ts.map +1 -1
- package/dist/runtime/create-runtime.js +7 -2
- package/dist/runtime/mount-game.d.ts +1 -1
- package/dist/runtime/mount-game.d.ts.map +1 -1
- package/dist/runtime/mount-manifest.d.ts.map +1 -1
- package/dist/runtime/mount-manifest.js +5 -1
- package/dist/world3d-react/r3f-adapter.d.ts.map +1 -1
- package/dist/world3d-react/r3f-adapter.js +69 -39
- package/dist/world3d-react/renderer-config.d.ts +15 -0
- package/dist/world3d-react/renderer-config.d.ts.map +1 -1
- package/dist/world3d-react/renderer-config.js +15 -0
- package/dist/world3d-react/world-context.d.ts +2 -1
- package/dist/world3d-react/world-context.d.ts.map +1 -1
- package/dist-config/config.js +140 -20
- package/dist-config/config.js.map +4 -4
- package/package.json +1 -1
- package/schemas/engine-capabilities.json +10 -10
- package/schemas/vgai-project.schema.json +21 -76
- package/src/adapter/authoring.ts +54 -31
- package/src/adapter/body-marks.ts +69 -0
- package/src/adapter/constraint.ts +71 -0
- package/src/adapter/hierarchy-marks.ts +155 -0
- package/src/adapter/index.ts +2 -3
- package/src/adapter/ingest/contract-system-adapters.ts +174 -0
- package/src/adapter/ingest/game-contract.ts +98 -9
- package/src/adapter/ingest/scene-capture.ts +61 -11
- package/src/adapter/ingest/structural-ids.ts +2 -2
- package/src/adapter/reflection-probe.ts +75 -0
- package/src/asset-formats/index.ts +4 -10
- package/src/asset-formats/material.ts +0 -11
- package/src/asset-formats/mesh.ts +3 -16
- package/src/asset-parse-error.ts +4 -5
- package/src/config.ts +13 -0
- package/src/data/curve.ts +263 -0
- package/src/data/vite-plugin-data.ts +48 -14
- package/src/dev/performance-profiler.ts +21 -2
- package/src/ecs/user-data.ts +50 -0
- package/src/index.ts +2 -3
- package/src/manifest/index.ts +3 -15
- package/src/manifest/load.ts +27 -143
- package/src/manifest/schema.ts +65 -223
- package/src/pixi/index.ts +2 -15
- package/src/pixi/ingest.ts +13 -87
- package/src/pixi/scene-capture.ts +2 -2
- package/src/react/use-data.ts +15 -20
- package/src/render/viewport-shading.ts +16 -1
- package/src/runtime/create-runtime.ts +30 -5
- package/src/runtime/mount-game.ts +1 -1
- package/src/runtime/mount-manifest.ts +5 -1
- package/src/world3d-react/r3f-adapter.tsx +73 -39
- package/src/world3d-react/renderer-config.ts +31 -0
- package/src/world3d-react/world-context.ts +2 -1
- package/dist/asset-formats/instances.d.ts +0 -17
- package/dist/asset-formats/instances.d.ts.map +0 -1
- package/dist/asset-formats/instances.js +0 -31
- package/dist/asset-formats/parse.d.ts +0 -20
- package/dist/asset-formats/parse.d.ts.map +0 -1
- package/dist/asset-formats/parse.js +0 -34
- package/dist/pixi/ingest-iframe.d.ts +0 -82
- package/dist/pixi/ingest-iframe.d.ts.map +0 -1
- package/dist/pixi/ingest-iframe.js +0 -166
- package/dist/render/instance-mesh.d.ts +0 -5
- package/dist/render/instance-mesh.d.ts.map +0 -1
- package/dist/render/instance-mesh.js +0 -19
- package/schemas/mat.schema.json +0 -255
- package/src/asset-formats/instances.ts +0 -38
- package/src/asset-formats/parse.ts +0 -39
- package/src/pixi/ingest-iframe.ts +0 -255
- package/src/render/instance-mesh.ts +0 -25
package/src/manifest/load.ts
CHANGED
|
@@ -17,10 +17,8 @@ import {
|
|
|
17
17
|
type AdapterRoot,
|
|
18
18
|
type GameManifest,
|
|
19
19
|
GameManifestSchema,
|
|
20
|
-
type IngestStrategy,
|
|
21
20
|
type LearnMetadata,
|
|
22
21
|
type RootAdapter,
|
|
23
|
-
type Tier,
|
|
24
22
|
} from './schema';
|
|
25
23
|
|
|
26
24
|
// ---------------------------------------------------------------------------
|
|
@@ -42,40 +40,28 @@ export type ResolvedAdapter =
|
|
|
42
40
|
}
|
|
43
41
|
| {
|
|
44
42
|
readonly type: 'ingest';
|
|
45
|
-
// 'ingest-react' (Track N, N1) is assigned here purely structurally
|
|
46
|
-
// === 'dom'), same as 'ingest-three'/'ingest-pixi'
|
|
47
|
-
// strategy-agnostic at resolve time, exactly like the other two ingest
|
|
48
|
-
// identities (`ceilingFor`/`resolveCapabilities` below already derive tiers
|
|
49
|
-
// per `strategy` regardless of `kind`). The v1 "deduped rung only" rule
|
|
50
|
-
// (D-N3) is enforced editor-side, at the resolver
|
|
51
|
-
// (`packages/editor/src/adapter-resolver.ts`'s `resolveIngestReactAdapter`)
|
|
52
|
-
// — not here — mirroring how THIS file never rejects
|
|
53
|
-
// `ingest-three`/`ingest-pixi`'s `iframe-reachable`/`opaque-embed`
|
|
54
|
-
// strategies either; `resolveIngestDescriptor`/`resolveIngest2DDescriptor`
|
|
55
|
-
// are where "not yet buildable" strategies throw.
|
|
43
|
+
// 'ingest-react' (Track N, N1) is assigned here purely structurally
|
|
44
|
+
// (surface === 'dom'), same as 'ingest-three'/'ingest-pixi'.
|
|
56
45
|
readonly identity: 'ingest-three' | 'ingest-pixi' | 'ingest-react';
|
|
57
46
|
readonly surface: 'three' | 'canvas' | 'dom';
|
|
58
|
-
readonly strategy: IngestStrategy;
|
|
59
|
-
readonly entryHtml: string | undefined;
|
|
60
47
|
/**
|
|
61
48
|
* Project-relative ES module declaring `window.vgaiGame` beside a
|
|
62
49
|
* pristine copy. OPTIONAL rather than required-and-possibly-undefined
|
|
63
|
-
* (the shape its siblings above use) because
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
* requiring the key would only make them all say `undefined`.
|
|
50
|
+
* (the shape its siblings above use) because most ingested games have
|
|
51
|
+
* nothing to say about it, and requiring the key would only make every
|
|
52
|
+
* construction site say `undefined`.
|
|
67
53
|
*/
|
|
68
54
|
readonly contractShim?: string | undefined;
|
|
55
|
+
/**
|
|
56
|
+
* Project-relative ES module that writes this game'''s own DATA file back
|
|
57
|
+
* (see the field'''s schema description). Same OPTIONAL shape and same
|
|
58
|
+
* reason as {@link contractShim}: a game whose truth is entirely source
|
|
59
|
+
* declares nothing here.
|
|
60
|
+
*/
|
|
61
|
+
readonly dataWriter?: string | undefined;
|
|
69
62
|
readonly assets: Record<string, string> | undefined;
|
|
70
63
|
readonly domStubs: string[] | undefined;
|
|
71
64
|
readonly captureTimeoutMs: number | undefined;
|
|
72
|
-
/** Iframe-reachable-multi mount fields. */
|
|
73
|
-
readonly bundleUrl: string | undefined;
|
|
74
|
-
readonly baseHref: string | undefined;
|
|
75
|
-
readonly assetBaseUrl: string | undefined;
|
|
76
|
-
readonly extraDeps: string[] | undefined;
|
|
77
|
-
readonly pixiModuleUrl: string | undefined;
|
|
78
|
-
readonly bodyHtml: string | undefined;
|
|
79
65
|
};
|
|
80
66
|
|
|
81
67
|
export interface ResolvedAdapterRoot {
|
|
@@ -90,8 +76,6 @@ export interface ResolvedAdapterRoot {
|
|
|
90
76
|
* `manifest/schema.ts`'s `dev` field for the four readers. */
|
|
91
77
|
readonly dev: boolean;
|
|
92
78
|
readonly loop: 'gated' | 'self-driven';
|
|
93
|
-
/** Every optional resolved: both contexts always present (§4/§5). */
|
|
94
|
-
readonly capabilities: { readonly local: Tier; readonly hosted: Tier };
|
|
95
79
|
}
|
|
96
80
|
|
|
97
81
|
export interface ResolvedGameManifest {
|
|
@@ -104,6 +88,8 @@ export interface ResolvedGameManifest {
|
|
|
104
88
|
readonly roots: readonly ResolvedAdapterRoot[];
|
|
105
89
|
readonly server: { readonly room: string; readonly module: string } | undefined;
|
|
106
90
|
readonly resolution: { readonly width: number; readonly height: number } | undefined;
|
|
91
|
+
/** Construction-time renderer properties no world can declare for itself — see the schema. */
|
|
92
|
+
readonly rendering: { readonly antialias: boolean } | undefined;
|
|
107
93
|
readonly authoring:
|
|
108
94
|
| {
|
|
109
95
|
readonly hierarchy?:
|
|
@@ -149,55 +135,6 @@ export interface ResolvedGameManifest {
|
|
|
149
135
|
readonly learn: LearnMetadata | undefined;
|
|
150
136
|
}
|
|
151
137
|
|
|
152
|
-
// ---------------------------------------------------------------------------
|
|
153
|
-
// §4 — the per-context ceiling table (named + exported so the tier-table test
|
|
154
|
-
// can pin its rows against this).
|
|
155
|
-
// ---------------------------------------------------------------------------
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Ceiling (maximum legal declared `Tier`) per adapter type and delivery
|
|
159
|
-
* context. `default` roots are always first-party in both contexts (D6/§2 —
|
|
160
|
-
* a first-party root is fully vgai-native everywhere). `ingest` roots are
|
|
161
|
-
* ceilinged by their own capture `strategy`: locally the local CLI's Vite
|
|
162
|
-
* pipeline gives bundler dedupe, so every strategy reaches its own natural
|
|
163
|
-
* rung; hosted has no bundler (esbuild-wasm + externals only), and a
|
|
164
|
-
* `deduped` root is DEFINED by being source built through our pipeline — no
|
|
165
|
-
* prebuilt bundle exists to fall back to an iframe rung, and nothing
|
|
166
|
-
* implements a hosted build for it, so hosted is `unsupported` (honesty over
|
|
167
|
-
* optimism; if the hosted esbuild-wasm path ever proves capable, raising
|
|
168
|
-
* this ceiling is a non-breaking widening). `shared`/`iframe-reachable`/
|
|
169
|
-
* `opaque-embed` don't depend on a bundler either way, so they carry through
|
|
170
|
-
* unchanged. `module` adapters have no derivable ceiling ("a custom
|
|
171
|
-
* adapter's reach is not derivable", §4) — modeled here as `first-party`
|
|
172
|
-
* (the top rank), i.e. no ceiling actually constrains a module adapter's
|
|
173
|
-
* declared tier; the loader instead requires the tier to be declared
|
|
174
|
-
* explicitly for module roots (see `resolveCapabilities`), since there is no
|
|
175
|
-
* default to derive.
|
|
176
|
-
*/
|
|
177
|
-
export const CAPABILITY_CEILINGS = {
|
|
178
|
-
builtin: { local: 'first-party', hosted: 'first-party' },
|
|
179
|
-
ingest: {
|
|
180
|
-
shared: { local: 'shared', hosted: 'shared' },
|
|
181
|
-
deduped: { local: 'deduped', hosted: 'unsupported' },
|
|
182
|
-
'iframe-reachable': { local: 'iframe-reachable', hosted: 'iframe-reachable' },
|
|
183
|
-
'opaque-embed': { local: 'opaque-embed', hosted: 'opaque-embed' },
|
|
184
|
-
},
|
|
185
|
-
module: { local: 'first-party', hosted: 'first-party' },
|
|
186
|
-
} as const satisfies Record<
|
|
187
|
-
string,
|
|
188
|
-
{ local: Tier; hosted: Tier } | Record<IngestStrategy, { local: Tier; hosted: Tier }>
|
|
189
|
-
>;
|
|
190
|
-
|
|
191
|
-
/** Total order over `Tier` (§4: `first-party > shared ≈ deduped > iframe-reachable > opaque-embed > unsupported`). */
|
|
192
|
-
const TIER_RANK: Record<Tier, number> = {
|
|
193
|
-
'first-party': 5,
|
|
194
|
-
shared: 4,
|
|
195
|
-
deduped: 4,
|
|
196
|
-
'iframe-reachable': 3,
|
|
197
|
-
'opaque-embed': 2,
|
|
198
|
-
unsupported: 1,
|
|
199
|
-
};
|
|
200
|
-
|
|
201
138
|
/** Default relative path for `server.module` when omitted (§3) — the scaffolded Colyseus bootstrap. */
|
|
202
139
|
export const DEFAULT_SERVER_MODULE = 'server/colyseus-setup.ts';
|
|
203
140
|
|
|
@@ -235,18 +172,14 @@ function checkAdapterEntryRules(root: AdapterRoot): void {
|
|
|
235
172
|
'`entry` — a built-in adapter root is authored as an entry module.',
|
|
236
173
|
);
|
|
237
174
|
}
|
|
175
|
+
if (typeof adapter === 'object' && 'ingest' in adapter && !root.entry) {
|
|
176
|
+
throw new Error(
|
|
177
|
+
`Game manifest: root "${root.id}" is an { ingest } root but declares no \`entry\` — the ` +
|
|
178
|
+
"game's own entry module is what the host imports.",
|
|
179
|
+
);
|
|
180
|
+
}
|
|
238
181
|
}
|
|
239
182
|
|
|
240
|
-
// Historical note (Track N, N1): this file used to reject EVERY `kind:
|
|
241
|
-
// 'react'` + `{ ingest }` root outright here (`checkReactAdapterRestriction`,
|
|
242
|
-
// citing "no react ingest program is un-parked"). Track N un-parks exactly
|
|
243
|
-
// that program — react+ingest is now a structurally legal combination,
|
|
244
|
-
// resolved to the `'ingest-react'` identity by `resolveAdapter` below like
|
|
245
|
-
// any other ingest root. There is nothing left to reject at THIS layer: the
|
|
246
|
-
// v1 "deduped strategy only" restriction is an editor-resolver concern (D-N3),
|
|
247
|
-
// not a manifest-shape concern — see the `ResolvedAdapter` type's comment
|
|
248
|
-
// above.
|
|
249
|
-
|
|
250
183
|
// ---------------------------------------------------------------------------
|
|
251
184
|
// Resolution (§5)
|
|
252
185
|
// ---------------------------------------------------------------------------
|
|
@@ -268,8 +201,7 @@ function resolveAdapter(root: AdapterRoot): ResolvedAdapter {
|
|
|
268
201
|
}
|
|
269
202
|
|
|
270
203
|
// isIngestAdapter (Track N, N1: 'ingest-react' joins 'ingest-three'/
|
|
271
|
-
// 'ingest-pixi'
|
|
272
|
-
// this stays strategy-agnostic here).
|
|
204
|
+
// 'ingest-pixi').
|
|
273
205
|
const identity =
|
|
274
206
|
adapter.surface === 'three'
|
|
275
207
|
? 'ingest-three'
|
|
@@ -281,62 +213,14 @@ function resolveAdapter(root: AdapterRoot): ResolvedAdapter {
|
|
|
281
213
|
type: 'ingest',
|
|
282
214
|
identity,
|
|
283
215
|
surface: adapter.surface,
|
|
284
|
-
strategy: ingest.strategy,
|
|
285
|
-
entryHtml: ingest.entryHtml,
|
|
286
216
|
contractShim: ingest.contractShim,
|
|
217
|
+
dataWriter: ingest.dataWriter,
|
|
287
218
|
assets: ingest.assets,
|
|
288
219
|
domStubs: ingest.domStubs,
|
|
289
220
|
captureTimeoutMs: ingest.captureTimeoutMs,
|
|
290
|
-
bundleUrl: ingest.bundleUrl,
|
|
291
|
-
baseHref: ingest.baseHref,
|
|
292
|
-
assetBaseUrl: ingest.assetBaseUrl,
|
|
293
|
-
extraDeps: ingest.extraDeps,
|
|
294
|
-
pixiModuleUrl: ingest.pixiModuleUrl,
|
|
295
|
-
bodyHtml: ingest.bodyHtml,
|
|
296
221
|
};
|
|
297
222
|
}
|
|
298
223
|
|
|
299
|
-
function ceilingFor(adapter: RootAdapter, context: 'local' | 'hosted'): Tier {
|
|
300
|
-
if (typeof adapter === 'string') return CAPABILITY_CEILINGS.builtin[context];
|
|
301
|
-
if (isModuleAdapter(adapter)) return CAPABILITY_CEILINGS.module[context];
|
|
302
|
-
return CAPABILITY_CEILINGS.ingest[adapter.ingest.strategy][context];
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
function resolveCapabilities(root: AdapterRoot): { local: Tier; hosted: Tier } {
|
|
306
|
-
const contexts = ['local', 'hosted'] as const;
|
|
307
|
-
const result = {} as { local: Tier; hosted: Tier };
|
|
308
|
-
|
|
309
|
-
for (const context of contexts) {
|
|
310
|
-
const declared = root.capabilities?.[context];
|
|
311
|
-
if (declared !== undefined) {
|
|
312
|
-
const ceiling = ceilingFor(root.adapter, context);
|
|
313
|
-
if (TIER_RANK[declared] > TIER_RANK[ceiling]) {
|
|
314
|
-
throw new Error(
|
|
315
|
-
`Game manifest: root "${root.id}": declared capabilities.${context} tier "${declared}" ` +
|
|
316
|
-
`exceeds the "${ceiling}" ceiling for this adapter in the ${context} context (§4). ` +
|
|
317
|
-
'Under-claiming (including `unsupported`) is legal; over-claiming is not.',
|
|
318
|
-
);
|
|
319
|
-
}
|
|
320
|
-
result[context] = declared;
|
|
321
|
-
continue;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
// Omitted -> derive.
|
|
325
|
-
if (typeof root.adapter === 'string') {
|
|
326
|
-
result[context] = 'first-party';
|
|
327
|
-
} else if (isModuleAdapter(root.adapter)) {
|
|
328
|
-
throw new Error(
|
|
329
|
-
`Game manifest: root "${root.id}": { module } adapter requires an explicit ` +
|
|
330
|
-
`capabilities.${context} declaration — a custom adapter's reach is not derivable (§4).`,
|
|
331
|
-
);
|
|
332
|
-
} else {
|
|
333
|
-
result[context] = CAPABILITY_CEILINGS.ingest[root.adapter.ingest.strategy][context];
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
return result;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
224
|
function checkEngineVersionPin(version: string): void {
|
|
341
225
|
if (!SEMVER_RE.test(version)) {
|
|
342
226
|
throw new Error(
|
|
@@ -348,17 +232,17 @@ function checkEngineVersionPin(version: string): void {
|
|
|
348
232
|
|
|
349
233
|
/**
|
|
350
234
|
* Resolve one already-Zod-validated root entry into its `ResolvedAdapterRoot`
|
|
351
|
-
* (adapter identity,
|
|
235
|
+
* (adapter identity, and a pass-through of every other field).
|
|
352
236
|
* Every `AdapterRoot` field participates here or in a check above:
|
|
353
237
|
* `id` drives uniqueness; `adapter` (incl. its surface and
|
|
354
|
-
* `module`/`ingest.*` sub-fields) drives identity
|
|
238
|
+
* `module`/`ingest.*` sub-fields) drives adapter identity
|
|
355
239
|
* resolution; `entry` drives the entry cross-field rule and is
|
|
356
240
|
* carried through; `zOrder` drives the final sort; `pausable`/`loop` are
|
|
357
241
|
* carried through as-is (their consumers are the runtime/CLI, T3.2/T3.3);
|
|
358
242
|
* `dev` is carried through for the four dev-layer readers (`mountManifestRoots`'s
|
|
359
243
|
* ship gate, the host's topmost stacking pass, the play compositor's capture
|
|
360
244
|
* exclusion, and the editor's chrome-not-content seam);
|
|
361
|
-
* `
|
|
245
|
+
* `description` (T3.3
|
|
362
246
|
* slice 3) is carried through as-is — its consumer today is
|
|
363
247
|
* `resolveIngestDescriptor` (packages/editor/src/adapter-resolver.ts), which
|
|
364
248
|
* threads an ingest-three root's description into `IngestGame.description`.
|
|
@@ -377,7 +261,6 @@ function resolveRoot(root: AdapterRoot): ResolvedAdapterRoot {
|
|
|
377
261
|
pausable: root.pausable,
|
|
378
262
|
dev: root.dev,
|
|
379
263
|
loop: root.loop,
|
|
380
|
-
capabilities: resolveCapabilities(root),
|
|
381
264
|
};
|
|
382
265
|
}
|
|
383
266
|
|
|
@@ -404,7 +287,7 @@ export function loadGameManifest(raw: unknown): ResolvedGameManifest {
|
|
|
404
287
|
// raw multi-issue dump, because each one already reads as a finished
|
|
405
288
|
// sentence naming the offending ids. Every other schema violation keeps
|
|
406
289
|
// propagating as the raw `ZodError` it always has (unchanged behavior,
|
|
407
|
-
// e.g.
|
|
290
|
+
// e.g. an unrecognized key or a bad `manifestVersion`).
|
|
408
291
|
const compositionIssue = parsed.error.issues.find(
|
|
409
292
|
(issue) =>
|
|
410
293
|
issue.message.startsWith('Game manifest: duplicate root id') ||
|
|
@@ -441,6 +324,7 @@ export function loadGameManifest(raw: unknown): ResolvedGameManifest {
|
|
|
441
324
|
roots,
|
|
442
325
|
server,
|
|
443
326
|
resolution: manifest.resolution,
|
|
327
|
+
rendering: manifest.rendering,
|
|
444
328
|
authoring: manifest.authoring,
|
|
445
329
|
debug: manifest.debug,
|
|
446
330
|
determinism: manifest.determinism,
|
package/src/manifest/schema.ts
CHANGED
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
//
|
|
10
10
|
// Naming: this file follows the repo's `XxxSchema` (Zod schema) / `Xxx`
|
|
11
11
|
// (inferred type) convention used throughout `scene/schema/` — the design
|
|
12
|
-
// doc's §3 sketch names the bare consts (`
|
|
13
|
-
// `
|
|
12
|
+
// doc's §3 sketch names the bare consts (`AdapterRoot`) without the
|
|
13
|
+
// `Schema` suffix; that sketch is explicitly a
|
|
14
14
|
// "Zod sketch" the doc tells implementers to adapt to real code style
|
|
15
15
|
// ("mirror the style in scene/schema/scene-file.ts" per CLAUDE.md), so the
|
|
16
16
|
// schema consts here are suffixed and the bare names are reserved for the
|
|
@@ -28,32 +28,6 @@ import { z } from 'zod';
|
|
|
28
28
|
*/
|
|
29
29
|
export const GAME_MANIFEST_VERSION = 2 as const;
|
|
30
30
|
|
|
31
|
-
// ---------------------------------------------------------------------------
|
|
32
|
-
// Ingest capture strategy (the general vocabulary D6/§4 names)
|
|
33
|
-
// ---------------------------------------------------------------------------
|
|
34
|
-
|
|
35
|
-
export const IngestStrategySchema = z.enum([
|
|
36
|
-
'shared', // game imports host-served ESM three — full in-realm capture
|
|
37
|
-
'deduped', // game source built by OUR pipeline, bundler dedupe — full capture
|
|
38
|
-
'iframe-reachable', // prebuilt bundle in iframe, three reachable — cross-realm capture
|
|
39
|
-
'opaque-embed', // prebuilt bundle, nothing reachable — host lifecycle only
|
|
40
|
-
]);
|
|
41
|
-
export type IngestStrategy = z.infer<typeof IngestStrategySchema>;
|
|
42
|
-
|
|
43
|
-
// ---------------------------------------------------------------------------
|
|
44
|
-
// Capability tier — one ordered enum, declared per delivery context (§4)
|
|
45
|
-
// ---------------------------------------------------------------------------
|
|
46
|
-
|
|
47
|
-
export const TierSchema = z.enum([
|
|
48
|
-
'first-party', // vgai-native root: full editor, full loop control
|
|
49
|
-
'shared', // = IngestStrategy 'shared' rung
|
|
50
|
-
'deduped', // = IngestStrategy 'deduped' rung
|
|
51
|
-
'iframe-reachable', // = IngestStrategy 'iframe-reachable' rung
|
|
52
|
-
'opaque-embed', // = IngestStrategy 'opaque-embed' rung
|
|
53
|
-
'unsupported', // this root does not function in this delivery context
|
|
54
|
-
]);
|
|
55
|
-
export type Tier = z.infer<typeof TierSchema>;
|
|
56
|
-
|
|
57
31
|
// ---------------------------------------------------------------------------
|
|
58
32
|
// Root adapter identity. The adapter is the sole discriminator: a root never
|
|
59
33
|
// repeats its rendering substrate in a sibling `kind` field. Module and ingest
|
|
@@ -160,39 +134,51 @@ export const RootAdapterSchema = z
|
|
|
160
134
|
.describe('Native surface captured from the unmodified game'),
|
|
161
135
|
ingest: z
|
|
162
136
|
.object({
|
|
163
|
-
strategy: IngestStrategySchema.describe(
|
|
164
|
-
'Capture mechanics rung this ingested root uses (§4) — also the root`s natural local capability tier',
|
|
165
|
-
),
|
|
166
|
-
entryHtml: z
|
|
167
|
-
.string()
|
|
168
|
-
.optional()
|
|
169
|
-
.describe(
|
|
170
|
-
'Entry HTML path, project-relative. WIRED for opaque-embed (D-W2): ' +
|
|
171
|
-
'the file`s bytes are read verbatim through ' +
|
|
172
|
-
'the project-static route and hosted in a sandboxed iframe (embed-only, no scene ' +
|
|
173
|
-
'introspection), for both canvas and three roots. Legal but NOT wired to a ' +
|
|
174
|
-
'mount for iframe-reachable (a named error at resolve names this — use `bundleUrl` ' +
|
|
175
|
-
'instead, the wired reachable route).',
|
|
176
|
-
),
|
|
177
137
|
contractShim: z
|
|
178
138
|
.string()
|
|
179
139
|
.optional()
|
|
180
140
|
.describe(
|
|
181
141
|
"Project-relative path to a HOST-ADDED ES module that declares this game's " +
|
|
182
142
|
'`window.vgaiGame` contract (adapter/ingest/game-contract.ts) WITHOUT editing a ' +
|
|
183
|
-
'vendored byte — the pristine-copy door. The host
|
|
184
|
-
|
|
185
|
-
'importmap (moving a module load ahead of an import map invalidates the map) and ' +
|
|
186
|
-
'BEFORE the game`s entry module, so deferred module scripts run it first. ' +
|
|
143
|
+
'vendored byte — the pristine-copy door. The host imports it immediately BEFORE ' +
|
|
144
|
+
"the game's own entry module, in the editor's realm. " +
|
|
187
145
|
'TIMING CONTRACT, which a shim author must obey: because it runs before the ' +
|
|
188
|
-
'game`s entry, it MUST assign `window.vgaiGame` SYNCHRONOUSLY at top level
|
|
189
|
-
'host waits for that assignment and fails the mount by name if it never arrives. ' +
|
|
146
|
+
'game`s entry, it MUST assign `window.vgaiGame` SYNCHRONOUSLY at top level. ' +
|
|
190
147
|
'Anything that needs the game`s own modules must be LAZY: a dynamic `import()` ' +
|
|
191
148
|
'INSIDE each verb/provider closure, resolved at call time. Importing a game module ' +
|
|
192
149
|
'eagerly from the shim would evaluate it ahead of the game`s own entry and reorder ' +
|
|
193
|
-
'its module side effects.
|
|
194
|
-
'
|
|
195
|
-
'
|
|
150
|
+
'its module side effects. ' +
|
|
151
|
+
'Every such `import()` MUST take a STRING LITERAL, never a variable/table lookup. ' +
|
|
152
|
+
'A variable specifier is not statically analyzable, so the dev server leaves it ' +
|
|
153
|
+
'alone and it resolves at runtime against the shim`s own `/@fs/` url — while the ' +
|
|
154
|
+
'game`s entry has had ITS relative imports rewritten to whatever url the server ' +
|
|
155
|
+
'considers canonical for those files. Module identity is per-url, so the shim ' +
|
|
156
|
+
'silently binds a SECOND, freshly-evaluated copy of the whole game and every ' +
|
|
157
|
+
'provider reports a game that never started. Measured on three-descent: 285 ' +
|
|
158
|
+
'segments through the game`s graph, 0 through the shim`s, and no error anywhere.',
|
|
159
|
+
),
|
|
160
|
+
dataWriter: z
|
|
161
|
+
.string()
|
|
162
|
+
.optional()
|
|
163
|
+
.describe(
|
|
164
|
+
"Project-relative path to a HOST-ADDED ES module that writes this game's own " +
|
|
165
|
+
'DATA file back — the sibling of a source write for a game whose authorable ' +
|
|
166
|
+
'truth is not source. Descent places its robots, powerups and hostages in ' +
|
|
167
|
+
'binary records inside `descent.hog`, reaching no source literal, so an ' +
|
|
168
|
+
'authored move of one is an edit to that file and nothing else can write it. ' +
|
|
169
|
+
'The module declares two exports and the host knows nothing else about it: ' +
|
|
170
|
+
'`dataFile` (a project-relative string — the ONE file this writer edits) and ' +
|
|
171
|
+
'`planDataEdit(bytes, {record, property, baseline, next})`, which returns ' +
|
|
172
|
+
'`{changed: true, bytes}` or `{changed: false, reason}` and may be async. ' +
|
|
173
|
+
'It is loaded in the editor realm beside the game, so it may `import()` the ' +
|
|
174
|
+
"game's own modules to resolve what only a running game knows (Descent's " +
|
|
175
|
+
'writer asks the game`s own `find_point_seg` which segment a moved object ' +
|
|
176
|
+
'landed in, and refuses "outside the mine" rather than writing data the game ' +
|
|
177
|
+
'would read back wrong). It NEVER fabricates: a record it cannot address, or ' +
|
|
178
|
+
'a property it does not model, is a named refusal. ' +
|
|
179
|
+
'An object is anchored to a record by carrying `userData.vgaiRecordIndex` — ' +
|
|
180
|
+
'the game declares that identity itself (a recorded patch or a shim); the ' +
|
|
181
|
+
'host never infers one.',
|
|
196
182
|
),
|
|
197
183
|
assets: z
|
|
198
184
|
.record(z.string(), z.string())
|
|
@@ -210,168 +196,16 @@ export const RootAdapterSchema = z
|
|
|
210
196
|
.number()
|
|
211
197
|
.optional()
|
|
212
198
|
.describe(
|
|
213
|
-
|
|
214
|
-
'
|
|
215
|
-
'
|
|
216
|
-
'reported-embed-only mount in place; the host clamps this value so a long ' +
|
|
217
|
-
'one cannot block the editor on a question the upgrade path answers anyway.',
|
|
218
|
-
),
|
|
219
|
-
// The six iframe-reachable-multi mount fields
|
|
220
|
-
// (`ingest-iframe-2d.ts`'s `IframeReachableMultiOpts`), legal
|
|
221
|
-
// ONLY when `strategy` is 'iframe-reachable' (enforced by the
|
|
222
|
-
// `.superRefine` below).
|
|
223
|
-
bundleUrl: z
|
|
224
|
-
.string()
|
|
225
|
-
.optional()
|
|
226
|
-
.describe(
|
|
227
|
-
'Absolute URL of the externalized built game bundle — the WIRED iframe-reachable ' +
|
|
228
|
-
'mount route (iframe-reachable only), for BOTH canvas (Track P, ' +
|
|
229
|
-
"ingest-iframe-2d.ts's mountIngestGame2DIframeReachableMulti) and three (D-W1, " +
|
|
230
|
-
"ingest-iframe-reachable-adapter.ts's mountIngestGameIframeReachableBundle). " +
|
|
231
|
-
'PRECONDITION: the bundle must externalize its root`s own runtime as a bare, ' +
|
|
232
|
-
'un-rewritten import (`pixi.js` for canvas, `three` for three — `vgai bundle` ' +
|
|
233
|
-
'does this for you) so it resolves through the iframe importmap to the HOST ' +
|
|
234
|
-
'instance the capture trap is installed on; a bundle with an inlined runtime is ' +
|
|
235
|
-
'unreachable and degrades to the embed-only floor. Exactly one of bundleUrl/' +
|
|
236
|
-
'entryHtml is required when strategy is iframe-reachable.',
|
|
237
|
-
),
|
|
238
|
-
baseHref: z
|
|
239
|
-
.string()
|
|
240
|
-
.optional()
|
|
241
|
-
.describe(
|
|
242
|
-
"Iframe <base href> so the game's relative asset URLs resolve (iframe-reachable only).",
|
|
243
|
-
),
|
|
244
|
-
assetBaseUrl: z
|
|
245
|
-
.string()
|
|
246
|
-
.optional()
|
|
247
|
-
.describe(
|
|
248
|
-
"Host-side basePath forced onto the trapped runtime's own asset resolution — " +
|
|
249
|
-
"pixi's `Assets.init` for a canvas root, three's " +
|
|
250
|
-
'`DefaultLoadingManager.setURLModifier` for a three root (D-W1) — absolute, or ' +
|
|
251
|
-
"root-relative (resolved against the editor page's own origin at mount time, " +
|
|
252
|
-
'ingest-mode.ts, so a static manifest never has to know the dev-server port) ' +
|
|
253
|
-
'(iframe-reachable only — a document.write iframe keeps the parent window.location).',
|
|
254
|
-
),
|
|
255
|
-
extraDeps: z
|
|
256
|
-
.array(z.string())
|
|
257
|
-
.optional()
|
|
258
|
-
.describe(
|
|
259
|
-
"Bare specifiers of this root's externalized deps beyond its own runtime " +
|
|
260
|
-
"(pixi.js/three — e.g. '@pixi/sound', 'gsap'). Resolved by the editor's " +
|
|
261
|
-
'host-namespace registry into module namespaces when known (D-P1 — the manifest ' +
|
|
262
|
-
'carries data, not code); an unregistered specifier falls back to the open ' +
|
|
263
|
-
"project's own node_modules (D-Z3), served " +
|
|
264
|
-
'as a verbatim iframe importmap URL. Throws a named error if neither resolves it ' +
|
|
265
|
-
'(iframe-reachable only).',
|
|
266
|
-
),
|
|
267
|
-
pixiModuleUrl: z
|
|
268
|
-
.string()
|
|
269
|
-
.optional()
|
|
270
|
-
.describe(
|
|
271
|
-
'PIXI-ONLY: standalone matching-major pixi ESM URL to trap instead of the host ' +
|
|
272
|
-
"pixi, for version-skewed games (e.g. a v6 game on a v8 host); this field's " +
|
|
273
|
-
'PRESENCE is how the skew is expressed (D-P2 — no separate strategy/tier for ' +
|
|
274
|
-
'version skew) (iframe-reachable only). Declaring this on a `kind: "three"` ' +
|
|
275
|
-
'root is schema-legal (this field is kind-agnostic here) but throws a NAMED ' +
|
|
276
|
-
'not-supported error at resolve — three has no version-skew mount this wave ' +
|
|
277
|
-
'(D-W7: a hypothetical `threeModuleUrl` is explicitly parked, no consumer ' +
|
|
278
|
-
'exists).',
|
|
279
|
-
),
|
|
280
|
-
bodyHtml: z
|
|
281
|
-
.string()
|
|
282
|
-
.optional()
|
|
283
|
-
.describe(
|
|
284
|
-
'HTML injected into the iframe body before the game script boots (e.g. a ' +
|
|
285
|
-
'`<div id="game-root">` the game expects to find) (iframe-reachable only).',
|
|
199
|
+
"How long the host waits for this game's first captured frame before the mount " +
|
|
200
|
+
'FAILS by name. A game that needs a long boot (streamed world assets, a menu ' +
|
|
201
|
+
'the player must clear) raises it; the default is 10s.',
|
|
286
202
|
),
|
|
287
203
|
})
|
|
204
|
+
.strict()
|
|
288
205
|
.describe(
|
|
289
206
|
'Ingest adapter configuration for an unmodified game (a repo-vendored game or your ' +
|
|
290
207
|
'own external folder)',
|
|
291
|
-
)
|
|
292
|
-
// `contractShim` is injected into the assembled ENTRY DOCUMENT, so
|
|
293
|
-
// the ONLY route that can read it is the self-hosted one
|
|
294
|
-
// (`iframe-reachable` + `entryHtml`,
|
|
295
|
-
// ingest-self-hosted-three-adapter.ts). An `opaque-embed` entry
|
|
296
|
-
// document is hosted sandboxed with no host wiring, and a `bundleUrl`
|
|
297
|
-
// mount has no game document at all — under either, a declared shim
|
|
298
|
-
// would be a silently dead declaration, the exact failure the
|
|
299
|
-
// dead-field-under-wrong-variant checks below exist to prevent. Its
|
|
300
|
-
// own `.superRefine` rather than a branch inside the next one: they
|
|
301
|
-
// check unrelated invariants, and folding them together only made
|
|
302
|
-
// one function harder to read.
|
|
303
|
-
.superRefine((ingest, ctx) => {
|
|
304
|
-
if (
|
|
305
|
-
ingest.contractShim === undefined ||
|
|
306
|
-
(ingest.strategy === 'iframe-reachable' && ingest.entryHtml !== undefined)
|
|
307
|
-
) {
|
|
308
|
-
return;
|
|
309
|
-
}
|
|
310
|
-
ctx.addIssue({
|
|
311
|
-
code: z.ZodIssueCode.custom,
|
|
312
|
-
message:
|
|
313
|
-
'`contractShim` is read ONLY by the self-hosted entry-document route, so it ' +
|
|
314
|
-
"requires strategy 'iframe-reachable' together with `entryHtml` (got strategy " +
|
|
315
|
-
`"${ingest.strategy}"${ingest.entryHtml === undefined ? ' and no `entryHtml`' : ''}) — ` +
|
|
316
|
-
"the host injects the shim module into the GAME'S OWN entry HTML " +
|
|
317
|
-
'(ingest-self-hosted-three-adapter.ts), and no other mount has such a document.',
|
|
318
|
-
path: ['contractShim'],
|
|
319
|
-
});
|
|
320
|
-
})
|
|
321
|
-
.superRefine((ingest, ctx) => {
|
|
322
|
-
// The six iframe-reachable-multi fields only make sense for the
|
|
323
|
-
// iframe-reachable-multi mount — reject them under any other
|
|
324
|
-
// strategy (mirrors ui.ts's dead-field-under-wrong-variant pattern).
|
|
325
|
-
const iframeOnlyFields: ReadonlyArray<
|
|
326
|
-
readonly [
|
|
327
|
-
key:
|
|
328
|
-
| 'bundleUrl'
|
|
329
|
-
| 'baseHref'
|
|
330
|
-
| 'assetBaseUrl'
|
|
331
|
-
| 'extraDeps'
|
|
332
|
-
| 'pixiModuleUrl'
|
|
333
|
-
| 'bodyHtml',
|
|
334
|
-
present: boolean,
|
|
335
|
-
]
|
|
336
|
-
> = [
|
|
337
|
-
['bundleUrl', ingest.bundleUrl !== undefined],
|
|
338
|
-
['baseHref', ingest.baseHref !== undefined],
|
|
339
|
-
['assetBaseUrl', ingest.assetBaseUrl !== undefined],
|
|
340
|
-
['extraDeps', ingest.extraDeps !== undefined],
|
|
341
|
-
['pixiModuleUrl', ingest.pixiModuleUrl !== undefined],
|
|
342
|
-
['bodyHtml', ingest.bodyHtml !== undefined],
|
|
343
|
-
];
|
|
344
|
-
if (ingest.strategy !== 'iframe-reachable') {
|
|
345
|
-
for (const [key, present] of iframeOnlyFields) {
|
|
346
|
-
if (present) {
|
|
347
|
-
ctx.addIssue({
|
|
348
|
-
code: z.ZodIssueCode.custom,
|
|
349
|
-
message:
|
|
350
|
-
`\`${key}\` is only legal when strategy is 'iframe-reachable' (got ` +
|
|
351
|
-
`"${ingest.strategy}") — bundleUrl/baseHref/assetBaseUrl/extraDeps/` +
|
|
352
|
-
"pixiModuleUrl/bodyHtml are the iframe-reachable-multi mount's options " +
|
|
353
|
-
'(canvas: ingest-iframe-2d.ts IframeReachableMultiOpts; three, D-W1: ' +
|
|
354
|
-
'ingest-iframe-reachable-adapter.ts IframeReachableBundleOpts) and have no ' +
|
|
355
|
-
'meaning under any other strategy.',
|
|
356
|
-
path: [key],
|
|
357
|
-
});
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
return;
|
|
361
|
-
}
|
|
362
|
-
const hasBundleUrl = ingest.bundleUrl !== undefined;
|
|
363
|
-
const hasEntryHtml = ingest.entryHtml !== undefined;
|
|
364
|
-
if (hasBundleUrl === hasEntryHtml) {
|
|
365
|
-
ctx.addIssue({
|
|
366
|
-
code: z.ZodIssueCode.custom,
|
|
367
|
-
message:
|
|
368
|
-
"strategy 'iframe-reachable' requires EXACTLY ONE of `bundleUrl` (externalized " +
|
|
369
|
-
'multi-file bundle, the iframe-reachable-multi mount) or `entryHtml` (single-' +
|
|
370
|
-
`file/legacy iframe entry) — ${hasBundleUrl ? 'both are present' : 'neither is present'}.`,
|
|
371
|
-
path: hasBundleUrl ? ['bundleUrl'] : ['entryHtml'],
|
|
372
|
-
});
|
|
373
|
-
}
|
|
374
|
-
}),
|
|
208
|
+
),
|
|
375
209
|
})
|
|
376
210
|
.strict(),
|
|
377
211
|
]),
|
|
@@ -439,21 +273,7 @@ export const AdapterRootSchema = z
|
|
|
439
273
|
.default('gated')
|
|
440
274
|
.describe(
|
|
441
275
|
'gated: host-driven loop (default). self-driven: this root drives its own loop ' +
|
|
442
|
-
'(
|
|
443
|
-
),
|
|
444
|
-
capabilities: z
|
|
445
|
-
.object({
|
|
446
|
-
local: TierSchema.optional().describe(
|
|
447
|
-
'Declared capability tier when served via the local CLI (Vite pipeline); omitted -> derived (§4)',
|
|
448
|
-
),
|
|
449
|
-
hosted: TierSchema.optional().describe(
|
|
450
|
-
'Declared capability tier when served hosted (no bundler: esbuild-wasm + externals only); omitted -> derived (§4)',
|
|
451
|
-
),
|
|
452
|
-
})
|
|
453
|
-
.optional()
|
|
454
|
-
.describe(
|
|
455
|
-
"Per-delivery-context capability tier declarations (§4). Declaring above the adapter's " +
|
|
456
|
-
'ceiling for that context is an error; declaring at or below it (including `unsupported`) is legal.',
|
|
276
|
+
'(composited, unsynchronized)',
|
|
457
277
|
),
|
|
458
278
|
})
|
|
459
279
|
.strict();
|
|
@@ -701,6 +521,28 @@ export const GameManifestSchema = z
|
|
|
701
521
|
})
|
|
702
522
|
.optional()
|
|
703
523
|
.describe('Canvas resolution'),
|
|
524
|
+
rendering: z
|
|
525
|
+
.object({
|
|
526
|
+
antialias: z
|
|
527
|
+
.boolean()
|
|
528
|
+
.describe(
|
|
529
|
+
'Whether every three root is built with a multisampled drawing buffer. This is the ' +
|
|
530
|
+
'ONE render property a world cannot declare for itself (world3d-react/' +
|
|
531
|
+
'renderer-config.ts): a WebGL context fixes its sample count at CREATION from this ' +
|
|
532
|
+
'boolean, long before a world mounts, so it belongs to the PROJECT. The runtime ' +
|
|
533
|
+
'reader is mount-manifest.ts, which threads it into createHostRenderer for each ' +
|
|
534
|
+
'three root. WebGL exposes no sample COUNT — the implementation picks one (4x on ' +
|
|
535
|
+
'every desktop browser measured), so a source engine that authored 8x/16x gets ' +
|
|
536
|
+
'multisampling but not its exact count.',
|
|
537
|
+
),
|
|
538
|
+
})
|
|
539
|
+
.strict()
|
|
540
|
+
.optional()
|
|
541
|
+
.describe(
|
|
542
|
+
'Construction-time renderer properties, which no world can declare after the fact. ' +
|
|
543
|
+
'Everything a world CAN declare (tone mapping, output colour space, clear colour, ' +
|
|
544
|
+
"shadow filter) lives on the world's own renderer config instead.",
|
|
545
|
+
),
|
|
704
546
|
debug: z
|
|
705
547
|
.object({
|
|
706
548
|
allowInProduction: z
|
package/src/pixi/index.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* PixiJS is opt-in: the engine core never imports it, so a three-only bundle
|
|
5
5
|
* never pays for it. What lives here is what the host needs to mount and
|
|
6
6
|
* inspect a PixiJS game it did not write — the render-call capture trap, the
|
|
7
|
-
* in-realm
|
|
7
|
+
* in-realm mount, the live display-tree authoring adapter, and the
|
|
8
8
|
* Rapier-2D handle registry the editor's transform coordination reads.
|
|
9
9
|
*/
|
|
10
10
|
|
|
@@ -16,20 +16,7 @@ export {
|
|
|
16
16
|
type Property2D,
|
|
17
17
|
type Transform2DValue,
|
|
18
18
|
} from './authoring';
|
|
19
|
-
export {
|
|
20
|
-
type ExtraDepsResolution2D,
|
|
21
|
-
type IngestGame2D,
|
|
22
|
-
type IngestMount2D,
|
|
23
|
-
mountIngestGame2D,
|
|
24
|
-
} from './ingest';
|
|
25
|
-
export {
|
|
26
|
-
type EmbedMount2D,
|
|
27
|
-
type IframeReachableMount2D,
|
|
28
|
-
type IframeReachableMultiOpts,
|
|
29
|
-
mountIngestGame2DEmbed,
|
|
30
|
-
mountIngestGame2DIframeReachable,
|
|
31
|
-
mountIngestGame2DIframeReachableMulti,
|
|
32
|
-
} from './ingest-iframe';
|
|
19
|
+
export { type IngestGame2D, type IngestMount2D, mountIngestGame2D } from './ingest';
|
|
33
20
|
export {
|
|
34
21
|
createPhysics2DRegistry,
|
|
35
22
|
type Physics2DRefs,
|