@vgai/engine 0.5.5 → 0.5.7
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,666 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { assertNever } from '../adapter/adapter-surface';
|
|
3
|
+
import { createAssetCache } from '../assets';
|
|
4
|
+
import { createGameLoop } from '../core/game-loop';
|
|
5
|
+
import { createHostRenderer } from '../setup/setup-renderer';
|
|
6
|
+
// TYPE-ONLY: `create-runtime.ts` must never value-import `pixi.js` — a canvas
|
|
7
|
+
// `RootMountSpec`'s `adapter` is supplied ALREADY-CONSTRUCTED by the caller, so
|
|
8
|
+
// the host only ever needs the seam's types.
|
|
9
|
+
import { createGame, createRootInstance, isFirstPartyMounted, } from './game';
|
|
10
|
+
import { createInputRouter, stackOrder } from './input-router';
|
|
11
|
+
import { installRenderControlHarness, isRenderModeRequested } from './render-control';
|
|
12
|
+
/**
|
|
13
|
+
* Register a three world for a freshly-mounted game onto the Game shell. Shared
|
|
14
|
+
* by `createGameRuntime` and every headless test harness
|
|
15
|
+
* (`test/game-root.test.ts`, `test/frame-order.test.ts`,
|
|
16
|
+
* `test/game-two-roots.test.ts`) so there is exactly one code path for this
|
|
17
|
+
* wiring (T7.1 slice 1, id-generalized in slice 3 for the two-world proof — stage
|
|
18
|
+
* 3) — `physics`/`collisions`/`camera`/ `frame` are populated from the mount's
|
|
19
|
+
* first-party `GameContext`/ `MountedSetupThreeRoot` when available, left
|
|
20
|
+
* `undefined` otherwise (an external adapter's mount has none of these
|
|
21
|
+
* first-party handles — `frame` in particular is what makes
|
|
22
|
+
* `GameInternal.runFrame` (T7.1 slice 2) fall back to a single opaque
|
|
23
|
+
* `mounted.update` call per substep for such a world).
|
|
24
|
+
*/
|
|
25
|
+
function firstPartyExtras(mounted) {
|
|
26
|
+
if (!isFirstPartyMounted(mounted))
|
|
27
|
+
return {};
|
|
28
|
+
return {
|
|
29
|
+
physics: mounted.ctx.physics,
|
|
30
|
+
collisions: mounted.ctx.collisions,
|
|
31
|
+
camera: mounted.ctx.camera,
|
|
32
|
+
frame: mounted.frame,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Register a three world onto the Game shell. `opts.id` defaults to
|
|
37
|
+
* `'main'` — the single-world callers (`createGameRuntime`, slice-1/2 tests)
|
|
38
|
+
* are unaffected; a second/third world (T7.1 slice 3's two-world proof, and
|
|
39
|
+
* real multi-world manifests later) pass an explicit id. This is the ONE
|
|
40
|
+
* registration code path for a three world, whatever its id.
|
|
41
|
+
*/
|
|
42
|
+
export function registerThreeRoot(game, adapter, mounted, opts) {
|
|
43
|
+
const world = createRootInstance({
|
|
44
|
+
id: opts?.id ?? 'main',
|
|
45
|
+
kind: 'three',
|
|
46
|
+
pausable: opts?.pausable ?? true,
|
|
47
|
+
adapter,
|
|
48
|
+
mounted,
|
|
49
|
+
scene: mounted.scene,
|
|
50
|
+
...firstPartyExtras(mounted),
|
|
51
|
+
});
|
|
52
|
+
game.registerRoot(world);
|
|
53
|
+
return world;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Register a canvas world onto the Game shell — the pixi analog of
|
|
57
|
+
* {@link registerThreeRoot}. `adapter` is the seam's own
|
|
58
|
+
* `RootAdapter<'canvas'>`; `RootInstance.adapter` itself only needs `.id`
|
|
59
|
+
* (`AdapterHandle`, `runtime/game.ts`), so this passes through with zero cast.
|
|
60
|
+
* `stage` is the one field every `MountedPixiRoot` actually carries.
|
|
61
|
+
*/
|
|
62
|
+
export function registerPixiRoot(game, adapter, mounted, opts) {
|
|
63
|
+
const id = opts?.id ?? 'main';
|
|
64
|
+
const world = createRootInstance({
|
|
65
|
+
id,
|
|
66
|
+
kind: 'canvas',
|
|
67
|
+
pausable: opts?.pausable ?? true,
|
|
68
|
+
adapter,
|
|
69
|
+
mounted,
|
|
70
|
+
stage: mounted.stage,
|
|
71
|
+
});
|
|
72
|
+
game.registerRoot(world);
|
|
73
|
+
return world;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Register a react world onto the Game shell (T6.2 slice 1) — the react
|
|
77
|
+
* analog of {@link registerThreeRoot}/{@link registerPixiRoot}. A react
|
|
78
|
+
* world has no `frame` hooks (react's own
|
|
79
|
+
* `createRoot` schedules its commits; `GameInternal.runFrame` correctly
|
|
80
|
+
* leaves a world with no `frame` untouched by its opaque-`update` fallback
|
|
81
|
+
* too, since `MountedReactGame` declares no `update`). `adapter` is typed
|
|
82
|
+
* as the real {@link ReactRootAdapter} shape (T7.5, same reasoning as
|
|
83
|
+
* `registerPixiRoot`'s doc comment above) — `RootInstance.adapter` only
|
|
84
|
+
* needs `.id`, so this passes through with zero cast.
|
|
85
|
+
*/
|
|
86
|
+
export function registerReactRoot(game, adapter, mounted, container, opts) {
|
|
87
|
+
const world = createRootInstance({
|
|
88
|
+
id: opts?.id ?? 'main',
|
|
89
|
+
kind: 'dom',
|
|
90
|
+
pausable: opts?.pausable ?? true,
|
|
91
|
+
adapter,
|
|
92
|
+
mounted,
|
|
93
|
+
container,
|
|
94
|
+
});
|
|
95
|
+
game.registerRoot(world);
|
|
96
|
+
return world;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Bootstrap the game host and mount a game adapter.
|
|
100
|
+
*
|
|
101
|
+
* `createGameRuntime` is the universal HOST: it owns the root surfaces,
|
|
102
|
+
* renderers, loop, and asset cache. Every game — including a one-root game —
|
|
103
|
+
* uses the same explicit adapter-root path.
|
|
104
|
+
*/
|
|
105
|
+
export async function createGameRuntime(config) {
|
|
106
|
+
return createRootsGameRuntime(config);
|
|
107
|
+
}
|
|
108
|
+
// ---------------------------------------------------------------------------
|
|
109
|
+
// Worlds path (T6.1 slice 1)
|
|
110
|
+
// ---------------------------------------------------------------------------
|
|
111
|
+
/** A stand-in `THREE.WebGLRenderer` for headless (`headless:true`) three
|
|
112
|
+
* roots — mirrors `SetupThreeRootAdapter.mount`'s own `headlessComposer`
|
|
113
|
+
* pattern (`adapter/setup-three-root-adapter.ts`): a headless first-party
|
|
114
|
+
* mount never calls a render-phase method on `host.renderer` at all, so
|
|
115
|
+
* this only needs to satisfy the handful of calls THIS file itself makes
|
|
116
|
+
* (`setPixelRatio`/`setClearColor`/`setSize` at mount, `dispose`/
|
|
117
|
+
* `forceContextLoss` at teardown) — never a real GL call. Node conformance
|
|
118
|
+
* tests only; never used when `headless` is left `false`/absent. */
|
|
119
|
+
function createHeadlessRendererStub() {
|
|
120
|
+
return {
|
|
121
|
+
setPixelRatio() { },
|
|
122
|
+
setClearColor() { },
|
|
123
|
+
setSize() { },
|
|
124
|
+
dispose() { },
|
|
125
|
+
forceContextLoss() { },
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
/** Mount one three `RootMountSpec` (canvas + renderer construction, per
|
|
129
|
+
* D5 §1/§4, then `registerThreeRoot`). Split out of
|
|
130
|
+
* `createRootsGameRuntime` purely to keep that function's own branching
|
|
131
|
+
* simple — see `mountOnePixiRoot` for the canvas sibling. */
|
|
132
|
+
async function mountOneThreeRoot(spec, ctx) {
|
|
133
|
+
const { game, canvas, w, h, dpr, isBottom, headless, assets } = ctx;
|
|
134
|
+
const renderer = headless
|
|
135
|
+
? createHeadlessRendererStub()
|
|
136
|
+
: createHostRenderer(canvas, w, h, undefined, {
|
|
137
|
+
alpha: !isBottom,
|
|
138
|
+
preserveDrawingBuffer: true,
|
|
139
|
+
});
|
|
140
|
+
renderer.setSize(w, h, false); // backing resolution only — CSS stacking owns layout size
|
|
141
|
+
// Defect E4.R1 (Fable review): `createHostRenderer`'s OWN construction-time
|
|
142
|
+
// `setSize` call (`setup-renderer.ts`, `updateStyle` defaulting `true` —
|
|
143
|
+
// unchanged there on purpose, see below) stamps `canvas.style.width`/
|
|
144
|
+
// `.height` to literal `${w}px`/`${h}px` the moment the renderer is built,
|
|
145
|
+
// OVERWRITING the container-relative `100%`/`100%` the surface-stacking
|
|
146
|
+
// loop above just set. The `renderer.setSize(w, h, false)` line right above
|
|
147
|
+
// this comment does NOT undo that stamp (updateStyle:false only skips
|
|
148
|
+
// TOUCHING style, it can't un-stamp a previous call) — so without this
|
|
149
|
+
// re-assertion, every roots-path three canvas' on-screen size was
|
|
150
|
+
// permanently pinned to whatever `w`/`h` it happened to mount at (usually
|
|
151
|
+
// the manifest's `resolution`, since standalone builds mount before a real
|
|
152
|
+
// container size is known — see `mount-manifest.ts`). Re-asserting here
|
|
153
|
+
// makes the CSS layout size and the render-buffer resolution fully
|
|
154
|
+
// independent, exactly like the react DOM world layer already is: this
|
|
155
|
+
// fixes the template-standalone bug (broken at any viewport other than the
|
|
156
|
+
// manifest's `resolution`, which is also Playwright's DEFAULT viewport —
|
|
157
|
+
// why it went unnoticed) and, for free, tri-world's pre-existing
|
|
158
|
+
// resize-staleness (the roots-path `resize()` below always calls
|
|
159
|
+
// `setSize(rw, rh, false)`, so nothing else was ever going to update this
|
|
160
|
+
// canvas' CSS after mount). `createHostRenderer`'s own default
|
|
161
|
+
// (`updateStyle:true`) is intentionally left alone — the LEGACY
|
|
162
|
+
// single-canvas path (editor play-mode's non-multi-world branch) still
|
|
163
|
+
// relies on that construction-time stamp + its own later `updateStyle:true`
|
|
164
|
+
// resizes for byte-identical behavior; this fix touches only the
|
|
165
|
+
// roots-path canvas, after the fact.
|
|
166
|
+
canvas.style.width = '100%';
|
|
167
|
+
canvas.style.height = '100%';
|
|
168
|
+
renderer.setPixelRatio(dpr);
|
|
169
|
+
if (!isBottom)
|
|
170
|
+
renderer.setClearColor(0x000000, 0); // D5 §1: alpha-clear above the bottom layer
|
|
171
|
+
const host = {
|
|
172
|
+
three: THREE,
|
|
173
|
+
surface: { canvas, width: w, height: h },
|
|
174
|
+
renderer,
|
|
175
|
+
assets,
|
|
176
|
+
headless,
|
|
177
|
+
game,
|
|
178
|
+
};
|
|
179
|
+
const mounted = await spec.adapter.mount(host);
|
|
180
|
+
registerThreeRoot(game, spec.adapter, mounted, { id: spec.id, pausable: spec.pausable });
|
|
181
|
+
return {
|
|
182
|
+
mountedEntry: { id: spec.id, kind: 'three', element: canvas, mounted, renderer },
|
|
183
|
+
routerEntry: { id: spec.id, zOrder: spec.zOrder ?? 0, canvas, hitTest: spec.hitTest },
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
/** Mount one canvas `RootMountSpec` (via its own `CanvasHostContext`, per D5
|
|
187
|
+
* §1/§3/§4, then `registerPixiRoot`) — the pixi sibling of
|
|
188
|
+
* `mountOneThreeRoot` above.
|
|
189
|
+
*
|
|
190
|
+
* Unlike `mountOneThreeRoot`, this needs no explicit `canvas.style.width`/
|
|
191
|
+
* `.height` re-assertion (E4.R1). `pixi-surface.ts` constructs its
|
|
192
|
+
* `Application` with `autoDensity: true`, which makes PIXI ITSELF re-stamp
|
|
193
|
+
* `canvas.style.width`/`.height` (real CSS px, matching the LOGICAL
|
|
194
|
+
* width/height passed to `resize()`) on every `app.renderer.resize()` call —
|
|
195
|
+
* including the one this world's `mounted.resize?.()` triggers from the
|
|
196
|
+
* roots-path `resize()` below. So while a pixi world's canvas can start
|
|
197
|
+
* pinned to the mount-time `w`/`h` (same as three, until PIXI's own
|
|
198
|
+
* construction-time resize runs), it self-heals the moment ANY real
|
|
199
|
+
* `session.resize(rw, rh)` fires — every shipped standalone entry
|
|
200
|
+
* (`packages/editor/template/src/main.ts`, `examples/tri-world/src/main.ts`)
|
|
201
|
+
* already calls `session.resize()` unconditionally right after mount, so
|
|
202
|
+
* this never surfaces as a lasting bug the way three' buffer-only resize
|
|
203
|
+
* did (never self-healing, by design — see above). */
|
|
204
|
+
async function mountOnePixiRoot(spec, ctx) {
|
|
205
|
+
const { game, canvas, w, h, dpr, headless, isBottom } = ctx;
|
|
206
|
+
const pixiHost = {
|
|
207
|
+
canvas,
|
|
208
|
+
width: w,
|
|
209
|
+
height: h,
|
|
210
|
+
game,
|
|
211
|
+
headless,
|
|
212
|
+
dpr,
|
|
213
|
+
transparent: !isBottom,
|
|
214
|
+
preserveDrawingBuffer: true,
|
|
215
|
+
};
|
|
216
|
+
const mounted = await spec.adapter.mount(pixiHost);
|
|
217
|
+
registerPixiRoot(game, spec.adapter, mounted, {
|
|
218
|
+
id: spec.id,
|
|
219
|
+
pausable: spec.pausable,
|
|
220
|
+
});
|
|
221
|
+
return {
|
|
222
|
+
mountedEntry: {
|
|
223
|
+
id: spec.id,
|
|
224
|
+
kind: 'canvas',
|
|
225
|
+
element: canvas,
|
|
226
|
+
mounted,
|
|
227
|
+
renderer: undefined,
|
|
228
|
+
},
|
|
229
|
+
routerEntry: {
|
|
230
|
+
id: spec.id,
|
|
231
|
+
zOrder: spec.zOrder ?? 0,
|
|
232
|
+
canvas,
|
|
233
|
+
hitTest: spec.hitTest,
|
|
234
|
+
},
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Mount one react `RootMountSpec` (T6.2 slice 1) — the react sibling of
|
|
239
|
+
* `mountOneThreeRoot`/`mountOnePixiRoot`. Unlike its canvas-backed siblings
|
|
240
|
+
* this returns NO `routerEntry`: a react world's DOM-root layer participates in
|
|
241
|
+
* D5's z-order/box stacking (the caller still creates and positions its `<div>`
|
|
242
|
+
* exactly like a canvas — see `createRootsGameRuntime`'s stack-building loop)
|
|
243
|
+
* but needs no entry in the delegating router's hit-test loop (§1.C — "DOM
|
|
244
|
+
* layers need no entry in the router's hit-test loop"): the layer's own
|
|
245
|
+
* `pointer-events` discipline (this file sets `none` on the layer by default;
|
|
246
|
+
* the mounted React tree opts specific elements back in with
|
|
247
|
+
* `pointer-events:auto`) is what lets its interactive elements claim events
|
|
248
|
+
* NATIVELY, via the real DOM, with zero router involvement — and lets a click
|
|
249
|
+
* over its non-interactive (transparent) area fall through to the canvas below
|
|
250
|
+
* it via the SAME native DOM hit-testing (a `pointer-events:none` element is
|
|
251
|
+
* invisible to hit-testing entirely, so the click lands on whatever real DOM
|
|
252
|
+
* element is beneath it — the router's normal canvas-vs-canvas forwarding,
|
|
253
|
+
* unaffected by this layer's presence).
|
|
254
|
+
*/
|
|
255
|
+
async function mountOneReactRoot(spec, game,
|
|
256
|
+
/** The ALREADY-created, already-stacked (position/z-index set, appended to
|
|
257
|
+
* `container`) DOM-root layer for this world — see
|
|
258
|
+
* `createRootsGameRuntime`'s surface-stack loop, which builds a `<div>`
|
|
259
|
+
* for every react-kind spec up front, in the SAME pass that builds every
|
|
260
|
+
* other world's canvas. This function must reuse that exact element (never
|
|
261
|
+
* create its own) so `RootInstance.reactRoot()` returns the SAME node
|
|
262
|
+
* that is actually positioned in the stack. */
|
|
263
|
+
layer) {
|
|
264
|
+
layer.style.pointerEvents = 'none';
|
|
265
|
+
// An absolutely-positioned layer with no width/height collapses to zero
|
|
266
|
+
// content size, so a child's
|
|
267
|
+
// own position:absolute offsets resolve against a degenerate containing
|
|
268
|
+
// block (found by the T6.2 slice-3 e2e — clicks landed outside the game).
|
|
269
|
+
layer.style.width = '100%';
|
|
270
|
+
layer.style.height = '100%';
|
|
271
|
+
const reactHost = { container: layer, game };
|
|
272
|
+
const mounted = await spec.adapter.mount(reactHost);
|
|
273
|
+
registerReactRoot(game, spec.adapter, mounted, layer, {
|
|
274
|
+
id: spec.id,
|
|
275
|
+
pausable: spec.pausable,
|
|
276
|
+
});
|
|
277
|
+
return {
|
|
278
|
+
mountedEntry: {
|
|
279
|
+
id: spec.id,
|
|
280
|
+
kind: 'dom',
|
|
281
|
+
element: layer,
|
|
282
|
+
mounted,
|
|
283
|
+
renderer: undefined,
|
|
284
|
+
},
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* The roots-path implementer behind {@link createGameRuntime} (T6.1 slice
|
|
289
|
+
* 1; react roots added T6.2 slice 1). Builds ONE surface per world — a
|
|
290
|
+
* canvas for three/canvas, a DOM-root `<div>` layer for react — stacked
|
|
291
|
+
* per D5 §1, z-order/ties exactly matching
|
|
292
|
+
* `manifest/load.ts`'s sort, ONE `Game`, and registers every world onto it
|
|
293
|
+
* via `registerThreeRoot`/`registerPixiRoot`/`registerReactRoot` — the
|
|
294
|
+
* SAME wiring `test/game-three-plus-pixi.test.ts` proves by hand for the
|
|
295
|
+
* three/pixi pair. Worlds MOUNT in `roots` ARRAY order ("manifest
|
|
296
|
+
* declaration order" — the frame/registration axis), independent of
|
|
297
|
+
* `zOrder` (the canvas-stacking/rendering axis) — the two orders can differ
|
|
298
|
+
* and both are honored correctly.
|
|
299
|
+
*/
|
|
300
|
+
/**
|
|
301
|
+
* Dev/e2e-only `window.__vgaiScene`/`__vgaiCamera` exposure for the roots
|
|
302
|
+
* path's DEFAULT world (E4) — split out of `createRootsGameRuntime` purely
|
|
303
|
+
* to keep that function's own cyclomatic complexity down. Mirrors the
|
|
304
|
+
* legacy single-world path's identical exposure (above, in this same file),
|
|
305
|
+
* using the SAME "first three world, else none" default-world rule the
|
|
306
|
+
* `GameSession.scene`/`.camera` getters alias (`Game.defaultRoot`): a
|
|
307
|
+
* non-threejs default world (or none at all) publishes neither global,
|
|
308
|
+
* exactly like those getters return `undefined` in that case. Returns a
|
|
309
|
+
* retraction callback — identity-guarded (a newer session's globals must
|
|
310
|
+
* never be clobbered by an older session's stop, same reason the legacy
|
|
311
|
+
* path's own cleanup guards it) — that is a no-op when nothing was
|
|
312
|
+
* published (non-DEV build, or non-threejs default world).
|
|
313
|
+
*/
|
|
314
|
+
function installDefaultRootDevGlobals(game) {
|
|
315
|
+
if (!import.meta.env?.DEV)
|
|
316
|
+
return () => { };
|
|
317
|
+
const defaultMounted = game.defaultRoot.mounted;
|
|
318
|
+
if (defaultMounted.kind !== 'three')
|
|
319
|
+
return () => { };
|
|
320
|
+
const scene = defaultMounted.scene;
|
|
321
|
+
const w = window;
|
|
322
|
+
w['__vgaiScene'] = scene;
|
|
323
|
+
// An ACCESSOR, not a value read once: a world may replace its camera after
|
|
324
|
+
// mount (fiber's `set({ camera })` — drei's `makeDefault`, or a translated
|
|
325
|
+
// Godot world installing the camera its `.tscn` authors), and a snapshot
|
|
326
|
+
// here reads as authoritative to the probe that reaches for it while naming
|
|
327
|
+
// a camera the frame no longer uses. The retraction guard compares the
|
|
328
|
+
// GETTER's identity, which is the same "don't clobber a newer session"
|
|
329
|
+
// rule the value comparison was.
|
|
330
|
+
const readCamera = () => defaultMounted.camera;
|
|
331
|
+
Object.defineProperty(w, '__vgaiCamera', {
|
|
332
|
+
get: readCamera,
|
|
333
|
+
configurable: true,
|
|
334
|
+
enumerable: true,
|
|
335
|
+
});
|
|
336
|
+
return () => {
|
|
337
|
+
if (w['__vgaiScene'] === scene)
|
|
338
|
+
delete w['__vgaiScene'];
|
|
339
|
+
if (Object.getOwnPropertyDescriptor(w, '__vgaiCamera')?.get === readCamera)
|
|
340
|
+
delete w['__vgaiCamera'];
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Mount + register every world spec, in ARRAY (declaration) order — split
|
|
345
|
+
* out of `createRootsGameRuntime` purely to keep that function's own
|
|
346
|
+
* cyclomatic complexity down (E4, same reason `mountOneThreeRoot`/
|
|
347
|
+
* `mountOnePixiRoot` are already split out). React roots contribute NO
|
|
348
|
+
* router entry ("DOM layers need no entry in the router's hit-test loop"):
|
|
349
|
+
* their layer's own `pointer-events` discipline handles claim/fall-through
|
|
350
|
+
* natively, with zero router involvement (see `mountOneReactRoot`'s doc
|
|
351
|
+
* comment).
|
|
352
|
+
*/
|
|
353
|
+
async function mountAllRootSpecs(mountSpecs, bottomId, inputs) {
|
|
354
|
+
const { surfacesById, ...shared } = inputs;
|
|
355
|
+
const mountedEntries = [];
|
|
356
|
+
const routerEntries = [];
|
|
357
|
+
for (const spec of mountSpecs) {
|
|
358
|
+
const isBottom = spec.id === bottomId;
|
|
359
|
+
if (spec.kind === 'dom') {
|
|
360
|
+
const layer = surfacesById.get(spec.id);
|
|
361
|
+
const { mountedEntry } = await mountOneReactRoot(spec, shared.game, layer);
|
|
362
|
+
mountedEntries.push(mountedEntry);
|
|
363
|
+
continue;
|
|
364
|
+
}
|
|
365
|
+
const canvas = surfacesById.get(spec.id);
|
|
366
|
+
const oneCtx = { ...shared, canvas, isBottom };
|
|
367
|
+
let mountedEntry;
|
|
368
|
+
let routerEntry;
|
|
369
|
+
if (spec.kind === 'three') {
|
|
370
|
+
({ mountedEntry, routerEntry } = await mountOneThreeRoot(spec, oneCtx));
|
|
371
|
+
}
|
|
372
|
+
else if (spec.kind === 'canvas') {
|
|
373
|
+
({ mountedEntry, routerEntry } = await mountOnePixiRoot(spec, oneCtx));
|
|
374
|
+
}
|
|
375
|
+
else {
|
|
376
|
+
// Exhaustiveness guard (§7.4-2): 'react' was already handled by the
|
|
377
|
+
// early `continue` above, so only a hypothetical 4th `AdapterSurface` can
|
|
378
|
+
// reach here — fail loudly rather than silently defaulting. `spec`
|
|
379
|
+
// itself (not `spec.kind`) is what TS has narrowed to `never`, since
|
|
380
|
+
// `RootMountSpec` is a discriminated union at the object level.
|
|
381
|
+
assertNever(spec, 'create-runtime mount loop');
|
|
382
|
+
}
|
|
383
|
+
mountedEntries.push(mountedEntry);
|
|
384
|
+
routerEntries.push(routerEntry);
|
|
385
|
+
}
|
|
386
|
+
return { mountedEntries, routerEntries };
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* G3/FT-11 — publish the render-control harness (`render-control.ts`) for a
|
|
390
|
+
* live session, returning its retraction (wired into the session's own
|
|
391
|
+
* `stop()`, same leave-nothing-live rule as the debug bridge's `uninstall()`
|
|
392
|
+
* in mount-manifest.ts — render-control has no uninstall surface of its own,
|
|
393
|
+
* a render page being a single-load host by design, so the retraction is
|
|
394
|
+
* the publication's inverse). Split out of `createRootsGameRuntime` purely
|
|
395
|
+
* to keep that function's cyclomatic complexity down (the same reason
|
|
396
|
+
* `mountAllRootSpecs`/`installDefaultRootDevGlobals` are split out).
|
|
397
|
+
*
|
|
398
|
+
* The clock is a documented no-op: a manifest-mounted game has no global
|
|
399
|
+
* cinematic AnimationClock to seek (a cinematic fixture that HAS one
|
|
400
|
+
* installs its own harness with the real clock, e.g.
|
|
401
|
+
* packages/engine/e2e/render-cinematic/main.ts) — the meaningful advance
|
|
402
|
+
* path for a plain game is `simulateSubsteps` (I5 `--simulate`), which
|
|
403
|
+
* drives `game.runFrame`.
|
|
404
|
+
*/
|
|
405
|
+
function installSessionRenderHarness(game, location, targetOverride) {
|
|
406
|
+
const target = targetOverride ??
|
|
407
|
+
(typeof window !== 'undefined' ? window : undefined);
|
|
408
|
+
if (target === undefined)
|
|
409
|
+
return undefined;
|
|
410
|
+
installRenderControlHarness({
|
|
411
|
+
game,
|
|
412
|
+
clock: {
|
|
413
|
+
seek() {
|
|
414
|
+
/* no global cinematic clock on a manifest-mounted game — see above */
|
|
415
|
+
},
|
|
416
|
+
seekFrame() {
|
|
417
|
+
/* intentional no-op, as seek() */
|
|
418
|
+
},
|
|
419
|
+
},
|
|
420
|
+
readiness: {
|
|
421
|
+
// Mount is complete by the time this harness exists (the install site
|
|
422
|
+
// in `createRootsGameRuntime` is after `mountAllRootSpecs`
|
|
423
|
+
// resolved) — the hook resolving immediately IS the readiness
|
|
424
|
+
// statement, not an assumption.
|
|
425
|
+
scene() { },
|
|
426
|
+
},
|
|
427
|
+
location,
|
|
428
|
+
target,
|
|
429
|
+
});
|
|
430
|
+
return () => {
|
|
431
|
+
delete target['__vgaiRender'];
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
async function createRootsGameRuntime(config) {
|
|
435
|
+
const { container, roots: specs, width, height, headless = false, seed, playtest } = config;
|
|
436
|
+
if (specs.length === 0) {
|
|
437
|
+
throw new Error('createGameRuntime: `roots` must contain at least one root.');
|
|
438
|
+
}
|
|
439
|
+
const mountSpecs = specs;
|
|
440
|
+
const w = Math.max(1, width ?? container.clientWidth ?? 0);
|
|
441
|
+
const h = Math.max(1, height ?? container.clientHeight ?? 0);
|
|
442
|
+
const dpr = headless
|
|
443
|
+
? 1
|
|
444
|
+
: Math.min(typeof window !== 'undefined' ? window.devicePixelRatio || 1 : 1, 2);
|
|
445
|
+
if (!container.style.position)
|
|
446
|
+
container.style.position = 'relative';
|
|
447
|
+
// --- Surface stack (D5 §1): DOM/z-order follows zOrder, ties -> array order
|
|
448
|
+
// — computed FIRST (bottom -> top) so both the z-index assignment below and
|
|
449
|
+
// the router's default-claim rule share one definition. A react world's
|
|
450
|
+
// DOM-root layer shares this SAME stacking pass (T6.2 slice 1 — "one
|
|
451
|
+
// stacking model, no special case") even though it is a `<div>`, not a
|
|
452
|
+
// canvas, and carries no `hitTest` (the router never sees react entries at
|
|
453
|
+
// all — see the dispatch loop below). ---
|
|
454
|
+
// Dev layers sit TOPMOST, above every non-dev root, whatever zOrder either
|
|
455
|
+
// declares: a dev GUI the game can paint over is not a dev GUI. Expressed as
|
|
456
|
+
// two independent `stackOrder` passes concatenated rather than a magic
|
|
457
|
+
// zOrder value, so `stackOrder`'s one rule (ascending zOrder, ties -> array
|
|
458
|
+
// order) still governs WITHIN each band and nothing has to reason about what
|
|
459
|
+
// number is "high enough".
|
|
460
|
+
const claimEntries = mountSpecs.map((spec) => ({
|
|
461
|
+
id: spec.id,
|
|
462
|
+
zOrder: spec.zOrder ?? 0,
|
|
463
|
+
hitTest: spec.hitTest,
|
|
464
|
+
dev: spec.dev === true,
|
|
465
|
+
}));
|
|
466
|
+
const stacked = [
|
|
467
|
+
...stackOrder(claimEntries.filter((e) => !e.dev)),
|
|
468
|
+
...stackOrder(claimEntries.filter((e) => e.dev)),
|
|
469
|
+
];
|
|
470
|
+
const bottomId = stacked[0]?.id;
|
|
471
|
+
const kindById = new Map(mountSpecs.map((spec) => [spec.id, spec.kind]));
|
|
472
|
+
const surfacesById = new Map();
|
|
473
|
+
stacked.forEach((entry, i) => {
|
|
474
|
+
const isReact = kindById.get(entry.id) === 'dom';
|
|
475
|
+
const surface = document.createElement(isReact ? 'div' : 'canvas');
|
|
476
|
+
surface.dataset['vgaiRootSurface'] = 'true';
|
|
477
|
+
// The capture's marker (`composite-screenshot.ts` reads exactly this
|
|
478
|
+
// attribute): a dev layer is excluded from a play capture unless the
|
|
479
|
+
// capture asks for it, because a contaminated "does the game look right"
|
|
480
|
+
// frame is worthless.
|
|
481
|
+
if (entry.dev)
|
|
482
|
+
surface.dataset['vgaiDevLayer'] = 'true';
|
|
483
|
+
if (!isReact) {
|
|
484
|
+
const canvas = surface;
|
|
485
|
+
canvas.width = w;
|
|
486
|
+
canvas.height = h;
|
|
487
|
+
}
|
|
488
|
+
// Defect E4.R1 (Fable review): layout size is ALWAYS container-relative
|
|
489
|
+
// (`width:100%;height:100%`), fully decoupled from the surface's
|
|
490
|
+
// intrinsic buffer resolution (`w`/`h`, set on the canvas element's
|
|
491
|
+
// `width`/`height` ATTRIBUTES above — a device-pixel/render-resolution
|
|
492
|
+
// concern only). Without this, a canvas with no CSS size falls back to
|
|
493
|
+
// its `width`/`height` attribute as its CSS layout size too, so whatever
|
|
494
|
+
// stamped those attributes (`createHostRenderer`'s construction-time
|
|
495
|
+
// `setSize`, `mountOneThreeRoot` below) pins the ON-SCREEN size — see
|
|
496
|
+
// that function's doc comment for the concrete bug this caused (template
|
|
497
|
+
// standalone at any viewport ≠ the manifest resolution). Setting it HERE
|
|
498
|
+
// too (not just in `mountOneThreeRoot`) means every surface, whatever
|
|
499
|
+
// kind, starts container-relative from its very first paint, before any
|
|
500
|
+
// per-kind mount work has even run.
|
|
501
|
+
// `contain:layout paint` makes each surface the CONTAINING BLOCK for
|
|
502
|
+
// `position:fixed` descendants (and clips overflow to the world's
|
|
503
|
+
// rectangle): full-screen game UI written the natural way (`fixed;
|
|
504
|
+
// inset:0`) then fills the WORLD, not the page. Without it, `fixed` UI
|
|
505
|
+
// looks correct standalone (surface == window) but escapes over the
|
|
506
|
+
// editor chrome whenever the surface is a sub-rectangle of the page —
|
|
507
|
+
// and toggles behavior when any ancestor gains a transform (e.g. the
|
|
508
|
+
// editor's space-pan). Dogfooded 2026-07-12 via a react shell world.
|
|
509
|
+
surface.style.cssText = `position:absolute;top:0;left:0;width:100%;height:100%;z-index:${i + 1};contain:layout paint;`;
|
|
510
|
+
container.appendChild(surface);
|
|
511
|
+
surfacesById.set(entry.id, surface);
|
|
512
|
+
});
|
|
513
|
+
const assets = createAssetCache();
|
|
514
|
+
// Every manifest/host-mounted game is a deterministic-capture candidate —
|
|
515
|
+
// the render-control seam (`?vgai-render=1`, render-control.ts) is wired
|
|
516
|
+
// HERE, at the one host every boot path shares (mountGameFromManifest,
|
|
517
|
+
// mountManifestRoots, and direct createGameRuntime callers all reach this
|
|
518
|
+
// function), instead of asking every project's entry page to install it
|
|
519
|
+
// the way the e2e fixtures do. Production-protected twice over:
|
|
520
|
+
// `isRenderModeRequested` gates on the query param, and
|
|
521
|
+
// `installRenderControlHarness` re-checks it internally (its AC 4), so a
|
|
522
|
+
// normal gameplay page sees zero change.
|
|
523
|
+
const renderModeLocation = config.renderControl?.location ?? (typeof window !== 'undefined' ? window.location : undefined);
|
|
524
|
+
const renderMode = renderModeLocation !== undefined && isRenderModeRequested(renderModeLocation);
|
|
525
|
+
let started = false;
|
|
526
|
+
const loop = createGameLoop({
|
|
527
|
+
fixedTimestep: 1 / 60,
|
|
528
|
+
maxSubSteps: 8,
|
|
529
|
+
// Render mode runs the loop in EXTERNAL-DRIVE mode (game-loop.ts, I2):
|
|
530
|
+
// no RAF is ever armed, so nothing advances gameplay between the capture
|
|
531
|
+
// host's explicit `simulateSubsteps`/`renderOnce` calls — wall-clock time
|
|
532
|
+
// passing while a screenshot is taken must not move the world.
|
|
533
|
+
externalDrive: renderMode,
|
|
534
|
+
// WO-P13 — sim and presentation are wired to different callbacks here:
|
|
535
|
+
// `update` runs the gameplay phases once per consumed fixed substep with
|
|
536
|
+
// `preRender`/`render` withheld, and `render` runs those two once per real
|
|
537
|
+
// display frame with the interpolation alpha. Both closures are invoked
|
|
538
|
+
// only from the loop's own rAF arm, which `externalDrive` never arms — so
|
|
539
|
+
// a capture/offline-export page (`renderMode`) reaches neither, and its
|
|
540
|
+
// `simulateSubsteps` → `game.runFrame(fixedDt)` path stays frame-exact,
|
|
541
|
+
// rendering inside the substep exactly as it did before this flip.
|
|
542
|
+
update: (dt) => {
|
|
543
|
+
if (started)
|
|
544
|
+
game.runFrame(dt, { skipRenderPhases: true });
|
|
545
|
+
},
|
|
546
|
+
render: (alpha, displayDt) => {
|
|
547
|
+
if (started)
|
|
548
|
+
game.runRenderFrame(alpha, displayDt);
|
|
549
|
+
},
|
|
550
|
+
});
|
|
551
|
+
const game = createGame({ loop, assets, seed, playtest });
|
|
552
|
+
// --- Mount + register every world, in ARRAY (declaration) order. ---
|
|
553
|
+
// Split out into its own top-level function purely to keep
|
|
554
|
+
// `createRootsGameRuntime`'s own cyclomatic complexity down (E4) — same
|
|
555
|
+
// reason `mountOneThreeRoot`/`mountOnePixiRoot` are already split out
|
|
556
|
+
// below.
|
|
557
|
+
const { mountedEntries, routerEntries } = await mountAllRootSpecs(mountSpecs, bottomId, {
|
|
558
|
+
game,
|
|
559
|
+
surfacesById,
|
|
560
|
+
w,
|
|
561
|
+
h,
|
|
562
|
+
dpr,
|
|
563
|
+
headless,
|
|
564
|
+
assets,
|
|
565
|
+
});
|
|
566
|
+
// --- Delegating input router (D5 §2a) ---
|
|
567
|
+
const router = createInputRouter(container, routerEntries);
|
|
568
|
+
started = true;
|
|
569
|
+
loop.start();
|
|
570
|
+
// Expose scene & camera for dev tools / e2e tests — mirrors the legacy
|
|
571
|
+
// single-world path's identical dev-only exposure above, generalized to
|
|
572
|
+
// the roots path's DEFAULT world (E4): `mountGameFromManifest`/
|
|
573
|
+
// `mountManifestRoots` route every caller (including a
|
|
574
|
+
// single-threejs-world scaffold project) through THIS path, so a caller
|
|
575
|
+
// migrating off the legacy `{canvas, adapter}` call must not silently
|
|
576
|
+
// lose `window.__vgaiScene`/`__vgaiCamera` — real e2e/dev tooling
|
|
577
|
+
// depends on them
|
|
578
|
+
// (`packages/editor/e2e/tests/04-standalone-game.spec.ts`). Split into
|
|
579
|
+
// its own top-level helper (with its retraction counterpart below)
|
|
580
|
+
// purely to keep this function's own cyclomatic complexity down.
|
|
581
|
+
const retractDevGlobals = installDefaultRootDevGlobals(game);
|
|
582
|
+
// G3/FT-11 — publish `window.__vgaiRender` for the deterministic capture
|
|
583
|
+
// host. Installed at the TAIL of the mount (same position as
|
|
584
|
+
// mount-manifest.ts's debug bridge): every world's `mount()`/`setup()` has
|
|
585
|
+
// resolved by now, so the harness's `scene` readiness hook reporting ready
|
|
586
|
+
// is truthful. See `installSessionRenderHarness` below.
|
|
587
|
+
const retractRenderHarness = renderMode && renderModeLocation !== undefined
|
|
588
|
+
? installSessionRenderHarness(game, renderModeLocation, config.renderControl?.target)
|
|
589
|
+
: undefined;
|
|
590
|
+
function fullCleanup() {
|
|
591
|
+
loop.stop();
|
|
592
|
+
router.dispose();
|
|
593
|
+
for (const entry of mountedEntries) {
|
|
594
|
+
entry.mounted.dispose();
|
|
595
|
+
entry.renderer?.dispose();
|
|
596
|
+
entry.renderer?.forceContextLoss();
|
|
597
|
+
// Remove from the element's CURRENT parent, not the mount-time
|
|
598
|
+
// `container`: the editor's Game panel re-parents the live surfaces
|
|
599
|
+
// when its mount element swaps (fill <-> device preset, W2c), and
|
|
600
|
+
// `container.removeChild` would throw NotFoundError after such a move.
|
|
601
|
+
// `container` remains the fallback for hosts whose element stand-ins
|
|
602
|
+
// never wire `parentNode` (headless unit fixtures); an element already
|
|
603
|
+
// detached by such a host is a no-op via the catch.
|
|
604
|
+
try {
|
|
605
|
+
(entry.element.parentNode ?? container).removeChild(entry.element);
|
|
606
|
+
}
|
|
607
|
+
catch {
|
|
608
|
+
/* already detached — nothing to remove */
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
game.dispose();
|
|
612
|
+
retractDevGlobals();
|
|
613
|
+
retractRenderHarness?.();
|
|
614
|
+
}
|
|
615
|
+
return {
|
|
616
|
+
stop: fullCleanup,
|
|
617
|
+
// D10/T7.6: `Game.play` fans out per-world pausable/loop-gate/audio-gate
|
|
618
|
+
// semantics itself now (see the legacy path's identical comment above) —
|
|
619
|
+
// a `pausable: false` world (a menu/HUD world) keeps ticking while every
|
|
620
|
+
// other world freezes, which the old blind `for (const entry of
|
|
621
|
+
// mountedEntries) entry.mounted.setPaused?.(true)` fan-out (with no
|
|
622
|
+
// `pausable` check at all) could never express.
|
|
623
|
+
pause() {
|
|
624
|
+
game.play.pause();
|
|
625
|
+
},
|
|
626
|
+
resume() {
|
|
627
|
+
game.play.resume();
|
|
628
|
+
},
|
|
629
|
+
step() {
|
|
630
|
+
game.play.step();
|
|
631
|
+
},
|
|
632
|
+
resize(rw, rh, pixelRatio) {
|
|
633
|
+
const safeWidth = Math.max(1, rw);
|
|
634
|
+
const safeHeight = Math.max(1, rh);
|
|
635
|
+
for (const entry of mountedEntries) {
|
|
636
|
+
// W2c device preview: re-pin DPR before setSize so the drawing
|
|
637
|
+
// buffer (and the first-party composer, whose `mounted.resize` reads
|
|
638
|
+
// `getDrawingBufferSize`) picks it up in this same pass. Pixi/react
|
|
639
|
+
// worlds have no `entry.renderer` and keep their own resolution.
|
|
640
|
+
if (pixelRatio !== undefined)
|
|
641
|
+
entry.renderer?.setPixelRatio(pixelRatio);
|
|
642
|
+
entry.renderer?.setSize(safeWidth, safeHeight, false);
|
|
643
|
+
entry.mounted.resize?.(safeWidth, safeHeight);
|
|
644
|
+
}
|
|
645
|
+
},
|
|
646
|
+
// `GameSession.scene`/`.camera`/`.mounted` alias `Game.defaultRoot` (T6.1
|
|
647
|
+
// slice 1's "first three world, else first world" rule) — a legacy
|
|
648
|
+
// convenience shaped for the threejs-only past. T7.5 narrows the read via
|
|
649
|
+
// the `kind` discriminant instead of a blind `.scene`/`.camera` cast
|
|
650
|
+
// through a nonexistent property (identical behavior to before: still
|
|
651
|
+
// `undefined` for a roots-path session whose default world isn't
|
|
652
|
+
// three — real per-world surface routing for that case is T7.6's).
|
|
653
|
+
get scene() {
|
|
654
|
+
const m = game.defaultRoot.mounted;
|
|
655
|
+
return (m.kind === 'three' ? m.scene : undefined);
|
|
656
|
+
},
|
|
657
|
+
get camera() {
|
|
658
|
+
const m = game.defaultRoot.mounted;
|
|
659
|
+
return (m.kind === 'three' ? m.camera : undefined);
|
|
660
|
+
},
|
|
661
|
+
get mounted() {
|
|
662
|
+
return game.defaultRoot.mounted;
|
|
663
|
+
},
|
|
664
|
+
game,
|
|
665
|
+
};
|
|
666
|
+
}
|