@vgai/engine 0.5.21 → 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/manifest-interpreter.d.ts +59 -0
- package/dist/adapter/manifest-interpreter.d.ts.map +1 -0
- package/dist/adapter/manifest-interpreter.js +50 -0
- package/dist/adapter/native-debug-module.d.ts +71 -3
- package/dist/adapter/native-debug-module.d.ts.map +1 -1
- package/dist/adapter/native-debug-module.js +146 -10
- 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 +3 -3
- package/dist/adapter/renderer-config.js +3 -3
- 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/canvas-react/index.d.ts +5 -12
- package/dist/canvas-react/index.d.ts.map +1 -1
- package/dist/canvas-react/index.js +5 -12
- package/dist/canvas-react/pixi-react-root-factory.d.ts +34 -21
- package/dist/canvas-react/pixi-react-root-factory.d.ts.map +1 -1
- package/dist/canvas-react/pixi-react-root-factory.js +274 -36
- package/dist/core/countdown-timer.d.ts +118 -0
- package/dist/core/countdown-timer.d.ts.map +1 -0
- package/dist/core/countdown-timer.js +137 -0
- package/dist/core/deferred-commands.d.ts +127 -0
- package/dist/core/deferred-commands.d.ts.map +1 -0
- package/dist/core/deferred-commands.js +132 -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 +19 -8
- package/dist/core/sim-clock.d.ts.map +1 -1
- package/dist/core/sim-clock.js +18 -7
- 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/instruments.d.ts +38 -11
- package/dist/dev/instruments.d.ts.map +1 -1
- package/dist/dev/instruments.js +81 -11
- 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 +33 -5
- package/dist/input/input-manager.d.ts.map +1 -1
- package/dist/input/input-manager.js +48 -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/directional-shadow-fit.d.ts +88 -0
- package/dist/render/directional-shadow-fit.d.ts.map +1 -0
- package/dist/render/directional-shadow-fit.js +133 -0
- package/dist/render/environment-capture.d.ts +68 -0
- package/dist/render/environment-capture.d.ts.map +1 -0
- package/dist/render/environment-capture.js +90 -0
- package/dist/render/ibl-override-material.d.ts +97 -0
- package/dist/render/ibl-override-material.d.ts.map +1 -0
- package/dist/render/ibl-override-material.js +114 -0
- 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 +51 -0
- package/dist/runtime/game-input-seams.d.ts.map +1 -0
- package/dist/runtime/game-input-seams.js +86 -0
- package/dist/runtime/game.d.ts +104 -40
- package/dist/runtime/game.d.ts.map +1 -1
- package/dist/runtime/game.js +119 -61
- 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 +26 -41
- 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 +22 -20
- 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/index.d.ts +15 -25
- package/dist/world3d-react/index.d.ts.map +1 -1
- package/dist/world3d-react/index.js +15 -25
- package/dist/world3d-react/r3f-root-factory.d.ts +28 -34
- package/dist/world3d-react/r3f-root-factory.d.ts.map +1 -1
- package/dist/world3d-react/r3f-root-factory.js +403 -57
- package/dist/world3d-react/rapier-physics-bridge.d.ts +30 -17
- package/dist/world3d-react/rapier-physics-bridge.d.ts.map +1 -1
- package/dist/world3d-react/rapier-physics-bridge.js +143 -58
- 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/manifest-interpreter.ts +64 -0
- package/src/adapter/native-debug-module.ts +248 -15
- package/src/adapter/rapier-physics-adapter.ts +76 -20
- package/src/adapter/renderer-config.ts +3 -3
- 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/canvas-react/index.ts +5 -21
- package/src/canvas-react/pixi-react-root-factory.tsx +301 -39
- package/src/core/countdown-timer.ts +188 -0
- package/src/core/deferred-commands.ts +174 -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 +19 -8
- package/src/core/types.ts +1 -3
- package/src/defaults.ts +6 -14
- package/src/dev/instruments.ts +108 -11
- 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 +49 -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/directional-shadow-fit.ts +156 -0
- package/src/render/environment-capture.ts +102 -0
- package/src/render/ibl-override-material.ts +170 -0
- 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 +108 -0
- package/src/runtime/game.ts +231 -85
- package/src/runtime/mount-game.ts +31 -57
- package/src/runtime/mount-manifest.ts +47 -36
- 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/index.ts +15 -31
- package/src/world3d-react/r3f-root-factory.tsx +451 -60
- package/src/world3d-react/rapier-physics-bridge.tsx +154 -58
- 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/canvas-react/engine-bridge.ts +0 -59
- package/src/canvas-react/pixi-react-adapter.tsx +0 -356
- package/src/canvas-react/world-context.ts +0 -253
- 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/world3d-react/engine-bridge.ts +0 -86
- package/src/world3d-react/r3f-adapter.tsx +0 -717
- package/src/world3d-react/world-context.ts +0 -358
|
@@ -1,358 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `createR3FRootContext` — the ENGINE runtime an R3F world owns, split out of
|
|
3
|
-
* `./r3f-adapter.tsx` so it stays react-free and headlessly unit-testable
|
|
4
|
-
* (`test/world3d-react-context-parity.test.tsx`).
|
|
5
|
-
*
|
|
6
|
-
* Context parity with the classic first-party adapter
|
|
7
|
-
* (`../adapter/setup-three-root-adapter.ts`) — closed here after a dogfood
|
|
8
|
-
* build had to shim around three silent gaps:
|
|
9
|
-
*
|
|
10
|
-
* 1. **`ctx.debug` / `ctx.random` / `ctx.game` / `ctx.roots` are wired**
|
|
11
|
-
* exactly the way the classic adapter wires them: the ONE game-scoped
|
|
12
|
-
* debug registry (`getDebugRegistry(host.game)`) provides
|
|
13
|
-
* `ctx.debug = registry.forRoot(id)`, so a component's
|
|
14
|
-
* effect can `ctx.debug.registerStateProvider(...)` and be visible
|
|
15
|
-
* to `vgai eval`/the editor's debug panels — previously a silent no-op.
|
|
16
|
-
* 2. **`ctx.input` is the game-owned `InputManager` when a Game hosts the
|
|
17
|
-
* root** (`host.game.input` —
|
|
18
|
-
* the same instance the classic adapter uses when hosted), and this
|
|
19
|
-
* module registers the SAME per-world debug-registry seams the classic
|
|
20
|
-
* adapter registers (`setVirtualInputTarget`/`setInputActionsSource`/
|
|
21
|
-
* `setInputTraceSource`), which is what makes `game.input.*` (the bot
|
|
22
|
-
* input doctrine) work instead of throwing `DEBUG_INPUT_UNAVAILABLE`.
|
|
23
|
-
* A bare/foreign mount receives `null`, visibly in the type, rather than
|
|
24
|
-
* a getter that throws later inside a frame callback.
|
|
25
|
-
* The project's input map is loaded through `Game.loadInputMap` (the
|
|
26
|
-
* game-owned, load-once path every root shares) with the SAME default
|
|
27
|
-
* path the classic adapter uses. A missing/unparseable map degrades
|
|
28
|
-
* LOUDLY (console.error naming the path and what breaks) without
|
|
29
|
-
* failing the mount — an R3F tree with no actions (e.g. a pure
|
|
30
|
-
* OrbitControls demo, `examples/r3f-first-party`) is legal.
|
|
31
|
-
* 3. **Absent subsystems are absent from the TYPE.** An R3F world builds no
|
|
32
|
-
* Rapier world, composer, audio, particles, or debug-draw, and
|
|
33
|
-
* {@link R3FGameContext} — the type `useGameContext()` hands back — simply
|
|
34
|
-
* does not have those fields. Reaching for one is a compile error at the
|
|
35
|
-
* call site, with the sanctioned alternative in that type's doc comment.
|
|
36
|
-
* */
|
|
37
|
-
|
|
38
|
-
import type * as THREE from 'three';
|
|
39
|
-
import type { ThreeHostContext } from '../adapter';
|
|
40
|
-
import type { SystemAdapters } from '../adapter/system-adapter';
|
|
41
|
-
import {
|
|
42
|
-
createSeededRandom,
|
|
43
|
-
DEFAULT_SEEDED_RANDOM_SEED,
|
|
44
|
-
getSeededRandom,
|
|
45
|
-
} from '../core/seeded-random';
|
|
46
|
-
import { createSimClock, getSimClock, type SimClockInternal } from '../core/sim-clock';
|
|
47
|
-
import { createSystemRunner } from '../core/system-runner';
|
|
48
|
-
import { createSceneIndex, type SceneIndex } from '../ecs/scene-index';
|
|
49
|
-
import {
|
|
50
|
-
createDebugRegistry,
|
|
51
|
-
type DebugRegistry,
|
|
52
|
-
getDebugRegistry,
|
|
53
|
-
} from '../runtime/debug-registry';
|
|
54
|
-
import { disposeDebrisSubtree } from '../runtime/game';
|
|
55
|
-
import type { ComponentContextBase, GameContext } from '../runtime/types';
|
|
56
|
-
|
|
57
|
-
/** The classic adapter's default input-map path — the conventional location
|
|
58
|
-
* every scaffolded project ships (`public/inputmaps/default.inputmap.json`). */
|
|
59
|
-
export const DEFAULT_INPUT_MAP_PATH = '/inputmaps/default.inputmap.json';
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* The engine context an R3F world genuinely provides — what
|
|
63
|
-
* `useGameContext()` hands back.
|
|
64
|
-
*
|
|
65
|
-
* An EXPLICIT `Pick`, never an `Omit`: a field added to `GameContext` later
|
|
66
|
-
* must be deliberately admitted here, so this surface can never silently widen
|
|
67
|
-
* into something an R3F mount does not build.
|
|
68
|
-
*
|
|
69
|
-
* **What an R3F world does NOT have, and what to reach for instead.** These
|
|
70
|
-
* are not oversights — the mount builds none of them, so they are absent from
|
|
71
|
-
* this type and naming one is a compile error rather than a crash mid-render:
|
|
72
|
-
*
|
|
73
|
-
* - **Physics** (`rapierWorld`, `rapier`, `physics`, `collisions`) — an R3F
|
|
74
|
-
* world does not build the first-party Rapier runtime. Use a physics
|
|
75
|
-
* solution inside the fiber tree (e.g. `@react-three/rapier`), or an
|
|
76
|
-
* imperative three root whose `setup(ctx)` receives the first-party Rapier
|
|
77
|
-
* runtime.
|
|
78
|
-
* - **`composer`** — R3F renders through react-three-fiber against the host
|
|
79
|
-
* renderer; there is no postprocessing `EffectComposer` here. Use
|
|
80
|
-
* fiber-native postprocessing inside the tree.
|
|
81
|
-
* - **`audio`** — no first-party audio context is built. Own a Web Audio graph
|
|
82
|
-
* inside the tree (or use drei's audio helpers) and register it as this
|
|
83
|
-
* world's `SystemAdapters.audio` via
|
|
84
|
-
* `ctx.registerSystemAdapter('audio', …)`, so host mute/pause can still
|
|
85
|
-
* silence it — `examples/third-person/src/lib/audio/sfx.ts` is the worked
|
|
86
|
-
* reference.
|
|
87
|
-
* - **`particles`** — no three.quarks particle runtime. Drive particles from
|
|
88
|
-
* the fiber tree.
|
|
89
|
-
* - **`debugDraw`** — no debug-draw helper. Add helper objects to the fiber
|
|
90
|
-
* tree directly.
|
|
91
|
-
*
|
|
92
|
-
* For the full classic runtime, use an imperative three root instead: a module
|
|
93
|
-
* exporting `setup(ctx): Promise<GameCleanup>`, which `SetupThreeRootAdapter`
|
|
94
|
-
* mounts with the complete {@link GameContext}.
|
|
95
|
-
*/
|
|
96
|
-
export type R3FGameContext = ComponentContextBase &
|
|
97
|
-
Pick<GameContext, 'scene' | 'sceneIndex' | 'assets' | 'clock'> & {
|
|
98
|
-
/** Fiber may install either a perspective or orthographic camera. */
|
|
99
|
-
camera: THREE.Camera;
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
export interface R3FRootContextOptions {
|
|
103
|
-
/** World id — provenance for every debug-registry registration (matches the
|
|
104
|
-
* manifest root id by the same convention the classic adapter follows). */
|
|
105
|
-
readonly id: string;
|
|
106
|
-
/**
|
|
107
|
-
* Input map to load through `Game.loadInputMap` (game-owned, load-once —
|
|
108
|
-
* several roots asking for the SAME path share one load; competing paths
|
|
109
|
-
* throw there). Defaults to {@link DEFAULT_INPUT_MAP_PATH}, the classic
|
|
110
|
-
* adapter's own default. Pass `null` to skip loading (a world with no
|
|
111
|
-
* actions). Ignored when no `host.game` is present.
|
|
112
|
-
*/
|
|
113
|
-
readonly inputMapPath?: string | null | undefined;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/** What {@link createR3FRootContext} returns — the engine runtime one R3F
|
|
117
|
-
* world owns, plus the wiring hooks `createR3FAdapter`'s `mount()` drives. */
|
|
118
|
-
export interface R3FRootRuntime {
|
|
119
|
-
/** The context this world's components read through `useGameContext()` —
|
|
120
|
-
* see {@link R3FGameContext} for exactly what an R3F world provides. */
|
|
121
|
-
readonly ctx: R3FGameContext;
|
|
122
|
-
/** The world-local phase runner `mount().update(dt)` ticks. */
|
|
123
|
-
readonly systems: ReturnType<typeof createSystemRunner>;
|
|
124
|
-
/** The mounted world's `SystemAdapters` bag (`mounted.systems`) —
|
|
125
|
-
* `ctx.registerSystemAdapter` writes into it; `debug` is pre-seeded here,
|
|
126
|
-
* and the R3F mount adds renderer-backed engine capabilities after commit. */
|
|
127
|
-
readonly systemAdapters: SystemAdapters;
|
|
128
|
-
/** The registry every registration of this world's lands in — the game's
|
|
129
|
-
* own when a `Game` hosts it, a private mount-local one otherwise. Exposed
|
|
130
|
-
* (rather than re-derived by the caller) because `createR3FAdapter` seeds
|
|
131
|
-
* the render-vitals door onto THIS registry after fiber's first commit
|
|
132
|
-
* resolves the scene, and two `getDebugRegistry` calls that are "obviously"
|
|
133
|
-
* the same object is exactly the second source of truth the classic
|
|
134
|
-
* adapter's single `debugRegistry` local avoids. */
|
|
135
|
-
readonly debugRegistry: DebugRegistry;
|
|
136
|
-
/** Resolves once the input map load settles (immediately when skipped).
|
|
137
|
-
* Never rejects — a failed load reports loudly and resolves. */
|
|
138
|
-
readonly inputMapReady: Promise<void>;
|
|
139
|
-
/** Backfill fiber's real scene/camera onto `ctx` after the first commit
|
|
140
|
-
* resolves them — before any tick can run. `camera` is fiber's union
|
|
141
|
-
* (perspective OR orthographic) — the ctx surface exposes whatever the
|
|
142
|
-
* tree declared, exactly as the mounted world does. */
|
|
143
|
-
setSceneCamera(scene: THREE.Scene, camera: THREE.Camera): void;
|
|
144
|
-
/** Detach every component and strip this world's debug registrations
|
|
145
|
-
* (scoped, like the classic adapter's teardown — sibling roots and
|
|
146
|
-
* react-door registrations are untouched when a Game hosts this world). */
|
|
147
|
-
dispose(): void;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* The GAME-SCOPED input wiring one three root owns — and the half that has
|
|
152
|
-
* nothing to do with the vgai runtime context.
|
|
153
|
-
*
|
|
154
|
-
* Two things happen here, both of them HOST work performed from outside the
|
|
155
|
-
* world's own tree:
|
|
156
|
-
*
|
|
157
|
-
* 1. the project's input map is loaded through `Game.loadInputMap` (game-owned,
|
|
158
|
-
* load-once), so the actions the project declared exist;
|
|
159
|
-
* 2. this root's seams are registered on the game-scoped debug registry
|
|
160
|
-
* (`setVirtualInputTarget`/`setInputActionsSource`/`setInputTraceSource`),
|
|
161
|
-
* which is what makes `game.input.hold/tap/...` (the bot/`vgai eval` input
|
|
162
|
-
* doctrine) and the built-in `input.actions`/`input.trace` providers
|
|
163
|
-
* resolve to this world instead of throwing `DEBUG_INPUT_UNAVAILABLE`.
|
|
164
|
-
*
|
|
165
|
-
* It is called on BOTH three-root paths, and that is the point: a world that
|
|
166
|
-
* mounts as a default-exported component receives no vgai runtime context
|
|
167
|
-
* (`engineRuntime: false` — see `r3f-root-factory.tsx`), but "no context in the
|
|
168
|
-
* tree" was never meant to say "the host does not wire this game's input". It
|
|
169
|
-
* was read that way, and the cost was measured on a fresh scaffold: the
|
|
170
|
-
* declared map never loaded and every `game.input.*` door threw, so the QA
|
|
171
|
-
* bot, autoplay routes and `vgai eval` could not drive the ONE world shape
|
|
172
|
-
* `vgai create` produces. Same split, same reasoning, as `WorldProvider`
|
|
173
|
-
* riding `host.game` rather than the runtime (see `r3f-adapter.tsx`).
|
|
174
|
-
*
|
|
175
|
-
* `optionalInputMap` is the CONVENTIONAL-PATH probe used when the project
|
|
176
|
-
* never named a map: an absent file is the ordinary state of a brand-new
|
|
177
|
-
* project, so it resolves quietly instead of printing an error on every boot.
|
|
178
|
-
* A map that exists and fails to parse is as loud as ever.
|
|
179
|
-
*
|
|
180
|
-
* LIFETIME, honestly: `registry.strip(id)` runs on the mount's dispose (both
|
|
181
|
-
* paths), but it walks providers/commands only — the three seams set here
|
|
182
|
-
* survive it, keyed by this world's id, until a remount of the same id
|
|
183
|
-
* overwrites them. That residue is inert rather than hidden: every closure
|
|
184
|
-
* below reads GAME-scoped state (`game.input`, `game.loop.fixedDt`, the game's
|
|
185
|
-
* seed), so a stale entry actuates exactly what a live one would. See the
|
|
186
|
-
* dispose comment in `r3f-adapter.tsx` for the full accounting.
|
|
187
|
-
*/
|
|
188
|
-
export function wireGameInputSeams(
|
|
189
|
-
host: ThreeHostContext,
|
|
190
|
-
registry: DebugRegistry,
|
|
191
|
-
options: {
|
|
192
|
-
readonly id: string;
|
|
193
|
-
readonly inputMapPath?: string | null | undefined;
|
|
194
|
-
readonly optionalInputMap?: boolean | undefined;
|
|
195
|
-
},
|
|
196
|
-
): Promise<void> {
|
|
197
|
-
const { id, inputMapPath = DEFAULT_INPUT_MAP_PATH, optionalInputMap = false } = options;
|
|
198
|
-
if (!host.game) return Promise.resolve();
|
|
199
|
-
const game = host.game;
|
|
200
|
-
const input = game.input;
|
|
201
|
-
registry.setInputActionsSource(id, () =>
|
|
202
|
-
input.actionNames().map((name) => ({ name, valueType: input.getActionValueType(name) })),
|
|
203
|
-
);
|
|
204
|
-
registry.setInputTraceSource(id, () => {
|
|
205
|
-
const raw = input.getInputTrace();
|
|
206
|
-
return {
|
|
207
|
-
version: raw.version,
|
|
208
|
-
seed: getSeededRandom(game)?.seed ?? null,
|
|
209
|
-
fixedDt: game.loop.fixedDt,
|
|
210
|
-
ticks: raw.ticks,
|
|
211
|
-
};
|
|
212
|
-
});
|
|
213
|
-
registry.setVirtualInputTarget(id, {
|
|
214
|
-
setVirtualAction: (action, value) => input.setVirtualAction(action, value),
|
|
215
|
-
tapVirtualAction: (action) => input.tapVirtualAction(action),
|
|
216
|
-
clearVirtualActions: () => input.clearVirtualActions(),
|
|
217
|
-
scheduleActionAtTick: (tick, action, value) => input.scheduleActionAtTick(tick, action, value),
|
|
218
|
-
startInputRecording: () => input.startInputRecording(),
|
|
219
|
-
stopInputRecording: () => input.stopInputRecording(),
|
|
220
|
-
isInputRecording: () => input.isInputRecording(),
|
|
221
|
-
injectAxis: (sourceId, value) => input.injectAxis(sourceId, value),
|
|
222
|
-
injectVector2: (sourceId, value) => input.injectVector2(sourceId, value),
|
|
223
|
-
injectPointerDelta: (sourceId, delta) => input.injectPointerDelta(sourceId, delta),
|
|
224
|
-
injectPointerPosition: (sourceId, value) => input.injectPointerPosition(sourceId, value),
|
|
225
|
-
});
|
|
226
|
-
if (host.headless || inputMapPath === null) return Promise.resolve();
|
|
227
|
-
// Load-once through the game-owned path (competing paths across roots throw
|
|
228
|
-
// THERE, loudly). A FAILED load (missing/bad file) must not fail the mount:
|
|
229
|
-
// a three world with no declared actions is legal. It degrades loudly
|
|
230
|
-
// instead — naming exactly what breaks.
|
|
231
|
-
// The non-optional call passes ONE argument, exactly as it always has — a
|
|
232
|
-
// trailing `undefined` is a different call to any observer of it.
|
|
233
|
-
const load = optionalInputMap
|
|
234
|
-
? game.loadInputMap(inputMapPath, { optional: true })
|
|
235
|
-
: game.loadInputMap(inputMapPath);
|
|
236
|
-
return load.catch((err: unknown) => {
|
|
237
|
-
// biome-ignore lint/suspicious/noConsole: deliberate loud degrade — the documented alternative to failing the mount (see comment above)
|
|
238
|
-
console.error(
|
|
239
|
-
`three world "${id}": failed to load input map "${inputMapPath}" — declared input ` +
|
|
240
|
-
'actions and `game.input.*` (bot/virtual input) will not work until a valid map ' +
|
|
241
|
-
'loads. Ship one at the conventional path or pass `inputMapPath` to ' +
|
|
242
|
-
`createR3FAdapter (null to opt out). Cause: ${err instanceof Error ? err.message : String(err)}`,
|
|
243
|
-
);
|
|
244
|
-
});
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
/**
|
|
248
|
-
* Build the engine runtime for one R3F world from a `ThreeHostContext` — the same
|
|
249
|
-
* wiring, at the same layer, as the classic `SetupThreeRootAdapter.mount()`
|
|
250
|
-
* performs for the subsystems an R3F world shares with it (debug, input,
|
|
251
|
-
* random). The ones it does not build are not on
|
|
252
|
-
* {@link R3FGameContext} at all.
|
|
253
|
-
*/
|
|
254
|
-
export function createR3FRootContext(
|
|
255
|
-
host: ThreeHostContext,
|
|
256
|
-
options: R3FRootContextOptions,
|
|
257
|
-
): R3FRootRuntime {
|
|
258
|
-
const { id, inputMapPath = DEFAULT_INPUT_MAP_PATH } = options;
|
|
259
|
-
|
|
260
|
-
// Same observer threading as the classic adapter — profiler sees this
|
|
261
|
-
// world's phases under the shared game profiler when hosted.
|
|
262
|
-
const systems = createSystemRunner(host.game?.profiler.systemObserver, 'three');
|
|
263
|
-
|
|
264
|
-
// The mounted world's adapter surface (`mounted.systems`) — declared before
|
|
265
|
-
// ctx so `ctx.registerSystemAdapter` can close over it (classic parity: a
|
|
266
|
-
// game-owned capability like networking registers here from component code).
|
|
267
|
-
const systemAdapters: SystemAdapters = {};
|
|
268
|
-
|
|
269
|
-
// The world's live scene index — built in `setSceneCamera` (below), because
|
|
270
|
-
// fiber resolves the scene after this function returns. Same lifetime as
|
|
271
|
-
// `ctx.scene`, which is backfilled at the same moment.
|
|
272
|
-
let sceneIndex: SceneIndex | null = null;
|
|
273
|
-
|
|
274
|
-
const ctxRaw: Record<string, unknown> = {
|
|
275
|
-
systems,
|
|
276
|
-
assets: host.assets,
|
|
277
|
-
input: host.game?.input ?? null,
|
|
278
|
-
registerSystemAdapter: (kind: keyof SystemAdapters, adapter: SystemAdapters[typeof kind]) => {
|
|
279
|
-
// biome-ignore lint/suspicious/noExplicitAny: same per-key record write the classic adapter performs; correct by construction
|
|
280
|
-
(systemAdapters as any)[kind] = adapter;
|
|
281
|
-
host.game?.notifySystemAdaptersChanged();
|
|
282
|
-
},
|
|
283
|
-
};
|
|
284
|
-
const ctx = ctxRaw as unknown as R3FGameContext;
|
|
285
|
-
if (host.game) {
|
|
286
|
-
ctx.game = host.game;
|
|
287
|
-
ctx.roots = host.game.roots;
|
|
288
|
-
ctx.playtest = host.game.playtest ?? null;
|
|
289
|
-
}
|
|
290
|
-
// --- ctx.debug (gap 1) — the ONE registry per Game root, shared across
|
|
291
|
-
// every world mounted onto it; a bare mount with no Game shell gets a
|
|
292
|
-
// private, mount-local registry instead (same absence precedent as the
|
|
293
|
-
// classic adapter). ---
|
|
294
|
-
const debugRegistry: DebugRegistry =
|
|
295
|
-
(host.game ? getDebugRegistry(host.game) : null) ??
|
|
296
|
-
createDebugRegistry({ getTick: () => 0, getSimT: () => 0 });
|
|
297
|
-
systemAdapters.debug = debugRegistry.adapter;
|
|
298
|
-
ctx.debug = debugRegistry.forRoot(id);
|
|
299
|
-
ctx.random =
|
|
300
|
-
(host.game ? getSeededRandom(host.game) : null) ??
|
|
301
|
-
createSeededRandom(DEFAULT_SEEDED_RANDOM_SEED);
|
|
302
|
-
|
|
303
|
-
// --- ctx.clock (P3) — every world has a sim clock, R3F included. Same
|
|
304
|
-
// game-scoped reach-in as `ctx.random` above; a bare mount with no Game
|
|
305
|
-
// shell gets a private, mount-local clock that nothing flushes (there is no
|
|
306
|
-
// fixed loop to bind timers to). The mount-local fallback uses the SAME
|
|
307
|
-
// `disposeDebrisSubtree` the hosted path uses — it drops
|
|
308
|
-
// the subtree and disposes geometry/materials, with no Rapier owners
|
|
309
|
-
// because this ctx carries no `physics`/`rapierWorld` (the
|
|
310
|
-
// honest "this world owns no bodies").
|
|
311
|
-
const gameClock: SimClockInternal | null = host.game ? getSimClock(host.game) : null;
|
|
312
|
-
const clock: SimClockInternal =
|
|
313
|
-
gameClock ?? createSimClock({ dispose: (obj) => disposeDebrisSubtree(obj, []) });
|
|
314
|
-
ctx.clock = clock;
|
|
315
|
-
|
|
316
|
-
// --- ctx.input + the debug-registry input seams (gap 3) — see
|
|
317
|
-
// `wireGameInputSeams` below; `ctx.input` is that same game-owned manager. ---
|
|
318
|
-
const inputMapReady = wireGameInputSeams(host, debugRegistry, { id, inputMapPath });
|
|
319
|
-
|
|
320
|
-
return {
|
|
321
|
-
ctx,
|
|
322
|
-
systems,
|
|
323
|
-
systemAdapters,
|
|
324
|
-
debugRegistry,
|
|
325
|
-
inputMapReady,
|
|
326
|
-
setSceneCamera(scene, camera): void {
|
|
327
|
-
const sameScene = ctxRaw['scene'] === scene && sceneIndex !== null;
|
|
328
|
-
ctxRaw['scene'] = scene;
|
|
329
|
-
ctxRaw['camera'] = camera;
|
|
330
|
-
// The live scene index (P2 `observe`) is a REAL value here, not a
|
|
331
|
-
// throwing getter — every three world has one. It can only be built once
|
|
332
|
-
// fiber has resolved the scene, which is the same moment `ctx.scene`
|
|
333
|
-
// itself becomes readable, so index and scene share one lifetime. A
|
|
334
|
-
// second commit (fiber handing back a different scene) replaces it.
|
|
335
|
-
//
|
|
336
|
-
// Keyed on the SCENE, so a camera-only backfill (a world swapping the
|
|
337
|
-
// default camera after mount) leaves the index — and every `observe`
|
|
338
|
-
// subscription hanging off it — alone.
|
|
339
|
-
if (sameScene) return;
|
|
340
|
-
sceneIndex?.dispose();
|
|
341
|
-
sceneIndex = createSceneIndex(scene);
|
|
342
|
-
ctxRaw['sceneIndex'] = sceneIndex;
|
|
343
|
-
},
|
|
344
|
-
dispose(): void {
|
|
345
|
-
// Same ownership rule as the classic adapter's teardown: dispose ONLY a
|
|
346
|
-
// clock this mount created. The game-scoped one belongs to
|
|
347
|
-
// `GameInternal.dispose()` — killing it here would freeze sim time and
|
|
348
|
-
// cancel every SIBLING world's timers.
|
|
349
|
-
if (!gameClock) clock.dispose();
|
|
350
|
-
sceneIndex?.dispose();
|
|
351
|
-
sceneIndex = null;
|
|
352
|
-
// Scoped strip when a Game hosts this world (sibling roots stay live);
|
|
353
|
-
// a bare standalone mount owns its private registry and clears it all.
|
|
354
|
-
if (host.game) debugRegistry.strip(id);
|
|
355
|
-
else debugRegistry.strip();
|
|
356
|
-
},
|
|
357
|
-
};
|
|
358
|
-
}
|