@vgai/engine 0.5.22 → 0.5.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -3
- package/dist/adapter/adapter-module.d.ts.map +1 -1
- package/dist/adapter/adapter-module.js +2 -4
- package/dist/adapter/adapter-surface.d.ts +1 -1
- package/dist/adapter/adapter-surface.js +1 -1
- package/dist/adapter/authoring.d.ts +19 -21
- package/dist/adapter/authoring.d.ts.map +1 -1
- package/dist/adapter/authoring.js +2 -2
- package/dist/adapter/binding.d.ts +341 -0
- package/dist/adapter/binding.d.ts.map +1 -0
- package/dist/adapter/binding.js +148 -0
- package/dist/adapter/colyseus-networking-adapter.d.ts.map +1 -1
- package/dist/adapter/colyseus-networking-adapter.js +23 -4
- package/dist/adapter/entrypoint-selection-readers.d.ts +24 -0
- package/dist/adapter/entrypoint-selection-readers.d.ts.map +1 -0
- package/dist/adapter/entrypoint-selection-readers.js +63 -0
- package/dist/adapter/entrypoint-selection-source.d.ts.map +1 -1
- package/dist/adapter/entrypoint-selection-source.js +1 -44
- package/dist/adapter/finders/scenes-from-entrypoint-selection.d.ts.map +1 -1
- package/dist/adapter/finders/scenes-from-entrypoint-selection.js +1 -52
- package/dist/adapter/host-context.d.ts +46 -15
- package/dist/adapter/host-context.d.ts.map +1 -1
- package/dist/adapter/host-context.js +2 -9
- package/dist/adapter/index.d.ts +11 -12
- package/dist/adapter/index.d.ts.map +1 -1
- package/dist/adapter/index.js +9 -10
- package/dist/adapter/ingest/game-contract-seams.d.ts +5 -0
- package/dist/adapter/ingest/game-contract-seams.d.ts.map +1 -1
- package/dist/adapter/ingest/game-contract-seams.js +1 -0
- package/dist/adapter/ingest/game-contract.d.ts +22 -3
- package/dist/adapter/ingest/game-contract.d.ts.map +1 -1
- package/dist/adapter/ingest/game-contract.js +0 -3
- package/dist/adapter/ingest/scene-capture.d.ts +19 -23
- package/dist/adapter/ingest/scene-capture.d.ts.map +1 -1
- package/dist/adapter/ingest/scene-capture.js +143 -17
- package/dist/adapter/ingest/visible-capture-window.d.ts +34 -0
- package/dist/adapter/ingest/visible-capture-window.d.ts.map +1 -1
- package/dist/adapter/native-debug-module.d.ts +40 -5
- package/dist/adapter/native-debug-module.d.ts.map +1 -1
- package/dist/adapter/native-debug-module.js +36 -9
- package/dist/adapter/rapier-physics-adapter.d.ts +31 -1
- package/dist/adapter/rapier-physics-adapter.d.ts.map +1 -1
- package/dist/adapter/rapier-physics-adapter.js +50 -36
- package/dist/adapter/renderer-config.d.ts +2 -2
- package/dist/adapter/renderer-config.js +2 -2
- package/dist/adapter/root-adapter.d.ts +7 -7
- package/dist/adapter/root-adapter.js +4 -4
- package/dist/adapter/system-adapter.d.ts +45 -7
- package/dist/adapter/system-adapter.d.ts.map +1 -1
- package/dist/adapter/system-seam-contract.d.ts +3 -3
- package/dist/adapter/system-seam-contract.js +3 -3
- package/dist/adapter/system-slot.d.ts +168 -0
- package/dist/adapter/system-slot.d.ts.map +1 -0
- package/dist/adapter/system-slot.js +229 -0
- package/dist/adapter/transform.d.ts +11 -1
- package/dist/adapter/transform.d.ts.map +1 -1
- package/dist/ai/navigation.d.ts +17 -1
- package/dist/ai/navigation.d.ts.map +1 -1
- package/dist/ai/navigation.js +26 -5
- package/dist/animation/anim-graph-types.d.ts +11 -3
- package/dist/animation/anim-graph-types.d.ts.map +1 -1
- package/dist/animation/theatre-clock-binding.d.ts +4 -4
- package/dist/animation/theatre-clock-binding.js +4 -4
- package/dist/animation/xstate-animation-binding.d.ts.map +1 -1
- package/dist/animation/xstate-animation-binding.js +2 -2
- package/dist/animation/xstate-animation-meta.d.ts +13 -0
- package/dist/animation/xstate-animation-meta.d.ts.map +1 -1
- package/dist/animation/xstate-animation-meta.js +14 -0
- package/dist/asset-formats/index.d.ts +4 -7
- package/dist/asset-formats/index.d.ts.map +1 -1
- package/dist/asset-formats/index.js +4 -7
- package/dist/asset-formats/render-env.d.ts +5 -8
- package/dist/asset-formats/render-env.d.ts.map +1 -1
- package/dist/asset-formats/render-env.js +3 -6
- package/dist/asset-parse-error.d.ts +2 -5
- package/dist/asset-parse-error.d.ts.map +1 -1
- package/dist/asset-parse-error.js +2 -5
- package/dist/audio/bus-mixer.d.ts +101 -0
- package/dist/audio/bus-mixer.d.ts.map +1 -0
- package/dist/audio/bus-mixer.js +115 -0
- package/dist/core/frame-pacing.d.ts +1 -1
- package/dist/core/frame-pacing.js +2 -2
- package/dist/core/game-loop.d.ts +1 -3
- package/dist/core/game-loop.d.ts.map +1 -1
- package/dist/core/game-loop.js +1 -3
- package/dist/core/seeded-random.d.ts +1 -1
- package/dist/core/sim-clock.d.ts +5 -6
- package/dist/core/sim-clock.d.ts.map +1 -1
- package/dist/core/sim-clock.js +4 -5
- package/dist/core/types.d.ts +1 -3
- package/dist/core/types.d.ts.map +1 -1
- package/dist/defaults.d.ts +6 -14
- package/dist/defaults.d.ts.map +1 -1
- package/dist/defaults.js +6 -14
- package/dist/dev/register-render-vitals.d.ts +1 -4
- package/dist/dev/register-render-vitals.d.ts.map +1 -1
- package/dist/dev/register-render-vitals.js +1 -4
- package/dist/dev/render-debug-adapter.d.ts +2 -3
- package/dist/dev/render-debug-adapter.d.ts.map +1 -1
- package/dist/dev/render-debug-adapter.js +2 -3
- package/dist/dev/render-vitals.d.ts +3 -3
- package/dist/dev/render-vitals.js +3 -3
- package/dist/dev/webgl-frame-capture.d.ts +1 -1
- package/dist/dev/webgl-frame-capture.js +1 -1
- package/dist/index.d.ts +2 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -4
- package/dist/input/host-pointer.d.ts +122 -0
- package/dist/input/host-pointer.d.ts.map +1 -0
- package/dist/input/host-pointer.js +160 -0
- package/dist/input/input-manager.d.ts +18 -5
- package/dist/input/input-manager.d.ts.map +1 -1
- package/dist/input/input-manager.js +33 -13
- package/dist/input/rebind-controller.d.ts.map +1 -1
- package/dist/input/rebind-controller.js +6 -8
- package/dist/input/schema.d.ts.map +1 -1
- package/dist/input/schema.js +56 -28
- package/dist/manifest/filename.d.ts.map +1 -1
- package/dist/manifest/filename.js +8 -12
- package/dist/manifest/load.d.ts +10 -10
- package/dist/manifest/load.d.ts.map +1 -1
- package/dist/manifest/load.js +9 -6
- package/dist/manifest/schema.d.ts +17 -21
- package/dist/manifest/schema.d.ts.map +1 -1
- package/dist/manifest/schema.js +45 -35
- package/dist/physics/collider-dimensions.d.ts +8 -12
- package/dist/physics/collider-dimensions.d.ts.map +1 -1
- package/dist/physics/collider-dimensions.js +8 -12
- package/dist/pixi/scene-capture.d.ts +11 -13
- package/dist/pixi/scene-capture.d.ts.map +1 -1
- package/dist/react/world-state.d.ts +1 -1
- package/dist/react/world-state.d.ts.map +1 -1
- package/dist/render/light-camera-factory.d.ts +5 -7
- package/dist/render/light-camera-factory.d.ts.map +1 -1
- package/dist/render/light-camera-factory.js +8 -11
- package/dist/render/material-factory.js +1 -1
- package/dist/render/render-batch-system.d.ts.map +1 -1
- package/dist/render/render-features.d.ts +17 -6
- package/dist/render/render-features.d.ts.map +1 -1
- package/dist/render/render-features.js +0 -28
- package/dist/runtime/create-runtime.d.ts +34 -25
- package/dist/runtime/create-runtime.d.ts.map +1 -1
- package/dist/runtime/create-runtime.js +218 -93
- package/dist/runtime/debug-bridge.d.ts +12 -0
- package/dist/runtime/debug-bridge.d.ts.map +1 -1
- package/dist/runtime/debug-bridge.js +4 -0
- package/dist/runtime/debug-registry.d.ts +95 -8
- package/dist/runtime/debug-registry.d.ts.map +1 -1
- package/dist/runtime/debug-registry.js +24 -3
- package/dist/runtime/dev-build.d.ts +2 -2
- package/dist/runtime/dev-build.js +2 -2
- package/dist/runtime/game-input-seams.d.ts +2 -2
- package/dist/runtime/game-input-seams.d.ts.map +1 -1
- package/dist/runtime/game.d.ts +102 -41
- package/dist/runtime/game.d.ts.map +1 -1
- package/dist/runtime/game.js +80 -54
- package/dist/runtime/mount-game.d.ts +0 -16
- package/dist/runtime/mount-game.d.ts.map +1 -1
- package/dist/runtime/mount-game.js +8 -39
- package/dist/runtime/mount-manifest.d.ts +22 -14
- package/dist/runtime/mount-manifest.d.ts.map +1 -1
- package/dist/runtime/mount-manifest.js +18 -18
- package/dist/runtime/playtest.d.ts +22 -0
- package/dist/runtime/playtest.d.ts.map +1 -0
- package/dist/runtime/playtest.js +12 -0
- package/dist/runtime/run-ticks-settled.d.ts +34 -0
- package/dist/runtime/run-ticks-settled.d.ts.map +1 -0
- package/dist/runtime/run-ticks-settled.js +59 -0
- package/dist/runtime/state-bridge.d.ts +2 -3
- package/dist/runtime/state-bridge.d.ts.map +1 -1
- package/dist/runtime/state-bridge.js +1 -0
- package/dist/setup/setup-audio.d.ts +12 -0
- package/dist/setup/setup-audio.d.ts.map +1 -1
- package/dist/setup/setup-audio.js +9 -10
- package/dist/setup/setup-renderer.d.ts +2 -25
- package/dist/setup/setup-renderer.d.ts.map +1 -1
- package/dist/setup/setup-renderer.js +2 -31
- package/dist/world3d-react/r3f-root-factory.d.ts +7 -7
- package/dist/world3d-react/r3f-root-factory.js +7 -7
- package/dist/world3d-react/rapier-physics-bridge.d.ts +9 -8
- package/dist/world3d-react/rapier-physics-bridge.d.ts.map +1 -1
- package/dist/world3d-react/rapier-physics-bridge.js +100 -48
- package/package.json +1 -1
- package/schemas/engine-capabilities.json +16 -14
- package/schemas/vgai-project.schema.json +35 -26
- package/src/adapter/adapter-module.ts +2 -4
- package/src/adapter/adapter-surface.ts +1 -1
- package/src/adapter/authoring.ts +19 -21
- package/src/adapter/binding.ts +468 -0
- package/src/adapter/colyseus-networking-adapter.ts +20 -5
- package/src/adapter/entrypoint-selection-readers.ts +66 -0
- package/src/adapter/entrypoint-selection-source.ts +1 -40
- package/src/adapter/finders/scenes-from-entrypoint-selection.ts +1 -48
- package/src/adapter/host-context.ts +45 -15
- package/src/adapter/index.ts +23 -11
- package/src/adapter/ingest/game-contract-seams.ts +1 -0
- package/src/adapter/ingest/game-contract.ts +22 -3
- package/src/adapter/ingest/scene-capture.ts +190 -39
- package/src/adapter/ingest/visible-capture-window.ts +35 -0
- package/src/adapter/native-debug-module.ts +66 -9
- package/src/adapter/rapier-physics-adapter.ts +76 -20
- package/src/adapter/renderer-config.ts +2 -2
- package/src/adapter/root-adapter.ts +7 -7
- package/src/adapter/system-adapter.ts +43 -8
- package/src/adapter/system-seam-contract.ts +3 -3
- package/src/adapter/system-slot.ts +291 -0
- package/src/adapter/transform.ts +18 -1
- package/src/ai/navigation.ts +30 -3
- package/src/animation/anim-graph-types.ts +11 -3
- package/src/animation/theatre-clock-binding.ts +4 -4
- package/src/animation/xstate-animation-binding.ts +2 -2
- package/src/animation/xstate-animation-meta.ts +16 -0
- package/src/asset-formats/index.ts +4 -7
- package/src/asset-formats/render-env.ts +3 -6
- package/src/asset-parse-error.ts +2 -5
- package/src/audio/bus-mixer.ts +161 -0
- package/src/core/frame-pacing.ts +2 -2
- package/src/core/game-loop.ts +1 -3
- package/src/core/seeded-random.ts +1 -1
- package/src/core/sim-clock.ts +5 -6
- package/src/core/types.ts +1 -3
- package/src/defaults.ts +6 -14
- package/src/dev/register-render-vitals.ts +1 -4
- package/src/dev/render-debug-adapter.ts +2 -3
- package/src/dev/render-vitals.ts +3 -3
- package/src/dev/webgl-frame-capture.ts +1 -1
- package/src/index.ts +2 -5
- package/src/input/host-pointer.ts +230 -0
- package/src/input/input-manager.ts +34 -13
- package/src/input/input-types.ts +1 -1
- package/src/input/rebind-controller.ts +6 -8
- package/src/input/schema.ts +216 -188
- package/src/manifest/filename.ts +8 -12
- package/src/manifest/load.ts +17 -13
- package/src/manifest/schema.ts +55 -47
- package/src/physics/collider-dimensions.ts +8 -12
- package/src/pixi/scene-capture.ts +12 -15
- package/src/react/world-state.tsx +1 -1
- package/src/render/light-camera-factory.ts +8 -11
- package/src/render/material-factory.ts +1 -1
- package/src/render/render-batch-system.ts +14 -6
- package/src/render/render-features.ts +17 -35
- package/src/runtime/create-runtime.ts +270 -108
- package/src/runtime/debug-bridge.ts +16 -0
- package/src/runtime/debug-registry.ts +121 -8
- package/src/runtime/dev-build.ts +2 -2
- package/src/runtime/game-input-seams.ts +2 -2
- package/src/runtime/game.ts +180 -80
- package/src/runtime/mount-game.ts +8 -56
- package/src/runtime/mount-manifest.ts +43 -34
- package/src/runtime/playtest.ts +22 -0
- package/src/runtime/run-ticks-settled.ts +72 -0
- package/src/runtime/state-bridge.ts +3 -3
- package/src/setup/setup-audio.ts +21 -11
- package/src/setup/setup-renderer.ts +2 -61
- package/src/world3d-react/r3f-root-factory.tsx +7 -7
- package/src/world3d-react/rapier-physics-bridge.tsx +107 -50
- package/dist/adapter/setup-three-root-adapter.d.ts +0 -86
- package/dist/adapter/setup-three-root-adapter.d.ts.map +0 -1
- package/dist/adapter/setup-three-root-adapter.js +0 -908
- package/dist/animation/clip-map.d.ts +0 -12
- package/dist/animation/clip-map.d.ts.map +0 -1
- package/dist/animation/clip-map.js +0 -31
- package/dist/asset-registry.d.ts +0 -38
- package/dist/asset-registry.d.ts.map +0 -1
- package/dist/asset-registry.js +0 -66
- package/dist/canvas-react/engine-bridge.d.ts +0 -45
- package/dist/canvas-react/engine-bridge.d.ts.map +0 -1
- package/dist/canvas-react/engine-bridge.js +0 -45
- package/dist/canvas-react/pixi-react-adapter.d.ts +0 -77
- package/dist/canvas-react/pixi-react-adapter.d.ts.map +0 -1
- package/dist/canvas-react/pixi-react-adapter.js +0 -294
- package/dist/canvas-react/world-context.d.ts +0 -98
- package/dist/canvas-react/world-context.d.ts.map +0 -1
- package/dist/canvas-react/world-context.js +0 -173
- package/dist/dev/debug-draw.d.ts +0 -24
- package/dist/dev/debug-draw.d.ts.map +0 -1
- package/dist/dev/debug-draw.js +0 -73
- package/dist/render/auto-batcher.d.ts +0 -34
- package/dist/render/auto-batcher.d.ts.map +0 -1
- package/dist/render/auto-batcher.js +0 -140
- package/dist/render/lod.d.ts +0 -13
- package/dist/render/lod.d.ts.map +0 -1
- package/dist/render/lod.js +0 -16
- package/dist/runtime/types.d.ts +0 -303
- package/dist/runtime/types.d.ts.map +0 -1
- package/dist/runtime/types.js +0 -1
- package/dist/world3d-react/engine-bridge.d.ts +0 -47
- package/dist/world3d-react/engine-bridge.d.ts.map +0 -1
- package/dist/world3d-react/engine-bridge.js +0 -73
- package/dist/world3d-react/r3f-adapter.d.ts +0 -58
- package/dist/world3d-react/r3f-adapter.d.ts.map +0 -1
- package/dist/world3d-react/r3f-adapter.js +0 -634
- package/dist/world3d-react/world-context.d.ts +0 -182
- package/dist/world3d-react/world-context.d.ts.map +0 -1
- package/dist/world3d-react/world-context.js +0 -235
- package/src/adapter/setup-three-root-adapter.ts +0 -1032
- package/src/animation/clip-map.ts +0 -34
- package/src/asset-registry.ts +0 -89
- package/src/dev/debug-draw.ts +0 -80
- package/src/render/auto-batcher.ts +0 -168
- package/src/render/lod.ts +0 -17
- package/src/runtime/types.ts +0 -328
package/src/manifest/filename.ts
CHANGED
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
// The project manifest's FILENAME. There is exactly ONE.
|
|
2
2
|
//
|
|
3
|
-
// The manifest is `vgai.project.json
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
// software, no such constituency exists, and a second way to spell the
|
|
9
|
-
// manifest is the defect — two accepted names meant both kept being written,
|
|
10
|
-
// and copies of the "try both" probe grew in five modules that agreed with the
|
|
11
|
-
// real resolver only by coincidence.
|
|
3
|
+
// The manifest is `vgai.project.json`, and NOTHING reads a second spelling
|
|
4
|
+
// (the legacy-removal doctrine, `docs/ARCHITECTURE-CORE.md` §Vocabulary). Two
|
|
5
|
+
// accepted names is the defect, not the convenience: both get written, and
|
|
6
|
+
// copies of the "try both" probe spread into modules that agree with the real
|
|
7
|
+
// resolver only by coincidence.
|
|
12
8
|
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
9
|
+
// The removed name REJECTS LOUDLY, naming the exact one-line fix — never
|
|
10
|
+
// silently ignored, never redirected. A directory
|
|
15
11
|
// carrying only `vgai.game.json` is an error with a `git mv` in the message,
|
|
16
12
|
// not a project that quietly fails to open.
|
|
17
13
|
//
|
|
@@ -40,7 +36,7 @@ export function isManifestFilename(name: string): boolean {
|
|
|
40
36
|
export function removedManifestFilenameMessage(where: string): string {
|
|
41
37
|
return (
|
|
42
38
|
`${where}: found \`${REMOVED_MANIFEST_FILENAME}\` and no \`${MANIFEST_FILENAME}\`. ` +
|
|
43
|
-
`\`${REMOVED_MANIFEST_FILENAME}\` was REMOVED (
|
|
39
|
+
`\`${REMOVED_MANIFEST_FILENAME}\` was REMOVED (the legacy-removal doctrine, ` +
|
|
44
40
|
'docs/ARCHITECTURE-CORE.md §Vocabulary) — nothing reads it any more, and it is ' +
|
|
45
41
|
'deliberately NOT read as a fallback, because a second accepted name is the defect.\n' +
|
|
46
42
|
`Fix: rename it — \`git mv ${REMOVED_MANIFEST_FILENAME} ${MANIFEST_FILENAME}\`. ` +
|
package/src/manifest/load.ts
CHANGED
|
@@ -62,13 +62,6 @@ export type ResolvedAdapter =
|
|
|
62
62
|
readonly assets: Record<string, string> | undefined;
|
|
63
63
|
readonly domStubs: string[] | undefined;
|
|
64
64
|
readonly captureTimeoutMs: number | undefined;
|
|
65
|
-
/**
|
|
66
|
-
* The component this root'''s WORLD is, in the game'''s own source (see the
|
|
67
|
-
* field'''s schema description). Present ⇒ Edit mounts THAT component
|
|
68
|
-
* alone as a still design-time document and Play mounts the game
|
|
69
|
-
* through `entry`; absent ⇒ `entry` is what both modes mount.
|
|
70
|
-
*/
|
|
71
|
-
readonly world?: { readonly entry: string; readonly export?: string | undefined } | undefined;
|
|
72
65
|
};
|
|
73
66
|
|
|
74
67
|
export interface ResolvedAdapterRoot {
|
|
@@ -77,6 +70,13 @@ export interface ResolvedAdapterRoot {
|
|
|
77
70
|
readonly description: string | undefined;
|
|
78
71
|
readonly adapter: ResolvedAdapter;
|
|
79
72
|
readonly entry: string | undefined;
|
|
73
|
+
/**
|
|
74
|
+
* The component this root's WORLD is, in the game's own source (see the
|
|
75
|
+
* field's schema description). Present ⇒ Edit mounts THAT component alone as
|
|
76
|
+
* its design-time document and Play mounts the game through `entry`;
|
|
77
|
+
* absent ⇒ `entry` is what both modes mount.
|
|
78
|
+
*/
|
|
79
|
+
readonly world?: { readonly entry: string; readonly export: string | undefined } | undefined;
|
|
80
80
|
readonly zOrder: number;
|
|
81
81
|
readonly pausable: boolean;
|
|
82
82
|
readonly loop: 'gated' | 'self-driven';
|
|
@@ -231,7 +231,6 @@ function resolveAdapter(root: AdapterRoot): ResolvedAdapter {
|
|
|
231
231
|
assets: ingest.assets,
|
|
232
232
|
domStubs: ingest.domStubs,
|
|
233
233
|
captureTimeoutMs: ingest.captureTimeoutMs,
|
|
234
|
-
world: ingest.world,
|
|
235
234
|
};
|
|
236
235
|
}
|
|
237
236
|
|
|
@@ -251,11 +250,14 @@ function checkEngineVersionPin(version: string): void {
|
|
|
251
250
|
* `id` drives uniqueness; `adapter` (incl. its surface and
|
|
252
251
|
* `module`/`ingest.*` sub-fields) drives adapter identity
|
|
253
252
|
* resolution; `entry` drives the entry cross-field rule and is
|
|
254
|
-
* carried through; `
|
|
253
|
+
* carried through; `world` is carried through for the ONE reader that mounts a
|
|
254
|
+
* design-time document (the editor's design session) and is deliberately not
|
|
255
|
+
* cross-checked against `entry` — the two name different modules on purpose;
|
|
256
|
+
* `zOrder` drives the final sort; `pausable`/`loop` are
|
|
255
257
|
* carried through as-is (their consumers are the runtime/CLI, T3.2/T3.3);
|
|
256
258
|
* `description` (T3.3
|
|
257
259
|
* slice 3) is carried through as-is — its consumer today is
|
|
258
|
-
* `resolveIngestDescriptor` (packages/editor/src/
|
|
260
|
+
* `resolveIngestDescriptor` (packages/editor/src/ingest/resolve-three.ts), which
|
|
259
261
|
* threads an ingest-three root's description into `IngestGame.description`.
|
|
260
262
|
*/
|
|
261
263
|
function resolveRoot(root: AdapterRoot): ResolvedAdapterRoot {
|
|
@@ -268,6 +270,8 @@ function resolveRoot(root: AdapterRoot): ResolvedAdapterRoot {
|
|
|
268
270
|
description: root.description,
|
|
269
271
|
adapter,
|
|
270
272
|
entry: root.entry,
|
|
273
|
+
world:
|
|
274
|
+
root.world === undefined ? undefined : { entry: root.world.entry, export: root.world.export },
|
|
271
275
|
zOrder: root.zOrder,
|
|
272
276
|
pausable: root.pausable,
|
|
273
277
|
loop: root.loop,
|
|
@@ -285,9 +289,9 @@ function resolveRoot(root: AdapterRoot): ResolvedAdapterRoot {
|
|
|
285
289
|
* any Zod validation failure or cross-field rule violation.
|
|
286
290
|
*/
|
|
287
291
|
export function loadGameManifest(raw: unknown): ResolvedGameManifest {
|
|
288
|
-
// Removed-format guard FIRST, on the raw value: a
|
|
289
|
-
// would otherwise fail Zod's `roots` discriminated union with
|
|
290
|
-
// shape error instead of
|
|
292
|
+
// Removed-format guard FIRST, on the raw value: a root declaring a removed
|
|
293
|
+
// content field would otherwise fail Zod's `roots` discriminated union with
|
|
294
|
+
// a confusing shape error instead of the named migration message.
|
|
291
295
|
const parsed = GameManifestSchema.safeParse(raw);
|
|
292
296
|
if (!parsed.success) {
|
|
293
297
|
// D-V6: the `roots` `superRefine`'s composition issues — a duplicate root
|
package/src/manifest/schema.ts
CHANGED
|
@@ -7,14 +7,9 @@
|
|
|
7
7
|
// has a `.describe()` (repo policy — powers `scripts/generate-schema.ts` and
|
|
8
8
|
// the T4.1 schema-walk coverage test).
|
|
9
9
|
//
|
|
10
|
-
// Naming:
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
// `Schema` suffix; that sketch is explicitly a
|
|
14
|
-
// "Zod sketch" the doc tells implementers to adapt to real code style
|
|
15
|
-
// ("mirror the style in scene/schema/scene-file.ts" per CLAUDE.md), so the
|
|
16
|
-
// schema consts here are suffixed and the bare names are reserved for the
|
|
17
|
-
// inferred types, matching every other schema file in the repo.
|
|
10
|
+
// Naming: `XxxSchema` is the Zod schema, `Xxx` the inferred type. Every schema
|
|
11
|
+
// file in this repo reads that way, so the bare names stay reserved for the
|
|
12
|
+
// types.
|
|
18
13
|
//
|
|
19
14
|
// Adapter surface values mirror `AdapterSurface` in
|
|
20
15
|
// `packages/engine/src/runtime/game.ts` (`'three' | 'canvas' | 'dom'`)
|
|
@@ -56,7 +51,7 @@ export const GAME_MANIFEST_VERSION = 2 as const;
|
|
|
56
51
|
// which is exactly why react is a `dom` root rather than its own kind.
|
|
57
52
|
//
|
|
58
53
|
// The pre-rename spellings `threejs`/`pixijs`/`react` are REMOVED, not
|
|
59
|
-
// normalized (
|
|
54
|
+
// normalized (the legacy-removal doctrine at
|
|
60
55
|
// ARCHITECTURE-CORE §Vocabulary). Normalization was a second way to say the
|
|
61
56
|
// same thing: two spellings both parsed, so both kept being written, and
|
|
62
57
|
// SECOND readers grew (the dev server's surface probe, the hosted-editor
|
|
@@ -83,8 +78,8 @@ function removedSpellingMessage(bad: string, where: 'adapter' | 'adapter.surface
|
|
|
83
78
|
const canonical =
|
|
84
79
|
where === 'adapter' ? REMOVED_BARE_ADAPTER_SPELLING[bad] : REMOVED_SURFACE_SPELLING[bad];
|
|
85
80
|
return (
|
|
86
|
-
`Game manifest: \`${where}\`: "${bad}" — that spelling was REMOVED
|
|
87
|
-
'ARCHITECTURE-CORE §Vocabulary). The surface vocabulary is ' +
|
|
81
|
+
`Game manifest: \`${where}\`: "${bad}" — that spelling was REMOVED ` +
|
|
82
|
+
'(ARCHITECTURE-CORE §Vocabulary). The surface vocabulary is ' +
|
|
88
83
|
"'three' | 'canvas' | 'dom' — what the HOST HANDS the root, never which " +
|
|
89
84
|
`library it uses.\nFix: change \`${where}\` to "${canonical}".`
|
|
90
85
|
);
|
|
@@ -219,34 +214,6 @@ export const RootAdapterSchema = z
|
|
|
219
214
|
'FAILS by name. A game that needs a long boot (streamed world assets, a menu ' +
|
|
220
215
|
'the player must clear) raises it; the default is 10s.',
|
|
221
216
|
),
|
|
222
|
-
world: z
|
|
223
|
-
.object({
|
|
224
|
-
entry: z
|
|
225
|
-
.string()
|
|
226
|
-
.describe(
|
|
227
|
-
"Project-relative path to the game's OWN module exporting that component",
|
|
228
|
-
),
|
|
229
|
-
export: z
|
|
230
|
-
.string()
|
|
231
|
-
.optional()
|
|
232
|
-
.describe(
|
|
233
|
-
'Named export to read from that module; omit when the module default-exports it',
|
|
234
|
-
),
|
|
235
|
-
})
|
|
236
|
-
.strict()
|
|
237
|
-
.optional()
|
|
238
|
-
.describe(
|
|
239
|
-
"The component this root's WORLD is, in the game's own source — a three root " +
|
|
240
|
-
'whose scene is a React/R3F component tree names it here. Two readers, and ' +
|
|
241
|
-
'they mount different things: the editor mounts THIS component alone as the ' +
|
|
242
|
-
"root's design-time document (a still scene — its frameloop runs ONE bounded " +
|
|
243
|
-
'settle at mount, so physics-owned bodies rest at their authored spawn, and ' +
|
|
244
|
-
'is then frozen forever; nothing moves in Edit), while `entry` ' +
|
|
245
|
-
'above stays what PLAY mounts (the whole game, its own composition, its own ' +
|
|
246
|
-
'HUD and loop). Declaring it is what lets a scene be a scene in Edit rather ' +
|
|
247
|
-
"than the running game's mount surfaces. A game whose world is not a " +
|
|
248
|
-
'component omits it and keeps mounting through `entry` in both modes.',
|
|
249
|
-
),
|
|
250
217
|
})
|
|
251
218
|
.strict()
|
|
252
219
|
.describe(
|
|
@@ -306,6 +273,37 @@ export const AdapterRootSchema = z
|
|
|
306
273
|
"the HUD is styled on the UI board's story cards and on the game surface without the " +
|
|
307
274
|
'editor seeing a single one of those rules. The files themselves are never modified.',
|
|
308
275
|
),
|
|
276
|
+
world: z
|
|
277
|
+
.object({
|
|
278
|
+
entry: z
|
|
279
|
+
.string()
|
|
280
|
+
.describe("Project-relative path to the game's OWN module exporting that component"),
|
|
281
|
+
export: z
|
|
282
|
+
.string()
|
|
283
|
+
.optional()
|
|
284
|
+
.describe(
|
|
285
|
+
'Named export to read from that module; omit when the module default-exports it',
|
|
286
|
+
),
|
|
287
|
+
})
|
|
288
|
+
.strict()
|
|
289
|
+
.optional()
|
|
290
|
+
.describe(
|
|
291
|
+
"The component this root's WORLD is, in the game's own source. Two readers, and they " +
|
|
292
|
+
"mount different things: the EDITOR mounts THIS component alone as the root's " +
|
|
293
|
+
'design-time document, while `entry` above stays what PLAY mounts (the whole game — ' +
|
|
294
|
+
'its own composition, its own HUD, its own loop). It sits on the ROOT rather than ' +
|
|
295
|
+
'inside any one adapter because the split it names is not about ingest: a game whose ' +
|
|
296
|
+
'runtime entry is a SHELL over the thing an author actually edits has this shape ' +
|
|
297
|
+
'whether the source is vendored or first-party. Two shipped cases, one field: an ' +
|
|
298
|
+
'ingested game whose `entry` mounts game+HUD+loop while the named export is the world ' +
|
|
299
|
+
'alone; and a translated Unity/Godot port, whose `entry` is a scene HOST that mounts ' +
|
|
300
|
+
'the scene the built player starts on (`EditorBuildSettings` index 0 — routinely a ' +
|
|
301
|
+
'menu with no 3D content at all) while the named export opens the scene an author ' +
|
|
302
|
+
"edits. That is Unity's own split: build settings say where the PLAYER starts; the " +
|
|
303
|
+
'Scene view opens a scene, and Unity keeps that fact somewhere else entirely. A game ' +
|
|
304
|
+
'whose world is not a separate component omits this and keeps mounting through ' +
|
|
305
|
+
'`entry` in both modes.',
|
|
306
|
+
),
|
|
309
307
|
zOrder: z
|
|
310
308
|
.number()
|
|
311
309
|
.int()
|
|
@@ -424,6 +422,7 @@ export const GameManifestSchema = z
|
|
|
424
422
|
'identity pin, not a range',
|
|
425
423
|
),
|
|
426
424
|
})
|
|
425
|
+
.strict()
|
|
427
426
|
.describe('Engine version pin'),
|
|
428
427
|
roots: z
|
|
429
428
|
.array(AdapterRootSchema)
|
|
@@ -498,21 +497,25 @@ export const GameManifestSchema = z
|
|
|
498
497
|
.describe('Optional editor labels keyed by adapter-root id'),
|
|
499
498
|
groups: z
|
|
500
499
|
.array(
|
|
501
|
-
z
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
500
|
+
z
|
|
501
|
+
.object({
|
|
502
|
+
id: z.string().describe('Unique editor-only group id'),
|
|
503
|
+
label: z.string().describe('Editor-only group label'),
|
|
504
|
+
roots: z
|
|
505
|
+
.array(z.string())
|
|
506
|
+
.min(1)
|
|
507
|
+
.describe('Adapter-root ids shown under this editor-only group'),
|
|
508
|
+
})
|
|
509
|
+
.strict(),
|
|
509
510
|
)
|
|
510
511
|
.optional()
|
|
511
512
|
.describe('Optional editor-only hierarchy groups'),
|
|
512
513
|
})
|
|
514
|
+
.strict()
|
|
513
515
|
.optional()
|
|
514
516
|
.describe('Editor projection for native adapter roots'),
|
|
515
517
|
})
|
|
518
|
+
.strict()
|
|
516
519
|
.optional()
|
|
517
520
|
.describe('Editor-only authoring metadata; never runtime ownership'),
|
|
518
521
|
server: z
|
|
@@ -558,6 +561,7 @@ export const GameManifestSchema = z
|
|
|
558
561
|
'Deploy-baked managed-relay credentials. NEVER hand-authored in source — written only into the staged manifest by `vgai deploy` and fetched at runtime by the standalone client',
|
|
559
562
|
),
|
|
560
563
|
})
|
|
564
|
+
.strict()
|
|
561
565
|
.optional()
|
|
562
566
|
.describe('Multiplayer server config (Colyseus), if this game registers a room'),
|
|
563
567
|
resolution: z
|
|
@@ -565,6 +569,7 @@ export const GameManifestSchema = z
|
|
|
565
569
|
width: z.number().describe('Canvas width in pixels'),
|
|
566
570
|
height: z.number().describe('Canvas height in pixels'),
|
|
567
571
|
})
|
|
572
|
+
.strict()
|
|
568
573
|
.optional()
|
|
569
574
|
.describe('Canvas resolution'),
|
|
570
575
|
rendering: z
|
|
@@ -599,6 +604,7 @@ export const GameManifestSchema = z
|
|
|
599
604
|
'runtime reader is the debug-bridge installer (D18).',
|
|
600
605
|
),
|
|
601
606
|
})
|
|
607
|
+
.strict()
|
|
602
608
|
.optional()
|
|
603
609
|
.describe(
|
|
604
610
|
'Debug-bridge production gating (D18) — governs whether ?vgai-debug=1 installs ' +
|
|
@@ -631,6 +637,7 @@ export const GameManifestSchema = z
|
|
|
631
637
|
"omit to fall back to the runtime's own fixed default seed.",
|
|
632
638
|
),
|
|
633
639
|
})
|
|
640
|
+
.strict()
|
|
634
641
|
.optional()
|
|
635
642
|
.describe(
|
|
636
643
|
'Seeded-RNG determinism contract (D15) — governs ' +
|
|
@@ -689,6 +696,7 @@ export const GameManifestSchema = z
|
|
|
689
696
|
'deterministic under a seed.',
|
|
690
697
|
),
|
|
691
698
|
})
|
|
699
|
+
.strict()
|
|
692
700
|
.refine((budget) => Object.values(budget).some((value) => value !== undefined), {
|
|
693
701
|
message:
|
|
694
702
|
'Game manifest: `budget` must set at least one metric (frameCpuMsP95, physicsMsP95, ' +
|
|
@@ -5,17 +5,13 @@
|
|
|
5
5
|
* shape is defined in absolute world units at creation time. Three.js meshes,
|
|
6
6
|
* by contrast, scale visually for free via the normal Object3D hierarchy. To
|
|
7
7
|
* keep the physical collider matching what's on screen, the LOADER must bake
|
|
8
|
-
* the entity's composed WORLD scale (self × every transformed ancestor
|
|
9
|
-
*
|
|
10
|
-
* creation time.
|
|
8
|
+
* the entity's composed WORLD scale (self × every transformed ancestor) into
|
|
9
|
+
* the collider's dimensions at creation time.
|
|
11
10
|
*
|
|
12
|
-
* This is the ONE place that does that math, so
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* Three.js parenting) while the Rapier body ignored scale entirely, so the
|
|
17
|
-
* two silently agreed by coincidence for uniform scale and disagreed for
|
|
18
|
-
* everything else.
|
|
11
|
+
* This is the ONE place that does that math, so every caller — the physics
|
|
12
|
+
* body creation path and the editor's collider gizmo alike — agrees on
|
|
13
|
+
* exactly the same numbers. Two copies silently agree by coincidence for
|
|
14
|
+
* uniform scale and disagree for everything else.
|
|
19
15
|
*
|
|
20
16
|
* Round colliders (ball/capsule) can only represent a uniform radius — Rapier
|
|
21
17
|
* has no ellipsoid/elliptical-capsule shape. A non-uniform world scale on a
|
|
@@ -40,8 +36,8 @@ export interface ColliderWorldDimensions {
|
|
|
40
36
|
|
|
41
37
|
/**
|
|
42
38
|
* Compute a collider's WORLD-space dimensions given the entity's composed
|
|
43
|
-
* world scale (self × ancestors, per-axis, in the entity's own local frame
|
|
44
|
-
* X/Y/Z order
|
|
39
|
+
* world scale (self × ancestors, per-axis, in the entity's own local frame,
|
|
40
|
+
* in X/Y/Z order).
|
|
45
41
|
*
|
|
46
42
|
* @param collider - the entity's authored (unscaled) collider definition.
|
|
47
43
|
* @param worldScale - composed world scale `[x, y, z]`.
|
|
@@ -19,25 +19,22 @@
|
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
21
|
import {
|
|
22
|
+
type CaptureWaitOptions,
|
|
22
23
|
documentVisibilityClock,
|
|
23
24
|
startVisibleCaptureWindow,
|
|
24
|
-
type VisibilityClock,
|
|
25
|
-
type VisibleCaptureWindow,
|
|
26
25
|
} from '../adapter/ingest/visible-capture-window';
|
|
27
26
|
|
|
28
27
|
/**
|
|
29
|
-
* Options for {@link SceneCapture2DHandle.waitForCapture} — the
|
|
30
|
-
*
|
|
31
|
-
*
|
|
28
|
+
* Options for {@link SceneCapture2DHandle.waitForCapture} — the WAIT's options,
|
|
29
|
+
* not this lane's, so they carry no `2D` suffix and are not declared here.
|
|
30
|
+
* They configure `visible-capture-window.ts`'s window, which both surfaces
|
|
31
|
+
* share; this lane used to restate them field-for-field under a `2D` name.
|
|
32
|
+
* The suffix marks what a surface genuinely owns
|
|
33
|
+
* ({@link CapturedRuntime2D} is a Pixi stage/renderer/app, and stays), and a
|
|
34
|
+
* budget of visible milliseconds is not that. Passing a bare number is
|
|
35
|
+
* `{ timeoutMs }`, which is what every existing caller does.
|
|
32
36
|
*/
|
|
33
|
-
export
|
|
34
|
-
/** The capture window, in VISIBLE milliseconds (default 10s). */
|
|
35
|
-
timeoutMs?: number | undefined;
|
|
36
|
-
/** Injected in tests; defaults to the document's own visibility. */
|
|
37
|
-
visibility?: VisibilityClock | undefined;
|
|
38
|
-
/** Live view of the wait while it runs, `null` the moment it ends. */
|
|
39
|
-
onWait?: ((wait: VisibleCaptureWindow | null) => void) | undefined;
|
|
40
|
-
}
|
|
37
|
+
export type { CaptureWaitOptions };
|
|
41
38
|
|
|
42
39
|
/** A live Pixi runtime captured from an external PixiJS game. */
|
|
43
40
|
export interface CapturedRuntime2D {
|
|
@@ -68,7 +65,7 @@ export interface SceneCapture2DHandle {
|
|
|
68
65
|
* frame the tab draws after it comes forward is trapped exactly as it would
|
|
69
66
|
* have been at boot. Rejects only when the window is spent while VISIBLE.
|
|
70
67
|
*/
|
|
71
|
-
waitForCapture(options?: number |
|
|
68
|
+
waitForCapture(options?: number | CaptureWaitOptions): Promise<CapturedRuntime2D>;
|
|
72
69
|
getDrawCount(): number;
|
|
73
70
|
/** Pause/resume the captured game's own ticker (loop-host gating). */
|
|
74
71
|
setPaused(paused: boolean): void;
|
|
@@ -138,7 +135,7 @@ export function installSceneCapture2D(
|
|
|
138
135
|
else app.ticker.start();
|
|
139
136
|
},
|
|
140
137
|
waitForCapture(options) {
|
|
141
|
-
const opts:
|
|
138
|
+
const opts: CaptureWaitOptions =
|
|
142
139
|
typeof options === 'number' ? { timeoutMs: options } : (options ?? {});
|
|
143
140
|
const timeoutMs = opts.timeoutMs ?? 10_000;
|
|
144
141
|
if (captured) return Promise.resolve(captured);
|
|
@@ -27,10 +27,10 @@ import {
|
|
|
27
27
|
} from 'react';
|
|
28
28
|
import type { z } from 'zod';
|
|
29
29
|
import type { RootStateObserver } from '../adapter';
|
|
30
|
+
import type { DebugCommandArgs } from '../runtime/debug-registry';
|
|
30
31
|
import { getDebugRegistry } from '../runtime/debug-registry';
|
|
31
32
|
import { createFrameSelectorCache, type Equals, shallow } from '../runtime/frame-selector-cache';
|
|
32
33
|
import type { Game } from '../runtime/game';
|
|
33
|
-
import type { DebugCommandArgs } from '../runtime/types';
|
|
34
34
|
|
|
35
35
|
/** Re-exported for convenience — the opt-in equality for selectors that
|
|
36
36
|
* return a fresh object/array/tuple every call (default is `Object.is`). */
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Shared light + camera factory
|
|
2
|
+
* Shared light + camera factory — the ONE place light/camera fallbacks are
|
|
3
|
+
* decided, and it decides them by READING `DEFAULTS.light`/`DEFAULTS.camera`.
|
|
3
4
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* '#ffffff', fov 60, near 0.1, far 1000, etc.) that happened to agree with
|
|
8
|
-
* `DEFAULTS.light`/`DEFAULTS.camera` by luck rather than by reading them. Any
|
|
9
|
-
* edit to one copy (or to `DEFAULTS`) could silently diverge from the other.
|
|
5
|
+
* A second copy hardcoding the same literals (color '#ffffff', fov 60, near
|
|
6
|
+
* 0.1, far 1000) would agree by luck rather than by construction, and any
|
|
7
|
+
* edit to either copy — or to `DEFAULTS` — would silently diverge.
|
|
10
8
|
*
|
|
11
9
|
* This module is now the ONE place that builds a `THREE.Light`/`THREE.Camera`
|
|
12
10
|
* from a `LightDescriptor`/`CameraDescriptor` descriptor, reading its fallbacks from
|
|
@@ -22,10 +20,9 @@ import * as THREE from 'three';
|
|
|
22
20
|
// `three/addons/*` alias (package.json `exports`: `"./addons/*":
|
|
23
21
|
// "./examples/jsm/*"` — the identical file as
|
|
24
22
|
// `three/examples/jsm/lights/RectAreaLightUniformsLib.js`) because a literal
|
|
25
|
-
// `/examples/` specifier trips
|
|
26
|
-
//
|
|
27
|
-
//
|
|
28
|
-
// to three.js's addon folder naming).
|
|
23
|
+
// `/examples/` specifier trips this repo's game/editor-example import guard —
|
|
24
|
+
// a same-substring false positive against our own `src/examples/` convention,
|
|
25
|
+
// unrelated to three.js's addon folder naming.
|
|
29
26
|
import { RectAreaLightUniformsLib } from 'three/addons/lights/RectAreaLightUniformsLib.js';
|
|
30
27
|
import type { CameraDescriptor } from '../asset-formats/camera';
|
|
31
28
|
import type { LightDescriptor } from '../asset-formats/light';
|
|
@@ -65,7 +65,7 @@ export function createMaterial(mat?: MaterialDescriptor): THREE.Material {
|
|
|
65
65
|
// R1c — every fallback below reads DEFAULTS.material.* instead of
|
|
66
66
|
// duplicating its value as a bare literal, so DEFAULTS stays the single
|
|
67
67
|
// source of truth for what an omitted field renders as (see
|
|
68
|
-
//
|
|
68
|
+
// `material-factory.test.ts`'s
|
|
69
69
|
// "omitted-field" locks, which fail if either copy drifts from the other).
|
|
70
70
|
const dMat = DEFAULTS.material;
|
|
71
71
|
const sideValue = mat.side ?? dMat.side;
|
|
@@ -13,21 +13,29 @@ import { staticBatchSignature } from './structural-signature';
|
|
|
13
13
|
* N logical objects → 1 draw call, ~0 CPU/frame. This is the classic "static
|
|
14
14
|
* batching" technique (cf. Unity/PlayCanvas static batch groups).
|
|
15
15
|
*
|
|
16
|
-
* Strategy 1 (keep identity, don't merge). Moving entities (boids-style,
|
|
17
|
-
* concern
|
|
16
|
+
* Strategy 1 (keep identity, don't merge). Moving entities (boids-style,
|
|
17
|
+
* all-frame churn) are a separate concern, and the engine does not answer it:
|
|
18
|
+
* a game's production answer is the `static-batch` capability's `<Frozen>`
|
|
19
|
+
* (see the scope note below).
|
|
18
20
|
*
|
|
19
21
|
* Eligibility (anything failing stays an ordinary draw — degrade, don't break):
|
|
20
22
|
* - plain THREE.Mesh (not Instanced/Skinned/Batched)
|
|
21
23
|
* - single, opaque material (transparency needs per-object sorting)
|
|
22
24
|
* - group of ≥2 sharing (geometry, material, shadow flags)
|
|
23
|
-
* -
|
|
25
|
+
* - (there is no per-entity opt-out setting: this docblock used to name
|
|
26
|
+
* `entity.render.autoBatch === false`, a render-feature field NO CODE HERE
|
|
27
|
+
* OR ANYWHERE EVER READ. The field was deleted with R-2's coverage fix;
|
|
28
|
+
* opting a subtree out is the `static-batch` capability's `<Frozen>`
|
|
29
|
+
* declaration, per the scope note below.)
|
|
24
30
|
* - STATIC members (no physics/components/animation) → detached; MOVING members →
|
|
25
31
|
* kept in-graph hidden + dirty-synced each frame. A bucket may split into both.
|
|
26
32
|
*
|
|
27
33
|
* Scope / limitations (v1):
|
|
28
|
-
* - NOT WIRED: nothing in the engine calls build()
|
|
29
|
-
*
|
|
30
|
-
*
|
|
34
|
+
* - NOT WIRED: nothing in the engine calls build(), and nothing constructs
|
|
35
|
+
* this class. The only remaining reference is the hosted editor's
|
|
36
|
+
* project-script module map (`editor/src/browser-project-scripts.ts`),
|
|
37
|
+
* which loads the module so a project script MAY drive it; the example
|
|
38
|
+
* that used to is gone. That is settled, not pending: a game's
|
|
31
39
|
* production answer is the `static-batch` capability's `<Frozen>`, a
|
|
32
40
|
* DECLARED mount-static subtree in the game's own TSX, and `dev/static-
|
|
33
41
|
* batch-advisor.ts` is what routes an author to it by measurement. Full-
|
|
@@ -2,12 +2,23 @@ import { z } from 'zod';
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* The render-feature registry — single source of truth for every togglable render
|
|
5
|
-
* setting. The
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
5
|
+
* setting. The render-env schema (`asset-formats/render-env.ts`) and the cascade
|
|
6
|
+
* resolver (`resolveRenderSettings`) are both derived from this list, so
|
|
7
|
+
* "everything togglable" stays consistent by construction (same posture as the
|
|
8
|
+
* component/material/instancer registries).
|
|
9
|
+
*
|
|
10
|
+
* EVERY ENTRY HERE MUST HAVE A RUNTIME READER of its resolved value, and that is
|
|
11
|
+
* now enforced: `schema-reader-coverage.test.ts` derives its walk from this
|
|
12
|
+
* array, so adding a feature adds a described schema path that fails coverage
|
|
13
|
+
* until `schema-consumption-map.ts` names the file that reads it.
|
|
14
|
+
*
|
|
15
|
+
* Three entries were deleted when that enforcement first ran, having reached it
|
|
16
|
+
* with no reader at all: `autoBatch` (its only mention was a COMMENT in
|
|
17
|
+
* `render-batch-system.ts`, a class whose own header says nothing calls it),
|
|
18
|
+
* `lod`, and `backend` (which offered a `webgpu` option while
|
|
19
|
+
* `setup-renderer.ts` unconditionally constructs a `THREE.WebGLRenderer`). A
|
|
20
|
+
* toggle that changes nothing is worse than a missing one — it tells an author
|
|
21
|
+
* the engine has a dial it does not have.
|
|
11
22
|
*/
|
|
12
23
|
|
|
13
24
|
export type RenderFeatureValue = boolean | number | string;
|
|
@@ -37,16 +48,6 @@ export interface RenderFeature {
|
|
|
37
48
|
}
|
|
38
49
|
|
|
39
50
|
export const RENDER_FEATURES: readonly RenderFeature[] = [
|
|
40
|
-
{
|
|
41
|
-
key: 'autoBatch',
|
|
42
|
-
label: 'Auto-batching',
|
|
43
|
-
description:
|
|
44
|
-
'Automatically batch entities sharing geometry+material into one draw call (InstancedMesh/BatchedMesh) while keeping each Object3D as the handle. The headline perf win; opt out per-entity for custom-shader/skinned meshes.',
|
|
45
|
-
kind: 'toggle',
|
|
46
|
-
default: true,
|
|
47
|
-
apply: 'live',
|
|
48
|
-
perEntity: true,
|
|
49
|
-
},
|
|
50
51
|
{
|
|
51
52
|
key: 'frustumCulling',
|
|
52
53
|
label: 'Frustum culling',
|
|
@@ -56,15 +57,6 @@ export const RENDER_FEATURES: readonly RenderFeature[] = [
|
|
|
56
57
|
apply: 'live',
|
|
57
58
|
perEntity: true,
|
|
58
59
|
},
|
|
59
|
-
{
|
|
60
|
-
key: 'lod',
|
|
61
|
-
label: 'Level of detail',
|
|
62
|
-
description: 'Distance-based geometry swap (LOD) for eligible entities.',
|
|
63
|
-
kind: 'toggle',
|
|
64
|
-
default: true,
|
|
65
|
-
apply: 'live',
|
|
66
|
-
perEntity: true,
|
|
67
|
-
},
|
|
68
60
|
{
|
|
69
61
|
key: 'shadows',
|
|
70
62
|
label: 'Shadows',
|
|
@@ -103,16 +95,6 @@ export const RENDER_FEATURES: readonly RenderFeature[] = [
|
|
|
103
95
|
apply: 'reload',
|
|
104
96
|
perEntity: false,
|
|
105
97
|
},
|
|
106
|
-
{
|
|
107
|
-
key: 'backend',
|
|
108
|
-
label: 'Renderer backend',
|
|
109
|
-
description: 'GPU backend: auto picks WebGPU when available, else WebGL2. Applies on reload.',
|
|
110
|
-
kind: 'enum',
|
|
111
|
-
default: 'auto',
|
|
112
|
-
apply: 'reload',
|
|
113
|
-
perEntity: false,
|
|
114
|
-
options: ['auto', 'webgl', 'webgpu'],
|
|
115
|
-
},
|
|
116
98
|
];
|
|
117
99
|
|
|
118
100
|
/** Map for O(1) lookup by key. */
|