@vgai/engine 0.5.22 → 0.5.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -3
- package/dist/adapter/adapter-module.d.ts.map +1 -1
- package/dist/adapter/adapter-module.js +2 -4
- package/dist/adapter/adapter-surface.d.ts +1 -1
- package/dist/adapter/adapter-surface.js +1 -1
- package/dist/adapter/authoring.d.ts +19 -21
- package/dist/adapter/authoring.d.ts.map +1 -1
- package/dist/adapter/authoring.js +2 -2
- package/dist/adapter/binding.d.ts +341 -0
- package/dist/adapter/binding.d.ts.map +1 -0
- package/dist/adapter/binding.js +148 -0
- package/dist/adapter/colyseus-networking-adapter.d.ts.map +1 -1
- package/dist/adapter/colyseus-networking-adapter.js +23 -4
- package/dist/adapter/entrypoint-selection-readers.d.ts +24 -0
- package/dist/adapter/entrypoint-selection-readers.d.ts.map +1 -0
- package/dist/adapter/entrypoint-selection-readers.js +63 -0
- package/dist/adapter/entrypoint-selection-source.d.ts.map +1 -1
- package/dist/adapter/entrypoint-selection-source.js +1 -44
- package/dist/adapter/finders/scenes-from-entrypoint-selection.d.ts.map +1 -1
- package/dist/adapter/finders/scenes-from-entrypoint-selection.js +1 -52
- package/dist/adapter/host-context.d.ts +46 -15
- package/dist/adapter/host-context.d.ts.map +1 -1
- package/dist/adapter/host-context.js +2 -9
- package/dist/adapter/index.d.ts +11 -12
- package/dist/adapter/index.d.ts.map +1 -1
- package/dist/adapter/index.js +9 -10
- package/dist/adapter/ingest/game-contract.d.ts +0 -3
- package/dist/adapter/ingest/game-contract.d.ts.map +1 -1
- package/dist/adapter/ingest/game-contract.js +0 -3
- package/dist/adapter/ingest/scene-capture.d.ts +19 -23
- package/dist/adapter/ingest/scene-capture.d.ts.map +1 -1
- package/dist/adapter/ingest/scene-capture.js +143 -17
- package/dist/adapter/ingest/visible-capture-window.d.ts +34 -0
- package/dist/adapter/ingest/visible-capture-window.d.ts.map +1 -1
- package/dist/adapter/native-debug-module.d.ts +31 -5
- package/dist/adapter/native-debug-module.d.ts.map +1 -1
- package/dist/adapter/native-debug-module.js +25 -7
- 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-registry.d.ts +77 -8
- package/dist/runtime/debug-registry.d.ts.map +1 -1
- package/dist/runtime/debug-registry.js +3 -3
- package/dist/runtime/dev-build.d.ts +2 -2
- package/dist/runtime/dev-build.js +2 -2
- package/dist/runtime/game-input-seams.d.ts +2 -2
- package/dist/runtime/game-input-seams.d.ts.map +1 -1
- package/dist/runtime/game.d.ts +90 -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/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.ts +0 -3
- package/src/adapter/ingest/scene-capture.ts +190 -39
- package/src/adapter/ingest/visible-capture-window.ts +35 -0
- package/src/adapter/native-debug-module.ts +43 -7
- 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-registry.ts +84 -8
- package/src/runtime/dev-build.ts +2 -2
- package/src/runtime/game-input-seams.ts +2 -2
- package/src/runtime/game.ts +168 -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/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/adapter/transform.ts
CHANGED
|
@@ -15,4 +15,21 @@ export interface Transform {
|
|
|
15
15
|
* needs simulation coordination (`physics`), or is best-effort/inspect-only
|
|
16
16
|
* (`script`/`network`/`external`).
|
|
17
17
|
*/
|
|
18
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Who drives a node's transform right now.
|
|
20
|
+
*
|
|
21
|
+
* `'unresolved'` is the answer for a node THIS ADAPTER DOES NOT KNOW, and it is
|
|
22
|
+
* a distinct answer on purpose: every other member names a driver, so returning
|
|
23
|
+
* one of them for an unknown id is a positive claim about a node the
|
|
24
|
+
* implementer has never seen. A game-scoped physics adapter is asked about
|
|
25
|
+
* every node the editor touches, including nodes belonging to another root —
|
|
26
|
+
* "not mine" has to be sayable.
|
|
27
|
+
*/
|
|
28
|
+
export type TransformOwner =
|
|
29
|
+
| 'editor'
|
|
30
|
+
| 'physics'
|
|
31
|
+
| 'animation'
|
|
32
|
+
| 'script'
|
|
33
|
+
| 'network'
|
|
34
|
+
| 'external'
|
|
35
|
+
| 'unresolved';
|
package/src/ai/navigation.ts
CHANGED
|
@@ -119,11 +119,38 @@ export class NavMeshManager {
|
|
|
119
119
|
return this.navMesh !== null;
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
/**
|
|
122
|
+
/**
|
|
123
|
+
* Find a straight path between two world positions.
|
|
124
|
+
*
|
|
125
|
+
* THREE OUTCOMES, and only one of them is an empty array:
|
|
126
|
+
*
|
|
127
|
+
* - **No pathfinder.** No navmesh has been built, so there is nothing to
|
|
128
|
+
* query. THROWS, the same way {@link createCrowd} does — `[]` here would
|
|
129
|
+
* say "I searched and there is no route between these points", which is a
|
|
130
|
+
* claim about the level rather than about this manager's state. Callers
|
|
131
|
+
* that can be in this position gate on {@link hasNavMesh} first.
|
|
132
|
+
* - **The query failed.** recast answered `success: false` WITH an error
|
|
133
|
+
* (bad half-extents, no polygon near an endpoint, a status code). THROWS,
|
|
134
|
+
* naming recast's own error — a failed search is not a searched-and-empty
|
|
135
|
+
* one, and the editor's probe already surfaces this separately from "no
|
|
136
|
+
* path found".
|
|
137
|
+
* - **Genuinely no route.** The query ran and found nothing. `[]`.
|
|
138
|
+
*/
|
|
123
139
|
findPath(start: Vector3Like, end: Vector3Like): Vector3Like[] {
|
|
124
|
-
if (!this.query)
|
|
140
|
+
if (!this.query) {
|
|
141
|
+
throw new Error(
|
|
142
|
+
'NavMeshManager.findPath: no navmesh has been built, so no path can be queried. ' +
|
|
143
|
+
'Build one first (buildFromMeshes/importNavMesh) — gate on hasNavMesh() if the ' +
|
|
144
|
+
'caller can run before a bake.',
|
|
145
|
+
);
|
|
146
|
+
}
|
|
125
147
|
const result = this.query.computePath(start, end);
|
|
126
|
-
if (!result.success)
|
|
148
|
+
if (!result.success && result.error) {
|
|
149
|
+
throw new Error(
|
|
150
|
+
`NavMeshManager.findPath: recast could not complete the query (${result.error.name}` +
|
|
151
|
+
`${result.error.status === undefined ? '' : `, status ${result.error.status}`}).`,
|
|
152
|
+
);
|
|
153
|
+
}
|
|
127
154
|
return result.path;
|
|
128
155
|
}
|
|
129
156
|
|
|
@@ -10,16 +10,24 @@
|
|
|
10
10
|
* the old `.animgraph.json` format) was deleted with the runtime that read
|
|
11
11
|
* them (`anim-graph.ts`).
|
|
12
12
|
*/
|
|
13
|
+
/**
|
|
14
|
+
* The optional fields spell `| undefined` explicitly because the repo compiles
|
|
15
|
+
* with `exactOptionalPropertyTypes`, and the one producer of these values is
|
|
16
|
+
* `xstate-animation-meta.ts`'s Zod schema, whose `.optional()` infers
|
|
17
|
+
* `?: T | undefined`. Without the explicit union the parsed value is not
|
|
18
|
+
* assignable here and the call site needs a cast — which is exactly what used
|
|
19
|
+
* to hide field drift between the two declarations (see `asBlendTreeDef`).
|
|
20
|
+
*/
|
|
13
21
|
export interface BlendTreeDef {
|
|
14
22
|
type: '1D' | '2D' | 'direct';
|
|
15
23
|
parameter: string;
|
|
16
|
-
parameterY?: string; // for 2D
|
|
24
|
+
parameterY?: string | undefined; // for 2D
|
|
17
25
|
children: BlendChild[];
|
|
18
26
|
}
|
|
19
27
|
|
|
20
28
|
export interface BlendChild {
|
|
21
29
|
clip: string;
|
|
22
30
|
threshold: number;
|
|
23
|
-
thresholdY?: number; // for 2D
|
|
24
|
-
weight?: number; // for direct
|
|
31
|
+
thresholdY?: number | undefined; // for 2D
|
|
32
|
+
weight?: number | undefined; // for direct
|
|
25
33
|
}
|
|
@@ -78,10 +78,10 @@ export interface TheatreClockBinding {
|
|
|
78
78
|
/**
|
|
79
79
|
* Subscribe `sequence.position = clock.time` to every crossing of `clock` in
|
|
80
80
|
* the given phase (default `'animation'`). Returns a disposer; call it to
|
|
81
|
-
* stop driving the sequence (e.g.
|
|
82
|
-
* rebinding on hot reload — this is what keeps HMR from
|
|
83
|
-
* duplicate listeners
|
|
84
|
-
*
|
|
81
|
+
* stop driving the sequence (e.g. in the owning component's unmount cleanup,
|
|
82
|
+
* or before rebinding on hot reload — this is what keeps HMR from
|
|
83
|
+
* accumulating duplicate listeners: dispose the old binding before creating
|
|
84
|
+
* a new one).
|
|
85
85
|
*
|
|
86
86
|
* Multiple sheets/sequences can each get their own binding with no shared
|
|
87
87
|
* mutable state on VGAI's side — collision avoidance for the underlying
|
|
@@ -2,7 +2,6 @@ import * as THREE from 'three';
|
|
|
2
2
|
import type { AnyStateMachine } from 'xstate';
|
|
3
3
|
import type { createSystemRunner } from '../core/system-runner';
|
|
4
4
|
import { deleteUserData, getUserData, setUserData } from '../ecs/user-data';
|
|
5
|
-
import type { BlendTreeDef } from './anim-graph-types';
|
|
6
5
|
import { evaluateBlendTree } from './blend-node';
|
|
7
6
|
import {
|
|
8
7
|
type AnimationPreviewTransport,
|
|
@@ -11,6 +10,7 @@ import {
|
|
|
11
10
|
import {
|
|
12
11
|
type AnimationBoneMask,
|
|
13
12
|
type AnimationMetaStateNodeLike,
|
|
13
|
+
asBlendTreeDef,
|
|
14
14
|
clipNamesOf,
|
|
15
15
|
collectMachineAnimationMeta,
|
|
16
16
|
isBlendTreeAnimationMeta,
|
|
@@ -365,7 +365,7 @@ export function bindXStateAnimation(
|
|
|
365
365
|
|
|
366
366
|
function weightsOf(stateId: string, meta: StateAnimationMeta, context: unknown): WeightedClip[] {
|
|
367
367
|
const weights = isBlendTreeAnimationMeta(meta)
|
|
368
|
-
? evaluateBlendTree(meta.blendTree
|
|
368
|
+
? evaluateBlendTree(asBlendTreeDef(meta.blendTree), readParameters(context))
|
|
369
369
|
: [{ clip: meta.clip, weight: 1 }];
|
|
370
370
|
return weights.map(({ clip, weight }) => ({
|
|
371
371
|
clip,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import type { BlendTreeDef } from './anim-graph-types';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* E1 — Zod/TypeScript metadata attached to XState state `meta.animation`
|
|
@@ -102,6 +103,21 @@ export const AnimationBlendTreeSchema = z.discriminatedUnion('type', [
|
|
|
102
103
|
|
|
103
104
|
export type AnimationBlendTree = z.infer<typeof AnimationBlendTreeSchema>;
|
|
104
105
|
|
|
106
|
+
/**
|
|
107
|
+
* The structural-identity claim in this file's header, made COMPILER-CHECKED.
|
|
108
|
+
*
|
|
109
|
+
* `evaluateBlendTree` takes `anim-graph-types.ts`'s `BlendTreeDef`, and the
|
|
110
|
+
* whole reason this schema mirrors that shape field-for-field is so a parsed
|
|
111
|
+
* value can be handed over with zero conversion. The binding used to spell that
|
|
112
|
+
* hand-over `as unknown as BlendTreeDef` — a double cast that would have gone on
|
|
113
|
+
* compiling if either declaration drifted, silently feeding the blend math a
|
|
114
|
+
* shape it does not describe. This identity function is the assignability
|
|
115
|
+
* assertion instead: drift here is a type error at the seam that claims it.
|
|
116
|
+
*/
|
|
117
|
+
export function asBlendTreeDef(tree: AnimationBlendTree): BlendTreeDef {
|
|
118
|
+
return tree;
|
|
119
|
+
}
|
|
120
|
+
|
|
105
121
|
// ---------------------------------------------------------------------------
|
|
106
122
|
// Crossfade / blend-in-out metadata (shared by clip and blend-tree states)
|
|
107
123
|
// ---------------------------------------------------------------------------
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The engine's runtime descriptor schemas.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* real runtime reader still consumes it:
|
|
4
|
+
* Each module is here because a real runtime READER consumes it — nothing in
|
|
5
|
+
* this directory exists as documentation of a format:
|
|
7
6
|
*
|
|
8
7
|
* - `material.ts` — the inline material descriptor `render/material-factory.ts` reads
|
|
9
8
|
* - `mesh.ts` — the geometry descriptor `render/material-factory.ts`'s `createGeometry` reads
|
|
@@ -16,10 +15,8 @@
|
|
|
16
15
|
* - `tuples.ts` — the shared Vec3/Quat/Transform tuples the above build on
|
|
17
16
|
*
|
|
18
17
|
* These are DESCRIPTORS, not documents: each names a slice of authored data a
|
|
19
|
-
* render/physics factory reads, and none of them is a scene
|
|
20
|
-
*
|
|
21
|
-
* was a leftover of the deleted `.vscn.json` format, not a statement about what
|
|
22
|
-
* they describe.
|
|
18
|
+
* render/physics factory reads, and none of them is a scene — which is why
|
|
19
|
+
* every one of them is named `*Descriptor`.
|
|
23
20
|
*/
|
|
24
21
|
|
|
25
22
|
export type { CameraDescriptor } from './camera';
|
|
@@ -2,12 +2,9 @@
|
|
|
2
2
|
* Render settings — the tone-mapping / post-processing / render-feature scope
|
|
3
3
|
* the engine's renderer setup reads (`setup/setup-renderer.ts`).
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* postprocessing chain from them. Everything that was `.vscn`-only (`skybox`,
|
|
9
|
-
* `fog`, `ambient`, `background`, `envMapIntensity`, `navigation`, `physics`)
|
|
10
|
-
* went with the format.
|
|
5
|
+
* Exactly THREE scopes, and each is here because `setup-renderer.ts` reads
|
|
6
|
+
* every one of its fields to build the postprocessing chain. A setting with
|
|
7
|
+
* no such reader does not belong in this descriptor.
|
|
11
8
|
*/
|
|
12
9
|
import { z } from 'zod';
|
|
13
10
|
import { buildRenderingZod } from '../render/render-features';
|
package/src/asset-parse-error.ts
CHANGED
|
@@ -7,11 +7,8 @@
|
|
|
7
7
|
* every caller (currently the input-map loader in `input/input-manager.ts`)
|
|
8
8
|
* does not have to reach into an unrelated subsystem for it.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* redesign"); with `.vscn` gone the old name described nothing — an
|
|
13
|
-
* `.inputmap.json` failure is not a scene failure — so the class and its
|
|
14
|
-
* message header now say `asset`.
|
|
10
|
+
* The name says ASSET, not scene: an `.inputmap.json` failure is not a scene
|
|
11
|
+
* failure, and the class covers every structured fetched asset.
|
|
15
12
|
*/
|
|
16
13
|
|
|
17
14
|
import type { ZodIssue } from 'zod';
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A named-bus mixer over Web Audio: buses created on demand, routed into each
|
|
3
|
+
* other by name, and set in DECIBELS.
|
|
4
|
+
*
|
|
5
|
+
* Every mixer a game reaches for is this shape — Unity's `AudioMixerGroup`,
|
|
6
|
+
* Godot's bus layout, FMOD's VCAs, and the `music`/`sfx`/`voice` trio
|
|
7
|
+
* `setup/setup-audio.ts` hands a first-party three world. What they share is
|
|
8
|
+
* not the protocol (that part is genuinely per-ecosystem and stays with the
|
|
9
|
+
* lane that speaks it) but the machinery underneath: a `GainNode` per bus, a
|
|
10
|
+
* name → node map, a parent to route into, and the one conversion below. This
|
|
11
|
+
* file owns exactly that, and nothing that names an ecosystem.
|
|
12
|
+
*
|
|
13
|
+
* ## dB is not a gain, and the mistake is silent
|
|
14
|
+
*
|
|
15
|
+
* `GainNode.gain` is a LINEAR amplitude multiplier; every mixer's authored
|
|
16
|
+
* volume is logarithmic dB, where 0 dB is unity and −80 dB is silence. Writing
|
|
17
|
+
* the dB number straight onto `gain.value` gives you a gain of −80 (a phase
|
|
18
|
+
* inversion at 80x) where the author asked for silence, and it does not throw,
|
|
19
|
+
* warn, or look wrong in a debugger — it is just loud. {@link dbToLinear} is
|
|
20
|
+
* the one conversion, `10^(dB/20)`, which is both Godot's `db_to_linear`
|
|
21
|
+
* (`core/math/math_funcs.h`: `exp(db * 0.11512925464970228…)`, the same
|
|
22
|
+
* function written in base e) and Unity's mixer volume curve.
|
|
23
|
+
*
|
|
24
|
+
* It deliberately does NOT clamp. A mixer's RANGE is protocol — Unity's
|
|
25
|
+
* exposed parameters saturate at its slider's ends, Godot's `volume_db` does
|
|
26
|
+
* not — so the lane that knows the range applies it before calling here, and
|
|
27
|
+
* this file cannot silently mute or silently boost anyone's authored value.
|
|
28
|
+
*
|
|
29
|
+
* ## Create-on-demand, and why it is the contract rather than a convenience
|
|
30
|
+
*
|
|
31
|
+
* {@link AudioBusMixer.bus} MINTS a bus the first time it is named and returns
|
|
32
|
+
* the SAME node forever after. The identity is the contract, not the minting:
|
|
33
|
+
* a source connects to a bus long before anything sets that bus's volume, and
|
|
34
|
+
* a parent is usually named by its child before anyone asks for it directly
|
|
35
|
+
* (`bus('music', 'master')` builds `master` too, and the later `bus('master')`
|
|
36
|
+
* must be that same node). A `bus()` that minted per call would hand the
|
|
37
|
+
* volume control a SECOND node — the sources would keep feeding the first one,
|
|
38
|
+
* every later write would land on a node nothing plays through, and nothing
|
|
39
|
+
* would throw or look wrong. So the map is authoritative, and the only way a
|
|
40
|
+
* name stops resolving to its node is {@link AudioBusMixer.remove} or
|
|
41
|
+
* {@link AudioBusMixer.disconnect}.
|
|
42
|
+
*
|
|
43
|
+
* A re-ask that names a DIFFERENT parent throws by name. Routing is decided at
|
|
44
|
+
* creation (the node is already connected by then), so honouring the second
|
|
45
|
+
* parent would mean silently re-routing live audio and ignoring it would mean
|
|
46
|
+
* silently keeping the first — a loud error is the only reading that is not a
|
|
47
|
+
* lie.
|
|
48
|
+
*
|
|
49
|
+
* ## RESOURCE OWNERSHIP
|
|
50
|
+
*
|
|
51
|
+
* No module-scoped state: {@link createAudioBusMixer} is a factory and the
|
|
52
|
+
* OWNER of an instance is whoever called it (a `setupAudio` graph, one
|
|
53
|
+
* translated port's mixer store). What an instance ALLOCATES is one `GainNode`
|
|
54
|
+
* per named bus, and disconnecting those is the whole of its teardown
|
|
55
|
+
* obligation — {@link AudioBusMixer.disconnect}, called once by that same
|
|
56
|
+
* owner. The `context` and the `destination` node are NOT its own: they are
|
|
57
|
+
* passed in, shared with everything else hanging off the same graph, and this
|
|
58
|
+
* file never creates, closes, suspends or disconnects either one.
|
|
59
|
+
*/
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* The graph an {@link AudioBusMixer} hangs off, as the two members it touches.
|
|
63
|
+
*
|
|
64
|
+
* Narrow on purpose: `createGain` is all it needs from the context, so a real
|
|
65
|
+
* `AudioContext`, an `OfflineAudioContext` and a headless stand-in are all
|
|
66
|
+
* acceptable without a cast.
|
|
67
|
+
*/
|
|
68
|
+
export interface AudioBusMixerOptions {
|
|
69
|
+
readonly context: { createGain(): GainNode };
|
|
70
|
+
/** The node every parentless bus feeds. Usually a master gain or the context's destination. */
|
|
71
|
+
readonly destination: AudioNode;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface AudioBusMixer {
|
|
75
|
+
/**
|
|
76
|
+
* The bus named `name`, created on the first ask and connected to `parent`
|
|
77
|
+
* (itself created on demand) or to the destination.
|
|
78
|
+
*
|
|
79
|
+
* The returned node is the real `GainNode` — set `gain.value`, schedule
|
|
80
|
+
* automation on `gain`, connect sources to it. Nothing here stands between a
|
|
81
|
+
* caller and Web Audio's own API.
|
|
82
|
+
*/
|
|
83
|
+
bus(name: string, parent?: string): GainNode;
|
|
84
|
+
/** The bus named `name` if it EXISTS, else null. Never mints one. */
|
|
85
|
+
find(name: string): GainNode | null;
|
|
86
|
+
/** Set this bus's gain from decibels, creating it if absent. Clamp before calling — see the header. */
|
|
87
|
+
setDb(name: string, db: number, parent?: string): void;
|
|
88
|
+
/**
|
|
89
|
+
* Disconnect one bus and forget its name, so a later {@link bus} mints a
|
|
90
|
+
* fresh node. Buses that named it as their parent are NOT re-routed — they
|
|
91
|
+
* keep feeding the removed node, which now reaches nothing.
|
|
92
|
+
*/
|
|
93
|
+
remove(name: string): void;
|
|
94
|
+
/** Disconnect every bus and forget them all. The owner's ONE teardown. */
|
|
95
|
+
disconnect(): void;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** dB → linear amplitude: `10^(dB/20)`. 0 dB is 1, −6 dB is ~0.5, −80 dB is ~0.0001. Never clamps. */
|
|
99
|
+
export function dbToLinear(db: number): number {
|
|
100
|
+
return 10 ** (db / 20);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
interface BusRecord {
|
|
104
|
+
readonly node: GainNode;
|
|
105
|
+
readonly parent: string | undefined;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function safeDisconnect(node: GainNode): void {
|
|
109
|
+
try {
|
|
110
|
+
node.disconnect();
|
|
111
|
+
} catch {
|
|
112
|
+
// already disconnected
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** Create one named-bus mixer. See the header for what owns the instance and what it allocates. */
|
|
117
|
+
export function createAudioBusMixer(options: AudioBusMixerOptions): AudioBusMixer {
|
|
118
|
+
const { context, destination } = options;
|
|
119
|
+
const buses = new Map<string, BusRecord>();
|
|
120
|
+
|
|
121
|
+
function bus(name: string, parent?: string): GainNode {
|
|
122
|
+
const existing = buses.get(name);
|
|
123
|
+
if (existing !== undefined) {
|
|
124
|
+
if (parent !== undefined && parent !== existing.parent) {
|
|
125
|
+
throw new Error(
|
|
126
|
+
`audio bus ${JSON.stringify(name)} already routes into ` +
|
|
127
|
+
`${existing.parent === undefined ? 'the destination' : JSON.stringify(existing.parent)}` +
|
|
128
|
+
`; it cannot also route into ${JSON.stringify(parent)}. Routing is decided when a bus ` +
|
|
129
|
+
'is created (see packages/engine/src/audio/bus-mixer.ts).',
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
return existing.node;
|
|
133
|
+
}
|
|
134
|
+
// The parent is resolved (and minted, recursively) before this bus is
|
|
135
|
+
// seated, so a conflicting-parent throw upstream leaves nothing half-built.
|
|
136
|
+
const into = parent === undefined ? destination : bus(parent);
|
|
137
|
+
const node = context.createGain();
|
|
138
|
+
node.gain.value = 1;
|
|
139
|
+
node.connect(into);
|
|
140
|
+
buses.set(name, { node, parent });
|
|
141
|
+
return node;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return {
|
|
145
|
+
bus,
|
|
146
|
+
find: (name) => buses.get(name)?.node ?? null,
|
|
147
|
+
setDb: (name, db, parent) => {
|
|
148
|
+
bus(name, parent).gain.value = dbToLinear(db);
|
|
149
|
+
},
|
|
150
|
+
remove: (name) => {
|
|
151
|
+
const record = buses.get(name);
|
|
152
|
+
if (record === undefined) return;
|
|
153
|
+
buses.delete(name);
|
|
154
|
+
safeDisconnect(record.node);
|
|
155
|
+
},
|
|
156
|
+
disconnect: () => {
|
|
157
|
+
for (const record of buses.values()) safeDisconnect(record.node);
|
|
158
|
+
buses.clear();
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
}
|
package/src/core/frame-pacing.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Frame pacing — the accumulator/alpha arithmetic of the fixed-timestep loop,
|
|
3
|
-
* extracted PURE
|
|
3
|
+
* extracted PURE.
|
|
4
4
|
*
|
|
5
5
|
* `core/game-loop.ts` owns the browser side (rAF, `visibilitychange`,
|
|
6
6
|
* `performance.now`); this module owns the arithmetic, so the interesting
|
|
@@ -108,7 +108,7 @@ export function paceFrame(
|
|
|
108
108
|
const maxAccumulator = fixedDt * maxSubSteps;
|
|
109
109
|
|
|
110
110
|
// Clamp large frame gaps (a slow frame, a debugger pause) BEFORE scaling by
|
|
111
|
-
// timeScale
|
|
111
|
+
// timeScale.
|
|
112
112
|
const displayDt = Math.min(rawDt, maxAccumulator) * timeScale;
|
|
113
113
|
let next = accumulator + displayDt;
|
|
114
114
|
// Spiral-of-death guard: bound the accumulator regardless of timeScale or
|
package/src/core/game-loop.ts
CHANGED
|
@@ -9,9 +9,7 @@ const LOOP_STARVATION_MS = 1_000;
|
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Fixed-timestep game loop with accumulator pattern — SIM at a fixed rate,
|
|
12
|
-
* PRESENTATION at the display's rate
|
|
13
|
-
* flipped the former D1 "render is fixed-rate too" decision this comment used
|
|
14
|
-
* to state).
|
|
12
|
+
* PRESENTATION at the display's rate.
|
|
15
13
|
*
|
|
16
14
|
* Per real (rAF) frame:
|
|
17
15
|
*
|
|
@@ -42,7 +42,7 @@ export const GAMEPLAY_STREAM = 'gameplay';
|
|
|
42
42
|
export const DEFAULT_SEEDED_RANDOM_SEED = 0x9e3779b9;
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
|
-
*
|
|
45
|
+
* A game-scoped random surface.
|
|
46
46
|
* Callable (draws from the `'gameplay'` stream), plus:
|
|
47
47
|
* - `stream(name)` — an independent named generator, `[0, 1)` floats, same
|
|
48
48
|
* call signature as `Math.random`/the bare `SeededRandom` call itself.
|
package/src/core/sim-clock.ts
CHANGED
|
@@ -93,10 +93,9 @@
|
|
|
93
93
|
* controller cancels everything a `setup()` scheduled:
|
|
94
94
|
*
|
|
95
95
|
* ```ts
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
* return { dispose: () => ac.abort() }; // cancels timers AND listeners
|
|
96
|
+
* const ac = new AbortController();
|
|
97
|
+
* clock.after(3, () => spawnWave(), { signal: ac.signal });
|
|
98
|
+
* // on dispose: ac.abort() — cancels timers AND listeners
|
|
100
99
|
* }
|
|
101
100
|
* ```
|
|
102
101
|
*
|
|
@@ -170,7 +169,7 @@ export interface SimClock {
|
|
|
170
169
|
/**
|
|
171
170
|
* The runtime-facing half — NOT for game code. Split off the public
|
|
172
171
|
* {@link SimClock} the same way `runtime/game.ts` splits `GameInternal` off
|
|
173
|
-
* `Game`:
|
|
172
|
+
* `Game`: game code only ever sees the public `SimClock`, so it cannot
|
|
174
173
|
* reach `flush`/`dispose`.
|
|
175
174
|
*/
|
|
176
175
|
export interface SimClockInternal extends SimClock {
|
|
@@ -394,7 +393,7 @@ export function registerSimClock(owner: object, clock: SimClockInternal): void {
|
|
|
394
393
|
* Returns the INTERNAL view because this registry is engine-only — but a
|
|
395
394
|
* caller that RESOLVES a clock here is not its owner and must not call
|
|
396
395
|
* `dispose()` on it (module header, ownership). Game code never reaches it at
|
|
397
|
-
* all:
|
|
396
|
+
* all: it only ever sees the public {@link SimClock}, which has
|
|
398
397
|
* neither `flush` nor `dispose`, the same way `Game` hides `GameInternal`. */
|
|
399
398
|
export function getSimClock(owner: object): SimClockInternal | null {
|
|
400
399
|
return clockByOwner.get(owner) ?? null;
|
package/src/core/types.ts
CHANGED
|
@@ -72,9 +72,7 @@ export interface GameLoopConfig {
|
|
|
72
72
|
*/
|
|
73
73
|
update: (dt: number) => void;
|
|
74
74
|
/**
|
|
75
|
-
* Called EXACTLY ONCE per real (rAF) frame — the PRESENTATION half
|
|
76
|
-
* (WO-P13, `docs/WORK.md` §2 P13; this is the callback whose absence the
|
|
77
|
-
* former D1 decision recorded).
|
|
75
|
+
* Called EXACTLY ONCE per real (rAF) frame — the PRESENTATION half.
|
|
78
76
|
*
|
|
79
77
|
* - `alpha` — `accumulator / fixedDt` after this frame's substeps were
|
|
80
78
|
* consumed, in `[0, 1]`: how far presentation sits past the last
|
package/src/defaults.ts
CHANGED
|
@@ -1,20 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Single source of truth for default values the engine's factories read.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* — wire the group to the factory that reads it, or delete it if truly unused —
|
|
11
|
-
* and there is no surviving factory to wire these to: `transform` restated
|
|
12
|
-
* THREE's own Object3D constructor values, `entity.locked`/ `pivot` were
|
|
13
|
-
* descriptor-only fields, and `fog`/`environment.envMapIntensity`/ `shadow` were
|
|
14
|
-
* the `.vscn` `environment` block that `render-env.ts` explicitly did NOT carry
|
|
15
|
-
* forward. Keeping them would have been exactly the dead documentation T1.13
|
|
16
|
-
* created this guard to prevent.
|
|
17
|
-
*
|
|
4
|
+
* A group belongs here only while a FACTORY reads it. A default with no
|
|
5
|
+
* reader is dead documentation: it looks authoritative, nothing consults it,
|
|
6
|
+
* and it drifts from the value the code actually uses. Restating a library's
|
|
7
|
+
* own constructor values (THREE's `Object3D` transform, say) is the same
|
|
8
|
+
* mistake in a different shape — the library is already the source of truth.
|
|
9
|
+
* So when a factory goes, its group goes with it.
|
|
18
10
|
*/
|
|
19
11
|
export const DEFAULTS = {
|
|
20
12
|
material: {
|
|
@@ -8,10 +8,7 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Engine-owned and first-party, seeded by BOTH three-root mount paths — a game
|
|
10
10
|
* writes nothing to get these, and there is no capability to install:
|
|
11
|
-
* - `
|
|
12
|
-
* `setup(ctx)` world), at the same spot it seeds
|
|
13
|
-
* `systemAdapters.renderDebug`;
|
|
14
|
-
* - `world3d-react/r3f-adapter.tsx` (a TSX/R3F world — the shape EVERY
|
|
11
|
+
* - `world3d-react/r3f-root-factory.tsx` (a TSX/R3F world — the shape EVERY
|
|
15
12
|
* scaffolded project's three root has), right after fiber's first commit
|
|
16
13
|
* resolves the scene.
|
|
17
14
|
* Both is the whole point and not redundancy: they are two independent mounts
|
|
@@ -3,11 +3,10 @@
|
|
|
3
3
|
* the WebGL2 frame capture (`webgl-frame-capture.ts`), a live three.js scene,
|
|
4
4
|
* and the render adapter's per-frame render pass.
|
|
5
5
|
*
|
|
6
|
-
* Split OUT of `
|
|
6
|
+
* Split OUT of `world3d-react/r3f-root-factory.tsx` so the capture/attribution/restore
|
|
7
7
|
* flow is unit-testable in a headless Node test with a mock GL context and a
|
|
8
8
|
* plain scene — a real non-headless GPU mount (EffectComposer + WebGLRenderer)
|
|
9
|
-
* cannot run under vitest here
|
|
10
|
-
* `setup(ctx)` only through hotReload on a data scene. `mount()` owns the
|
|
9
|
+
* cannot run under vitest here. `mount()` owns the
|
|
11
10
|
* DECISION to construct this (only under a real WebGL2 context, never
|
|
12
11
|
* headless — see `frameCaptureContextFor`); this module owns the BEHAVIOR.
|
|
13
12
|
*
|
package/src/dev/render-vitals.ts
CHANGED
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
* OWNER: the caller of {@link createRenderVitals}, which allocates one state
|
|
44
44
|
* object and one `profiler.subscribe` registration. SHARER: none — the state
|
|
45
45
|
* is private to that call. TEARDOWN: the returned `dispose()`, the ONE path
|
|
46
|
-
* that ends the subscription (`
|
|
47
|
-
* `
|
|
46
|
+
* that ends the subscription (`world3d-react/r3f-root-factory.tsx` calls it
|
|
47
|
+
* from the mounted root's own `dispose()`).
|
|
48
48
|
*/
|
|
49
49
|
|
|
50
50
|
import type { PerformanceFrame, PerformanceProfiler } from './performance-profiler';
|
|
@@ -52,7 +52,7 @@ import type { PerformanceFrame, PerformanceProfiler } from './performance-profil
|
|
|
52
52
|
/**
|
|
53
53
|
* The profiler phase name the three adapter brackets its CPU render
|
|
54
54
|
* submission with — spelled HERE and nowhere else, so the producer
|
|
55
|
-
* (`
|
|
55
|
+
* (`world3d-react/r3f-root-factory.tsx`) and the consumer ({@link foldProfilerFrame})
|
|
56
56
|
* cannot drift apart. Dotted, so it reads as a decomposition of the enclosing
|
|
57
57
|
* `render` phase rather than a ninth peer of `SystemPhase`.
|
|
58
58
|
*/
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* WHY FIRST-PARTY, NOT spectorjs (recorded per the "use libraries directly, no
|
|
5
5
|
* wrappers" rule): the capture seam we need is the WebGL2 context this engine
|
|
6
6
|
* ALREADY owns end-to-end (`renderer.getContext()` in
|
|
7
|
-
* `
|
|
7
|
+
* `world3d-react/r3f-root-factory.tsx`). spectorjs is absent from node_modules, and its
|
|
8
8
|
* actual value is a bundled inspector UI we would discard — adopting it imports
|
|
9
9
|
* ~2MB of library to keep ~10% of it, and it wraps the context with its own
|
|
10
10
|
* global patching model rather than the instance-shadow-and-restore discipline
|
package/src/index.ts
CHANGED
|
@@ -10,21 +10,19 @@
|
|
|
10
10
|
* remain the primary way to reach engine internals — reach for a subpath
|
|
11
11
|
* first. This barrel exists only so the package's bare-name entry point is
|
|
12
12
|
* HONEST (resolves to something real and useful) instead of dangling; it
|
|
13
|
-
* covers just the handful of symbols a
|
|
14
|
-
*
|
|
13
|
+
* covers just the handful of symbols a consumer needs to mount a game
|
|
14
|
+
* from its manifest, plus the manifest file
|
|
15
15
|
* entry points. Keep it small when extending it — prefer a new subpath
|
|
16
16
|
* export over growing this file into a firehose.
|
|
17
17
|
*
|
|
18
18
|
* Groups (import order below is alphabetical-by-specifier, per the repo's
|
|
19
19
|
* biome `organizeImports` rule, not by group — see this list instead):
|
|
20
|
-
* - game setup contract: `GameContext`/`GameCleanup`/`GameSetupFn`, `fromSetup`
|
|
21
20
|
* - surface vocabulary: `AdapterSurface`
|
|
22
21
|
* - manifest-driven mount: `mountManifestRoots` + its option/result types
|
|
23
22
|
* - game manifest (vgai.project.json) entry point: `loadGameManifest`
|
|
24
23
|
*/
|
|
25
24
|
|
|
26
25
|
export type { AdapterSurface } from './adapter/adapter-surface';
|
|
27
|
-
export { fromSetup } from './adapter/setup-three-root-adapter';
|
|
28
26
|
export { AssetParseError } from './asset-parse-error';
|
|
29
27
|
export type {
|
|
30
28
|
AdapterRoot,
|
|
@@ -42,4 +40,3 @@ export type {
|
|
|
42
40
|
MountManifestOptions,
|
|
43
41
|
} from './runtime/mount-manifest';
|
|
44
42
|
export { mountManifestRoots } from './runtime/mount-manifest';
|
|
45
|
-
export type { GameCleanup, GameContext, GameSetupFn } from './runtime/types';
|