@vgai/engine 0.5.4 → 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/runtime/mount-game.ts +6 -0
- package/src/runtime/unexported-game-trap.ts +82 -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,302 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE UNIVERSAL INSTRUMENTS — time scale, pause/frame-step, collider draw and
|
|
3
|
+
* frame time, furnished by the ENGINE for every game before it has written a
|
|
4
|
+
* line.
|
|
5
|
+
*
|
|
6
|
+
* These are physics of the medium, not genre ontology. Time runs; it can run
|
|
7
|
+
* slower or stop; a frame can be stepped; colliders can be drawn; frames take
|
|
8
|
+
* time. None of that is a decision any particular game makes, so none of it
|
|
9
|
+
* belongs in a game's own declarations — and none of it belongs on the game's
|
|
10
|
+
* own dev panel either, which shows ONLY what the game itself declared
|
|
11
|
+
* (`stat()`, `cheat()`). They publish as DOORS: an agent drives them through
|
|
12
|
+
* `game.state()`/`game.command()`, and a human drives the same controls from
|
|
13
|
+
* the editor chrome that already owns them — pause and frame-step on the
|
|
14
|
+
* transport, frame time on the stats overlay, colliders in the play-adopted
|
|
15
|
+
* Scene viewport.
|
|
16
|
+
*
|
|
17
|
+
* WHAT IS NOT HERE, and why: a FREE CAMERA. The editor already ships one
|
|
18
|
+
* (owner, 2026-08-10): play adoption swaps the live game scene into the editor
|
|
19
|
+
* viewport (`enterPlayScene`), so the Scene view during play IS a free orbit
|
|
20
|
+
* camera over the running game — no game-side camera override needed, and the
|
|
21
|
+
* game's own camera writes never fight it because the game keeps rendering
|
|
22
|
+
* through its own canvas untouched. Per the non-redundancy rule that governs
|
|
23
|
+
* this list, a control the editor's own chrome furnishes gets no instrument;
|
|
24
|
+
* agents reach that camera through the editor half of `vgai eval`, not the
|
|
25
|
+
* game registry.
|
|
26
|
+
*
|
|
27
|
+
* ── THE DOOR ────────────────────────────────────────────────────────────────
|
|
28
|
+
* This module is IMPLEMENTATION ONLY. It publishes nothing itself: the dev-menu
|
|
29
|
+
* capability's own registry adopts this list (`installDevMenuInstruments`) and
|
|
30
|
+
* publishes each instrument through the SAME door every declaration in that
|
|
31
|
+
* capability uses — one provider per reading (`instrument.timescale`), one
|
|
32
|
+
* command per action (`instrument.timescale.set`), plus the `dev-menu` index
|
|
33
|
+
* provider. That is deliberate and load-bearing: the registry IS the product,
|
|
34
|
+
* so every reader of an instrument reaches the SAME registration.
|
|
35
|
+
*
|
|
36
|
+
* ── DEGRADING ───────────────────────────────────────────────────────────────
|
|
37
|
+
* An instrument whose subject this game does not have (no physics adapter ⇒ no
|
|
38
|
+
* colliders) READS `null` — honest emptiness rather than a fabricated value.
|
|
39
|
+
* Its ACTION, invoked anyway, THROWS and names what is missing. Silence is the
|
|
40
|
+
* one thing forbidden: an agent that calls `instrument.colliders.toggle` and
|
|
41
|
+
* gets `undefined` back learns nothing.
|
|
42
|
+
*
|
|
43
|
+
* ── RESOURCE OWNERSHIP, STATED ONCE ─────────────────────────────────────────
|
|
44
|
+
* {@link createDevInstruments} owns everything it allocates: the frame-time
|
|
45
|
+
* ring buffer and its ONE `game.onRenderStep` subscription. SHARER: the
|
|
46
|
+
* dev-menu capability's `DevMenuBridge`, which creates one set per mounted
|
|
47
|
+
* game. TEARDOWN: the returned {@link DevInstrumentSet.dispose} — the ONE path
|
|
48
|
+
* that ends it. Nothing else here holds a resource; the time-scale, pause and
|
|
49
|
+
* collider instruments only drive state that `Game` already owns.
|
|
50
|
+
*/
|
|
51
|
+
|
|
52
|
+
import { z } from 'zod';
|
|
53
|
+
import { clampTimeScale, TIME_SCALE_RANGE } from '../core/frame-pacing';
|
|
54
|
+
import type { Game } from '../runtime/game';
|
|
55
|
+
|
|
56
|
+
/** What shape an instrument's reading is, and what drives it. Data, not
|
|
57
|
+
* layout: a reader learns how to interpret and actuate an instrument without
|
|
58
|
+
* having to recognise it by name. */
|
|
59
|
+
export type DevInstrumentControl =
|
|
60
|
+
/** A value only. */
|
|
61
|
+
| { readonly kind: 'reading' }
|
|
62
|
+
/** On/off, driven by the named action. */
|
|
63
|
+
| { readonly kind: 'toggle'; readonly action: string }
|
|
64
|
+
/** A continuous value, driven by the named action (one numeric argument). */
|
|
65
|
+
| {
|
|
66
|
+
readonly kind: 'scale';
|
|
67
|
+
readonly action: string;
|
|
68
|
+
readonly min: number;
|
|
69
|
+
readonly max: number;
|
|
70
|
+
readonly step: number;
|
|
71
|
+
}
|
|
72
|
+
/** A {@link FrameTimeReading} — a window of samples, not a scalar. */
|
|
73
|
+
| { readonly kind: 'plot' };
|
|
74
|
+
|
|
75
|
+
/** One instrument verb. Every action declares an args tuple — `z.tuple([])`
|
|
76
|
+
* for a verb that takes none — so the debug registry REJECTS an unexpected
|
|
77
|
+
* argument at the door instead of passing it through to a handler that
|
|
78
|
+
* ignores it. */
|
|
79
|
+
export interface DevInstrumentAction {
|
|
80
|
+
/** Second half of the command name: `instrument.<id>.<this>`. */
|
|
81
|
+
readonly id: string;
|
|
82
|
+
readonly label: string;
|
|
83
|
+
readonly hint: string;
|
|
84
|
+
readonly args: z.ZodTuple;
|
|
85
|
+
run(values: readonly unknown[]): unknown;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface DevInstrument {
|
|
89
|
+
/** Second half of the provider name: `instrument.<this>`. */
|
|
90
|
+
readonly id: string;
|
|
91
|
+
readonly label: string;
|
|
92
|
+
readonly hint: string;
|
|
93
|
+
/** Trailing unit for a scalar reading (`x`, `ms`). */
|
|
94
|
+
readonly unit?: string;
|
|
95
|
+
readonly control: DevInstrumentControl;
|
|
96
|
+
readonly actions: readonly DevInstrumentAction[];
|
|
97
|
+
/** This instant's value, or `null` when this game has no such subject. */
|
|
98
|
+
read(): unknown;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface DevInstrumentSet {
|
|
102
|
+
readonly instruments: readonly DevInstrument[];
|
|
103
|
+
/** See the ownership note above — the ONE teardown path. */
|
|
104
|
+
dispose(): void;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* How many display frames the frame-time reading keeps. ~1 second at 60 Hz —
|
|
109
|
+
* long enough that a hitch is still in the window when you look, short enough
|
|
110
|
+
* that the mean tracks what the game is doing NOW.
|
|
111
|
+
*/
|
|
112
|
+
export const FRAME_TIME_WINDOW = 60;
|
|
113
|
+
|
|
114
|
+
/** What `instrument.frame-time` reads. `null`s (rather than zeros) before the
|
|
115
|
+
* first sampled frame: a stopped game has no frame time, and `0 ms / 0 fps`
|
|
116
|
+
* would read as a measurement. */
|
|
117
|
+
export interface FrameTimeReading {
|
|
118
|
+
/** Mean wall-clock milliseconds per display frame over the window. */
|
|
119
|
+
readonly ms: number | null;
|
|
120
|
+
/** Frames per second implied by {@link ms}. */
|
|
121
|
+
readonly fps: number | null;
|
|
122
|
+
/** The worst single frame in the window — the hitch the mean hides. */
|
|
123
|
+
readonly worstMs: number | null;
|
|
124
|
+
/** Oldest first, for the plot. */
|
|
125
|
+
readonly samples: readonly number[];
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Pure: the whole frame-time reading from a window of samples. */
|
|
129
|
+
export function summarizeFrameTimes(samples: readonly number[]): FrameTimeReading {
|
|
130
|
+
if (samples.length === 0) return { ms: null, fps: null, worstMs: null, samples: [] };
|
|
131
|
+
let total = 0;
|
|
132
|
+
let worst = 0;
|
|
133
|
+
for (const sample of samples) {
|
|
134
|
+
total += sample;
|
|
135
|
+
if (sample > worst) worst = sample;
|
|
136
|
+
}
|
|
137
|
+
const ms = total / samples.length;
|
|
138
|
+
return {
|
|
139
|
+
ms: round(ms, 2),
|
|
140
|
+
fps: ms > 0 ? round(1000 / ms, 1) : null,
|
|
141
|
+
worstMs: round(worst, 2),
|
|
142
|
+
samples: samples.map((sample) => round(sample, 2)),
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function round(value: number, places: number): number {
|
|
147
|
+
const factor = 10 ** places;
|
|
148
|
+
return Math.round(value * factor) / factor;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const NO_COLLIDERS =
|
|
152
|
+
'No physics adapter on this game implements setDebugDrawEnabled, so nothing can draw its ' +
|
|
153
|
+
'colliders. A first-party three root with Rapier physics registers one; a game with no ' +
|
|
154
|
+
'physics has no colliders to draw.';
|
|
155
|
+
|
|
156
|
+
const NO_ARGS = z.tuple([]);
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Build this game's universal instrument set. One call per mounted game; the
|
|
160
|
+
* caller owns the returned {@link DevInstrumentSet.dispose}.
|
|
161
|
+
*/
|
|
162
|
+
export function createDevInstruments(game: Game): DevInstrumentSet {
|
|
163
|
+
// --- Frame time: one subscription, one ring buffer ------------------------
|
|
164
|
+
const samples: number[] = [];
|
|
165
|
+
let previousFrameAt = now();
|
|
166
|
+
const stopSampling = game.onRenderStep(() => {
|
|
167
|
+
const at = now();
|
|
168
|
+
samples.push(at - previousFrameAt);
|
|
169
|
+
previousFrameAt = at;
|
|
170
|
+
if (samples.length > FRAME_TIME_WINDOW) samples.shift();
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// --- Collider draw: the adapter has a setter and no getter, so the ON/OFF
|
|
174
|
+
// state is ours to remember. It is only ever written through the one action
|
|
175
|
+
// below, which is also the only thing that calls the adapter.
|
|
176
|
+
let collidersDrawn = false;
|
|
177
|
+
const colliderDraw = () => {
|
|
178
|
+
const adapter = game.systemAdapters.physics;
|
|
179
|
+
return adapter?.setDebugDrawEnabled ? adapter : null;
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
const instruments: readonly DevInstrument[] = [
|
|
183
|
+
{
|
|
184
|
+
id: 'timescale',
|
|
185
|
+
label: 'Time scale',
|
|
186
|
+
hint: 'Sim speed multiplier. 1 is real time, 0 freezes the simulation while the game keeps drawing.',
|
|
187
|
+
unit: 'x',
|
|
188
|
+
control: {
|
|
189
|
+
kind: 'scale',
|
|
190
|
+
action: 'set',
|
|
191
|
+
min: TIME_SCALE_RANGE.min,
|
|
192
|
+
max: TIME_SCALE_RANGE.max,
|
|
193
|
+
step: 0.05,
|
|
194
|
+
},
|
|
195
|
+
actions: [
|
|
196
|
+
{
|
|
197
|
+
id: 'set',
|
|
198
|
+
label: 'Set',
|
|
199
|
+
hint: `Set the sim speed multiplier (${TIME_SCALE_RANGE.min}–${TIME_SCALE_RANGE.max}).`,
|
|
200
|
+
args: z.tuple([z.number()]),
|
|
201
|
+
run: (values) => {
|
|
202
|
+
// The LOOP clamps and warns; asking for the clamp here too would
|
|
203
|
+
// be a second opinion about the same range. It reads back the
|
|
204
|
+
// value that actually took effect, never the one requested.
|
|
205
|
+
game.loop.timeScale = clampTimeScale(values[0] as number);
|
|
206
|
+
return game.loop.timeScale;
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
],
|
|
210
|
+
read: () => game.loop.timeScale,
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
id: 'paused',
|
|
214
|
+
label: 'Paused',
|
|
215
|
+
hint: 'Freeze the simulation. The game keeps drawing, so you can look at a frozen frame.',
|
|
216
|
+
control: { kind: 'toggle', action: 'toggle' },
|
|
217
|
+
actions: [
|
|
218
|
+
{
|
|
219
|
+
id: 'toggle',
|
|
220
|
+
label: 'Toggle',
|
|
221
|
+
hint: 'Pause or resume the simulation.',
|
|
222
|
+
args: NO_ARGS,
|
|
223
|
+
run: () => {
|
|
224
|
+
if (game.play.paused) game.play.resume();
|
|
225
|
+
else game.play.pause();
|
|
226
|
+
return game.play.paused;
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
id: 'step',
|
|
231
|
+
label: 'Step',
|
|
232
|
+
hint: 'Advance exactly one fixed substep. Pauses first if the game is running.',
|
|
233
|
+
args: NO_ARGS,
|
|
234
|
+
run: () => {
|
|
235
|
+
// Frame advance implies pause — `Game.play.step()` is a
|
|
236
|
+
// deliberate whole-call no-op while running, and a button that
|
|
237
|
+
// silently does nothing is the failure this instrument exists to
|
|
238
|
+
// avoid.
|
|
239
|
+
if (!game.play.paused) game.play.pause();
|
|
240
|
+
game.play.step();
|
|
241
|
+
return game.play.paused;
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
],
|
|
245
|
+
read: () => game.play.paused,
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
id: 'colliders',
|
|
249
|
+
label: 'Colliders drawn',
|
|
250
|
+
hint: "Draw the physics colliders over the world, through the game's own physics adapter.",
|
|
251
|
+
control: { kind: 'toggle', action: 'toggle' },
|
|
252
|
+
actions: [
|
|
253
|
+
{
|
|
254
|
+
id: 'toggle',
|
|
255
|
+
label: 'Toggle',
|
|
256
|
+
hint: 'Turn collider wireframes on or off.',
|
|
257
|
+
args: NO_ARGS,
|
|
258
|
+
run: () => {
|
|
259
|
+
const adapter = colliderDraw();
|
|
260
|
+
if (!adapter) throw new Error(NO_COLLIDERS);
|
|
261
|
+
collidersDrawn = !collidersDrawn;
|
|
262
|
+
adapter.setDebugDrawEnabled?.(collidersDrawn);
|
|
263
|
+
return collidersDrawn;
|
|
264
|
+
},
|
|
265
|
+
},
|
|
266
|
+
],
|
|
267
|
+
read: () => (colliderDraw() === null ? null : collidersDrawn),
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
id: 'frame-time',
|
|
271
|
+
label: 'Frame time',
|
|
272
|
+
hint: 'Wall-clock milliseconds per display frame, newest last. The window is where a hitch shows; the mean hides it.',
|
|
273
|
+
unit: 'ms',
|
|
274
|
+
control: { kind: 'plot' },
|
|
275
|
+
actions: [
|
|
276
|
+
{
|
|
277
|
+
id: 'clear',
|
|
278
|
+
label: 'Clear',
|
|
279
|
+
hint: 'Forget the sampled window and start measuring again.',
|
|
280
|
+
args: NO_ARGS,
|
|
281
|
+
run: () => {
|
|
282
|
+
samples.length = 0;
|
|
283
|
+
return null;
|
|
284
|
+
},
|
|
285
|
+
},
|
|
286
|
+
],
|
|
287
|
+
read: () => summarizeFrameTimes(samples),
|
|
288
|
+
},
|
|
289
|
+
];
|
|
290
|
+
|
|
291
|
+
return {
|
|
292
|
+
instruments,
|
|
293
|
+
dispose() {
|
|
294
|
+
stopSampling();
|
|
295
|
+
samples.length = 0;
|
|
296
|
+
},
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
function now(): number {
|
|
301
|
+
return typeof performance === 'undefined' ? Date.now() : performance.now();
|
|
302
|
+
}
|
|
@@ -22,6 +22,7 @@ import type { ResolvedAdapterRoot } from '../manifest/load';
|
|
|
22
22
|
import type { GameSession } from './create-runtime';
|
|
23
23
|
import { type MountEntry, mountManifestRoots, resolveManifest } from './mount-manifest';
|
|
24
24
|
import type { GameSetupFn } from './types';
|
|
25
|
+
import { assertExportedOrInEditor } from './unexported-game-trap';
|
|
25
26
|
|
|
26
27
|
// ---------------------------------------------------------------------------
|
|
27
28
|
// The host contract (design/26 §5 D1's `ManifestHost`)
|
|
@@ -232,6 +233,11 @@ export async function mountGameFromManifest(
|
|
|
232
233
|
host: ManifestHost,
|
|
233
234
|
opts: MountGameOptions = {},
|
|
234
235
|
): Promise<GameSession> {
|
|
236
|
+
// Owner invariant: an unexported game never mounts outside the editor. The
|
|
237
|
+
// editor mounts through its own resolver, so every caller of THIS function
|
|
238
|
+
// is a standalone page — and on a dev server, that page refuses to boot
|
|
239
|
+
// (see unexported-game-trap.ts for why this is a trap and not a rule).
|
|
240
|
+
assertExportedOrInEditor();
|
|
235
241
|
const manifest = resolveManifest(manifestInput);
|
|
236
242
|
const entries: Record<string, MountEntry> = { ...opts.entries };
|
|
237
243
|
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE UNEXPORTED-GAME TRAP: a dev-served standalone game page REFUSES to boot.
|
|
3
|
+
*
|
|
4
|
+
* Owner decision (2026-08-09): until a game is EXPORTED, it is never played
|
|
5
|
+
* outside the editor. The editor is the one authoring, viewing and
|
|
6
|
+
* verification surface; the standalone page exists to serve the exported
|
|
7
|
+
* artifact, not to be a second door during development.
|
|
8
|
+
*
|
|
9
|
+
* Why this is a trap in CODE and not a rule in prose: the rule already
|
|
10
|
+
* existed, and it drifted. When an editor session broke mid-task, an agent
|
|
11
|
+
* "temporarily" switched to `npm run game`, the fallback fed its whole
|
|
12
|
+
* feedback loop (pixels for screenshots), nothing broken ever pushed it back,
|
|
13
|
+
* and hours of verification ran outside the editor without anyone deciding
|
|
14
|
+
* that. A workaround whose cost lands outside the loop that chose it is
|
|
15
|
+
* sticky; the only fix that holds is for the workaround PATH ITSELF to fail
|
|
16
|
+
* immediately, loudly, and with the way back in its hands. That is this file.
|
|
17
|
+
*
|
|
18
|
+
* The boundary is DEV-SERVED vs EXPORTED, decided by the bundler: a Vite dev
|
|
19
|
+
* server strips nothing, so `import.meta.env.DEV` is true; a production build
|
|
20
|
+
* (`vite build` — what `vgai deploy` runs) compiles it false and this module
|
|
21
|
+
* costs an exported game nothing. Headless contexts (unit tests, playtest's
|
|
22
|
+
* node leg) have no real browser page and never trip it — the check requires
|
|
23
|
+
* a document whose `defaultView` is the window, which no test stub wires up.
|
|
24
|
+
*
|
|
25
|
+
* There is deliberately NO opt-out flag, env var, or query param. An escape
|
|
26
|
+
* hatch an agent can reach for is the workaround again, one hop later.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/** What the refusal says — one place, so the page and the thrown Error agree. */
|
|
30
|
+
const REFUSAL = [
|
|
31
|
+
'UNEXPORTED GAME, OUTSIDE THE EDITOR — refusing to mount.',
|
|
32
|
+
'',
|
|
33
|
+
'This game has not been exported. Until it is, the ONLY way to run, see,',
|
|
34
|
+
'or drive it is the editor:',
|
|
35
|
+
'',
|
|
36
|
+
' vgai edit . open (or reuse) the editor for this project',
|
|
37
|
+
' vgai play enter play mode from the terminal',
|
|
38
|
+
" vgai eval '<js>' drive and read the running game",
|
|
39
|
+
'',
|
|
40
|
+
'The standalone page serves EXPORTED builds only (`vgai deploy`, or the',
|
|
41
|
+
'production build it runs). Do not script around this page — no headless',
|
|
42
|
+
'browsers, bots, or screenshots against the dev server. Every agent',
|
|
43
|
+
'workflow goes through the editor session.',
|
|
44
|
+
].join('\n');
|
|
45
|
+
|
|
46
|
+
/** True only on a real, dev-served browser page — the one context the trap is for. */
|
|
47
|
+
function isDevServedBrowserPage(): boolean {
|
|
48
|
+
if (typeof window === 'undefined' || typeof document === 'undefined') return false;
|
|
49
|
+
// Test stubs install a bare `document` object; only a real page has the
|
|
50
|
+
// document↔window linkage.
|
|
51
|
+
if (document.defaultView !== window) return false;
|
|
52
|
+
return Boolean(import.meta.env?.DEV);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Throws (and paints a full-screen refusal, so a human at the tab sees it as
|
|
57
|
+
* immediately as a harness watching the console does) when an unexported game
|
|
58
|
+
* is being mounted on a dev-served page. Called by `mountGameFromManifest`
|
|
59
|
+
* before any root is resolved; exported builds and headless tests pass
|
|
60
|
+
* through untouched.
|
|
61
|
+
*/
|
|
62
|
+
export function assertExportedOrInEditor(): void {
|
|
63
|
+
if (!isDevServedBrowserPage()) return;
|
|
64
|
+
|
|
65
|
+
const screen = document.createElement('pre');
|
|
66
|
+
screen.textContent = REFUSAL;
|
|
67
|
+
screen.style.cssText = [
|
|
68
|
+
'position:fixed',
|
|
69
|
+
'inset:0',
|
|
70
|
+
'z-index:2147483647',
|
|
71
|
+
'margin:0',
|
|
72
|
+
'padding:48px',
|
|
73
|
+
'background:#1A0E0E',
|
|
74
|
+
'color:#FF9B8A',
|
|
75
|
+
'font:600 15px/1.7 ui-monospace,SFMono-Regular,Menlo,monospace',
|
|
76
|
+
'white-space:pre-wrap',
|
|
77
|
+
].join(';');
|
|
78
|
+
document.body.appendChild(screen);
|
|
79
|
+
document.title = 'UNEXPORTED — use the editor';
|
|
80
|
+
|
|
81
|
+
throw new Error(`mountGameFromManifest: ${REFUSAL}`);
|
|
82
|
+
}
|
|
@@ -29,6 +29,15 @@
|
|
|
29
29
|
* to use instead.
|
|
30
30
|
* - `EngineBridge` / `EngineBridgeValue` — the context contract, exported
|
|
31
31
|
* for advanced adopters building their own bridge.
|
|
32
|
+
*
|
|
33
|
+
* Deliberately NOT re-exported here: `<RapierPhysicsBridge>`
|
|
34
|
+
* (`@engine/world3d-react/rapier-physics-bridge`), which registers an R3F
|
|
35
|
+
* world's `@react-three/rapier` physics as the game's
|
|
36
|
+
* `SystemAdapters.physics` — so the dev menu's colliders instrument and the
|
|
37
|
+
* editor's transform coordination can see it. It imports
|
|
38
|
+
* `@react-three/rapier`, and only a world that already depends on that library
|
|
39
|
+
* should pull it into its graph; a deep import keeps this barrel's peer
|
|
40
|
+
* contract to `react`/`@react-three/fiber`/`three` alone.
|
|
32
41
|
*/
|
|
33
42
|
|
|
34
43
|
export { EngineBridge, type EngineBridgeValue, useGameContext } from './engine-bridge';
|
|
@@ -0,0 +1,137 @@
|
|
|
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
|
+
|
|
62
|
+
import { type RapierRigidBody, useRapier } from '@react-three/rapier';
|
|
63
|
+
import { useEffect } from 'react';
|
|
64
|
+
import type * as THREE from 'three';
|
|
65
|
+
import {
|
|
66
|
+
createRapierBodyEditing,
|
|
67
|
+
type RapierEditableBody,
|
|
68
|
+
} from '../adapter/rapier-physics-adapter';
|
|
69
|
+
import type { PhysicsAdapter } from '../adapter/system-adapter';
|
|
70
|
+
import { useGameContext } from './engine-bridge';
|
|
71
|
+
|
|
72
|
+
export interface RapierPhysicsBridgeProps {
|
|
73
|
+
/**
|
|
74
|
+
* Set the `debug` prop of the SAME `<Physics>` this bridge is mounted in.
|
|
75
|
+
* The dev menu's "Colliders drawn" toggle calls it; the world's own state is
|
|
76
|
+
* what `<Physics debug={…}>` reads, so the library's debug rendering is the
|
|
77
|
+
* only thing that ever draws a collider.
|
|
78
|
+
*/
|
|
79
|
+
readonly onDebugChange: (debug: boolean) => void;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Register this R3F world's `@react-three/rapier` physics as the game's
|
|
84
|
+
* `SystemAdapters.physics`. Mount it once, INSIDE `<Physics>` (it reads
|
|
85
|
+
* `useRapier()`). Renders nothing.
|
|
86
|
+
*/
|
|
87
|
+
export function RapierPhysicsBridge({ onDebugChange }: RapierPhysicsBridgeProps): null {
|
|
88
|
+
const ctx = useGameContext();
|
|
89
|
+
const { rigidBodyStates } = useRapier();
|
|
90
|
+
const registerSystemAdapter = ctx.registerSystemAdapter;
|
|
91
|
+
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
if (!registerSystemAdapter) return;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* node id → the Rapier body driving it, in two hops the library and the
|
|
97
|
+
* engine each already own:
|
|
98
|
+
*
|
|
99
|
+
* 1. id → `Object3D`, through the live scene index — `userData.entityId`
|
|
100
|
+
* is this stack's identity convention (the editor's R3F authoring
|
|
101
|
+
* adapter stamps it; `../adapter/setup-three-root-adapter.ts` resolves
|
|
102
|
+
* the same way for the imperative root).
|
|
103
|
+
* 2. `Object3D` → body, through `rigidBodyStates` — the library's OWN
|
|
104
|
+
* body↔object map, carried on the `RapierContext` `useRapier()`
|
|
105
|
+
* returns. Walking ANCESTORS matters: `<RigidBody>` owns a subtree, so
|
|
106
|
+
* the selected mesh is usually a descendant of the object the state
|
|
107
|
+
* names.
|
|
108
|
+
*
|
|
109
|
+
* Both maps are live, so this is computed per call rather than cached —
|
|
110
|
+
* calls arrive at gesture rate (a gizmo drag start/end, a dev command),
|
|
111
|
+
* never per frame. `ctx.sceneIndex` is read AT CALL TIME, never captured:
|
|
112
|
+
* the R3F root backfills it once fiber resolves the scene, which can land
|
|
113
|
+
* after this component's first effect (`world-context.ts`'s
|
|
114
|
+
* `setSceneCamera`), so a destructured copy would be permanently absent.
|
|
115
|
+
*/
|
|
116
|
+
const bodyFor = (nodeId: string): RapierEditableBody | undefined => {
|
|
117
|
+
const object = ctx.sceneIndex?.byEntityId(nodeId);
|
|
118
|
+
if (!object) return undefined;
|
|
119
|
+
const byObject = new Map<THREE.Object3D, RapierRigidBody>();
|
|
120
|
+
for (const state of rigidBodyStates.values()) byObject.set(state.object, state.rigidBody);
|
|
121
|
+
for (let node: THREE.Object3D | null = object; node; node = node.parent) {
|
|
122
|
+
const body = byObject.get(node);
|
|
123
|
+
if (body) return body;
|
|
124
|
+
}
|
|
125
|
+
return undefined;
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
const adapter: PhysicsAdapter = {
|
|
129
|
+
...createRapierBodyEditing(bodyFor),
|
|
130
|
+
setDebugDrawEnabled: (enabled) => onDebugChange(enabled),
|
|
131
|
+
};
|
|
132
|
+
registerSystemAdapter('physics', adapter);
|
|
133
|
+
return () => registerSystemAdapter('physics', undefined);
|
|
134
|
+
}, [ctx, registerSystemAdapter, rigidBodyStates, onDebugChange]);
|
|
135
|
+
|
|
136
|
+
return null;
|
|
137
|
+
}
|