@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,288 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The standalone in-page debug bridge. Query-gated `window.__vgai`, the same
|
|
3
|
+
* production-protection-lives-in-the-installer pattern `render-control.ts`'s
|
|
4
|
+
* `installRenderControlHarness` established for `?vgai-render=1` (production
|
|
5
|
+
* protection lives HERE, not just at whatever call site invokes this — a
|
|
6
|
+
* caller that calls {@link maybeInstallDebugBridge} unconditionally on every
|
|
7
|
+
* boot still only ever gets a handle when the gate below actually passes).
|
|
8
|
+
*
|
|
9
|
+
* D17: this is door (a) of the seam's three doors — the SAME `DebugAdapter`
|
|
10
|
+
* names/JSON the editor relay (door b) and `@vgai/live` (door c, which
|
|
11
|
+
* drives door (a) itself over Playwright) all read. D18: the bridge installs
|
|
12
|
+
* only when the page opts in (`?vgai-debug=1`) AND is either a dev build
|
|
13
|
+
* (`import.meta.env.DEV`) or the project's manifest explicitly opts a
|
|
14
|
+
* production build in (`manifest.debug.allowInProduction`, the described
|
|
15
|
+
* field whose runtime reader THIS module is).
|
|
16
|
+
*/
|
|
17
|
+
import type { DebugAdapter, TickStampedEvent } from '../adapter/system-adapter';
|
|
18
|
+
import type { GameLoopLiveness } from '../core/types';
|
|
19
|
+
import { type DebugRegistry, type RunTicksOptions } from './debug-registry';
|
|
20
|
+
/** Query-param name that opts a standalone page into the debug bridge (D18) —
|
|
21
|
+
* mirrors `render-seed.ts`'s `RENDER_MODE_QUERY_PARAM` naming/shape, own
|
|
22
|
+
* const because this is a different call site with a different flag. */
|
|
23
|
+
export declare const DEBUG_MODE_QUERY_PARAM = "vgai-debug";
|
|
24
|
+
/** The subset of `ResolvedGameManifest` the D18 gate reads — typed narrowly
|
|
25
|
+
* (not imported from `manifest/load.ts`) so this module doesn't need the
|
|
26
|
+
* full manifest shape, just the one described field it is the runtime
|
|
27
|
+
* reader for. */
|
|
28
|
+
export interface DebugBridgeManifest {
|
|
29
|
+
readonly debug?: {
|
|
30
|
+
readonly allowInProduction: boolean;
|
|
31
|
+
} | undefined;
|
|
32
|
+
}
|
|
33
|
+
/** The bridge's actuation surface — byte-identical method names to
|
|
34
|
+
* `InputManager`'s virtual-action primitives (Task 1.4), reached through
|
|
35
|
+
* `DebugRegistry.getVirtualInputTarget(worldId?)` rather than a direct
|
|
36
|
+
* import. Every method takes an optional trailing `worldId` (D15/T-D15.5,
|
|
37
|
+
* the review-objection-2 fix): omitted, it resolves to the SAME default
|
|
38
|
+
* world the editor relay's `inject-input` case resolves to (one shared
|
|
39
|
+
* resolution function, `debug-registry.ts`'s `resolveInputRootId`) — never
|
|
40
|
+
* "whichever world's `InputManager` happened to register last". An
|
|
41
|
+
* explicit `worldId` reaches that world's `InputManager` specifically. */
|
|
42
|
+
export interface VgaiDebugInputHandle {
|
|
43
|
+
setVirtualAction(action: string, value: boolean | number | {
|
|
44
|
+
x: number;
|
|
45
|
+
y: number;
|
|
46
|
+
}, worldId?: string): {
|
|
47
|
+
delivered: boolean;
|
|
48
|
+
reason?: string;
|
|
49
|
+
};
|
|
50
|
+
tapVirtualAction(action: string, worldId?: string): {
|
|
51
|
+
delivered: boolean;
|
|
52
|
+
reason?: string;
|
|
53
|
+
};
|
|
54
|
+
clearVirtualActions(worldId?: string): void;
|
|
55
|
+
/**
|
|
56
|
+
* D15/T-D15.5: schedule a virtual actuation for a specific tick — applied
|
|
57
|
+
* at the START of that tick's input phase, composing with `runTicks` (a
|
|
58
|
+
* schedule for tick 500 fires exactly once the sim has been driven
|
|
59
|
+
* through tick 500, regardless of burst size). A digital `true` produces
|
|
60
|
+
* a genuine `isJustPressed` edge exactly at the target tick. Throws
|
|
61
|
+
* `INPUT_ACTION_NOT_FOUND`/a valueType mismatch (same as
|
|
62
|
+
* `setVirtualAction`) or `TICK_ALREADY_PASSED` (`data.currentTick`, the
|
|
63
|
+
* NEXT tick to be serviced) for a tick that already elapsed.
|
|
64
|
+
*
|
|
65
|
+
* A scheduled tick whose input phase never runs at all (that world
|
|
66
|
+
* paused/frozen, or skipped by a multi-tick gap, when the target tick
|
|
67
|
+
* would have been serviced) DROPS the actuation rather than applying it
|
|
68
|
+
* late — it is never delivered, and there is no `{delivered: false,
|
|
69
|
+
* reason}`-shaped result to read here (the call already returned, long
|
|
70
|
+
* before the drop happens). The only observable trace is an
|
|
71
|
+
* `'input.schedule.dropped'` debug event (`{tick, action}`), readable via
|
|
72
|
+
* `state()`/`stateAll()`'s `events` or `snapshot().events`.
|
|
73
|
+
*/
|
|
74
|
+
scheduleActionAtTick(tick: number, action: string, value: boolean | number | {
|
|
75
|
+
x: number;
|
|
76
|
+
y: number;
|
|
77
|
+
}, worldId?: string): void;
|
|
78
|
+
/** Start (or restart) recording the post-gate action-delta trace, readable
|
|
79
|
+
* back via `state('input.trace')`/`stateAll()` (a built-in provider —
|
|
80
|
+
* itself resolved against the DEFAULT world only; see that provider's own
|
|
81
|
+
* doc comment in `debug-registry.ts`). */
|
|
82
|
+
startRecording(worldId?: string): void;
|
|
83
|
+
/** Stop recording — the trace accumulated so far stays readable. */
|
|
84
|
+
stopRecording(worldId?: string): void;
|
|
85
|
+
/** Whether a recording is currently active. */
|
|
86
|
+
isRecording(worldId?: string): boolean;
|
|
87
|
+
/** Accumulate a synthetic pointer delta for a named test source — mirrors
|
|
88
|
+
* `InputManager.injectPointerDelta` (the "injected test input" seam):
|
|
89
|
+
* multiple calls within the same frame SUM, and the accumulator clears
|
|
90
|
+
* each frame (`endFrame`). Bindings with `valueType: 'pointerDelta'`
|
|
91
|
+
* reading this source (`{ type: 'test_pointer_delta', sourceId }`) see the
|
|
92
|
+
* accumulated value via `getPointerDelta`. */
|
|
93
|
+
injectPointerDelta(sourceId: string, delta: {
|
|
94
|
+
x: number;
|
|
95
|
+
y: number;
|
|
96
|
+
}, worldId?: string): void;
|
|
97
|
+
/** Set a synthetic absolute pointer position for a named test source —
|
|
98
|
+
* mirrors `InputManager.injectPointerPosition`: LAST-WRITE-WINS across
|
|
99
|
+
* contributing sources on read, and persists until changed. Bindings with
|
|
100
|
+
* `valueType: 'pointerPosition'` reading this source (`{ type:
|
|
101
|
+
* 'test_pointer_position', sourceId }`) see it via `getPointerPosition`. */
|
|
102
|
+
injectPointerPosition(sourceId: string, value: {
|
|
103
|
+
x: number;
|
|
104
|
+
y: number;
|
|
105
|
+
}, worldId?: string): void;
|
|
106
|
+
}
|
|
107
|
+
/** `snapshot()`'s return shape — ONE synchronous pass over the registry, so
|
|
108
|
+
* every field reflects the exact same instant (AC-B1.2's batched-read
|
|
109
|
+
* primitive: a probe polling this never sees `time` from one tick and
|
|
110
|
+
* `state` from another). */
|
|
111
|
+
export interface VgaiDebugSnapshot {
|
|
112
|
+
/** `loopLiveness` (issue #175): the REAL `GameLoop.liveness` behind this
|
|
113
|
+
* session — `'hidden-paused'` while the T2.1 idle throttle has stopped
|
|
114
|
+
* the loop (tab hidden), `null` only when no loop is wired at all (a
|
|
115
|
+
* bare debug-registry test stand-in with no real `Game`). Never a
|
|
116
|
+
* fabricated `'running'`. */
|
|
117
|
+
time: {
|
|
118
|
+
simSeconds: number;
|
|
119
|
+
tick: number;
|
|
120
|
+
loopLiveness: GameLoopLiveness | null;
|
|
121
|
+
};
|
|
122
|
+
state: Record<string, unknown>;
|
|
123
|
+
events: TickStampedEvent[];
|
|
124
|
+
pageErrors: string[];
|
|
125
|
+
}
|
|
126
|
+
/** The frozen `window.__vgai` shape (D18/spec §3.4) — version it if it ever
|
|
127
|
+
* needs a breaking change; `providers`/`state`/`stateAll`/`commands`/`events`
|
|
128
|
+
* are straight off the game's `DebugAdapter`, `invoke` re-checks D18 gating
|
|
129
|
+
* (belt-and-braces, AC-A1.7), and `input`/`snapshot` are bridge-only. */
|
|
130
|
+
export interface VgaiDebugHandle {
|
|
131
|
+
readonly version: 1;
|
|
132
|
+
providers: DebugAdapter['providers'];
|
|
133
|
+
state: DebugAdapter['state'];
|
|
134
|
+
stateAll: DebugAdapter['stateAll'];
|
|
135
|
+
commands: DebugAdapter['commands'];
|
|
136
|
+
invoke(name: string, args: unknown[]): Promise<unknown>;
|
|
137
|
+
events: DebugAdapter['events'];
|
|
138
|
+
input: VgaiDebugInputHandle;
|
|
139
|
+
/** See `DebugAdapter.events`'s doc comment for `sinceSeq`'s contract
|
|
140
|
+
* (run-4 friction #5) — `snapshot`'s `events` member is filtered the exact
|
|
141
|
+
* same way, just batched with `time`/`state`/`pageErrors` into one
|
|
142
|
+
* synchronous read. */
|
|
143
|
+
snapshot(sinceSeq?: number): VgaiDebugSnapshot;
|
|
144
|
+
/**
|
|
145
|
+
* D15/T-D15.4 door (a): synchronously drive `n` fixed gameplay ticks via the
|
|
146
|
+
* live `Game`'s `GameInternal.runTicks` (`runtime/game.ts`) — reached through
|
|
147
|
+
* `DebugRegistry.getRunTicksTarget()`, the SAME target the editor relay's
|
|
148
|
+
* `run-ticks` case (→ `play.runTicks`, door b) calls, so behavior is
|
|
149
|
+
* byte-identical across every door (D17). Throws `DEBUG_RUN_TICKS_UNAVAILABLE`
|
|
150
|
+
* if no `Game` has wired a target yet (no world mounted); throws whatever
|
|
151
|
+
* `runTicks` itself throws otherwise (e.g. `RUN_TICKS_PAUSED`) — never a
|
|
152
|
+
* silent no-op.
|
|
153
|
+
*/
|
|
154
|
+
runTicks(n: number, opts?: RunTicksOptions): void;
|
|
155
|
+
/**
|
|
156
|
+
* Collapses `input.setVirtualAction(action, true)` → wait `simSeconds` of
|
|
157
|
+
* REAL sim time (real ticks — deliberately NOT `runTicks`/fast-forward;
|
|
158
|
+
* this is the honest human-input-path proof) → `input.clearVirtualActions()`
|
|
159
|
+
* into ONE async bridge call, as a TOP-LEVEL method (not under `input`)
|
|
160
|
+
* because it needs the sim clock, not just the input target. Was 15+
|
|
161
|
+
* transport round trips over the editor relay (`@vgai/live`'s old
|
|
162
|
+
* `GameInput.hold`: set → a 150ms-interval `waitSimTime` snapshot poll loop
|
|
163
|
+
* → clear); now one `page.evaluate`/relay call that runs the wait
|
|
164
|
+
* in-process on the page.
|
|
165
|
+
*
|
|
166
|
+
* Resolves the world's input target exactly like the other `input.*`
|
|
167
|
+
* methods (`worldId` omitted → the same default-world resolution every
|
|
168
|
+
* door on this seam shares). A gated actuation (the initial
|
|
169
|
+
* `setVirtualAction` reports `delivered:false`) clears immediately and
|
|
170
|
+
* resolves that SAME `{delivered:false, reason}` shape WITHOUT waiting —
|
|
171
|
+
* matching `setVirtualAction`'s own gated-result contract. If the live
|
|
172
|
+
* game's sim clock stalls while waiting (play stopped/paused mid-hold),
|
|
173
|
+
* the action is still cleared (never left stuck) and this resolves
|
|
174
|
+
* `{delivered:false, reason:'play stopped during hold'}` instead of
|
|
175
|
+
* hanging forever. Throws `DEBUG_INPUT_UNAVAILABLE`/
|
|
176
|
+
* `DEBUG_INPUT_WORLD_NOT_FOUND` up front, same as `input.setVirtualAction`,
|
|
177
|
+
* when no target is wired/resolvable at all.
|
|
178
|
+
*/
|
|
179
|
+
holdFor(action: string, simSeconds: number, worldId?: string): Promise<{
|
|
180
|
+
delivered: boolean;
|
|
181
|
+
reason?: string;
|
|
182
|
+
}>;
|
|
183
|
+
/**
|
|
184
|
+
* Defect 5 fix — undo everything THIS install did: remove the
|
|
185
|
+
* `error`/`unhandledrejection` window listeners it added, and delete
|
|
186
|
+
* `window.__vgai` so the registry is no longer reachable from the page.
|
|
187
|
+
* Idempotent (a second call is a harmless no-op). `mountManifestRoots`
|
|
188
|
+
* wires this into its session's `stop()`; a caller mounting more
|
|
189
|
+
* directly (a hand-rolled host) should call it on its own teardown path.
|
|
190
|
+
*/
|
|
191
|
+
uninstall(): void;
|
|
192
|
+
}
|
|
193
|
+
/** Structural `window` surface this module needs — just enough to publish
|
|
194
|
+
* the handle and listen for page errors, typed narrowly (no `any`, no DOM
|
|
195
|
+
* lib dependency beyond what every other runtime module already assumes). */
|
|
196
|
+
export interface DebugBridgeWindowTarget {
|
|
197
|
+
addEventListener?(type: 'error' | 'unhandledrejection', listener: (event: {
|
|
198
|
+
message?: string;
|
|
199
|
+
error?: unknown;
|
|
200
|
+
reason?: unknown;
|
|
201
|
+
}) => void): void;
|
|
202
|
+
/** Defect 5 fix — the installer's `uninstall()` calls this (when present)
|
|
203
|
+
* to remove the exact listener references it added via `addEventListener`
|
|
204
|
+
* above. Optional, like `addEventListener`, so a minimal test/host stub
|
|
205
|
+
* that never needs to uninstall can omit it. */
|
|
206
|
+
removeEventListener?(type: 'error' | 'unhandledrejection', listener: (event: {
|
|
207
|
+
message?: string;
|
|
208
|
+
error?: unknown;
|
|
209
|
+
reason?: unknown;
|
|
210
|
+
}) => void): void;
|
|
211
|
+
[key: string]: unknown;
|
|
212
|
+
}
|
|
213
|
+
export interface MaybeInstallDebugBridgeOptions {
|
|
214
|
+
/** The game-scoped registry (`getDebugRegistry(session.game)`) — its
|
|
215
|
+
* `.adapter` backs every read/invoke method on the published handle, and
|
|
216
|
+
* its `getVirtualInputTarget()` backs `input.*`. */
|
|
217
|
+
readonly registry: DebugRegistry;
|
|
218
|
+
readonly manifest: DebugBridgeManifest;
|
|
219
|
+
/** Where to read `?vgai-debug=1` from. Defaults to `window.location` when a
|
|
220
|
+
* real `window` exists; a headless caller with no `window` at all (and no
|
|
221
|
+
* override) gets no bridge — there's nowhere to read a URL from. */
|
|
222
|
+
readonly url?: {
|
|
223
|
+
readonly search: string;
|
|
224
|
+
} | undefined;
|
|
225
|
+
/** Where to publish the handle and install the page-error listeners.
|
|
226
|
+
* Defaults to the real `window`; override in a unit test to avoid
|
|
227
|
+
* touching (or requiring) the global object. */
|
|
228
|
+
readonly window?: DebugBridgeWindowTarget | undefined;
|
|
229
|
+
}
|
|
230
|
+
/** The message a hold gets when the loop is hidden-paused and NOTHING can
|
|
231
|
+
* drive it — the one case where the platform genuinely prevents the verb
|
|
232
|
+
* from working. Names the cause and the fix rather than expiring into a
|
|
233
|
+
* generic stall (which reported the wrong cause: "play stopped during
|
|
234
|
+
* hold"). One exported constant so both doors and their tests read the same
|
|
235
|
+
* string. */
|
|
236
|
+
export declare const HOLD_HIDDEN_NO_DRIVER_REASON: string;
|
|
237
|
+
/**
|
|
238
|
+
* Resolves once `simSeconds` of sim time has elapsed since the call, or once
|
|
239
|
+
* the wait provably cannot make progress. Never rejects. Exported (not just
|
|
240
|
+
* used by `holdFor` below) so the editor relay's `command-listener.ts`
|
|
241
|
+
* `holdFor` case can share the EXACT same logic against its own
|
|
242
|
+
* `DebugAdapter` (reached via `getActiveSystems().debug` rather than a
|
|
243
|
+
* `DebugRegistry`) — D17: byte-identical behavior across doors, not two
|
|
244
|
+
* hand-copies that can silently drift apart.
|
|
245
|
+
*
|
|
246
|
+
* Two regimes, and the split is the whole point:
|
|
247
|
+
*
|
|
248
|
+
* - **Visible**: the host loop is ticking on its own, so this polls it every
|
|
249
|
+
* `HOLD_FOR_POLL_MS` and gives up after `HOLD_FOR_STALL_POLL_LIMIT`
|
|
250
|
+
* consecutive unchanged-tick polls (`stalled: true` — play stopped/paused).
|
|
251
|
+
*
|
|
252
|
+
* - **Hidden-paused**: the host loop has stopped outright (T2.1's idle
|
|
253
|
+
* throttle), so sim time only moves if this drives it. It therefore drives
|
|
254
|
+
* the WHOLE remaining budget in synchronous batches, yielding a MICROTASK
|
|
255
|
+
* between them — never a timer. That distinction is load-bearing, not
|
|
256
|
+
* stylistic: a hidden tab clamps `setTimeout` to ~1s (and to ~1/minute under
|
|
257
|
+
* Chrome's intensive throttling after 5 minutes hidden), so the previous
|
|
258
|
+
* "drive 3 ticks, then `setTimeout(poll, 50)`" shape ran the sim at ~3
|
|
259
|
+
* ticks per SECOND. A 1.2s hold needed ~24 clamped turns — ~24s of wall
|
|
260
|
+
* clock against the editor relay's 5s per-command budget, which is exactly
|
|
261
|
+
* how a hold that passes on a foregrounded tab died with a generic
|
|
262
|
+
* "editor connected but did not respond" on a backgrounded one. Microtasks
|
|
263
|
+
* are not throttled, so the hidden path now costs sim-work time and nothing
|
|
264
|
+
* else.
|
|
265
|
+
*
|
|
266
|
+
* The regime is re-read every iteration, so a tab foregrounded (or hidden)
|
|
267
|
+
* mid-hold crosses over without restarting the budget.
|
|
268
|
+
*
|
|
269
|
+
* `hiddenWithoutDriver: true` is the one honest refusal: hidden-paused with
|
|
270
|
+
* no `driveHiddenTicks` hook means nothing in this process can advance the
|
|
271
|
+
* clock, so it reports that IMMEDIATELY (see
|
|
272
|
+
* {@link HOLD_HIDDEN_NO_DRIVER_REASON}) instead of burning the stall guard
|
|
273
|
+
* and then blaming a stopped game.
|
|
274
|
+
*/
|
|
275
|
+
export declare function waitForHoldBudget(adapter: DebugAdapter, simSeconds: number, driveHiddenTicks?: (n: number) => void): Promise<{
|
|
276
|
+
stalled: boolean;
|
|
277
|
+
hiddenWithoutDriver?: boolean;
|
|
278
|
+
}>;
|
|
279
|
+
/**
|
|
280
|
+
* Install `window.__vgai` iff the page opted in (`?vgai-debug=1`) AND D18's
|
|
281
|
+
* gate passes (dev build, or manifest `debug.allowInProduction`). When the
|
|
282
|
+
* param is present but the gate fails, warns once (this single call IS the
|
|
283
|
+
* "once" — there is exactly one install attempt per boot) and installs
|
|
284
|
+
* nothing. Returns the installed handle (mostly useful for tests), or
|
|
285
|
+
* `undefined` when nothing was installed.
|
|
286
|
+
*/
|
|
287
|
+
export declare function maybeInstallDebugBridge(opts: MaybeInstallDebugBridgeOptions): VgaiDebugHandle | undefined;
|
|
288
|
+
//# sourceMappingURL=debug-bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debug-bridge.d.ts","sourceRoot":"","sources":["../../src/runtime/debug-bridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The standalone in-page debug bridge. Query-gated `window.__vgai`, the same
|
|
3
|
+
* production-protection-lives-in-the-installer pattern `render-control.ts`'s
|
|
4
|
+
* `installRenderControlHarness` established for `?vgai-render=1` (production
|
|
5
|
+
* protection lives HERE, not just at whatever call site invokes this — a
|
|
6
|
+
* caller that calls {@link maybeInstallDebugBridge} unconditionally on every
|
|
7
|
+
* boot still only ever gets a handle when the gate below actually passes).
|
|
8
|
+
*
|
|
9
|
+
* D17: this is door (a) of the seam's three doors — the SAME `DebugAdapter`
|
|
10
|
+
* names/JSON the editor relay (door b) and `@vgai/live` (door c, which
|
|
11
|
+
* drives door (a) itself over Playwright) all read. D18: the bridge installs
|
|
12
|
+
* only when the page opts in (`?vgai-debug=1`) AND is either a dev build
|
|
13
|
+
* (`import.meta.env.DEV`) or the project's manifest explicitly opts a
|
|
14
|
+
* production build in (`manifest.debug.allowInProduction`, the described
|
|
15
|
+
* field whose runtime reader THIS module is).
|
|
16
|
+
*/
|
|
17
|
+
import { DebugError } from './debug-registry';
|
|
18
|
+
/** Query-param name that opts a standalone page into the debug bridge (D18) —
|
|
19
|
+
* mirrors `render-seed.ts`'s `RENDER_MODE_QUERY_PARAM` naming/shape, own
|
|
20
|
+
* const because this is a different call site with a different flag. */
|
|
21
|
+
export const DEBUG_MODE_QUERY_PARAM = 'vgai-debug';
|
|
22
|
+
const PAGE_ERROR_CAP = 100;
|
|
23
|
+
/** `holdFor`'s in-process poll interval — this loop never leaves the page
|
|
24
|
+
* (no transport round trip per poll, unlike `@vgai/live`'s old
|
|
25
|
+
* `waitSimTime`), so it can afford to be tighter than that loop's 150ms. */
|
|
26
|
+
const HOLD_FOR_POLL_MS = 50;
|
|
27
|
+
/** Consecutive `HOLD_FOR_POLL_MS` polls with the tick unchanged before
|
|
28
|
+
* `holdFor` gives up waiting and treats the game as stopped — mirrors
|
|
29
|
+
* `@vgai/live`'s `WAIT_FOR_STALL_POLL_LIMIT` reasoning (`wait-for.ts`:
|
|
30
|
+
* a genuinely frozen sim clock must never poll forever), scaled to this
|
|
31
|
+
* faster in-process interval so the wall-clock grace period (~5s) lands in
|
|
32
|
+
* the same neighborhood. */
|
|
33
|
+
const HOLD_FOR_STALL_POLL_LIMIT = 100;
|
|
34
|
+
/** Ticks driven per synchronous hidden-tab batch. Sized like
|
|
35
|
+
* `fast-forward.ts`'s own batching rationale: big enough that per-batch
|
|
36
|
+
* bookkeeping is negligible, small enough that one batch of a complex game's
|
|
37
|
+
* phases stays a short synchronous burst. */
|
|
38
|
+
const HIDDEN_DRIVE_BATCH_TICKS = 60;
|
|
39
|
+
/** Hard ceiling on hidden-drive batches for ONE hold — `HIDDEN_DRIVE_BATCH_TICKS
|
|
40
|
+
* * this` ≈ 33 sim-minutes. A bound, not a timeout: it exists so a
|
|
41
|
+
* `runTicks` target that advances the tick counter without advancing the sim
|
|
42
|
+
* clock can never spin forever, and it is far past any honest hold. */
|
|
43
|
+
const HIDDEN_DRIVE_MAX_BATCHES = 2000;
|
|
44
|
+
/** The message a hold gets when the loop is hidden-paused and NOTHING can
|
|
45
|
+
* drive it — the one case where the platform genuinely prevents the verb
|
|
46
|
+
* from working. Names the cause and the fix rather than expiring into a
|
|
47
|
+
* generic stall (which reported the wrong cause: "play stopped during
|
|
48
|
+
* hold"). One exported constant so both doors and their tests read the same
|
|
49
|
+
* string. */
|
|
50
|
+
export const HOLD_HIDDEN_NO_DRIVER_REASON = 'the editor tab is hidden and this session has no way to drive ticks — the engine ' +
|
|
51
|
+
'hidden-pauses its loop while document.hidden, so zero ticks are happening. Bring the ' +
|
|
52
|
+
'editor tab to the foreground (or start play, which wires the run-ticks target) and retry.';
|
|
53
|
+
/**
|
|
54
|
+
* Resolves once `simSeconds` of sim time has elapsed since the call, or once
|
|
55
|
+
* the wait provably cannot make progress. Never rejects. Exported (not just
|
|
56
|
+
* used by `holdFor` below) so the editor relay's `command-listener.ts`
|
|
57
|
+
* `holdFor` case can share the EXACT same logic against its own
|
|
58
|
+
* `DebugAdapter` (reached via `getActiveSystems().debug` rather than a
|
|
59
|
+
* `DebugRegistry`) — D17: byte-identical behavior across doors, not two
|
|
60
|
+
* hand-copies that can silently drift apart.
|
|
61
|
+
*
|
|
62
|
+
* Two regimes, and the split is the whole point:
|
|
63
|
+
*
|
|
64
|
+
* - **Visible**: the host loop is ticking on its own, so this polls it every
|
|
65
|
+
* `HOLD_FOR_POLL_MS` and gives up after `HOLD_FOR_STALL_POLL_LIMIT`
|
|
66
|
+
* consecutive unchanged-tick polls (`stalled: true` — play stopped/paused).
|
|
67
|
+
*
|
|
68
|
+
* - **Hidden-paused**: the host loop has stopped outright (T2.1's idle
|
|
69
|
+
* throttle), so sim time only moves if this drives it. It therefore drives
|
|
70
|
+
* the WHOLE remaining budget in synchronous batches, yielding a MICROTASK
|
|
71
|
+
* between them — never a timer. That distinction is load-bearing, not
|
|
72
|
+
* stylistic: a hidden tab clamps `setTimeout` to ~1s (and to ~1/minute under
|
|
73
|
+
* Chrome's intensive throttling after 5 minutes hidden), so the previous
|
|
74
|
+
* "drive 3 ticks, then `setTimeout(poll, 50)`" shape ran the sim at ~3
|
|
75
|
+
* ticks per SECOND. A 1.2s hold needed ~24 clamped turns — ~24s of wall
|
|
76
|
+
* clock against the editor relay's 5s per-command budget, which is exactly
|
|
77
|
+
* how a hold that passes on a foregrounded tab died with a generic
|
|
78
|
+
* "editor connected but did not respond" on a backgrounded one. Microtasks
|
|
79
|
+
* are not throttled, so the hidden path now costs sim-work time and nothing
|
|
80
|
+
* else.
|
|
81
|
+
*
|
|
82
|
+
* The regime is re-read every iteration, so a tab foregrounded (or hidden)
|
|
83
|
+
* mid-hold crosses over without restarting the budget.
|
|
84
|
+
*
|
|
85
|
+
* `hiddenWithoutDriver: true` is the one honest refusal: hidden-paused with
|
|
86
|
+
* no `driveHiddenTicks` hook means nothing in this process can advance the
|
|
87
|
+
* clock, so it reports that IMMEDIATELY (see
|
|
88
|
+
* {@link HOLD_HIDDEN_NO_DRIVER_REASON}) instead of burning the stall guard
|
|
89
|
+
* and then blaming a stopped game.
|
|
90
|
+
*/
|
|
91
|
+
export async function waitForHoldBudget(adapter, simSeconds, driveHiddenTicks) {
|
|
92
|
+
const readTime = () => adapter.state('time');
|
|
93
|
+
const start = readTime();
|
|
94
|
+
let lastTick = start.tick;
|
|
95
|
+
let stalledPolls = 0;
|
|
96
|
+
let hiddenBatches = 0;
|
|
97
|
+
for (;;) {
|
|
98
|
+
const current = readTime();
|
|
99
|
+
if (current.simSeconds - start.simSeconds >= simSeconds)
|
|
100
|
+
return { stalled: false };
|
|
101
|
+
if (current.loopLiveness === 'hidden-paused') {
|
|
102
|
+
if (!driveHiddenTicks)
|
|
103
|
+
return { stalled: true, hiddenWithoutDriver: true };
|
|
104
|
+
if (hiddenBatches >= HIDDEN_DRIVE_MAX_BATCHES)
|
|
105
|
+
return { stalled: true };
|
|
106
|
+
hiddenBatches += 1;
|
|
107
|
+
driveHiddenTicks(HIDDEN_DRIVE_BATCH_TICKS);
|
|
108
|
+
const after = readTime();
|
|
109
|
+
// A batch that moved neither the tick counter nor the sim clock means
|
|
110
|
+
// the drive is a no-op (paused game, torn-down runtime) — the same
|
|
111
|
+
// "nothing is advancing" verdict the visible path's stall guard
|
|
112
|
+
// reaches, just observable in one batch instead of a hundred polls.
|
|
113
|
+
if (after.tick === current.tick && after.simSeconds === current.simSeconds) {
|
|
114
|
+
return { stalled: true };
|
|
115
|
+
}
|
|
116
|
+
lastTick = after.tick;
|
|
117
|
+
stalledPolls = 0;
|
|
118
|
+
// Yield so the page can service other work between batches, WITHOUT
|
|
119
|
+
// handing control to a clock a hidden tab is allowed to starve.
|
|
120
|
+
await Promise.resolve();
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
stalledPolls = current.tick === lastTick ? stalledPolls + 1 : 0;
|
|
124
|
+
lastTick = current.tick;
|
|
125
|
+
if (stalledPolls >= HOLD_FOR_STALL_POLL_LIMIT)
|
|
126
|
+
return { stalled: true };
|
|
127
|
+
await new Promise((resolve) => setTimeout(resolve, HOLD_FOR_POLL_MS));
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
function hasRealWindow() {
|
|
131
|
+
return typeof window !== 'undefined';
|
|
132
|
+
}
|
|
133
|
+
function isDebugModeRequested(url) {
|
|
134
|
+
return new URLSearchParams(url.search).get(DEBUG_MODE_QUERY_PARAM) === '1';
|
|
135
|
+
}
|
|
136
|
+
/** D18's gate: a dev build, or a production build the manifest explicitly
|
|
137
|
+
* opted in. Read fresh on every call (not cached at install time) so
|
|
138
|
+
* `invoke()`'s belt-and-braces re-check (AC-A1.7) is a genuine second
|
|
139
|
+
* evaluation, not a rubber stamp of a value computed once at install. */
|
|
140
|
+
function isDebugAllowed(manifest) {
|
|
141
|
+
return Boolean(import.meta.env?.DEV) || manifest.debug?.allowInProduction === true;
|
|
142
|
+
}
|
|
143
|
+
function buildDebugHandle(opts) {
|
|
144
|
+
const { registry, manifest } = opts;
|
|
145
|
+
const adapter = registry.adapter;
|
|
146
|
+
const pageErrors = [];
|
|
147
|
+
function pushPageError(message) {
|
|
148
|
+
pageErrors.push(message);
|
|
149
|
+
if (pageErrors.length > PAGE_ERROR_CAP)
|
|
150
|
+
pageErrors.shift();
|
|
151
|
+
}
|
|
152
|
+
// Named (not inline-anonymous) so `uninstall()` below can pass the exact
|
|
153
|
+
// same reference to `removeEventListener` (Defect 5 fix).
|
|
154
|
+
const onWindowError = (event) => {
|
|
155
|
+
pushPageError(event.message || String(event.error));
|
|
156
|
+
};
|
|
157
|
+
const onWindowRejection = (event) => {
|
|
158
|
+
pushPageError(`Unhandled promise rejection: ${String(event.reason)}`);
|
|
159
|
+
};
|
|
160
|
+
opts.window.addEventListener?.('error', onWindowError);
|
|
161
|
+
opts.window.addEventListener?.('unhandledrejection', onWindowRejection);
|
|
162
|
+
function requireInputTarget(method, worldId) {
|
|
163
|
+
const target = registry.getVirtualInputTarget(worldId);
|
|
164
|
+
if (!target) {
|
|
165
|
+
throw new DebugError('DEBUG_INPUT_UNAVAILABLE', `debug bridge: ${method}() has no virtual-input target wired — no default three ` +
|
|
166
|
+
"world has mounted yet, or this project's mount path never wired one");
|
|
167
|
+
}
|
|
168
|
+
return target;
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
version: 1,
|
|
172
|
+
// None of these `DebugAdapter` methods reference `this` (they close over
|
|
173
|
+
// the registry's own private maps) — passing the references directly is
|
|
174
|
+
// safe and avoids five redundant wrapper closures.
|
|
175
|
+
providers: adapter.providers,
|
|
176
|
+
state: adapter.state,
|
|
177
|
+
stateAll: adapter.stateAll,
|
|
178
|
+
commands: adapter.commands,
|
|
179
|
+
events: adapter.events,
|
|
180
|
+
async invoke(name, args) {
|
|
181
|
+
// Belt-and-braces D18 re-check (AC-A1.7): the outer install gate
|
|
182
|
+
// already required this to be true, but a caller could hold onto this
|
|
183
|
+
// handle across an environment/manifest change — refuse loudly rather
|
|
184
|
+
// than trust a decision made once at install time.
|
|
185
|
+
if (!isDebugAllowed(manifest)) {
|
|
186
|
+
throw new DebugError('DEBUG_COMMANDS_UNSUPPORTED', `debug: command "${name}" invocation refused — production build without ` +
|
|
187
|
+
'debug.allowInProduction (D18)', { name });
|
|
188
|
+
}
|
|
189
|
+
return adapter.invoke(name, args);
|
|
190
|
+
},
|
|
191
|
+
input: {
|
|
192
|
+
setVirtualAction: (action, value, worldId) => requireInputTarget('setVirtualAction', worldId).setVirtualAction(action, value),
|
|
193
|
+
tapVirtualAction: (action, worldId) => requireInputTarget('tapVirtualAction', worldId).tapVirtualAction(action),
|
|
194
|
+
clearVirtualActions: (worldId) => requireInputTarget('clearVirtualActions', worldId).clearVirtualActions(),
|
|
195
|
+
scheduleActionAtTick: (tick, action, value, worldId) => requireInputTarget('scheduleActionAtTick', worldId).scheduleActionAtTick(tick, action, value),
|
|
196
|
+
startRecording: (worldId) => requireInputTarget('startRecording', worldId).startInputRecording(),
|
|
197
|
+
stopRecording: (worldId) => requireInputTarget('stopRecording', worldId).stopInputRecording(),
|
|
198
|
+
isRecording: (worldId) => requireInputTarget('isRecording', worldId).isInputRecording(),
|
|
199
|
+
injectPointerDelta: (sourceId, delta, worldId) => requireInputTarget('injectPointerDelta', worldId).injectPointerDelta(sourceId, delta),
|
|
200
|
+
injectPointerPosition: (sourceId, value, worldId) => requireInputTarget('injectPointerPosition', worldId).injectPointerPosition(sourceId, value),
|
|
201
|
+
},
|
|
202
|
+
snapshot(sinceSeq) {
|
|
203
|
+
// One synchronous pass — see VgaiDebugSnapshot's doc comment.
|
|
204
|
+
return {
|
|
205
|
+
time: adapter.state('time'),
|
|
206
|
+
state: adapter.stateAll(),
|
|
207
|
+
events: adapter.events(sinceSeq),
|
|
208
|
+
pageErrors: pageErrors.slice(),
|
|
209
|
+
};
|
|
210
|
+
},
|
|
211
|
+
runTicks(n, runTicksOpts) {
|
|
212
|
+
const target = registry.getRunTicksTarget();
|
|
213
|
+
if (!target) {
|
|
214
|
+
throw new DebugError('DEBUG_RUN_TICKS_UNAVAILABLE', 'debug bridge: runTicks() has no run-ticks target wired — no Game has mounted yet');
|
|
215
|
+
}
|
|
216
|
+
target.runTicks(n, runTicksOpts);
|
|
217
|
+
},
|
|
218
|
+
async holdFor(action, simSeconds, worldId) {
|
|
219
|
+
const target = requireInputTarget('holdFor', worldId);
|
|
220
|
+
const setResult = target.setVirtualAction(action, true);
|
|
221
|
+
if (!setResult.delivered) {
|
|
222
|
+
target.clearVirtualActions();
|
|
223
|
+
// `exactOptionalPropertyTypes`: don't write an explicit `reason:
|
|
224
|
+
// undefined` when the gate itself didn't supply one — omit the key
|
|
225
|
+
// entirely rather than assign `undefined` into an optional `string`
|
|
226
|
+
// property.
|
|
227
|
+
return setResult.reason !== undefined
|
|
228
|
+
? { delivered: false, reason: setResult.reason }
|
|
229
|
+
: { delivered: false };
|
|
230
|
+
}
|
|
231
|
+
const runTicksTarget = registry.getRunTicksTarget();
|
|
232
|
+
const { stalled, hiddenWithoutDriver } = await waitForHoldBudget(adapter, simSeconds, runTicksTarget ? (n) => runTicksTarget.runTicks(n, { render: 'last' }) : undefined);
|
|
233
|
+
target.clearVirtualActions();
|
|
234
|
+
if (!stalled)
|
|
235
|
+
return { delivered: true };
|
|
236
|
+
return {
|
|
237
|
+
delivered: false,
|
|
238
|
+
reason: hiddenWithoutDriver ? HOLD_HIDDEN_NO_DRIVER_REASON : 'play stopped during hold',
|
|
239
|
+
};
|
|
240
|
+
},
|
|
241
|
+
uninstall() {
|
|
242
|
+
opts.window.removeEventListener?.('error', onWindowError);
|
|
243
|
+
opts.window.removeEventListener?.('unhandledrejection', onWindowRejection);
|
|
244
|
+
delete opts.window['__vgai'];
|
|
245
|
+
},
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Install `window.__vgai` iff the page opted in (`?vgai-debug=1`) AND D18's
|
|
250
|
+
* gate passes (dev build, or manifest `debug.allowInProduction`). When the
|
|
251
|
+
* param is present but the gate fails, warns once (this single call IS the
|
|
252
|
+
* "once" — there is exactly one install attempt per boot) and installs
|
|
253
|
+
* nothing. Returns the installed handle (mostly useful for tests), or
|
|
254
|
+
* `undefined` when nothing was installed.
|
|
255
|
+
*/
|
|
256
|
+
export function maybeInstallDebugBridge(opts) {
|
|
257
|
+
const url = opts.url ?? (hasRealWindow() ? window.location : undefined);
|
|
258
|
+
if (!url)
|
|
259
|
+
return undefined;
|
|
260
|
+
if (!isDebugModeRequested(url))
|
|
261
|
+
return undefined;
|
|
262
|
+
const windowTarget = opts.window ?? (hasRealWindow() ? window : undefined);
|
|
263
|
+
if (!windowTarget)
|
|
264
|
+
return undefined;
|
|
265
|
+
if (!isDebugAllowed(opts.manifest)) {
|
|
266
|
+
// biome-ignore lint/suspicious/noConsole: structured, greppable D18 signal — mirrors debug-registry.ts's own console.warn idiom.
|
|
267
|
+
console.warn('[debug] ?vgai-debug=1 ignored: production build without debug.allowInProduction (D18)');
|
|
268
|
+
return undefined;
|
|
269
|
+
}
|
|
270
|
+
const handle = buildDebugHandle({
|
|
271
|
+
registry: opts.registry,
|
|
272
|
+
manifest: opts.manifest,
|
|
273
|
+
window: windowTarget,
|
|
274
|
+
});
|
|
275
|
+
windowTarget['__vgai'] = handle;
|
|
276
|
+
return handle;
|
|
277
|
+
}
|