@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,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `pixiReactRootFactory` — mount a `canvas` root whose entry module
|
|
3
|
+
* DEFAULT-EXPORTS a React component.
|
|
4
|
+
*
|
|
5
|
+
* A model asked for a 2D world writes:
|
|
6
|
+
*
|
|
7
|
+
* ```tsx
|
|
8
|
+
* export default function World() {
|
|
9
|
+
* return <pixiContainer><pixiSprite texture={Texture.WHITE} /></pixiContainer>;
|
|
10
|
+
* }
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* It does NOT write `export const adapter = createPixiReactAdapter({ id, content })`.
|
|
14
|
+
* That export is vgai ceremony wrapped around a component the author already
|
|
15
|
+
* wrote. The `three` and `dom` roots both settled this convention — read
|
|
16
|
+
* `entryModule.default` and wrap it — and this is the same contract for canvas
|
|
17
|
+
* roots, so all three surfaces answer "what do I export?" the same way.
|
|
18
|
+
*
|
|
19
|
+
* ## Why this is NOT in `mount-game.ts`
|
|
20
|
+
*
|
|
21
|
+
* The kind registry beside `mount-game.ts` is deliberately dependency-free:
|
|
22
|
+
* registering a canvas factory there would make `pixi.js` + `@pixi/react`
|
|
23
|
+
* unconditional for every game, including three-only ones. `canvas-react` is
|
|
24
|
+
* the opt-in module that owns those dependencies, so the factory lives here and
|
|
25
|
+
* a project opts in with `registerAdapter('canvas', pixiReactRootFactory)`.
|
|
26
|
+
*
|
|
27
|
+
* ## Compatibility
|
|
28
|
+
*
|
|
29
|
+
* An `adapter` export still wins, so a game needing full control over its own
|
|
30
|
+
* `RootAdapter<'canvas'>` keeps it.
|
|
31
|
+
*/
|
|
32
|
+
import { createElement } from 'react';
|
|
33
|
+
import { createPixiReactAdapter } from './pixi-react-adapter';
|
|
34
|
+
/**
|
|
35
|
+
* What a canvas entry module MEANS, in one place.
|
|
36
|
+
*
|
|
37
|
+
* Two callers need this answer and must never disagree about it: the runtime
|
|
38
|
+
* mount ({@link pixiReactRootFactory}, below) and the EDITOR, which resolves
|
|
39
|
+
* the same entry for play mode and for the design-time layer. When only one
|
|
40
|
+
* side knows about the default-export shape, a world plays fine and shows
|
|
41
|
+
* "(no scene loaded)" in edit mode — the exact split the three lane already
|
|
42
|
+
* paid for.
|
|
43
|
+
*
|
|
44
|
+
* Returns `null` when the module is neither shape — the callers differ on what
|
|
45
|
+
* to do about that (the factory throws; the editor reports a mount failure on
|
|
46
|
+
* that root's boundary node and leaves every sibling working).
|
|
47
|
+
*/
|
|
48
|
+
export function resolveCanvasEntryAdapter(entryModule, rootId) {
|
|
49
|
+
const mod = entryModule;
|
|
50
|
+
if (mod?.adapter)
|
|
51
|
+
return mod.adapter;
|
|
52
|
+
if (typeof mod?.default === 'function') {
|
|
53
|
+
return createPixiReactAdapter({
|
|
54
|
+
id: rootId,
|
|
55
|
+
content: createElement(mod.default),
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Register with `registerAdapter('canvas', pixiReactRootFactory)`.
|
|
62
|
+
*
|
|
63
|
+
* Resolution order mirrors the three lane's (explicit adapter wins) and then
|
|
64
|
+
* accepts the default-exported component.
|
|
65
|
+
*/
|
|
66
|
+
export const pixiReactRootFactory = (root, ctx) => {
|
|
67
|
+
const adapter = resolveCanvasEntryAdapter(ctx.entryModule, root.id);
|
|
68
|
+
if (adapter)
|
|
69
|
+
return { kind: 'canvas', adapter };
|
|
70
|
+
throw new Error(`pixiReactRootFactory: entry module "${root.entry ?? '(none)'}" for root "${root.id}" must ` +
|
|
71
|
+
'default-export a React component (`export default function World() { … }`) — or export ' +
|
|
72
|
+
'an `adapter` for full control.');
|
|
73
|
+
};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `createCanvasRootContext` — the ENGINE runtime a canvas world owns, split out
|
|
3
|
+
* of `./pixi-react-adapter.tsx` so it stays react-free and headlessly
|
|
4
|
+
* unit-testable (`test/canvas-react-context-parity.test.tsx`).
|
|
5
|
+
*
|
|
6
|
+
* This is the canvas surface's answer to the same question
|
|
7
|
+
* `world3d-react/world-context.ts` answers for three: what does a component
|
|
8
|
+
* inside the world tree reach when it asks the engine for something?
|
|
9
|
+
*
|
|
10
|
+
* 1. **`ctx.debug` / `ctx.random` / `ctx.game` / `ctx.roots` are wired** from
|
|
11
|
+
* the ONE game-scoped registry (`getDebugRegistry(host.game)`), so a
|
|
12
|
+
* component's effect can `ctx.debug.registerStateProvider(...)` and be
|
|
13
|
+
* visible to `vgai eval`/the editor's debug panels.
|
|
14
|
+
* 2. **`ctx.input` is the game-owned `InputManager`** (`host.game.input` — the
|
|
15
|
+
* same instance every sibling root shares), and this module registers the
|
|
16
|
+
* per-world debug-registry seams (`setVirtualInputTarget`/
|
|
17
|
+
* `setInputActionsSource`/`setInputTraceSource`) that make `game.input.*`
|
|
18
|
+
* (the bot-input doctrine) resolve instead of throwing
|
|
19
|
+
* `DEBUG_INPUT_UNAVAILABLE`. The project's input map loads through
|
|
20
|
+
* `Game.loadInputMap` (the game-owned, load-once path every root shares).
|
|
21
|
+
* A missing/unparseable map degrades LOUDLY without failing the mount — a
|
|
22
|
+
* canvas world with no declared actions is legal.
|
|
23
|
+
* 3. **Absent subsystems fail loudly at the ctx surface.** A canvas world
|
|
24
|
+
* builds no THREE scene/camera, no Rapier world, no composer, no first-party
|
|
25
|
+
* audio/particles/debug-draw, and is handed no `AssetCache` (the canvas host
|
|
26
|
+
* context carries none — see `adapter/host-context.ts`). Reading those
|
|
27
|
+
* `ctx` fields yields a throwing getter naming the limitation and the
|
|
28
|
+
* sanctioned alternative, never a silent `undefined`.
|
|
29
|
+
*
|
|
30
|
+
* The Pixi handles themselves are deliberately NOT re-exposed here: a component
|
|
31
|
+
* reaches the live `Application` (and therefore `app.stage`, `app.renderer`,
|
|
32
|
+
* `app.ticker`) through `@pixi/react`'s own `useApplication()`, and its assets
|
|
33
|
+
* through Pixi's own `Assets`. Re-publishing them on `ctx` would be a wrapper
|
|
34
|
+
* standing between the author and the library.
|
|
35
|
+
*/
|
|
36
|
+
import type { Application } from 'pixi.js';
|
|
37
|
+
import type { CanvasHostContext } from '../adapter';
|
|
38
|
+
import type { SystemAdapters } from '../adapter/system-adapter';
|
|
39
|
+
import { createSystemRunner } from '../core/system-runner';
|
|
40
|
+
import type { GameContext } from '../runtime/types';
|
|
41
|
+
/** The conventional input-map location every scaffolded project ships. Shared
|
|
42
|
+
* verbatim with the three lane — a project has ONE input map, whatever surface
|
|
43
|
+
* reads it. */
|
|
44
|
+
export declare const DEFAULT_INPUT_MAP_PATH = "/inputmaps/default.inputmap.json";
|
|
45
|
+
export interface CanvasRootContextOptions {
|
|
46
|
+
/** World id — provenance for every debug-registry registration (matches the
|
|
47
|
+
* manifest root id). */
|
|
48
|
+
readonly id: string;
|
|
49
|
+
/**
|
|
50
|
+
* Input map to load through `Game.loadInputMap` (game-owned, load-once —
|
|
51
|
+
* several roots asking for the SAME path share one load; competing paths
|
|
52
|
+
* throw there). Defaults to {@link DEFAULT_INPUT_MAP_PATH}. Pass `null` to
|
|
53
|
+
* skip loading (a world with no actions). Ignored when no `host.game` is
|
|
54
|
+
* present.
|
|
55
|
+
*/
|
|
56
|
+
readonly inputMapPath?: string | null | undefined;
|
|
57
|
+
}
|
|
58
|
+
/** What {@link createCanvasRootContext} returns — the engine runtime one canvas
|
|
59
|
+
* world owns, plus the wiring hooks the adapter's `mount()` drives. */
|
|
60
|
+
export interface CanvasRootRuntime {
|
|
61
|
+
/** The (partial, loud-on-absence) `GameContext` this world's components read
|
|
62
|
+
* through `useGameContext`. See this module's header for what is present. */
|
|
63
|
+
readonly ctx: GameContext;
|
|
64
|
+
/** The world-local phase runner `mount().update(dt)` ticks. */
|
|
65
|
+
readonly systems: ReturnType<typeof createSystemRunner>;
|
|
66
|
+
/** The mounted world's `SystemAdapters` bag (`mounted.systems`) —
|
|
67
|
+
* `ctx.registerSystemAdapter` writes into it; `debug` is pre-seeded. */
|
|
68
|
+
readonly systemAdapters: SystemAdapters;
|
|
69
|
+
/** Resolves once the input map load settles (immediately when skipped).
|
|
70
|
+
* Never rejects — a failed load reports loudly and resolves. */
|
|
71
|
+
readonly inputMapReady: Promise<void>;
|
|
72
|
+
/** Backfill the live `Application` once `@pixi/react` has initialized it —
|
|
73
|
+
* before any tick can run. Read back via {@link CanvasRootRuntime.app}. */
|
|
74
|
+
setApplication(app: Application): void;
|
|
75
|
+
/** The live `Application`, or `null` before the first commit resolves it. */
|
|
76
|
+
readonly app: Application | null;
|
|
77
|
+
/** Strip this world's debug registrations (scoped, so sibling roots and
|
|
78
|
+
* react-door registrations are untouched when a Game hosts this world) and
|
|
79
|
+
* dispose a clock this mount created. */
|
|
80
|
+
dispose(): void;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Build the engine runtime for one canvas world from a `CanvasHostContext`.
|
|
84
|
+
* React-free on purpose: everything here is plain engine wiring the adapter
|
|
85
|
+
* threads into the `@pixi/react` tree through `EngineBridge`.
|
|
86
|
+
*/
|
|
87
|
+
export declare function createCanvasRootContext(host: CanvasHostContext, options: CanvasRootContextOptions): CanvasRootRuntime;
|
|
88
|
+
//# sourceMappingURL=world-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"world-context.d.ts","sourceRoot":"","sources":["../../src/canvas-react/world-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAOhE,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAM3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD;;gBAEgB;AAChB,eAAO,MAAM,sBAAsB,qCAAqC,CAAC;AAEzE,MAAM,WAAW,wBAAwB;IACvC;6BACyB;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB;;;;;;OAMG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;CACnD;AAED;wEACwE;AACxE,MAAM,WAAW,iBAAiB;IAChC;kFAC8E;IAC9E,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAC;IAC1B,+DAA+D;IAC/D,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC;IACxD;6EACyE;IACzE,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;IACxC;qEACiE;IACjE,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC;gFAC4E;IAC5E,cAAc,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI,CAAC;IACvC,6EAA6E;IAC7E,QAAQ,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI,CAAC;IACjC;;8CAE0C;IAC1C,OAAO,IAAI,IAAI,CAAC;CACjB;AA4BD;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,iBAAiB,EACvB,OAAO,EAAE,wBAAwB,GAChC,iBAAiB,CAoMnB"}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `createCanvasRootContext` — the ENGINE runtime a canvas world owns, split out
|
|
3
|
+
* of `./pixi-react-adapter.tsx` so it stays react-free and headlessly
|
|
4
|
+
* unit-testable (`test/canvas-react-context-parity.test.tsx`).
|
|
5
|
+
*
|
|
6
|
+
* This is the canvas surface's answer to the same question
|
|
7
|
+
* `world3d-react/world-context.ts` answers for three: what does a component
|
|
8
|
+
* inside the world tree reach when it asks the engine for something?
|
|
9
|
+
*
|
|
10
|
+
* 1. **`ctx.debug` / `ctx.random` / `ctx.game` / `ctx.roots` are wired** from
|
|
11
|
+
* the ONE game-scoped registry (`getDebugRegistry(host.game)`), so a
|
|
12
|
+
* component's effect can `ctx.debug.registerStateProvider(...)` and be
|
|
13
|
+
* visible to `vgai eval`/the editor's debug panels.
|
|
14
|
+
* 2. **`ctx.input` is the game-owned `InputManager`** (`host.game.input` — the
|
|
15
|
+
* same instance every sibling root shares), and this module registers the
|
|
16
|
+
* per-world debug-registry seams (`setVirtualInputTarget`/
|
|
17
|
+
* `setInputActionsSource`/`setInputTraceSource`) that make `game.input.*`
|
|
18
|
+
* (the bot-input doctrine) resolve instead of throwing
|
|
19
|
+
* `DEBUG_INPUT_UNAVAILABLE`. The project's input map loads through
|
|
20
|
+
* `Game.loadInputMap` (the game-owned, load-once path every root shares).
|
|
21
|
+
* A missing/unparseable map degrades LOUDLY without failing the mount — a
|
|
22
|
+
* canvas world with no declared actions is legal.
|
|
23
|
+
* 3. **Absent subsystems fail loudly at the ctx surface.** A canvas world
|
|
24
|
+
* builds no THREE scene/camera, no Rapier world, no composer, no first-party
|
|
25
|
+
* audio/particles/debug-draw, and is handed no `AssetCache` (the canvas host
|
|
26
|
+
* context carries none — see `adapter/host-context.ts`). Reading those
|
|
27
|
+
* `ctx` fields yields a throwing getter naming the limitation and the
|
|
28
|
+
* sanctioned alternative, never a silent `undefined`.
|
|
29
|
+
*
|
|
30
|
+
* The Pixi handles themselves are deliberately NOT re-exposed here: a component
|
|
31
|
+
* reaches the live `Application` (and therefore `app.stage`, `app.renderer`,
|
|
32
|
+
* `app.ticker`) through `@pixi/react`'s own `useApplication()`, and its assets
|
|
33
|
+
* through Pixi's own `Assets`. Re-publishing them on `ctx` would be a wrapper
|
|
34
|
+
* standing between the author and the library.
|
|
35
|
+
*/
|
|
36
|
+
import { createSeededRandom, DEFAULT_SEEDED_RANDOM_SEED, getSeededRandom, } from '../core/seeded-random';
|
|
37
|
+
import { createSimClock, getSimClock } from '../core/sim-clock';
|
|
38
|
+
import { createSystemRunner } from '../core/system-runner';
|
|
39
|
+
import { createDebugRegistry, getDebugRegistry, } from '../runtime/debug-registry';
|
|
40
|
+
/** The conventional input-map location every scaffolded project ships. Shared
|
|
41
|
+
* verbatim with the three lane — a project has ONE input map, whatever surface
|
|
42
|
+
* reads it. */
|
|
43
|
+
export const DEFAULT_INPUT_MAP_PATH = '/inputmaps/default.inputmap.json';
|
|
44
|
+
/** Install a throwing getter for a `GameContext` field this world genuinely
|
|
45
|
+
* does not build — a component reaching for it fails LOUDLY at its own call
|
|
46
|
+
* site, naming the limitation, instead of reading `undefined` and breaking
|
|
47
|
+
* somewhere downstream. Non-enumerable so spreads/serialization of the ctx
|
|
48
|
+
* never trip it. */
|
|
49
|
+
function defineAbsentCtxField(target, worldId, key, why) {
|
|
50
|
+
Object.defineProperty(target, key, {
|
|
51
|
+
configurable: true,
|
|
52
|
+
enumerable: false,
|
|
53
|
+
get() {
|
|
54
|
+
throw new Error(`canvas world "${worldId}": ctx.${key} is not available — ${why} ` +
|
|
55
|
+
'(A canvas world ctx provides: input, systems, clock, debug, random, game, roots, ' +
|
|
56
|
+
"registerSystemAdapter. The Pixi runtime itself comes from @pixi/react's " +
|
|
57
|
+
'useApplication() — app.stage, app.renderer, app.ticker — and assets from Pixi`s own ' +
|
|
58
|
+
'Assets.)');
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Build the engine runtime for one canvas world from a `CanvasHostContext`.
|
|
64
|
+
* React-free on purpose: everything here is plain engine wiring the adapter
|
|
65
|
+
* threads into the `@pixi/react` tree through `EngineBridge`.
|
|
66
|
+
*/
|
|
67
|
+
export function createCanvasRootContext(host, options) {
|
|
68
|
+
const { id, inputMapPath = DEFAULT_INPUT_MAP_PATH } = options;
|
|
69
|
+
// Same observer threading as the three lane — this world's phases show up
|
|
70
|
+
// under the shared game profiler when hosted.
|
|
71
|
+
const systems = createSystemRunner(host.game?.profiler.systemObserver, 'canvas');
|
|
72
|
+
// The mounted world's adapter surface (`mounted.systems`) — declared before
|
|
73
|
+
// ctx so `ctx.registerSystemAdapter` can close over it (a game-owned
|
|
74
|
+
// capability like networking registers here from component code).
|
|
75
|
+
const systemAdapters = {};
|
|
76
|
+
let app = null;
|
|
77
|
+
const ctxRaw = {
|
|
78
|
+
systems,
|
|
79
|
+
registerSystemAdapter: (kind, adapter) => {
|
|
80
|
+
// biome-ignore lint/suspicious/noExplicitAny: same per-key record write the three lane performs; correct by construction
|
|
81
|
+
systemAdapters[kind] = adapter;
|
|
82
|
+
host.game?.notifySystemAdaptersChanged();
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
const ctx = ctxRaw;
|
|
86
|
+
if (host.game) {
|
|
87
|
+
ctx.game = host.game;
|
|
88
|
+
ctx.roots = host.game.roots;
|
|
89
|
+
ctx.playtest = host.game.playtest ?? null;
|
|
90
|
+
}
|
|
91
|
+
// --- ctx.debug — the ONE registry per Game root, shared across every world
|
|
92
|
+
// mounted onto it; a bare mount with no Game shell gets a private,
|
|
93
|
+
// mount-local registry instead. ---
|
|
94
|
+
const debugRegistry = (host.game ? getDebugRegistry(host.game) : null) ??
|
|
95
|
+
createDebugRegistry({ getTick: () => 0, getSimT: () => 0 });
|
|
96
|
+
systemAdapters.debug = debugRegistry.adapter;
|
|
97
|
+
ctx.debug = debugRegistry.forRoot(id);
|
|
98
|
+
ctx.random =
|
|
99
|
+
(host.game ? getSeededRandom(host.game) : null) ??
|
|
100
|
+
createSeededRandom(DEFAULT_SEEDED_RANDOM_SEED);
|
|
101
|
+
// --- ctx.clock — a REAL value, never a throwing getter: every world has a
|
|
102
|
+
// sim clock. A bare mount with no Game shell gets a private, mount-local one.
|
|
103
|
+
// `SimClock.disposeAfter` takes a THREE.Object3D, so the mount-local
|
|
104
|
+
// fallback's disposer is a loud refusal rather than a fabricated no-op: a
|
|
105
|
+
// canvas world's debris is a `PIXI.Container`, destroyed with its own
|
|
106
|
+
// `container.destroy()`.
|
|
107
|
+
const gameClock = host.game ? getSimClock(host.game) : null;
|
|
108
|
+
const clock = gameClock ??
|
|
109
|
+
createSimClock({
|
|
110
|
+
dispose: () => {
|
|
111
|
+
throw new Error(`canvas world "${id}": clock.disposeAfter() disposes a THREE.Object3D and has no ` +
|
|
112
|
+
'meaning in a canvas world — destroy a display object with its own ' +
|
|
113
|
+
'`container.destroy({ children: true })`, scheduled with `clock.after(seconds, ...)`.');
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
ctx.clock = clock;
|
|
117
|
+
// --- ctx.input + the debug-registry input seams — the game-owned
|
|
118
|
+
// InputManager, polled by the game-scoped runner each frame; this world
|
|
119
|
+
// registers the per-world seams so `game.input.*` (virtual input) and the
|
|
120
|
+
// built-in `input.actions`/`input.trace` providers resolve to it. ---
|
|
121
|
+
let inputMapReady = Promise.resolve();
|
|
122
|
+
if (host.game) {
|
|
123
|
+
const game = host.game;
|
|
124
|
+
const input = game.input;
|
|
125
|
+
ctxRaw['input'] = input;
|
|
126
|
+
debugRegistry.setInputActionsSource(id, () => input.actionNames().map((name) => ({ name, valueType: input.getActionValueType(name) })));
|
|
127
|
+
debugRegistry.setInputTraceSource(id, () => {
|
|
128
|
+
const raw = input.getInputTrace();
|
|
129
|
+
return {
|
|
130
|
+
version: raw.version,
|
|
131
|
+
seed: getSeededRandom(game)?.seed ?? null,
|
|
132
|
+
fixedDt: game.loop.fixedDt,
|
|
133
|
+
ticks: raw.ticks,
|
|
134
|
+
};
|
|
135
|
+
});
|
|
136
|
+
debugRegistry.setVirtualInputTarget(id, {
|
|
137
|
+
setVirtualAction: (action, value) => input.setVirtualAction(action, value),
|
|
138
|
+
tapVirtualAction: (action) => input.tapVirtualAction(action),
|
|
139
|
+
clearVirtualActions: () => input.clearVirtualActions(),
|
|
140
|
+
scheduleActionAtTick: (tick, action, value) => input.scheduleActionAtTick(tick, action, value),
|
|
141
|
+
startInputRecording: () => input.startInputRecording(),
|
|
142
|
+
stopInputRecording: () => input.stopInputRecording(),
|
|
143
|
+
isInputRecording: () => input.isInputRecording(),
|
|
144
|
+
injectAxis: (sourceId, value) => input.injectAxis(sourceId, value),
|
|
145
|
+
injectVector2: (sourceId, value) => input.injectVector2(sourceId, value),
|
|
146
|
+
injectPointerDelta: (sourceId, delta) => input.injectPointerDelta(sourceId, delta),
|
|
147
|
+
injectPointerPosition: (sourceId, value) => input.injectPointerPosition(sourceId, value),
|
|
148
|
+
});
|
|
149
|
+
if (!host.headless && inputMapPath !== null) {
|
|
150
|
+
// Load-once through the game-owned path (competing paths across roots
|
|
151
|
+
// throw THERE, loudly). A FAILED load must not fail this mount: a canvas
|
|
152
|
+
// world with no declared actions is legal. It degrades loudly instead.
|
|
153
|
+
inputMapReady = game.loadInputMap(inputMapPath).catch((err) => {
|
|
154
|
+
// biome-ignore lint/suspicious/noConsole: deliberate loud degrade — the documented alternative to failing the mount
|
|
155
|
+
console.error(`canvas world "${id}": failed to load input map "${inputMapPath}" — declared input ` +
|
|
156
|
+
'actions and `game.input.*` (bot/virtual input) will not work until a valid map ' +
|
|
157
|
+
'loads. Ship one at the conventional path or pass `inputMapPath` to ' +
|
|
158
|
+
`createPixiReactAdapter (null to opt out). Cause: ${err instanceof Error ? err.message : String(err)}`);
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
defineAbsentCtxField(ctxRaw, id, 'input', 'input is game-owned and this mount has no Game host (host.game is absent — bare ' +
|
|
164
|
+
'harness/foreign host); mount through the vgai host to get the shared InputManager.');
|
|
165
|
+
}
|
|
166
|
+
// --- Loud absence for everything a canvas world genuinely does not build. ---
|
|
167
|
+
const threeWhy = 'a canvas world renders through PixiJS and owns no THREE scene graph; the world root is ' +
|
|
168
|
+
"the Pixi stage, reached with @pixi/react's useApplication().app.stage.";
|
|
169
|
+
defineAbsentCtxField(ctxRaw, id, 'scene', threeWhy);
|
|
170
|
+
defineAbsentCtxField(ctxRaw, id, 'camera', threeWhy);
|
|
171
|
+
defineAbsentCtxField(ctxRaw, id, 'sceneIndex', 'the live scene index walks a THREE.Scene; a canvas world has none (walk the Pixi display ' +
|
|
172
|
+
'tree from useApplication().app.stage instead).');
|
|
173
|
+
const rapierWhy = 'canvas worlds do not build the first-party Rapier runtime; drive physics from inside the ' +
|
|
174
|
+
'tree with the 2D physics library of your choice.';
|
|
175
|
+
defineAbsentCtxField(ctxRaw, id, 'rapierWorld', rapierWhy);
|
|
176
|
+
defineAbsentCtxField(ctxRaw, id, 'rapier', rapierWhy);
|
|
177
|
+
defineAbsentCtxField(ctxRaw, id, 'physics', rapierWhy);
|
|
178
|
+
defineAbsentCtxField(ctxRaw, id, 'collisions', rapierWhy);
|
|
179
|
+
defineAbsentCtxField(ctxRaw, id, 'assets', 'the canvas host context carries no AssetCache (that cache is a GLTF/texture loader ' +
|
|
180
|
+
"resolving THREE objects); load textures/spritesheets with Pixi's own `Assets`.");
|
|
181
|
+
defineAbsentCtxField(ctxRaw, id, 'composer', 'a canvas world has no postprocessing EffectComposer; use Pixi filters on a Container.');
|
|
182
|
+
defineAbsentCtxField(ctxRaw, id, 'audio', 'canvas worlds build no first-party audio context; use Web Audio directly (or @pixi/sound).');
|
|
183
|
+
defineAbsentCtxField(ctxRaw, id, 'particles', 'canvas worlds build no three.quarks particle runtime; use a Pixi particle container.');
|
|
184
|
+
defineAbsentCtxField(ctxRaw, id, 'debugDraw', 'canvas worlds build no debug-draw helper; draw into a Pixi `Graphics` in the tree.');
|
|
185
|
+
return {
|
|
186
|
+
ctx,
|
|
187
|
+
systems,
|
|
188
|
+
systemAdapters,
|
|
189
|
+
inputMapReady,
|
|
190
|
+
get app() {
|
|
191
|
+
return app;
|
|
192
|
+
},
|
|
193
|
+
setApplication(next) {
|
|
194
|
+
app = next;
|
|
195
|
+
},
|
|
196
|
+
dispose() {
|
|
197
|
+
// Same ownership rule the three lane follows: dispose ONLY a clock this
|
|
198
|
+
// mount created. The game-scoped one belongs to `GameInternal.dispose()`
|
|
199
|
+
// — killing it here would freeze sim time and cancel every SIBLING
|
|
200
|
+
// world's timers.
|
|
201
|
+
if (!gameClock)
|
|
202
|
+
clock.dispose();
|
|
203
|
+
app = null;
|
|
204
|
+
// Scoped strip when a Game hosts this world (sibling roots stay live);
|
|
205
|
+
// a bare standalone mount owns its private registry and clears it all.
|
|
206
|
+
if (host.game)
|
|
207
|
+
debugRegistry.strip(id);
|
|
208
|
+
else
|
|
209
|
+
debugRegistry.strip();
|
|
210
|
+
},
|
|
211
|
+
};
|
|
212
|
+
}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node-loadable engine APIs used while a project's Vite configuration is
|
|
3
|
+
* evaluated. The package build emits this entry as ordinary JavaScript, so
|
|
4
|
+
* project config remains package-native without asking Node to execute raw
|
|
5
|
+
* TypeScript or reach into an adjacent checkout.
|
|
6
|
+
*/
|
|
7
|
+
export { type DataRef, dataRef, getRef } from './data/data-ref';
|
|
8
|
+
export { type VgaiDataCheckOptions, vgaiDataCheck } from './data/vite-plugin-data';
|
|
9
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,KAAK,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAChE,OAAO,EAAE,KAAK,oBAAoB,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node-loadable engine APIs used while a project's Vite configuration is
|
|
3
|
+
* evaluated. The package build emits this entry as ordinary JavaScript, so
|
|
4
|
+
* project config remains package-native without asking Node to execute raw
|
|
5
|
+
* TypeScript or reach into an adjacent checkout.
|
|
6
|
+
*/
|
|
7
|
+
export { dataRef, getRef } from './data/data-ref';
|
|
8
|
+
export { vgaiDataCheck } from './data/vite-plugin-data';
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Frame pacing — the accumulator/alpha arithmetic of the fixed-timestep loop,
|
|
3
|
+
* extracted PURE (WO-P13, `docs/WORK.md` §2 P13).
|
|
4
|
+
*
|
|
5
|
+
* `core/game-loop.ts` owns the browser side (rAF, `visibilitychange`,
|
|
6
|
+
* `performance.now`); this module owns the arithmetic, so the interesting
|
|
7
|
+
* cases — a display frame that consumes zero substeps, a frame that hits the
|
|
8
|
+
* substep ceiling, the spiral-of-death clamp, alpha's monotonic march across a
|
|
9
|
+
* substep gap — are testable without stubbing a single global.
|
|
10
|
+
*
|
|
11
|
+
* The substep half is byte-for-byte the pacing the loop has always used
|
|
12
|
+
* (clamp the raw frame gap, scale by `timeScale`, clamp the accumulator, then
|
|
13
|
+
* consume up to `maxSubSteps` whole steps). The addition is `alpha`: the
|
|
14
|
+
* fraction of a fixed step the accumulator is holding AFTER those substeps
|
|
15
|
+
* were consumed, which is what lets a renderer present between two fixed
|
|
16
|
+
* states instead of only at them.
|
|
17
|
+
*/
|
|
18
|
+
/** The two constants that define a loop's fixed cadence. */
|
|
19
|
+
export interface FramePacingLimits {
|
|
20
|
+
/** Seconds per fixed substep (the loop's `fixedTimestep`). */
|
|
21
|
+
readonly fixedDt: number;
|
|
22
|
+
/** Substep ceiling per display frame — also the accumulator's hard ceiling. */
|
|
23
|
+
readonly maxSubSteps: number;
|
|
24
|
+
}
|
|
25
|
+
/** What one display frame's worth of wall time resolves to. */
|
|
26
|
+
export interface PacedFrame {
|
|
27
|
+
/** Whole fixed substeps this display frame should consume (0..maxSubSteps). */
|
|
28
|
+
readonly steps: number;
|
|
29
|
+
/** The accumulator AFTER those substeps were consumed. */
|
|
30
|
+
readonly accumulator: number;
|
|
31
|
+
/**
|
|
32
|
+
* Interpolation alpha in `[0, 1]` — `accumulator / fixedDt`, i.e. how far
|
|
33
|
+
* the presentation clock sits past the last completed fixed state. `0` means
|
|
34
|
+
* "exactly on the last fixed state"; `0.5` means "halfway to the next one".
|
|
35
|
+
*/
|
|
36
|
+
readonly alpha: number;
|
|
37
|
+
/**
|
|
38
|
+
* The display frame's own delta in seconds, clamped and `timeScale`d exactly
|
|
39
|
+
* like the time fed to the accumulator. This is the delta a per-display-frame
|
|
40
|
+
* consumer (post-processing, particles, a `RenderStepped`-shaped callback)
|
|
41
|
+
* should integrate against — NOT `fixedDt`, which is a sim quantity.
|
|
42
|
+
*/
|
|
43
|
+
readonly displayDt: number;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* `accumulator / fixedDt`, clamped to `[0, 1]`.
|
|
47
|
+
*
|
|
48
|
+
* Clamped rather than asserted because the accumulator can legitimately still
|
|
49
|
+
* hold a whole step when a frame hits the `maxSubSteps` ceiling; presenting
|
|
50
|
+
* "all the way at the next fixed state" is the only honest answer there, and a
|
|
51
|
+
* NaN/negative/zero-`fixedDt` degenerate resolves to `0` (present the last
|
|
52
|
+
* fixed state) rather than poisoning every transform downstream.
|
|
53
|
+
*/
|
|
54
|
+
export declare function interpolationAlpha(accumulator: number, fixedDt: number): number;
|
|
55
|
+
/**
|
|
56
|
+
* The one legal range for `GameLoop.timeScale`, and therefore the range any
|
|
57
|
+
* instrument that DRIVES it must offer (`dev/instruments.ts`'s Time-scale
|
|
58
|
+
* slider reads exactly this — a second copy of `[0, 8]` in a control's bounds
|
|
59
|
+
* is how a slider ends up able to request a value the loop then silently
|
|
60
|
+
* refuses).
|
|
61
|
+
*/
|
|
62
|
+
export declare const TIME_SCALE_RANGE: {
|
|
63
|
+
readonly min: 0;
|
|
64
|
+
readonly max: 8;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Clamp a requested time scale into {@link TIME_SCALE_RANGE}. Extracted from
|
|
68
|
+
* `core/game-loop.ts`'s `set timeScale` (which still owns the out-of-range
|
|
69
|
+
* console warning — this function only computes) so the loop and every reader
|
|
70
|
+
* of the range agree by construction.
|
|
71
|
+
*
|
|
72
|
+
* A NON-FINITE request resolves to `min`, not to itself: `Math.min(8,
|
|
73
|
+
* Math.max(0, NaN))` is `NaN`, and a `NaN` time scale poisons the accumulator
|
|
74
|
+
* permanently — every frame afterwards consumes zero substeps and no warning
|
|
75
|
+
* ever repeats. Freezing (loudly, via the setter's warning) is recoverable;
|
|
76
|
+
* a silently `NaN`-ed loop is not.
|
|
77
|
+
*/
|
|
78
|
+
export declare function clampTimeScale(value: number): number;
|
|
79
|
+
/**
|
|
80
|
+
* Resolve one display frame: how many fixed substeps it consumes, what the
|
|
81
|
+
* accumulator holds afterwards, and the alpha/displayDt the render pass should
|
|
82
|
+
* present with.
|
|
83
|
+
*
|
|
84
|
+
* @param accumulator unconsumed sim time carried in from the previous frame
|
|
85
|
+
* @param rawDt wall-clock seconds since the previous frame
|
|
86
|
+
* @param timeScale the loop's live time scale (already clamped to [0, 8] by
|
|
87
|
+
* its setter — this function does not re-clamp it)
|
|
88
|
+
*/
|
|
89
|
+
export declare function paceFrame(accumulator: number, rawDt: number, timeScale: number, limits: FramePacingLimits): PacedFrame;
|
|
90
|
+
//# sourceMappingURL=frame-pacing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frame-pacing.d.ts","sourceRoot":"","sources":["../../src/core/frame-pacing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,4DAA4D;AAC5D,MAAM,WAAW,iBAAiB;IAChC,8DAA8D;IAC9D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,+EAA+E;IAC/E,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED,+DAA+D;AAC/D,MAAM,WAAW,UAAU;IACzB,+EAA+E;IAC/E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,0DAA0D;IAC1D,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAK/E;AAED;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB;;;CAA8B,CAAC;AAE5D;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGpD;AAED;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CACvB,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,iBAAiB,GACxB,UAAU,CAqBZ"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Frame pacing — the accumulator/alpha arithmetic of the fixed-timestep loop,
|
|
3
|
+
* extracted PURE (WO-P13, `docs/WORK.md` §2 P13).
|
|
4
|
+
*
|
|
5
|
+
* `core/game-loop.ts` owns the browser side (rAF, `visibilitychange`,
|
|
6
|
+
* `performance.now`); this module owns the arithmetic, so the interesting
|
|
7
|
+
* cases — a display frame that consumes zero substeps, a frame that hits the
|
|
8
|
+
* substep ceiling, the spiral-of-death clamp, alpha's monotonic march across a
|
|
9
|
+
* substep gap — are testable without stubbing a single global.
|
|
10
|
+
*
|
|
11
|
+
* The substep half is byte-for-byte the pacing the loop has always used
|
|
12
|
+
* (clamp the raw frame gap, scale by `timeScale`, clamp the accumulator, then
|
|
13
|
+
* consume up to `maxSubSteps` whole steps). The addition is `alpha`: the
|
|
14
|
+
* fraction of a fixed step the accumulator is holding AFTER those substeps
|
|
15
|
+
* were consumed, which is what lets a renderer present between two fixed
|
|
16
|
+
* states instead of only at them.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* `accumulator / fixedDt`, clamped to `[0, 1]`.
|
|
20
|
+
*
|
|
21
|
+
* Clamped rather than asserted because the accumulator can legitimately still
|
|
22
|
+
* hold a whole step when a frame hits the `maxSubSteps` ceiling; presenting
|
|
23
|
+
* "all the way at the next fixed state" is the only honest answer there, and a
|
|
24
|
+
* NaN/negative/zero-`fixedDt` degenerate resolves to `0` (present the last
|
|
25
|
+
* fixed state) rather than poisoning every transform downstream.
|
|
26
|
+
*/
|
|
27
|
+
export function interpolationAlpha(accumulator, fixedDt) {
|
|
28
|
+
if (!Number.isFinite(accumulator) || !Number.isFinite(fixedDt) || fixedDt <= 0)
|
|
29
|
+
return 0;
|
|
30
|
+
if (accumulator <= 0)
|
|
31
|
+
return 0;
|
|
32
|
+
const alpha = accumulator / fixedDt;
|
|
33
|
+
return alpha >= 1 ? 1 : alpha;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The one legal range for `GameLoop.timeScale`, and therefore the range any
|
|
37
|
+
* instrument that DRIVES it must offer (`dev/instruments.ts`'s Time-scale
|
|
38
|
+
* slider reads exactly this — a second copy of `[0, 8]` in a control's bounds
|
|
39
|
+
* is how a slider ends up able to request a value the loop then silently
|
|
40
|
+
* refuses).
|
|
41
|
+
*/
|
|
42
|
+
export const TIME_SCALE_RANGE = { min: 0, max: 8 };
|
|
43
|
+
/**
|
|
44
|
+
* Clamp a requested time scale into {@link TIME_SCALE_RANGE}. Extracted from
|
|
45
|
+
* `core/game-loop.ts`'s `set timeScale` (which still owns the out-of-range
|
|
46
|
+
* console warning — this function only computes) so the loop and every reader
|
|
47
|
+
* of the range agree by construction.
|
|
48
|
+
*
|
|
49
|
+
* A NON-FINITE request resolves to `min`, not to itself: `Math.min(8,
|
|
50
|
+
* Math.max(0, NaN))` is `NaN`, and a `NaN` time scale poisons the accumulator
|
|
51
|
+
* permanently — every frame afterwards consumes zero substeps and no warning
|
|
52
|
+
* ever repeats. Freezing (loudly, via the setter's warning) is recoverable;
|
|
53
|
+
* a silently `NaN`-ed loop is not.
|
|
54
|
+
*/
|
|
55
|
+
export function clampTimeScale(value) {
|
|
56
|
+
if (!Number.isFinite(value))
|
|
57
|
+
return TIME_SCALE_RANGE.min;
|
|
58
|
+
return Math.min(TIME_SCALE_RANGE.max, Math.max(TIME_SCALE_RANGE.min, value));
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Resolve one display frame: how many fixed substeps it consumes, what the
|
|
62
|
+
* accumulator holds afterwards, and the alpha/displayDt the render pass should
|
|
63
|
+
* present with.
|
|
64
|
+
*
|
|
65
|
+
* @param accumulator unconsumed sim time carried in from the previous frame
|
|
66
|
+
* @param rawDt wall-clock seconds since the previous frame
|
|
67
|
+
* @param timeScale the loop's live time scale (already clamped to [0, 8] by
|
|
68
|
+
* its setter — this function does not re-clamp it)
|
|
69
|
+
*/
|
|
70
|
+
export function paceFrame(accumulator, rawDt, timeScale, limits) {
|
|
71
|
+
const { fixedDt, maxSubSteps } = limits;
|
|
72
|
+
// Also the accumulator's hard ceiling (see the spiral-of-death clamp below).
|
|
73
|
+
const maxAccumulator = fixedDt * maxSubSteps;
|
|
74
|
+
// Clamp large frame gaps (a slow frame, a debugger pause) BEFORE scaling by
|
|
75
|
+
// timeScale — unchanged from the pre-WO-P13 loop.
|
|
76
|
+
const displayDt = Math.min(rawDt, maxAccumulator) * timeScale;
|
|
77
|
+
let next = accumulator + displayDt;
|
|
78
|
+
// Spiral-of-death guard: bound the accumulator regardless of timeScale or
|
|
79
|
+
// frame-gap size. Time that can't possibly be caught up on is dropped, never
|
|
80
|
+
// carried forward.
|
|
81
|
+
if (next > maxAccumulator)
|
|
82
|
+
next = maxAccumulator;
|
|
83
|
+
let steps = 0;
|
|
84
|
+
while (next >= fixedDt && steps < maxSubSteps) {
|
|
85
|
+
next -= fixedDt;
|
|
86
|
+
steps++;
|
|
87
|
+
}
|
|
88
|
+
return { steps, accumulator: next, alpha: interpolationAlpha(next, fixedDt), displayDt };
|
|
89
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { GameLoopConfig, GameLoopLiveness } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Fixed-timestep game loop with accumulator pattern — SIM at a fixed rate,
|
|
4
|
+
* PRESENTATION at the display's rate (WO-P13, `docs/WORK.md` §2 P13, which
|
|
5
|
+
* flipped the former D1 "render is fixed-rate too" decision this comment used
|
|
6
|
+
* to state).
|
|
7
|
+
*
|
|
8
|
+
* Per real (rAF) frame:
|
|
9
|
+
*
|
|
10
|
+
* 1. the accumulator absorbs the frame gap (clamped, `timeScale`d) and
|
|
11
|
+
* `config.update(fixedDt)` runs once per WHOLE fixed substep it can
|
|
12
|
+
* consume, up to `maxSubSteps` — unchanged, and still the only thing that
|
|
13
|
+
* advances gameplay, physics, `tick`/`simT` and the sim clock;
|
|
14
|
+
* 2. `config.render(alpha, displayDt)` runs EXACTLY ONCE, whatever step 1
|
|
15
|
+
* did — including zero times. `alpha` is `accumulator / fixedDt` after
|
|
16
|
+
* step 1 (see `core/frame-pacing.ts`): how far presentation sits past the
|
|
17
|
+
* last completed fixed state, in `[0, 1]`.
|
|
18
|
+
*
|
|
19
|
+
* So a 120 Hz display draws 120 frames a second off a 60 Hz simulation, and a
|
|
20
|
+
* frame that consumes zero substeps still presents — which is the whole point:
|
|
21
|
+
* before this, motion presented at SIM rate, so half of every 120 Hz display's
|
|
22
|
+
* frames were duplicates and there was nowhere at all to host
|
|
23
|
+
* `RenderStepped`-shaped per-display-frame code (camera polish, procedural
|
|
24
|
+
* sway). `Game.onRenderStep` (`runtime/game.ts`) is that host, driven from
|
|
25
|
+
* this callback.
|
|
26
|
+
*
|
|
27
|
+
* `config.render` is OPTIONAL, and the hosts that don't pass it keep the old
|
|
28
|
+
* shape exactly: the `render` phase then still runs inside `config.update` as
|
|
29
|
+
* the last phase of `PHASE_ORDER` (`runtime/game.ts` only skips the render
|
|
30
|
+
* phases when its caller asks it to). That is deliberate, because two paths
|
|
31
|
+
* must stay frame-exact and neither goes through the rAF arm at all:
|
|
32
|
+
* `externalDrive` capture/offline export (see `GameLoopConfig.externalDrive`)
|
|
33
|
+
* and `Game.runTicks`, which drives `runFrame` directly.
|
|
34
|
+
*/
|
|
35
|
+
export declare function createGameLoop(config: GameLoopConfig): {
|
|
36
|
+
start(): void;
|
|
37
|
+
stop(): void;
|
|
38
|
+
readonly isRunning: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Truthful liveness (issue #175 — see `GameLoopLiveness`'s doc comment
|
|
41
|
+
* in `core/types.ts` for the full contract). Unlike `isRunning` above,
|
|
42
|
+
* this DISTINGUISHES a hidden-tab pause from an actually-stopped loop:
|
|
43
|
+
* `hiddenPaused` is only ever set by `handleVisibilityChange` (T2.1's
|
|
44
|
+
* idle throttle) and cleared by `start()`/`stop()`/visibility-restore,
|
|
45
|
+
* so it can never be true at the same time `running` is true. An
|
|
46
|
+
* `externalDrive` loop never installs the visibility listener at all
|
|
47
|
+
* (see `start()` above), so `hiddenPaused` stays permanently `false` for
|
|
48
|
+
* it — it only ever reports `'running'` or `'stopped'`.
|
|
49
|
+
*/
|
|
50
|
+
readonly liveness: GameLoopLiveness;
|
|
51
|
+
timeScale: number;
|
|
52
|
+
/**
|
|
53
|
+
* The fixed substep timestep (seconds) this loop's accumulator consumes
|
|
54
|
+
* per `config.update()` call (`config.fixedTimestep ?? 1/60`) — read by
|
|
55
|
+
* `Game.runTicks` (D15, `runtime/game.ts`) so a synchronous fast-forward
|
|
56
|
+
* burst drives `game.runFrame` with the SAME `fixedDt` this loop's own
|
|
57
|
+
* rAF-driven accumulator would have used, without exposing (or
|
|
58
|
+
* `runTicks` needing) any other internal loop state.
|
|
59
|
+
*/
|
|
60
|
+
readonly fixedDt: number;
|
|
61
|
+
};
|
|
62
|
+
//# sourceMappingURL=game-loop.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"game-loop.d.ts","sourceRoot":"","sources":["../../src/core/game-loop.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEhE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,cAAc;;;;IA6HjD;;;;;;;;;;OAUG;uBACa,gBAAgB;eAKX,MAAM;IAe3B;;;;;;;OAOG;;EAKN"}
|