@vgai/engine 0.5.5 → 0.5.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapter/adapter-surface.d.ts +30 -0
- package/dist/adapter/adapter-surface.d.ts.map +1 -0
- package/dist/adapter/adapter-surface.js +18 -0
- package/dist/adapter/authoring.d.ts +597 -0
- package/dist/adapter/authoring.d.ts.map +1 -0
- package/dist/adapter/authoring.js +22 -0
- package/dist/adapter/colyseus-networking-adapter.d.ts +77 -0
- package/dist/adapter/colyseus-networking-adapter.d.ts.map +1 -0
- package/dist/adapter/colyseus-networking-adapter.js +76 -0
- package/dist/adapter/first-party-systems.d.ts +23 -0
- package/dist/adapter/first-party-systems.d.ts.map +1 -0
- package/dist/adapter/first-party-systems.js +196 -0
- package/dist/adapter/host-context.d.ts +194 -0
- package/dist/adapter/host-context.d.ts.map +1 -0
- package/dist/adapter/host-context.js +80 -0
- package/dist/adapter/index.d.ts +33 -0
- package/dist/adapter/index.d.ts.map +1 -0
- package/dist/adapter/index.js +25 -0
- package/dist/adapter/ingest/game-contract.d.ts +53 -0
- package/dist/adapter/ingest/game-contract.d.ts.map +1 -0
- package/dist/adapter/ingest/game-contract.js +30 -0
- package/dist/adapter/ingest/scene-capture.d.ts +121 -0
- package/dist/adapter/ingest/scene-capture.d.ts.map +1 -0
- package/dist/adapter/ingest/scene-capture.js +270 -0
- package/dist/adapter/ingest/structural-ids.d.ts +64 -0
- package/dist/adapter/ingest/structural-ids.d.ts.map +1 -0
- package/dist/adapter/ingest/structural-ids.js +110 -0
- package/dist/adapter/ingest/upstream-pin.d.ts +44 -0
- package/dist/adapter/ingest/upstream-pin.d.ts.map +1 -0
- package/dist/adapter/ingest/upstream-pin.js +47 -0
- package/dist/adapter/loop-gate-report.d.ts +34 -0
- package/dist/adapter/loop-gate-report.d.ts.map +1 -0
- package/dist/adapter/loop-gate-report.js +37 -0
- package/dist/adapter/rapier-physics-adapter.d.ts +69 -0
- package/dist/adapter/rapier-physics-adapter.d.ts.map +1 -0
- package/dist/adapter/rapier-physics-adapter.js +135 -0
- package/dist/adapter/root-adapter.d.ts +195 -0
- package/dist/adapter/root-adapter.d.ts.map +1 -0
- package/dist/adapter/root-adapter.js +25 -0
- package/dist/adapter/setup-three-root-adapter.d.ts +87 -0
- package/dist/adapter/setup-three-root-adapter.d.ts.map +1 -0
- package/dist/adapter/setup-three-root-adapter.js +791 -0
- package/dist/adapter/system-adapter.d.ts +453 -0
- package/dist/adapter/system-adapter.d.ts.map +1 -0
- package/dist/adapter/system-adapter.js +13 -0
- package/dist/adapter/transform.d.ts +18 -0
- package/dist/adapter/transform.d.ts.map +1 -0
- package/dist/adapter/transform.js +1 -0
- package/dist/ai/navigation.d.ts +78 -0
- package/dist/ai/navigation.d.ts.map +1 -0
- package/dist/ai/navigation.js +152 -0
- package/dist/animation/anim-graph-types.d.ts +25 -0
- package/dist/animation/anim-graph-types.d.ts.map +1 -0
- package/dist/animation/anim-graph-types.js +1 -0
- package/dist/animation/animation-clock.d.ts +213 -0
- package/dist/animation/animation-clock.d.ts.map +1 -0
- package/dist/animation/animation-clock.js +301 -0
- package/dist/animation/blend-node.d.ts +22 -0
- package/dist/animation/blend-node.d.ts.map +1 -0
- package/dist/animation/blend-node.js +97 -0
- package/dist/animation/camera-ownership.d.ts +249 -0
- package/dist/animation/camera-ownership.d.ts.map +1 -0
- package/dist/animation/camera-ownership.js +169 -0
- package/dist/animation/cinematic-cues.d.ts +200 -0
- package/dist/animation/cinematic-cues.d.ts.map +1 -0
- package/dist/animation/cinematic-cues.js +213 -0
- package/dist/animation/clip-map.d.ts +12 -0
- package/dist/animation/clip-map.d.ts.map +1 -0
- package/dist/animation/clip-map.js +31 -0
- package/dist/animation/cubic-spline-interpolant.d.ts +54 -0
- package/dist/animation/cubic-spline-interpolant.d.ts.map +1 -0
- package/dist/animation/cubic-spline-interpolant.js +111 -0
- package/dist/animation/theatre-clock-binding.d.ts +89 -0
- package/dist/animation/theatre-clock-binding.d.ts.map +1 -0
- package/dist/animation/theatre-clock-binding.js +29 -0
- package/dist/animation/theatre-director.d.ts +277 -0
- package/dist/animation/theatre-director.d.ts.map +1 -0
- package/dist/animation/theatre-director.js +248 -0
- package/dist/animation/theatre-object-binding.d.ts +305 -0
- package/dist/animation/theatre-object-binding.d.ts.map +1 -0
- package/dist/animation/theatre-object-binding.js +351 -0
- package/dist/animation/xstate-animation-binding.d.ts +119 -0
- package/dist/animation/xstate-animation-binding.d.ts.map +1 -0
- package/dist/animation/xstate-animation-binding.js +349 -0
- package/dist/animation/xstate-animation-meta.d.ts +266 -0
- package/dist/animation/xstate-animation-meta.d.ts.map +1 -0
- package/dist/animation/xstate-animation-meta.js +252 -0
- package/dist/asset-formats/camera.d.ts +15 -0
- package/dist/asset-formats/camera.d.ts.map +1 -0
- package/dist/asset-formats/camera.js +15 -0
- package/dist/asset-formats/collider.d.ts +21 -0
- package/dist/asset-formats/collider.d.ts.map +1 -0
- package/dist/asset-formats/collider.js +53 -0
- package/dist/asset-formats/index.d.ts +46 -0
- package/dist/asset-formats/index.d.ts.map +1 -0
- package/dist/asset-formats/index.js +36 -0
- package/dist/asset-formats/instances.d.ts +17 -0
- package/dist/asset-formats/instances.d.ts.map +1 -0
- package/dist/asset-formats/instances.js +31 -0
- package/dist/asset-formats/light.d.ts +21 -0
- package/dist/asset-formats/light.d.ts.map +1 -0
- package/dist/asset-formats/light.js +35 -0
- package/dist/asset-formats/material.d.ts +129 -0
- package/dist/asset-formats/material.d.ts.map +1 -0
- package/dist/asset-formats/material.js +88 -0
- package/dist/asset-formats/mesh.d.ts +22 -0
- package/dist/asset-formats/mesh.d.ts.map +1 -0
- package/dist/asset-formats/mesh.js +64 -0
- package/dist/asset-formats/parse.d.ts +20 -0
- package/dist/asset-formats/parse.d.ts.map +1 -0
- package/dist/asset-formats/parse.js +34 -0
- package/dist/asset-formats/particles.d.ts +1390 -0
- package/dist/asset-formats/particles.d.ts.map +1 -0
- package/dist/asset-formats/particles.js +319 -0
- package/dist/asset-formats/render-env.d.ts +387 -0
- package/dist/asset-formats/render-env.d.ts.map +1 -0
- package/dist/asset-formats/render-env.js +300 -0
- package/dist/asset-formats/tuples.d.ts +12 -0
- package/dist/asset-formats/tuples.d.ts.map +1 -0
- package/dist/asset-formats/tuples.js +14 -0
- package/dist/asset-loaders.d.ts +97 -0
- package/dist/asset-loaders.d.ts.map +1 -0
- package/dist/asset-loaders.js +209 -0
- package/dist/asset-parse-error.d.ts +24 -0
- package/dist/asset-parse-error.d.ts.map +1 -0
- package/dist/asset-parse-error.js +29 -0
- package/dist/asset-registry.d.ts +38 -0
- package/dist/asset-registry.d.ts.map +1 -0
- package/dist/asset-registry.js +66 -0
- package/dist/assets.d.ts +26 -0
- package/dist/assets.d.ts.map +1 -0
- package/dist/assets.js +55 -0
- package/dist/audio/wav-encode.d.ts +38 -0
- package/dist/audio/wav-encode.d.ts.map +1 -0
- package/dist/audio/wav-encode.js +97 -0
- package/dist/canvas-react/engine-bridge.d.ts +45 -0
- package/dist/canvas-react/engine-bridge.d.ts.map +1 -0
- package/dist/canvas-react/engine-bridge.js +45 -0
- package/dist/canvas-react/index.d.ts +42 -0
- package/dist/canvas-react/index.d.ts.map +1 -0
- package/dist/canvas-react/index.js +41 -0
- package/dist/canvas-react/pixi-primitive.d.ts +85 -0
- package/dist/canvas-react/pixi-primitive.d.ts.map +1 -0
- package/dist/canvas-react/pixi-primitive.js +181 -0
- package/dist/canvas-react/pixi-react-adapter.d.ts +71 -0
- package/dist/canvas-react/pixi-react-adapter.d.ts.map +1 -0
- package/dist/canvas-react/pixi-react-adapter.js +229 -0
- package/dist/canvas-react/pixi-react-root-factory.d.ts +56 -0
- package/dist/canvas-react/pixi-react-root-factory.d.ts.map +1 -0
- package/dist/canvas-react/pixi-react-root-factory.js +73 -0
- package/dist/canvas-react/world-context.d.ts +88 -0
- package/dist/canvas-react/world-context.d.ts.map +1 -0
- package/dist/canvas-react/world-context.js +212 -0
- package/dist/config.d.ts +9 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +8 -0
- package/dist/core/frame-pacing.d.ts +90 -0
- package/dist/core/frame-pacing.d.ts.map +1 -0
- package/dist/core/frame-pacing.js +89 -0
- package/dist/core/game-loop.d.ts +62 -0
- package/dist/core/game-loop.d.ts.map +1 -0
- package/dist/core/game-loop.js +189 -0
- package/dist/core/seeded-random.d.ts +69 -0
- package/dist/core/seeded-random.d.ts.map +1 -0
- package/dist/core/seeded-random.js +121 -0
- package/dist/core/sim-clock.d.ts +199 -0
- package/dist/core/sim-clock.d.ts.map +1 -0
- package/dist/core/sim-clock.js +291 -0
- package/dist/core/system-runner.d.ts +96 -0
- package/dist/core/system-runner.d.ts.map +1 -0
- package/dist/core/system-runner.js +253 -0
- package/dist/core/types.d.ts +111 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +25 -0
- package/dist/data/data-asset.d.ts +101 -0
- package/dist/data/data-asset.d.ts.map +1 -0
- package/dist/data/data-asset.js +122 -0
- package/dist/data/data-check-core.d.ts +109 -0
- package/dist/data/data-check-core.d.ts.map +1 -0
- package/dist/data/data-check-core.js +177 -0
- package/dist/data/data-ref.d.ts +79 -0
- package/dist/data/data-ref.d.ts.map +1 -0
- package/dist/data/data-ref.js +130 -0
- package/dist/data/vite-plugin-data.d.ts +79 -0
- package/dist/data/vite-plugin-data.d.ts.map +1 -0
- package/dist/data/vite-plugin-data.js +217 -0
- package/dist/defaults.d.ts +233 -0
- package/dist/defaults.d.ts.map +1 -0
- package/dist/defaults.js +137 -0
- package/dist/dev/chrome-trace.d.ts +45 -0
- package/dist/dev/chrome-trace.d.ts.map +1 -0
- package/dist/dev/chrome-trace.js +114 -0
- package/dist/dev/console-bridge.d.ts +22 -0
- package/dist/dev/console-bridge.d.ts.map +1 -0
- package/dist/dev/console-bridge.js +71 -0
- package/dist/dev/debug-draw.d.ts +24 -0
- package/dist/dev/debug-draw.d.ts.map +1 -0
- package/dist/dev/debug-draw.js +73 -0
- package/dist/dev/instruments.d.ts +133 -0
- package/dist/dev/instruments.d.ts.map +1 -0
- package/dist/dev/instruments.js +231 -0
- package/dist/dev/logger.d.ts +30 -0
- package/dist/dev/logger.d.ts.map +1 -0
- package/dist/dev/logger.js +90 -0
- package/dist/dev/performance-profiler.d.ts +111 -0
- package/dist/dev/performance-profiler.d.ts.map +1 -0
- package/dist/dev/performance-profiler.js +215 -0
- package/dist/dev/render-debug-adapter.d.ts +57 -0
- package/dist/dev/render-debug-adapter.d.ts.map +1 -0
- package/dist/dev/render-debug-adapter.js +141 -0
- package/dist/dev/render-memory.d.ts +53 -0
- package/dist/dev/render-memory.d.ts.map +1 -0
- package/dist/dev/render-memory.js +190 -0
- package/dist/dev/webgl-frame-capture.d.ts +134 -0
- package/dist/dev/webgl-frame-capture.d.ts.map +1 -0
- package/dist/dev/webgl-frame-capture.js +270 -0
- package/dist/dev/webgl-gpu-timer.d.ts +8 -0
- package/dist/dev/webgl-gpu-timer.d.ts.map +1 -0
- package/dist/dev/webgl-gpu-timer.js +52 -0
- package/dist/ecs/scene-index.d.ts +179 -0
- package/dist/ecs/scene-index.d.ts.map +1 -0
- package/dist/ecs/scene-index.js +331 -0
- package/dist/ecs/scene-query.d.ts +6 -0
- package/dist/ecs/scene-query.d.ts.map +1 -0
- package/dist/ecs/scene-query.js +40 -0
- package/dist/ecs/user-data.d.ts +193 -0
- package/dist/ecs/user-data.d.ts.map +1 -0
- package/dist/ecs/user-data.js +145 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/input/input-manager.d.ts +944 -0
- package/dist/input/input-manager.d.ts.map +1 -0
- package/dist/input/input-manager.js +2209 -0
- package/dist/input/input-types.d.ts +174 -0
- package/dist/input/input-types.d.ts.map +1 -0
- package/dist/input/input-types.js +1 -0
- package/dist/input/prompt-labels.d.ts +21 -0
- package/dist/input/prompt-labels.d.ts.map +1 -0
- package/dist/input/prompt-labels.js +121 -0
- package/dist/input/rebind-controller.d.ts +59 -0
- package/dist/input/rebind-controller.d.ts.map +1 -0
- package/dist/input/rebind-controller.js +85 -0
- package/dist/input/schema.d.ts +16 -0
- package/dist/input/schema.d.ts.map +1 -0
- package/dist/input/schema.js +228 -0
- package/dist/loader.d.ts +76 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +114 -0
- package/dist/manifest/editor-port.d.ts +53 -0
- package/dist/manifest/editor-port.d.ts.map +1 -0
- package/dist/manifest/editor-port.js +67 -0
- package/dist/manifest/filename.d.ts +14 -0
- package/dist/manifest/filename.d.ts.map +1 -0
- package/dist/manifest/filename.js +43 -0
- package/dist/manifest/index.d.ts +6 -0
- package/dist/manifest/index.d.ts.map +1 -0
- package/dist/manifest/index.js +9 -0
- package/dist/manifest/load-file.d.ts +7 -0
- package/dist/manifest/load-file.d.ts.map +1 -0
- package/dist/manifest/load-file.js +23 -0
- package/dist/manifest/load.d.ts +161 -0
- package/dist/manifest/load.d.ts.map +1 -0
- package/dist/manifest/load.js +269 -0
- package/dist/manifest/locate.d.ts +24 -0
- package/dist/manifest/locate.d.ts.map +1 -0
- package/dist/manifest/locate.js +48 -0
- package/dist/manifest/schema.d.ts +293 -0
- package/dist/manifest/schema.d.ts.map +1 -0
- package/dist/manifest/schema.js +633 -0
- package/dist/physics/collider-dimensions.d.ts +63 -0
- package/dist/physics/collider-dimensions.d.ts.map +1 -0
- package/dist/physics/collider-dimensions.js +98 -0
- package/dist/physics/collision-system.d.ts +41 -0
- package/dist/physics/collision-system.d.ts.map +1 -0
- package/dist/physics/collision-system.js +64 -0
- package/dist/physics/physics-registry.d.ts +45 -0
- package/dist/physics/physics-registry.d.ts.map +1 -0
- package/dist/physics/physics-registry.js +65 -0
- package/dist/physics/transform-writer.d.ts +16 -0
- package/dist/physics/transform-writer.d.ts.map +1 -0
- package/dist/physics/transform-writer.js +38 -0
- package/dist/pixi/authoring.d.ts +93 -0
- package/dist/pixi/authoring.d.ts.map +1 -0
- package/dist/pixi/authoring.js +207 -0
- package/dist/pixi/index.d.ts +16 -0
- package/dist/pixi/index.d.ts.map +1 -0
- package/dist/pixi/index.js +15 -0
- package/dist/pixi/ingest-iframe.d.ts +82 -0
- package/dist/pixi/ingest-iframe.d.ts.map +1 -0
- package/dist/pixi/ingest-iframe.js +166 -0
- package/dist/pixi/ingest.d.ts +97 -0
- package/dist/pixi/ingest.d.ts.map +1 -0
- package/dist/pixi/ingest.js +40 -0
- package/dist/pixi/physics-registry.d.ts +24 -0
- package/dist/pixi/physics-registry.d.ts.map +1 -0
- package/dist/pixi/physics-registry.js +38 -0
- package/dist/pixi/scene-capture.d.ts +43 -0
- package/dist/pixi/scene-capture.d.ts.map +1 -0
- package/dist/pixi/scene-capture.js +92 -0
- package/dist/pixi/system-adapters.d.ts +16 -0
- package/dist/pixi/system-adapters.d.ts.map +1 -0
- package/dist/pixi/system-adapters.js +37 -0
- package/dist/react/unmanaged-root-detector.d.ts +18 -0
- package/dist/react/unmanaged-root-detector.d.ts.map +1 -0
- package/dist/react/unmanaged-root-detector.js +70 -0
- package/dist/react/use-data.d.ts +60 -0
- package/dist/react/use-data.d.ts.map +1 -0
- package/dist/react/use-data.js +101 -0
- package/dist/react/use-selection.d.ts +54 -0
- package/dist/react/use-selection.d.ts.map +1 -0
- package/dist/react/use-selection.js +71 -0
- package/dist/react/world-state.d.ts +154 -0
- package/dist/react/world-state.d.ts.map +1 -0
- package/dist/react/world-state.js +220 -0
- package/dist/render/auto-batcher.d.ts +34 -0
- package/dist/render/auto-batcher.d.ts.map +1 -0
- package/dist/render/auto-batcher.js +140 -0
- package/dist/render/instance-mesh.d.ts +5 -0
- package/dist/render/instance-mesh.d.ts.map +1 -0
- package/dist/render/instance-mesh.js +19 -0
- package/dist/render/light-camera-factory.d.ts +24 -0
- package/dist/render/light-camera-factory.d.ts.map +1 -0
- package/dist/render/light-camera-factory.js +71 -0
- package/dist/render/lod.d.ts +13 -0
- package/dist/render/lod.d.ts.map +1 -0
- package/dist/render/lod.js +16 -0
- package/dist/render/material-factory.d.ts +15 -0
- package/dist/render/material-factory.d.ts.map +1 -0
- package/dist/render/material-factory.js +186 -0
- package/dist/render/mesh-shadow.d.ts +11 -0
- package/dist/render/mesh-shadow.d.ts.map +1 -0
- package/dist/render/mesh-shadow.js +19 -0
- package/dist/render/particles-factory.d.ts +99 -0
- package/dist/render/particles-factory.d.ts.map +1 -0
- package/dist/render/particles-factory.js +361 -0
- package/dist/render/render-batch-system.d.ts +33 -0
- package/dist/render/render-batch-system.d.ts.map +1 -0
- package/dist/render/render-batch-system.js +223 -0
- package/dist/render/render-features.d.ts +47 -0
- package/dist/render/render-features.d.ts.map +1 -0
- package/dist/render/render-features.js +105 -0
- package/dist/render/render-settings.d.ts +35 -0
- package/dist/render/render-settings.d.ts.map +1 -0
- package/dist/render/render-settings.js +51 -0
- package/dist/render/spark-renderer-lifecycle.d.ts +18 -0
- package/dist/render/spark-renderer-lifecycle.d.ts.map +1 -0
- package/dist/render/spark-renderer-lifecycle.js +57 -0
- package/dist/render/viewport-shading.d.ts +17 -0
- package/dist/render/viewport-shading.d.ts.map +1 -0
- package/dist/render/viewport-shading.js +87 -0
- package/dist/runtime/create-runtime.d.ts +259 -0
- package/dist/runtime/create-runtime.d.ts.map +1 -0
- package/dist/runtime/create-runtime.js +666 -0
- package/dist/runtime/debug-bridge.d.ts +288 -0
- package/dist/runtime/debug-bridge.d.ts.map +1 -0
- package/dist/runtime/debug-bridge.js +277 -0
- package/dist/runtime/debug-registry.d.ts +287 -0
- package/dist/runtime/debug-registry.d.ts.map +1 -0
- package/dist/runtime/debug-registry.js +528 -0
- package/dist/runtime/dev-layers.d.ts +34 -0
- package/dist/runtime/dev-layers.d.ts.map +1 -0
- package/dist/runtime/dev-layers.js +40 -0
- package/dist/runtime/frame-selector-cache.d.ts +41 -0
- package/dist/runtime/frame-selector-cache.d.ts.map +1 -0
- package/dist/runtime/frame-selector-cache.js +65 -0
- package/dist/runtime/game.d.ts +576 -0
- package/dist/runtime/game.d.ts.map +1 -0
- package/dist/runtime/game.js +1003 -0
- package/dist/runtime/gameplay-rng-trap.d.ts +47 -0
- package/dist/runtime/gameplay-rng-trap.d.ts.map +1 -0
- package/dist/runtime/gameplay-rng-trap.js +95 -0
- package/dist/runtime/input-router.d.ts +78 -0
- package/dist/runtime/input-router.d.ts.map +1 -0
- package/dist/runtime/input-router.js +171 -0
- package/dist/runtime/mount-game.d.ts +126 -0
- package/dist/runtime/mount-game.d.ts.map +1 -0
- package/dist/runtime/mount-game.js +159 -0
- package/dist/runtime/mount-manifest.d.ts +174 -0
- package/dist/runtime/mount-manifest.d.ts.map +1 -0
- package/dist/runtime/mount-manifest.js +304 -0
- package/dist/runtime/presentation.d.ts +85 -0
- package/dist/runtime/presentation.d.ts.map +1 -0
- package/dist/runtime/presentation.js +92 -0
- package/dist/runtime/render-audio-control.d.ts +126 -0
- package/dist/runtime/render-audio-control.d.ts.map +1 -0
- package/dist/runtime/render-audio-control.js +116 -0
- package/dist/runtime/render-control.d.ts +347 -0
- package/dist/runtime/render-control.d.ts.map +1 -0
- package/dist/runtime/render-control.js +317 -0
- package/dist/runtime/render-seed.d.ts +56 -0
- package/dist/runtime/render-seed.d.ts.map +1 -0
- package/dist/runtime/render-seed.js +73 -0
- package/dist/runtime/state-bridge.d.ts +60 -0
- package/dist/runtime/state-bridge.d.ts.map +1 -0
- package/dist/runtime/state-bridge.js +62 -0
- package/dist/runtime/types.d.ts +285 -0
- package/dist/runtime/types.d.ts.map +1 -0
- package/dist/runtime/types.js +1 -0
- package/dist/runtime/unexported-game-trap.d.ts +36 -0
- package/dist/runtime/unexported-game-trap.d.ts.map +1 -0
- package/dist/runtime/unexported-game-trap.js +80 -0
- package/dist/setup/setup-audio.d.ts +20 -0
- package/dist/setup/setup-audio.d.ts.map +1 -0
- package/dist/setup/setup-audio.js +41 -0
- package/dist/setup/setup-particles.d.ts +17 -0
- package/dist/setup/setup-particles.d.ts.map +1 -0
- package/dist/setup/setup-particles.js +16 -0
- package/dist/setup/setup-physics.d.ts +25 -0
- package/dist/setup/setup-physics.d.ts.map +1 -0
- package/dist/setup/setup-physics.js +51 -0
- package/dist/setup/setup-renderer.d.ts +82 -0
- package/dist/setup/setup-renderer.d.ts.map +1 -0
- package/dist/setup/setup-renderer.js +381 -0
- package/dist/world3d-react/engine-bridge.d.ts +47 -0
- package/dist/world3d-react/engine-bridge.d.ts.map +1 -0
- package/dist/world3d-react/engine-bridge.js +48 -0
- package/dist/world3d-react/index.d.ts +47 -0
- package/dist/world3d-react/index.d.ts.map +1 -0
- package/dist/world3d-react/index.js +46 -0
- package/dist/world3d-react/r3f-adapter.d.ts +51 -0
- package/dist/world3d-react/r3f-adapter.d.ts.map +1 -0
- package/dist/world3d-react/r3f-adapter.js +368 -0
- package/dist/world3d-react/r3f-root-factory.d.ts +62 -0
- package/dist/world3d-react/r3f-root-factory.d.ts.map +1 -0
- package/dist/world3d-react/r3f-root-factory.js +79 -0
- package/dist/world3d-react/rapier-physics-bridge.d.ts +76 -0
- package/dist/world3d-react/rapier-physics-bridge.d.ts.map +1 -0
- package/dist/world3d-react/rapier-physics-bridge.js +120 -0
- package/dist/world3d-react/renderer-config.d.ts +58 -0
- package/dist/world3d-react/renderer-config.d.ts.map +1 -0
- package/dist/world3d-react/renderer-config.js +96 -0
- package/dist/world3d-react/world-context.d.ts +123 -0
- package/dist/world3d-react/world-context.d.ts.map +1 -0
- package/dist/world3d-react/world-context.js +204 -0
- package/dist-config/config.js +303 -0
- package/dist-config/config.js.map +7 -0
- package/package.json +14 -3
- package/src/adapter/rapier-physics-adapter.ts +77 -34
- package/src/config.ts +8 -0
- package/src/core/frame-pacing.ts +26 -0
- package/src/core/game-loop.ts +4 -3
- package/src/dev/instruments.ts +302 -0
- package/src/setup/setup-renderer.ts +2 -0
- package/src/world3d-react/index.ts +9 -0
- package/src/world3d-react/rapier-physics-bridge.tsx +137 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `<RapierPhysicsBridge>` — the one line that makes an R3F world's
|
|
3
|
+
* `@react-three/rapier` physics VISIBLE to the engine's editor/dev seams.
|
|
4
|
+
*
|
|
5
|
+
* WHY IT EXISTS. `SystemAdapters.physics` is what the editor's transform
|
|
6
|
+
* coordination (`freeze → apply → unfreeze`) and the dev menu's universal
|
|
7
|
+
* "Colliders drawn" instrument (`@engine/dev/instruments`) read. The
|
|
8
|
+
* first-party imperative three root registers one from
|
|
9
|
+
* `../adapter/setup-three-root-adapter.ts`; an R3F world builds no first-party
|
|
10
|
+
* Rapier runtime at all (see `R3FGameContext`'s doc comment) — it does physics
|
|
11
|
+
* with `@react-three/rapier` INSIDE the fiber tree, where nothing engine-side
|
|
12
|
+
* can see it. Result, before this: the colliders instrument read `null` (an
|
|
13
|
+
* em-dash) and its toggle threw "no physics adapter" in every shipped example
|
|
14
|
+
* and every scaffolded game.
|
|
15
|
+
*
|
|
16
|
+
* NOT A WRAPPER. This registers an adapter and gets out of the way: the world
|
|
17
|
+
* still writes `<Physics>` itself, with the library's own props, and every
|
|
18
|
+
* `<RigidBody>`/collider call stays `@react-three/rapier`'s own API. The one
|
|
19
|
+
* thing it cannot do for you is flip the library's debug rendering, because
|
|
20
|
+
* `@react-three/rapier@2` exposes that ONLY as the `debug` boolean PROP on
|
|
21
|
+
* `<Physics>` (its `<Debug>` component is internal and unexported). A prop is
|
|
22
|
+
* the parent's to own, so the world holds the state and this bridge hands the
|
|
23
|
+
* setter to the instrument — which is why `onDebugChange` is required:
|
|
24
|
+
*
|
|
25
|
+
* ```tsx
|
|
26
|
+
* const [physicsDebug, setPhysicsDebug] = useState(false);
|
|
27
|
+
* // …
|
|
28
|
+
* <Physics debug={physicsDebug}>
|
|
29
|
+
* <RapierPhysicsBridge onDebugChange={setPhysicsDebug} />
|
|
30
|
+
* …
|
|
31
|
+
* </Physics>
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* Nothing draws colliders here: the wireframes are the library's own
|
|
35
|
+
* `world.debugRender()` output, rendered by its own component.
|
|
36
|
+
*
|
|
37
|
+
* ANTI-SHIM. `debugDraw()` and `contactPoints()` are OMITTED, not stubbed —
|
|
38
|
+
* the library owns its debug line segments inside the tree and hands out no
|
|
39
|
+
* handle to them, so claiming the capability would be a fabrication. Absence
|
|
40
|
+
* is how a `SystemAdapters` member says "not supported".
|
|
41
|
+
*
|
|
42
|
+
* ── RESOURCE OWNERSHIP, STATED ONCE ─────────────────────────────────────────
|
|
43
|
+
* OWNER: this component owns exactly ONE `SystemAdapters.physics` registration,
|
|
44
|
+
* on the R3F root it is mounted in. It allocates nothing else — no timers, no
|
|
45
|
+
* subscriptions, no per-frame work (see the phase note below), and no Rapier
|
|
46
|
+
* objects: the bodies it edits belong to `<Physics>`.
|
|
47
|
+
* SHARERS: every reader of `game.systemAdapters.physics` — the dev menu's
|
|
48
|
+
* colliders instrument, the editor's transform coordination. They read; they
|
|
49
|
+
* never dispose.
|
|
50
|
+
* TEARDOWN: the effect's cleanup, and nothing else — it clears the SAME key it
|
|
51
|
+
* set (`registerSystemAdapter('physics', undefined)`, which
|
|
52
|
+
* `Game.computeSystemAdapters` skips), so a play stop/start, a hot restart, or
|
|
53
|
+
* a world that unmounts `<Physics>` leaves no stale adapter behind. Two
|
|
54
|
+
* bridges in one root would fight over that one key; mount exactly one.
|
|
55
|
+
*
|
|
56
|
+
* PHASE ORDERING: none to respect — this component registers pull-only
|
|
57
|
+
* callbacks and runs no per-frame work. Every method it exposes is invoked
|
|
58
|
+
* BETWEEN frames, by an editor gesture or a dev-menu command, never from a
|
|
59
|
+
* phase.
|
|
60
|
+
*/
|
|
61
|
+
import { useRapier } from '@react-three/rapier';
|
|
62
|
+
import { useEffect } from 'react';
|
|
63
|
+
import { createRapierBodyEditing, } from '../adapter/rapier-physics-adapter';
|
|
64
|
+
import { useGameContext } from './engine-bridge';
|
|
65
|
+
/**
|
|
66
|
+
* Register this R3F world's `@react-three/rapier` physics as the game's
|
|
67
|
+
* `SystemAdapters.physics`. Mount it once, INSIDE `<Physics>` (it reads
|
|
68
|
+
* `useRapier()`). Renders nothing.
|
|
69
|
+
*/
|
|
70
|
+
export function RapierPhysicsBridge({ onDebugChange }) {
|
|
71
|
+
const ctx = useGameContext();
|
|
72
|
+
const { rigidBodyStates } = useRapier();
|
|
73
|
+
const registerSystemAdapter = ctx.registerSystemAdapter;
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
if (!registerSystemAdapter)
|
|
76
|
+
return;
|
|
77
|
+
/**
|
|
78
|
+
* node id → the Rapier body driving it, in two hops the library and the
|
|
79
|
+
* engine each already own:
|
|
80
|
+
*
|
|
81
|
+
* 1. id → `Object3D`, through the live scene index — `userData.entityId`
|
|
82
|
+
* is this stack's identity convention (the editor's R3F authoring
|
|
83
|
+
* adapter stamps it; `../adapter/setup-three-root-adapter.ts` resolves
|
|
84
|
+
* the same way for the imperative root).
|
|
85
|
+
* 2. `Object3D` → body, through `rigidBodyStates` — the library's OWN
|
|
86
|
+
* body↔object map, carried on the `RapierContext` `useRapier()`
|
|
87
|
+
* returns. Walking ANCESTORS matters: `<RigidBody>` owns a subtree, so
|
|
88
|
+
* the selected mesh is usually a descendant of the object the state
|
|
89
|
+
* names.
|
|
90
|
+
*
|
|
91
|
+
* Both maps are live, so this is computed per call rather than cached —
|
|
92
|
+
* calls arrive at gesture rate (a gizmo drag start/end, a dev command),
|
|
93
|
+
* never per frame. `ctx.sceneIndex` is read AT CALL TIME, never captured:
|
|
94
|
+
* the R3F root backfills it once fiber resolves the scene, which can land
|
|
95
|
+
* after this component's first effect (`world-context.ts`'s
|
|
96
|
+
* `setSceneCamera`), so a destructured copy would be permanently absent.
|
|
97
|
+
*/
|
|
98
|
+
const bodyFor = (nodeId) => {
|
|
99
|
+
const object = ctx.sceneIndex?.byEntityId(nodeId);
|
|
100
|
+
if (!object)
|
|
101
|
+
return undefined;
|
|
102
|
+
const byObject = new Map();
|
|
103
|
+
for (const state of rigidBodyStates.values())
|
|
104
|
+
byObject.set(state.object, state.rigidBody);
|
|
105
|
+
for (let node = object; node; node = node.parent) {
|
|
106
|
+
const body = byObject.get(node);
|
|
107
|
+
if (body)
|
|
108
|
+
return body;
|
|
109
|
+
}
|
|
110
|
+
return undefined;
|
|
111
|
+
};
|
|
112
|
+
const adapter = {
|
|
113
|
+
...createRapierBodyEditing(bodyFor),
|
|
114
|
+
setDebugDrawEnabled: (enabled) => onDebugChange(enabled),
|
|
115
|
+
};
|
|
116
|
+
registerSystemAdapter('physics', adapter);
|
|
117
|
+
return () => registerSystemAdapter('physics', undefined);
|
|
118
|
+
}, [ctx, registerSystemAdapter, rigidBodyStates, onDebugChange]);
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* world3d-react/renderer-config.ts — the seam a WORLD uses to state how its own frame is rendered.
|
|
3
|
+
*
|
|
4
|
+
* The host owns the `WebGLRenderer` (`ThreeHostContext.renderer`) and configures it with this
|
|
5
|
+
* engine's defaults: ACES tone mapping, sRGB output, PCF-soft shadows. Those defaults are right for
|
|
6
|
+
* a world authored against them and WRONG for a world that was authored against a different
|
|
7
|
+
* engine's pipeline — an imported Godot 3 GLES2 game does gamma-space lighting with no tonemapper
|
|
8
|
+
* at all, so ACES quietly desaturates and darkens every colour its author picked.
|
|
9
|
+
*
|
|
10
|
+
* So a world may DECLARE the pipeline it was authored for, and `createR3FAdapter` applies it to the
|
|
11
|
+
* host's renderer for the life of the mount, restoring what it found on dispose. Three properties
|
|
12
|
+
* of that shape are load-bearing:
|
|
13
|
+
*
|
|
14
|
+
* - **It is per-renderer, never engine-wide.** Every field here is a `WebGLRenderer` instance
|
|
15
|
+
* property, and a play root gets its own renderer (`create-runtime.ts`). Nothing here reaches a
|
|
16
|
+
* module-level three global, so one world's declaration cannot change how the editor's own
|
|
17
|
+
* viewport, another root, or a thumbnail bake renders.
|
|
18
|
+
* - **Absent means "leave the host's value alone".** Every field is optional and an omitted one
|
|
19
|
+
* is never written, so declaring a tone mapping does not silently reset the clear colour.
|
|
20
|
+
* - **It is restored on dispose.** The renderer outlives the mount, so a world that did not put
|
|
21
|
+
* back what it found would leak its pipeline into whatever mounts next.
|
|
22
|
+
*
|
|
23
|
+
* This is deliberately NOT a general render-settings system. It carries what a world can honestly
|
|
24
|
+
* state about its own colour pipeline and nothing else; a property the host fixes at CONSTRUCTION
|
|
25
|
+
* (the WebGL context's `antialias` attribute, and therefore the MSAA sample count) cannot be
|
|
26
|
+
* declared here, because there would be no honest moment to apply it.
|
|
27
|
+
*/
|
|
28
|
+
import type * as THREE from 'three';
|
|
29
|
+
/** The tone-mapping operators three exposes, named as data rather than as three's numeric enum. */
|
|
30
|
+
export type WorldToneMapping = 'none' | 'linear' | 'reinhard' | 'cineon' | 'aces' | 'agx' | 'neutral';
|
|
31
|
+
/**
|
|
32
|
+
* The output transfer function the frame is written with.
|
|
33
|
+
*
|
|
34
|
+
* - `srgb` — three's own default and this engine's: linear lighting, sRGB encode on output.
|
|
35
|
+
* - `srgb-linear` — NO output transform. This is what a gamma-space renderer needs: the shading
|
|
36
|
+
* result is already in display space and encoding it a second time washes the frame out.
|
|
37
|
+
*/
|
|
38
|
+
export type WorldOutputColorSpace = 'srgb' | 'srgb-linear';
|
|
39
|
+
/** What a world may declare about the renderer that draws it. Every field is optional; see header. */
|
|
40
|
+
export interface WorldRendererConfig {
|
|
41
|
+
readonly toneMapping?: WorldToneMapping | undefined;
|
|
42
|
+
readonly toneMappingExposure?: number | undefined;
|
|
43
|
+
readonly outputColorSpace?: WorldOutputColorSpace | undefined;
|
|
44
|
+
/**
|
|
45
|
+
* The colour the frame is cleared to, as a CSS hex string. The renderer's existing clear ALPHA
|
|
46
|
+
* is preserved: a stacked canvas is transparent on purpose (`create-runtime.ts` gives every
|
|
47
|
+
* non-bottom root `alpha: true`), and forcing it opaque here would hide every layer below.
|
|
48
|
+
*/
|
|
49
|
+
readonly clearColor?: string | undefined;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Apply `config` to `renderer`, returning the restore function that puts back what was there.
|
|
53
|
+
*
|
|
54
|
+
* `three` is passed in rather than imported for values so the enum constants come from the HOST's
|
|
55
|
+
* three instance — the same identity rule `r3f-adapter.tsx` follows for the scene and camera.
|
|
56
|
+
*/
|
|
57
|
+
export declare function applyWorldRendererConfig(three: typeof THREE, renderer: THREE.WebGLRenderer, config: WorldRendererConfig): () => void;
|
|
58
|
+
//# sourceMappingURL=renderer-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renderer-config.d.ts","sourceRoot":"","sources":["../../src/world3d-react/renderer-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AAEpC,mGAAmG;AACnG,MAAM,MAAM,gBAAgB,GACxB,MAAM,GACN,QAAQ,GACR,UAAU,GACV,QAAQ,GACR,MAAM,GACN,KAAK,GACL,SAAS,CAAC;AAEd;;;;;;GAMG;AACH,MAAM,MAAM,qBAAqB,GAAG,MAAM,GAAG,aAAa,CAAC;AAE3D,sGAAsG;AACtG,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,WAAW,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC;IACpD,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClD,QAAQ,CAAC,gBAAgB,CAAC,EAAE,qBAAqB,GAAG,SAAS,CAAC;IAC9D;;;;OAIG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1C;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,OAAO,KAAK,EACnB,QAAQ,EAAE,KAAK,CAAC,aAAa,EAC7B,MAAM,EAAE,mBAAmB,GAC1B,MAAM,IAAI,CAgEZ"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* world3d-react/renderer-config.ts — the seam a WORLD uses to state how its own frame is rendered.
|
|
3
|
+
*
|
|
4
|
+
* The host owns the `WebGLRenderer` (`ThreeHostContext.renderer`) and configures it with this
|
|
5
|
+
* engine's defaults: ACES tone mapping, sRGB output, PCF-soft shadows. Those defaults are right for
|
|
6
|
+
* a world authored against them and WRONG for a world that was authored against a different
|
|
7
|
+
* engine's pipeline — an imported Godot 3 GLES2 game does gamma-space lighting with no tonemapper
|
|
8
|
+
* at all, so ACES quietly desaturates and darkens every colour its author picked.
|
|
9
|
+
*
|
|
10
|
+
* So a world may DECLARE the pipeline it was authored for, and `createR3FAdapter` applies it to the
|
|
11
|
+
* host's renderer for the life of the mount, restoring what it found on dispose. Three properties
|
|
12
|
+
* of that shape are load-bearing:
|
|
13
|
+
*
|
|
14
|
+
* - **It is per-renderer, never engine-wide.** Every field here is a `WebGLRenderer` instance
|
|
15
|
+
* property, and a play root gets its own renderer (`create-runtime.ts`). Nothing here reaches a
|
|
16
|
+
* module-level three global, so one world's declaration cannot change how the editor's own
|
|
17
|
+
* viewport, another root, or a thumbnail bake renders.
|
|
18
|
+
* - **Absent means "leave the host's value alone".** Every field is optional and an omitted one
|
|
19
|
+
* is never written, so declaring a tone mapping does not silently reset the clear colour.
|
|
20
|
+
* - **It is restored on dispose.** The renderer outlives the mount, so a world that did not put
|
|
21
|
+
* back what it found would leak its pipeline into whatever mounts next.
|
|
22
|
+
*
|
|
23
|
+
* This is deliberately NOT a general render-settings system. It carries what a world can honestly
|
|
24
|
+
* state about its own colour pipeline and nothing else; a property the host fixes at CONSTRUCTION
|
|
25
|
+
* (the WebGL context's `antialias` attribute, and therefore the MSAA sample count) cannot be
|
|
26
|
+
* declared here, because there would be no honest moment to apply it.
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* Apply `config` to `renderer`, returning the restore function that puts back what was there.
|
|
30
|
+
*
|
|
31
|
+
* `three` is passed in rather than imported for values so the enum constants come from the HOST's
|
|
32
|
+
* three instance — the same identity rule `r3f-adapter.tsx` follows for the scene and camera.
|
|
33
|
+
*/
|
|
34
|
+
export function applyWorldRendererConfig(three, renderer, config) {
|
|
35
|
+
// A host that mounts a world WITHOUT rasterizing it hands the adapter a duck-typed renderer —
|
|
36
|
+
// the editor's design session (`createDesignTimeRenderer`: four members, deliberately never
|
|
37
|
+
// widened) and jsdom test harnesses both do. Such a surface has no colour pipeline to configure:
|
|
38
|
+
// the frame the user sees is drawn by a DIFFERENT renderer (the editor's own), so applying the
|
|
39
|
+
// world's config there is meaningless — and calling `getClearColor` on it is a TypeError that
|
|
40
|
+
// unmounts the whole world at edit time (measured: every Godot port's edit viewport blanked with
|
|
41
|
+
// '"world" failed to mount — renderer.getClearColor is not a function'). Detect the real
|
|
42
|
+
// `WebGLRenderer` surface by the one method this function must call, and no-op otherwise.
|
|
43
|
+
if (typeof renderer.getClearColor !== 'function') {
|
|
44
|
+
return () => { };
|
|
45
|
+
}
|
|
46
|
+
const toneMappings = {
|
|
47
|
+
none: three.NoToneMapping,
|
|
48
|
+
linear: three.LinearToneMapping,
|
|
49
|
+
reinhard: three.ReinhardToneMapping,
|
|
50
|
+
cineon: three.CineonToneMapping,
|
|
51
|
+
aces: three.ACESFilmicToneMapping,
|
|
52
|
+
agx: three.AgXToneMapping,
|
|
53
|
+
neutral: three.NeutralToneMapping,
|
|
54
|
+
};
|
|
55
|
+
const colorSpaces = {
|
|
56
|
+
srgb: three.SRGBColorSpace,
|
|
57
|
+
'srgb-linear': three.LinearSRGBColorSpace,
|
|
58
|
+
};
|
|
59
|
+
const restores = [];
|
|
60
|
+
if (config.toneMapping !== undefined) {
|
|
61
|
+
const previous = renderer.toneMapping;
|
|
62
|
+
renderer.toneMapping = toneMappings[config.toneMapping];
|
|
63
|
+
restores.push(() => {
|
|
64
|
+
renderer.toneMapping = previous;
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
if (config.toneMappingExposure !== undefined) {
|
|
68
|
+
const previous = renderer.toneMappingExposure;
|
|
69
|
+
renderer.toneMappingExposure = config.toneMappingExposure;
|
|
70
|
+
restores.push(() => {
|
|
71
|
+
renderer.toneMappingExposure = previous;
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
if (config.outputColorSpace !== undefined) {
|
|
75
|
+
const previous = renderer.outputColorSpace;
|
|
76
|
+
renderer.outputColorSpace = colorSpaces[config.outputColorSpace];
|
|
77
|
+
restores.push(() => {
|
|
78
|
+
renderer.outputColorSpace = previous;
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
if (config.clearColor !== undefined) {
|
|
82
|
+
const previousColor = new three.Color();
|
|
83
|
+
renderer.getClearColor(previousColor);
|
|
84
|
+
// Alpha is READ BACK and re-passed, never assumed: see `clearColor`'s doc above.
|
|
85
|
+
const alpha = renderer.getClearAlpha();
|
|
86
|
+
renderer.setClearColor(new three.Color(config.clearColor), alpha);
|
|
87
|
+
restores.push(() => {
|
|
88
|
+
renderer.setClearColor(previousColor, alpha);
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
return () => {
|
|
92
|
+
// Reverse order, so a field written twice (it cannot be, today) unwinds correctly.
|
|
93
|
+
for (let i = restores.length - 1; i >= 0; i--)
|
|
94
|
+
restores[i]?.();
|
|
95
|
+
};
|
|
96
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
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`** (`host.game.input` —
|
|
17
|
+
* the same instance the classic adapter uses when hosted), and this
|
|
18
|
+
* module registers the SAME per-world debug-registry seams the classic
|
|
19
|
+
* adapter registers (`setVirtualInputTarget`/`setInputActionsSource`/
|
|
20
|
+
* `setInputTraceSource`), which is what makes `game.input.*` (the bot
|
|
21
|
+
* input doctrine) work instead of throwing `DEBUG_INPUT_UNAVAILABLE`.
|
|
22
|
+
* The project's input map is loaded through `Game.loadInputMap` (the
|
|
23
|
+
* game-owned, load-once path every root shares) with the SAME default
|
|
24
|
+
* path the classic adapter uses. A missing/unparseable map degrades
|
|
25
|
+
* LOUDLY (console.error naming the path and what breaks) without
|
|
26
|
+
* failing the mount — an R3F tree with no actions (e.g. a pure
|
|
27
|
+
* OrbitControls demo, `examples/r3f-first-party`) is legal.
|
|
28
|
+
* 3. **Absent subsystems are absent from the TYPE.** An R3F world builds no
|
|
29
|
+
* Rapier world, composer, audio, particles, or debug-draw, and
|
|
30
|
+
* {@link R3FGameContext} — the type `useGameContext()` hands back — simply
|
|
31
|
+
* does not have those fields. Reaching for one is a compile error at the
|
|
32
|
+
* call site, with the sanctioned alternative in that type's doc comment.
|
|
33
|
+
* */
|
|
34
|
+
import type * as THREE from 'three';
|
|
35
|
+
import type { ThreeHostContext } from '../adapter';
|
|
36
|
+
import type { SystemAdapters } from '../adapter/system-adapter';
|
|
37
|
+
import { createSystemRunner } from '../core/system-runner';
|
|
38
|
+
import type { GameContext } from '../runtime/types';
|
|
39
|
+
/** The classic adapter's default input-map path — the conventional location
|
|
40
|
+
* every scaffolded project ships (`public/inputmaps/default.inputmap.json`). */
|
|
41
|
+
export declare const DEFAULT_INPUT_MAP_PATH = "/inputmaps/default.inputmap.json";
|
|
42
|
+
/**
|
|
43
|
+
* The engine context an R3F world genuinely provides — what
|
|
44
|
+
* `useGameContext()` hands back.
|
|
45
|
+
*
|
|
46
|
+
* An EXPLICIT `Pick`, never an `Omit`: a field added to `GameContext` later
|
|
47
|
+
* must be deliberately admitted here, so this surface can never silently widen
|
|
48
|
+
* into something an R3F mount does not build.
|
|
49
|
+
*
|
|
50
|
+
* **What an R3F world does NOT have, and what to reach for instead.** These
|
|
51
|
+
* are not oversights — the mount builds none of them, so they are absent from
|
|
52
|
+
* this type and naming one is a compile error rather than a crash mid-render:
|
|
53
|
+
*
|
|
54
|
+
* - **Physics** (`rapierWorld`, `rapier`, `physics`, `collisions`) — an R3F
|
|
55
|
+
* world does not build the first-party Rapier runtime. Use a physics
|
|
56
|
+
* solution inside the fiber tree (e.g. `@react-three/rapier`), or an
|
|
57
|
+
* imperative three root whose `setup(ctx)` receives the first-party Rapier
|
|
58
|
+
* runtime.
|
|
59
|
+
* - **`composer`** — R3F renders through react-three-fiber against the host
|
|
60
|
+
* renderer; there is no postprocessing `EffectComposer` here. Use
|
|
61
|
+
* fiber-native postprocessing inside the tree.
|
|
62
|
+
* - **`audio`** — no first-party audio context is built. Own a Web Audio graph
|
|
63
|
+
* inside the tree (or use drei's audio helpers) and register it as this
|
|
64
|
+
* world's `SystemAdapters.audio` via
|
|
65
|
+
* `ctx.registerSystemAdapter('audio', …)`, so host mute/pause can still
|
|
66
|
+
* silence it — `examples/third-person/src/lib/audio/sfx.ts` is the worked
|
|
67
|
+
* reference.
|
|
68
|
+
* - **`particles`** — no three.quarks particle runtime. Drive particles from
|
|
69
|
+
* the fiber tree.
|
|
70
|
+
* - **`debugDraw`** — no debug-draw helper. Add helper objects to the fiber
|
|
71
|
+
* tree directly.
|
|
72
|
+
*
|
|
73
|
+
* For the full classic runtime, use an imperative three root instead: a module
|
|
74
|
+
* exporting `setup(ctx): Promise<GameCleanup>`, which `SetupThreeRootAdapter`
|
|
75
|
+
* mounts with the complete {@link GameContext}.
|
|
76
|
+
*/
|
|
77
|
+
export type R3FGameContext = Pick<GameContext, 'scene' | 'camera' | 'sceneIndex' | 'input' | 'assets' | 'systems' | 'clock' | 'debug' | 'random' | 'game' | 'roots' | 'playtest' | 'registerSystemAdapter'>;
|
|
78
|
+
export interface R3FRootContextOptions {
|
|
79
|
+
/** World id — provenance for every debug-registry registration (matches the
|
|
80
|
+
* manifest root id by the same convention the classic adapter follows). */
|
|
81
|
+
readonly id: string;
|
|
82
|
+
/**
|
|
83
|
+
* Input map to load through `Game.loadInputMap` (game-owned, load-once —
|
|
84
|
+
* several roots asking for the SAME path share one load; competing paths
|
|
85
|
+
* throw there). Defaults to {@link DEFAULT_INPUT_MAP_PATH}, the classic
|
|
86
|
+
* adapter's own default. Pass `null` to skip loading (a world with no
|
|
87
|
+
* actions). Ignored when no `host.game` is present.
|
|
88
|
+
*/
|
|
89
|
+
readonly inputMapPath?: string | null | undefined;
|
|
90
|
+
}
|
|
91
|
+
/** What {@link createR3FRootContext} returns — the engine runtime one R3F
|
|
92
|
+
* world owns, plus the wiring hooks `createR3FAdapter`'s `mount()` drives. */
|
|
93
|
+
export interface R3FRootRuntime {
|
|
94
|
+
/** The context this world's components read through `useGameContext()` —
|
|
95
|
+
* see {@link R3FGameContext} for exactly what an R3F world provides. */
|
|
96
|
+
readonly ctx: R3FGameContext;
|
|
97
|
+
/** The world-local phase runner `mount().update(dt)` ticks. */
|
|
98
|
+
readonly systems: ReturnType<typeof createSystemRunner>;
|
|
99
|
+
/** The mounted world's `SystemAdapters` bag (`mounted.systems`) —
|
|
100
|
+
* `ctx.registerSystemAdapter` writes into it; `debug` is pre-seeded. */
|
|
101
|
+
readonly systemAdapters: SystemAdapters;
|
|
102
|
+
/** Resolves once the input map load settles (immediately when skipped).
|
|
103
|
+
* Never rejects — a failed load reports loudly and resolves. */
|
|
104
|
+
readonly inputMapReady: Promise<void>;
|
|
105
|
+
/** Backfill fiber's real scene/camera onto `ctx` after the first commit
|
|
106
|
+
* resolves them — before any tick can run. `camera` is fiber's union
|
|
107
|
+
* (perspective OR orthographic) — the ctx surface exposes whatever the
|
|
108
|
+
* tree declared, exactly as the mounted world does. */
|
|
109
|
+
setSceneCamera(scene: THREE.Scene, camera: THREE.Camera): void;
|
|
110
|
+
/** Detach every component and strip this world's debug registrations
|
|
111
|
+
* (scoped, like the classic adapter's teardown — sibling roots and
|
|
112
|
+
* react-door registrations are untouched when a Game hosts this world). */
|
|
113
|
+
dispose(): void;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Build the engine runtime for one R3F world from a `ThreeHostContext` — the same
|
|
117
|
+
* wiring, at the same layer, as the classic `SetupThreeRootAdapter.mount()`
|
|
118
|
+
* performs for the subsystems an R3F world shares with it (debug, input,
|
|
119
|
+
* random). The ones it does not build are not on
|
|
120
|
+
* {@link R3FGameContext} at all.
|
|
121
|
+
*/
|
|
122
|
+
export declare function createR3FRootContext(host: ThreeHostContext, options: R3FRootContextOptions): R3FRootRuntime;
|
|
123
|
+
//# sourceMappingURL=world-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"world-context.d.ts","sourceRoot":"","sources":["../../src/world3d-react/world-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAgCK;AAEL,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AACpC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAOhE,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAQ3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD;iFACiF;AACjF,eAAO,MAAM,sBAAsB,qCAAqC,CAAC;AAEzE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,MAAM,cAAc,GAAG,IAAI,CAC/B,WAAW,EACT,OAAO,GACP,QAAQ,GACR,YAAY,GACZ,OAAO,GACP,QAAQ,GACR,SAAS,GACT,OAAO,GACP,OAAO,GACP,QAAQ,GACR,MAAM,GACN,OAAO,GACP,UAAU,GACV,uBAAuB,CAC1B,CAAC;AAEF,MAAM,WAAW,qBAAqB;IACpC;gFAC4E;IAC5E,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB;;;;;;OAMG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;CACnD;AAED;+EAC+E;AAC/E,MAAM,WAAW,cAAc;IAC7B;6EACyE;IACzE,QAAQ,CAAC,GAAG,EAAE,cAAc,CAAC;IAC7B,+DAA+D;IAC/D,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC;IACxD;6EACyE;IACzE,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;IACxC;qEACiE;IACjE,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC;;;4DAGwD;IACxD,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC;IAC/D;;gFAE4E;IAC5E,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,gBAAgB,EACtB,OAAO,EAAE,qBAAqB,GAC7B,cAAc,CAqKhB"}
|
|
@@ -0,0 +1,204 @@
|
|
|
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`** (`host.game.input` —
|
|
17
|
+
* the same instance the classic adapter uses when hosted), and this
|
|
18
|
+
* module registers the SAME per-world debug-registry seams the classic
|
|
19
|
+
* adapter registers (`setVirtualInputTarget`/`setInputActionsSource`/
|
|
20
|
+
* `setInputTraceSource`), which is what makes `game.input.*` (the bot
|
|
21
|
+
* input doctrine) work instead of throwing `DEBUG_INPUT_UNAVAILABLE`.
|
|
22
|
+
* The project's input map is loaded through `Game.loadInputMap` (the
|
|
23
|
+
* game-owned, load-once path every root shares) with the SAME default
|
|
24
|
+
* path the classic adapter uses. A missing/unparseable map degrades
|
|
25
|
+
* LOUDLY (console.error naming the path and what breaks) without
|
|
26
|
+
* failing the mount — an R3F tree with no actions (e.g. a pure
|
|
27
|
+
* OrbitControls demo, `examples/r3f-first-party`) is legal.
|
|
28
|
+
* 3. **Absent subsystems are absent from the TYPE.** An R3F world builds no
|
|
29
|
+
* Rapier world, composer, audio, particles, or debug-draw, and
|
|
30
|
+
* {@link R3FGameContext} — the type `useGameContext()` hands back — simply
|
|
31
|
+
* does not have those fields. Reaching for one is a compile error at the
|
|
32
|
+
* call site, with the sanctioned alternative in that type's doc comment.
|
|
33
|
+
* */
|
|
34
|
+
import { createSeededRandom, DEFAULT_SEEDED_RANDOM_SEED, getSeededRandom, } from '../core/seeded-random';
|
|
35
|
+
import { createSimClock, getSimClock } from '../core/sim-clock';
|
|
36
|
+
import { createSystemRunner } from '../core/system-runner';
|
|
37
|
+
import { createSceneIndex } from '../ecs/scene-index';
|
|
38
|
+
import { createDebugRegistry, getDebugRegistry, } from '../runtime/debug-registry';
|
|
39
|
+
import { disposeDebrisSubtree } from '../runtime/game';
|
|
40
|
+
/** The classic adapter's default input-map path — the conventional location
|
|
41
|
+
* every scaffolded project ships (`public/inputmaps/default.inputmap.json`). */
|
|
42
|
+
export const DEFAULT_INPUT_MAP_PATH = '/inputmaps/default.inputmap.json';
|
|
43
|
+
/**
|
|
44
|
+
* Build the engine runtime for one R3F world from a `ThreeHostContext` — the same
|
|
45
|
+
* wiring, at the same layer, as the classic `SetupThreeRootAdapter.mount()`
|
|
46
|
+
* performs for the subsystems an R3F world shares with it (debug, input,
|
|
47
|
+
* random). The ones it does not build are not on
|
|
48
|
+
* {@link R3FGameContext} at all.
|
|
49
|
+
*/
|
|
50
|
+
export function createR3FRootContext(host, options) {
|
|
51
|
+
const { id, inputMapPath = DEFAULT_INPUT_MAP_PATH } = options;
|
|
52
|
+
// Same observer threading as the classic adapter — profiler sees this
|
|
53
|
+
// world's phases under the shared game profiler when hosted.
|
|
54
|
+
const systems = createSystemRunner(host.game?.profiler.systemObserver, 'three');
|
|
55
|
+
// The mounted world's adapter surface (`mounted.systems`) — declared before
|
|
56
|
+
// ctx so `ctx.registerSystemAdapter` can close over it (classic parity: a
|
|
57
|
+
// game-owned capability like networking registers here from component code).
|
|
58
|
+
const systemAdapters = {};
|
|
59
|
+
// The world's live scene index — built in `setSceneCamera` (below), because
|
|
60
|
+
// fiber resolves the scene after this function returns. Same lifetime as
|
|
61
|
+
// `ctx.scene`, which is backfilled at the same moment.
|
|
62
|
+
let sceneIndex = null;
|
|
63
|
+
const ctxRaw = {
|
|
64
|
+
systems,
|
|
65
|
+
assets: host.assets,
|
|
66
|
+
registerSystemAdapter: (kind, adapter) => {
|
|
67
|
+
// biome-ignore lint/suspicious/noExplicitAny: same per-key record write the classic adapter performs; correct by construction
|
|
68
|
+
systemAdapters[kind] = adapter;
|
|
69
|
+
host.game?.notifySystemAdaptersChanged();
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
const ctx = ctxRaw;
|
|
73
|
+
if (host.game) {
|
|
74
|
+
ctx.game = host.game;
|
|
75
|
+
ctx.roots = host.game.roots;
|
|
76
|
+
ctx.playtest = host.game.playtest ?? null;
|
|
77
|
+
}
|
|
78
|
+
// --- ctx.debug (gap 1) — the ONE registry per Game root, shared across
|
|
79
|
+
// every world mounted onto it; a bare mount with no Game shell gets a
|
|
80
|
+
// private, mount-local registry instead (same absence precedent as the
|
|
81
|
+
// classic adapter). ---
|
|
82
|
+
const debugRegistry = (host.game ? getDebugRegistry(host.game) : null) ??
|
|
83
|
+
createDebugRegistry({ getTick: () => 0, getSimT: () => 0 });
|
|
84
|
+
systemAdapters.debug = debugRegistry.adapter;
|
|
85
|
+
ctx.debug = debugRegistry.forRoot(id);
|
|
86
|
+
ctx.random =
|
|
87
|
+
(host.game ? getSeededRandom(host.game) : null) ??
|
|
88
|
+
createSeededRandom(DEFAULT_SEEDED_RANDOM_SEED);
|
|
89
|
+
// --- ctx.clock (P3) — every world has a sim clock, R3F included. Same
|
|
90
|
+
// game-scoped reach-in as `ctx.random` above; a bare mount with no Game
|
|
91
|
+
// shell gets a private, mount-local clock that nothing flushes (there is no
|
|
92
|
+
// fixed loop to bind timers to). The mount-local fallback uses the SAME
|
|
93
|
+
// `disposeDebrisSubtree` the hosted path uses — it drops
|
|
94
|
+
// the subtree and disposes geometry/materials, with no Rapier owners
|
|
95
|
+
// because this ctx carries no `physics`/`rapierWorld` (the
|
|
96
|
+
// honest "this world owns no bodies").
|
|
97
|
+
const gameClock = host.game ? getSimClock(host.game) : null;
|
|
98
|
+
const clock = gameClock ?? createSimClock({ dispose: (obj) => disposeDebrisSubtree(obj, []) });
|
|
99
|
+
ctx.clock = clock;
|
|
100
|
+
// --- ctx.input + the debug-registry input seams (gap 3) — the game-owned
|
|
101
|
+
// InputManager, polled by the game-scoped runner each frame; this world
|
|
102
|
+
// registers the SAME per-world seams the classic adapter registers so
|
|
103
|
+
// `game.input.*` (virtual input) and the built-in `input.actions`/
|
|
104
|
+
// `input.trace` providers resolve to it. ---
|
|
105
|
+
let inputMapReady = Promise.resolve();
|
|
106
|
+
if (host.game) {
|
|
107
|
+
const game = host.game;
|
|
108
|
+
const input = game.input;
|
|
109
|
+
ctxRaw['input'] = input;
|
|
110
|
+
debugRegistry.setInputActionsSource(id, () => input.actionNames().map((name) => ({ name, valueType: input.getActionValueType(name) })));
|
|
111
|
+
debugRegistry.setInputTraceSource(id, () => {
|
|
112
|
+
const raw = input.getInputTrace();
|
|
113
|
+
return {
|
|
114
|
+
version: raw.version,
|
|
115
|
+
seed: getSeededRandom(game)?.seed ?? null,
|
|
116
|
+
fixedDt: game.loop.fixedDt,
|
|
117
|
+
ticks: raw.ticks,
|
|
118
|
+
};
|
|
119
|
+
});
|
|
120
|
+
debugRegistry.setVirtualInputTarget(id, {
|
|
121
|
+
setVirtualAction: (action, value) => input.setVirtualAction(action, value),
|
|
122
|
+
tapVirtualAction: (action) => input.tapVirtualAction(action),
|
|
123
|
+
clearVirtualActions: () => input.clearVirtualActions(),
|
|
124
|
+
scheduleActionAtTick: (tick, action, value) => input.scheduleActionAtTick(tick, action, value),
|
|
125
|
+
startInputRecording: () => input.startInputRecording(),
|
|
126
|
+
stopInputRecording: () => input.stopInputRecording(),
|
|
127
|
+
isInputRecording: () => input.isInputRecording(),
|
|
128
|
+
injectAxis: (sourceId, value) => input.injectAxis(sourceId, value),
|
|
129
|
+
injectVector2: (sourceId, value) => input.injectVector2(sourceId, value),
|
|
130
|
+
injectPointerDelta: (sourceId, delta) => input.injectPointerDelta(sourceId, delta),
|
|
131
|
+
injectPointerPosition: (sourceId, value) => input.injectPointerPosition(sourceId, value),
|
|
132
|
+
});
|
|
133
|
+
if (!host.headless && inputMapPath !== null) {
|
|
134
|
+
// Load-once through the game-owned path (classic parity — competing
|
|
135
|
+
// paths across roots throw THERE, loudly). A FAILED load (missing/bad
|
|
136
|
+
// file) must not fail this mount: an R3F tree with no declared actions
|
|
137
|
+
// is legal. It degrades loudly instead — naming exactly what breaks.
|
|
138
|
+
inputMapReady = game.loadInputMap(inputMapPath).catch((err) => {
|
|
139
|
+
// biome-ignore lint/suspicious/noConsole: deliberate loud degrade — the documented alternative to failing the mount (see comment above)
|
|
140
|
+
console.error(`R3F world "${id}": failed to load input map "${inputMapPath}" — declared input ` +
|
|
141
|
+
'actions and `game.input.*` (bot/virtual input) will not work until a valid map ' +
|
|
142
|
+
'loads. Ship one at the conventional path or pass `inputMapPath` to ' +
|
|
143
|
+
`createR3FAdapter (null to opt out). Cause: ${err instanceof Error ? err.message : String(err)}`);
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
// `input` IS a field of every R3F world's ctx — it is game-owned, and this
|
|
149
|
+
// particular mount has no Game to own it (a bare harness or a foreign
|
|
150
|
+
// host). A throwing getter names that at the read, instead of handing back
|
|
151
|
+
// `undefined` that breaks deep inside a frame callback. Non-enumerable so
|
|
152
|
+
// spreads/serialization of the ctx never trip it.
|
|
153
|
+
Object.defineProperty(ctxRaw, 'input', {
|
|
154
|
+
configurable: true,
|
|
155
|
+
enumerable: false,
|
|
156
|
+
get() {
|
|
157
|
+
throw new Error(`R3F world "${id}": ctx.input is game-owned and this mount has no Game host ` +
|
|
158
|
+
'(host.game is absent — bare harness/foreign host); mount through the vgai host ' +
|
|
159
|
+
'to get the shared InputManager.');
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
ctx,
|
|
165
|
+
systems,
|
|
166
|
+
systemAdapters,
|
|
167
|
+
inputMapReady,
|
|
168
|
+
setSceneCamera(scene, camera) {
|
|
169
|
+
const sameScene = ctxRaw['scene'] === scene && sceneIndex !== null;
|
|
170
|
+
ctxRaw['scene'] = scene;
|
|
171
|
+
ctxRaw['camera'] = camera;
|
|
172
|
+
// The live scene index (P2 `observe`) is a REAL value here, not a
|
|
173
|
+
// throwing getter — every three world has one. It can only be built once
|
|
174
|
+
// fiber has resolved the scene, which is the same moment `ctx.scene`
|
|
175
|
+
// itself becomes readable, so index and scene share one lifetime. A
|
|
176
|
+
// second commit (fiber handing back a different scene) replaces it.
|
|
177
|
+
//
|
|
178
|
+
// Keyed on the SCENE, so a camera-only backfill (a world swapping the
|
|
179
|
+
// default camera after mount) leaves the index — and every `observe`
|
|
180
|
+
// subscription hanging off it — alone.
|
|
181
|
+
if (sameScene)
|
|
182
|
+
return;
|
|
183
|
+
sceneIndex?.dispose();
|
|
184
|
+
sceneIndex = createSceneIndex(scene);
|
|
185
|
+
ctxRaw['sceneIndex'] = sceneIndex;
|
|
186
|
+
},
|
|
187
|
+
dispose() {
|
|
188
|
+
// Same ownership rule as the classic adapter's teardown: dispose ONLY a
|
|
189
|
+
// clock this mount created. The game-scoped one belongs to
|
|
190
|
+
// `GameInternal.dispose()` — killing it here would freeze sim time and
|
|
191
|
+
// cancel every SIBLING world's timers.
|
|
192
|
+
if (!gameClock)
|
|
193
|
+
clock.dispose();
|
|
194
|
+
sceneIndex?.dispose();
|
|
195
|
+
sceneIndex = null;
|
|
196
|
+
// Scoped strip when a Game hosts this world (sibling roots stay live);
|
|
197
|
+
// a bare standalone mount owns its private registry and clears it all.
|
|
198
|
+
if (host.game)
|
|
199
|
+
debugRegistry.strip(id);
|
|
200
|
+
else
|
|
201
|
+
debugRegistry.strip();
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
}
|