@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,633 @@
|
|
|
1
|
+
// T3.1 slice 1 — the game manifest schema (`vgai.project.json`).
|
|
2
|
+
//
|
|
3
|
+
// This is the serialized form of the Game's root list for the adjudicated
|
|
4
|
+
// field list this file implements exactly. `load.ts` is this schema's runtime
|
|
5
|
+
// reader (T4.1 policy): it parses via this schema, then layers the
|
|
6
|
+
// cross-field checks and default resolution §3/§5 describe. Every field below
|
|
7
|
+
// has a `.describe()` (repo policy — powers `scripts/generate-schema.ts` and
|
|
8
|
+
// the T4.1 schema-walk coverage test).
|
|
9
|
+
//
|
|
10
|
+
// Naming: this file follows the repo's `XxxSchema` (Zod schema) / `Xxx`
|
|
11
|
+
// (inferred type) convention used throughout `scene/schema/` — the design
|
|
12
|
+
// doc's §3 sketch names the bare consts (`Tier`, `IngestStrategy`,
|
|
13
|
+
// `AdapterRoot`) without the `Schema` suffix; that sketch is explicitly a
|
|
14
|
+
// "Zod sketch" the doc tells implementers to adapt to real code style
|
|
15
|
+
// ("mirror the style in scene/schema/scene-file.ts" per CLAUDE.md), so the
|
|
16
|
+
// schema consts here are suffixed and the bare names are reserved for the
|
|
17
|
+
// inferred types, matching every other schema file in the repo.
|
|
18
|
+
//
|
|
19
|
+
// Adapter surface values mirror `AdapterSurface` in
|
|
20
|
+
// `packages/engine/src/runtime/game.ts` (`'three' | 'canvas' | 'dom'`)
|
|
21
|
+
// by value, not by import. The adapter remains the sole root discriminator.
|
|
22
|
+
import { z } from 'zod';
|
|
23
|
+
/**
|
|
24
|
+
* Current on-disk `vgai.project.json` format. Exported so editor/server
|
|
25
|
+
* compatibility checks do not duplicate the schema's literal value.
|
|
26
|
+
*/
|
|
27
|
+
export const GAME_MANIFEST_VERSION = 2;
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
// Ingest capture strategy (the general vocabulary D6/§4 names)
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
export const IngestStrategySchema = z.enum([
|
|
32
|
+
'shared', // game imports host-served ESM three — full in-realm capture
|
|
33
|
+
'deduped', // game source built by OUR pipeline, bundler dedupe — full capture
|
|
34
|
+
'iframe-reachable', // prebuilt bundle in iframe, three reachable — cross-realm capture
|
|
35
|
+
'opaque-embed', // prebuilt bundle, nothing reachable — host lifecycle only
|
|
36
|
+
]);
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
// Capability tier — one ordered enum, declared per delivery context (§4)
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
export const TierSchema = z.enum([
|
|
41
|
+
'first-party', // vgai-native root: full editor, full loop control
|
|
42
|
+
'shared', // = IngestStrategy 'shared' rung
|
|
43
|
+
'deduped', // = IngestStrategy 'deduped' rung
|
|
44
|
+
'iframe-reachable', // = IngestStrategy 'iframe-reachable' rung
|
|
45
|
+
'opaque-embed', // = IngestStrategy 'opaque-embed' rung
|
|
46
|
+
'unsupported', // this root does not function in this delivery context
|
|
47
|
+
]);
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
// Root adapter identity. The adapter is the sole discriminator: a root never
|
|
50
|
+
// repeats its rendering substrate in a sibling `kind` field. Module and ingest
|
|
51
|
+
// adapters carry the surface their adapter contract exposes because the host
|
|
52
|
+
// must allocate a layer before the module has mounted.
|
|
53
|
+
//
|
|
54
|
+
// The surface vocabulary is `three | canvas | dom` — what the HOST HANDS the
|
|
55
|
+
// root, not which library it uses. `canvas` and `dom` are platform primitives:
|
|
56
|
+
// a canvas root may be Pixi, Phaser, Babylon, raw WebGL/WebGPU or a 2D context,
|
|
57
|
+
// and a dom root may be React, Vue, Svelte or plain HTML, all through the
|
|
58
|
+
// identical host. The former `canvas`/`react` named two libraries in a seam
|
|
59
|
+
// that has nothing to do with either, which foreclosed the rest by
|
|
60
|
+
// construction.
|
|
61
|
+
//
|
|
62
|
+
// All three surfaces are legal as a BARE adapter string: each names a root the
|
|
63
|
+
// engine itself mounts from an `entry` module — `three` through the R3F lane
|
|
64
|
+
// (`@engine/world3d-react`), `canvas` through the Pixi lane
|
|
65
|
+
// (`@engine/canvas-react`), `dom` through the React lane. In every case the
|
|
66
|
+
// entry's document is its own TSX source. A root the engine does NOT mount
|
|
67
|
+
// arrives as an `{ ingest }` root or a `{ module }` adapter the project
|
|
68
|
+
// supplies, both of which name their `surface` explicitly.
|
|
69
|
+
//
|
|
70
|
+
// `three` earns a kind of its own because the host must provide something the
|
|
71
|
+
// platform cannot: the ONE shared `three` instance (identity matters — ingest
|
|
72
|
+
// games bring their own, and r3f depends on dedupe). React needs no equivalent,
|
|
73
|
+
// which is exactly why react is a `dom` root rather than its own kind.
|
|
74
|
+
//
|
|
75
|
+
// The pre-rename spellings `threejs`/`pixijs`/`react` are REMOVED, not
|
|
76
|
+
// normalized (WO-LR1 item 2, the legacy-removal doctrine at
|
|
77
|
+
// ARCHITECTURE-CORE §Vocabulary). Normalization was a second way to say the
|
|
78
|
+
// same thing: two spellings both parsed, so both kept being written, and
|
|
79
|
+
// SECOND readers grew (the dev server's surface probe, the hosted-editor
|
|
80
|
+
// bundler's alias sets) each re-implementing the same map. A manifest naming
|
|
81
|
+
// an old spelling now fails to parse with an issue that names the canonical
|
|
82
|
+
// value and the exact one-line edit.
|
|
83
|
+
// ---------------------------------------------------------------------------
|
|
84
|
+
/** Removed spellings → the canonical value each one must be rewritten to. */
|
|
85
|
+
const REMOVED_SURFACE_SPELLING = {
|
|
86
|
+
threejs: 'three',
|
|
87
|
+
pixijs: 'canvas',
|
|
88
|
+
react: 'dom',
|
|
89
|
+
};
|
|
90
|
+
/** Removed spellings legal as a BARE adapter (a root the engine itself mounts). */
|
|
91
|
+
const REMOVED_BARE_ADAPTER_SPELLING = {
|
|
92
|
+
threejs: 'three',
|
|
93
|
+
pixijs: 'canvas',
|
|
94
|
+
react: 'dom',
|
|
95
|
+
};
|
|
96
|
+
function removedSpellingMessage(bad, where) {
|
|
97
|
+
const canonical = where === 'adapter' ? REMOVED_BARE_ADAPTER_SPELLING[bad] : REMOVED_SURFACE_SPELLING[bad];
|
|
98
|
+
return (`Game manifest: \`${where}\`: "${bad}" — that spelling was REMOVED (WO-LR1; ` +
|
|
99
|
+
'ARCHITECTURE-CORE §Vocabulary). The surface vocabulary is ' +
|
|
100
|
+
"'three' | 'canvas' | 'dom' — what the HOST HANDS the root, never which " +
|
|
101
|
+
`library it uses.\nFix: change \`${where}\` to "${canonical}".`);
|
|
102
|
+
}
|
|
103
|
+
/** Reject a removed surface spelling wherever one may appear — the bare
|
|
104
|
+
* shorthand, or the `surface` field of a module/ingest adapter — with an issue
|
|
105
|
+
* naming the canonical value. Runs as a Zod preprocess so the message wins
|
|
106
|
+
* over the union's generic discriminant error. */
|
|
107
|
+
function rejectRemovedRootAdapterSpelling(value, ctx) {
|
|
108
|
+
if (typeof value === 'string' && REMOVED_BARE_ADAPTER_SPELLING[value]) {
|
|
109
|
+
ctx.addIssue({ code: 'custom', message: removedSpellingMessage(value, 'adapter') });
|
|
110
|
+
return z.NEVER;
|
|
111
|
+
}
|
|
112
|
+
if (value && typeof value === 'object' && 'surface' in value) {
|
|
113
|
+
const surface = value.surface;
|
|
114
|
+
if (typeof surface === 'string' && REMOVED_SURFACE_SPELLING[surface]) {
|
|
115
|
+
ctx.addIssue({
|
|
116
|
+
code: 'custom',
|
|
117
|
+
message: removedSpellingMessage(surface, 'adapter.surface'),
|
|
118
|
+
});
|
|
119
|
+
return z.NEVER;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return value;
|
|
123
|
+
}
|
|
124
|
+
export const RootAdapterSchema = z
|
|
125
|
+
.preprocess(rejectRemovedRootAdapterSpelling, z.union([
|
|
126
|
+
z.enum(['three', 'canvas', 'dom']),
|
|
127
|
+
z
|
|
128
|
+
.object({
|
|
129
|
+
module: z
|
|
130
|
+
.string()
|
|
131
|
+
.describe('Game-folder-relative path to a custom adapter module (trust boundary)'),
|
|
132
|
+
surface: z
|
|
133
|
+
.enum(['three', 'canvas', 'dom'])
|
|
134
|
+
.describe('Native surface exposed by this custom adapter contract'),
|
|
135
|
+
})
|
|
136
|
+
.strict(),
|
|
137
|
+
z
|
|
138
|
+
.object({
|
|
139
|
+
surface: z
|
|
140
|
+
.enum(['three', 'canvas', 'dom'])
|
|
141
|
+
.describe('Native surface captured from the unmodified game'),
|
|
142
|
+
ingest: z
|
|
143
|
+
.object({
|
|
144
|
+
strategy: IngestStrategySchema.describe('Capture mechanics rung this ingested root uses (§4) — also the root`s natural local capability tier'),
|
|
145
|
+
entryHtml: z
|
|
146
|
+
.string()
|
|
147
|
+
.optional()
|
|
148
|
+
.describe('Entry HTML path, project-relative. WIRED for opaque-embed (D-W2): ' +
|
|
149
|
+
'the file`s bytes are read verbatim through ' +
|
|
150
|
+
'the project-static route and hosted in a sandboxed iframe (embed-only, no scene ' +
|
|
151
|
+
'introspection), for both canvas and three roots. Legal but NOT wired to a ' +
|
|
152
|
+
'mount for iframe-reachable (a named error at resolve names this — use `bundleUrl` ' +
|
|
153
|
+
'instead, the wired reachable route).'),
|
|
154
|
+
assets: z
|
|
155
|
+
.record(z.string(), z.string())
|
|
156
|
+
.optional()
|
|
157
|
+
.describe('Path-substring -> served-URL rewrites for this ingested game (IngestGame.assets today)'),
|
|
158
|
+
domStubs: z
|
|
159
|
+
.array(z.string())
|
|
160
|
+
.optional()
|
|
161
|
+
.describe('DOM API stub ids this ingested game requires to run headlessly/in-realm'),
|
|
162
|
+
captureTimeoutMs: z
|
|
163
|
+
.number()
|
|
164
|
+
.optional()
|
|
165
|
+
.describe('How long to wait for capture before REPORTING the degrade loudly — not how ' +
|
|
166
|
+
'long to keep listening. On the self-hosted-three route the devtools ' +
|
|
167
|
+
'subscription is permanent, so a renderer appearing later still upgrades a ' +
|
|
168
|
+
'reported-embed-only mount in place; the host clamps this value so a long ' +
|
|
169
|
+
'one cannot block the editor on a question the upgrade path answers anyway.'),
|
|
170
|
+
// The six iframe-reachable-multi mount fields
|
|
171
|
+
// (`ingest-iframe-2d.ts`'s `IframeReachableMultiOpts`), legal
|
|
172
|
+
// ONLY when `strategy` is 'iframe-reachable' (enforced by the
|
|
173
|
+
// `.superRefine` below).
|
|
174
|
+
bundleUrl: z
|
|
175
|
+
.string()
|
|
176
|
+
.optional()
|
|
177
|
+
.describe('Absolute URL of the externalized built game bundle — the WIRED iframe-reachable ' +
|
|
178
|
+
'mount route (iframe-reachable only), for BOTH canvas (Track P, ' +
|
|
179
|
+
"ingest-iframe-2d.ts's mountIngestGame2DIframeReachableMulti) and three (D-W1, " +
|
|
180
|
+
"ingest-iframe-reachable-adapter.ts's mountIngestGameIframeReachableBundle). " +
|
|
181
|
+
'PRECONDITION: the bundle must externalize its root`s own runtime as a bare, ' +
|
|
182
|
+
'un-rewritten import (`pixi.js` for canvas, `three` for three — `vgai bundle` ' +
|
|
183
|
+
'does this for you) so it resolves through the iframe importmap to the HOST ' +
|
|
184
|
+
'instance the capture trap is installed on; a bundle with an inlined runtime is ' +
|
|
185
|
+
'unreachable and degrades to the embed-only floor. Exactly one of bundleUrl/' +
|
|
186
|
+
'entryHtml is required when strategy is iframe-reachable.'),
|
|
187
|
+
baseHref: z
|
|
188
|
+
.string()
|
|
189
|
+
.optional()
|
|
190
|
+
.describe("Iframe <base href> so the game's relative asset URLs resolve (iframe-reachable only)."),
|
|
191
|
+
assetBaseUrl: z
|
|
192
|
+
.string()
|
|
193
|
+
.optional()
|
|
194
|
+
.describe("Host-side basePath forced onto the trapped runtime's own asset resolution — " +
|
|
195
|
+
"pixi's `Assets.init` for a canvas root, three's " +
|
|
196
|
+
'`DefaultLoadingManager.setURLModifier` for a three root (D-W1) — absolute, or ' +
|
|
197
|
+
"root-relative (resolved against the editor page's own origin at mount time, " +
|
|
198
|
+
'ingest-mode.ts, so a static manifest never has to know the dev-server port) ' +
|
|
199
|
+
'(iframe-reachable only — a document.write iframe keeps the parent window.location).'),
|
|
200
|
+
extraDeps: z
|
|
201
|
+
.array(z.string())
|
|
202
|
+
.optional()
|
|
203
|
+
.describe("Bare specifiers of this root's externalized deps beyond its own runtime " +
|
|
204
|
+
"(pixi.js/three — e.g. '@pixi/sound', 'gsap'). Resolved by the editor's " +
|
|
205
|
+
'host-namespace registry into module namespaces when known (D-P1 — the manifest ' +
|
|
206
|
+
'carries data, not code); an unregistered specifier falls back to the open ' +
|
|
207
|
+
"project's own node_modules (D-Z3), served " +
|
|
208
|
+
'as a verbatim iframe importmap URL. Throws a named error if neither resolves it ' +
|
|
209
|
+
'(iframe-reachable only).'),
|
|
210
|
+
pixiModuleUrl: z
|
|
211
|
+
.string()
|
|
212
|
+
.optional()
|
|
213
|
+
.describe('PIXI-ONLY: standalone matching-major pixi ESM URL to trap instead of the host ' +
|
|
214
|
+
"pixi, for version-skewed games (e.g. a v6 game on a v8 host); this field's " +
|
|
215
|
+
'PRESENCE is how the skew is expressed (D-P2 — no separate strategy/tier for ' +
|
|
216
|
+
'version skew) (iframe-reachable only). Declaring this on a `kind: "three"` ' +
|
|
217
|
+
'root is schema-legal (this field is kind-agnostic here) but throws a NAMED ' +
|
|
218
|
+
'not-supported error at resolve — three has no version-skew mount this wave ' +
|
|
219
|
+
'(D-W7: a hypothetical `threeModuleUrl` is explicitly parked, no consumer ' +
|
|
220
|
+
'exists).'),
|
|
221
|
+
bodyHtml: z
|
|
222
|
+
.string()
|
|
223
|
+
.optional()
|
|
224
|
+
.describe('HTML injected into the iframe body before the game script boots (e.g. a ' +
|
|
225
|
+
'`<div id="game-root">` the game expects to find) (iframe-reachable only).'),
|
|
226
|
+
})
|
|
227
|
+
.describe('Ingest adapter configuration for an unmodified game (a repo-vendored game or your ' +
|
|
228
|
+
'own external folder)')
|
|
229
|
+
.superRefine((ingest, ctx) => {
|
|
230
|
+
// The six iframe-reachable-multi fields only make sense for the
|
|
231
|
+
// iframe-reachable-multi mount — reject them under any other
|
|
232
|
+
// strategy (mirrors ui.ts's dead-field-under-wrong-variant pattern).
|
|
233
|
+
const iframeOnlyFields = [
|
|
234
|
+
['bundleUrl', ingest.bundleUrl !== undefined],
|
|
235
|
+
['baseHref', ingest.baseHref !== undefined],
|
|
236
|
+
['assetBaseUrl', ingest.assetBaseUrl !== undefined],
|
|
237
|
+
['extraDeps', ingest.extraDeps !== undefined],
|
|
238
|
+
['pixiModuleUrl', ingest.pixiModuleUrl !== undefined],
|
|
239
|
+
['bodyHtml', ingest.bodyHtml !== undefined],
|
|
240
|
+
];
|
|
241
|
+
if (ingest.strategy !== 'iframe-reachable') {
|
|
242
|
+
for (const [key, present] of iframeOnlyFields) {
|
|
243
|
+
if (present) {
|
|
244
|
+
ctx.addIssue({
|
|
245
|
+
code: z.ZodIssueCode.custom,
|
|
246
|
+
message: `\`${key}\` is only legal when strategy is 'iframe-reachable' (got ` +
|
|
247
|
+
`"${ingest.strategy}") — bundleUrl/baseHref/assetBaseUrl/extraDeps/` +
|
|
248
|
+
"pixiModuleUrl/bodyHtml are the iframe-reachable-multi mount's options " +
|
|
249
|
+
'(canvas: ingest-iframe-2d.ts IframeReachableMultiOpts; three, D-W1: ' +
|
|
250
|
+
'ingest-iframe-reachable-adapter.ts IframeReachableBundleOpts) and have no ' +
|
|
251
|
+
'meaning under any other strategy.',
|
|
252
|
+
path: [key],
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
const hasBundleUrl = ingest.bundleUrl !== undefined;
|
|
259
|
+
const hasEntryHtml = ingest.entryHtml !== undefined;
|
|
260
|
+
if (hasBundleUrl === hasEntryHtml) {
|
|
261
|
+
ctx.addIssue({
|
|
262
|
+
code: z.ZodIssueCode.custom,
|
|
263
|
+
message: "strategy 'iframe-reachable' requires EXACTLY ONE of `bundleUrl` (externalized " +
|
|
264
|
+
'multi-file bundle, the iframe-reachable-multi mount) or `entryHtml` (single-' +
|
|
265
|
+
`file/legacy iframe entry) — ${hasBundleUrl ? 'both are present' : 'neither is present'}.`,
|
|
266
|
+
path: hasBundleUrl ? ['bundleUrl'] : ['entryHtml'],
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
}),
|
|
270
|
+
})
|
|
271
|
+
.strict(),
|
|
272
|
+
]))
|
|
273
|
+
.describe("Root adapter identity: built-in 'three'/'canvas'/'dom' (what the host hands " +
|
|
274
|
+
"the root — 'canvas' covers Pixi/Phaser/Babylon/raw WebGL, 'dom' covers " +
|
|
275
|
+
'React/Vue/plain HTML), a custom { module, surface } adapter, or an ' +
|
|
276
|
+
'{ ingest, surface } adapter for an unmodified game.');
|
|
277
|
+
// ---------------------------------------------------------------------------
|
|
278
|
+
// Root entry
|
|
279
|
+
// ---------------------------------------------------------------------------
|
|
280
|
+
export const AdapterRootSchema = z
|
|
281
|
+
.object({
|
|
282
|
+
id: z
|
|
283
|
+
.string()
|
|
284
|
+
.describe('Unique id for this root within the manifest (enforced-unique, D-V6 — GameManifestSchema.roots rejects duplicates)'),
|
|
285
|
+
description: z
|
|
286
|
+
.string()
|
|
287
|
+
.optional()
|
|
288
|
+
.describe("Optional one-line description of this root's game/content (e.g. an ingested game's " +
|
|
289
|
+
"blurb — the manifest-native replacement for a registry entry's description field)"),
|
|
290
|
+
adapter: RootAdapterSchema.describe("This root's adapter and sole rendering/lifecycle discriminator"),
|
|
291
|
+
entry: z
|
|
292
|
+
.string()
|
|
293
|
+
.optional()
|
|
294
|
+
.describe('Module exporting a world root — a TSX/R3F component or a setup()/adapter (three), or a ' +
|
|
295
|
+
'React component (dom). Required for every built-in adapter root.'),
|
|
296
|
+
zOrder: z
|
|
297
|
+
.number()
|
|
298
|
+
.int()
|
|
299
|
+
.default(0)
|
|
300
|
+
.describe('Canvas stacking order; ties broken by array order'),
|
|
301
|
+
pausable: z
|
|
302
|
+
.boolean()
|
|
303
|
+
.default(true)
|
|
304
|
+
.describe('Whether play-mode pause/step applies to this root'),
|
|
305
|
+
dev: z
|
|
306
|
+
.boolean()
|
|
307
|
+
.default(false)
|
|
308
|
+
.describe("Marks this root as a DEV LAYER: the game's own dev GUI, not shipped game content. " +
|
|
309
|
+
'Four readers act on it. `mountManifestRoots` mounts it only when dev layers are ' +
|
|
310
|
+
'enabled (`devLayersEnabled`, runtime/dev-layers.ts), so a production build carries ' +
|
|
311
|
+
'no dev GUI; the host stacks every dev root ABOVE every non-dev root (a dev layer ' +
|
|
312
|
+
'sits topmost, and as a DOM layer it steals no input from the game while closed); ' +
|
|
313
|
+
'the play compositor EXCLUDES dev layers from a capture unless the capture asks for ' +
|
|
314
|
+
'them; and the editor mounts a dev root as edit-time CHROME rather than authorable ' +
|
|
315
|
+
'content (no hierarchy entry, no OID stamping, no JSX write-back, not selectable).'),
|
|
316
|
+
loop: z
|
|
317
|
+
.enum(['gated', 'self-driven'])
|
|
318
|
+
.default('gated')
|
|
319
|
+
.describe('gated: host-driven loop (default). self-driven: this root drives its own loop ' +
|
|
320
|
+
'(the "composited, unsynchronized" tier) — an axis independent of capability tier'),
|
|
321
|
+
capabilities: z
|
|
322
|
+
.object({
|
|
323
|
+
local: TierSchema.optional().describe('Declared capability tier when served via the local CLI (Vite pipeline); omitted -> derived (§4)'),
|
|
324
|
+
hosted: TierSchema.optional().describe('Declared capability tier when served hosted (no bundler: esbuild-wasm + externals only); omitted -> derived (§4)'),
|
|
325
|
+
})
|
|
326
|
+
.optional()
|
|
327
|
+
.describe("Per-delivery-context capability tier declarations (§4). Declaring above the adapter's " +
|
|
328
|
+
'ceiling for that context is an error; declaring at or below it (including `unsupported`) is legal.'),
|
|
329
|
+
})
|
|
330
|
+
.strict();
|
|
331
|
+
/**
|
|
332
|
+
* The MEDIUM a root occupies — its surface, i.e. what the host hands it. A
|
|
333
|
+
* bare adapter string names its own surface; `{ module, surface }` and
|
|
334
|
+
* `{ ingest, surface }` name it explicitly. Bucketing by surface is what makes
|
|
335
|
+
* a first-party `@pixi/react` world, an ingested canvas game and a custom
|
|
336
|
+
* canvas module ONE medium: they all compete for the same canvas surface, and
|
|
337
|
+
* which library draws on it is not what the rule below is about.
|
|
338
|
+
*/
|
|
339
|
+
function rootMedium(root) {
|
|
340
|
+
return typeof root.adapter === 'string' ? root.adapter : root.adapter.surface;
|
|
341
|
+
}
|
|
342
|
+
// ---------------------------------------------------------------------------
|
|
343
|
+
// Learn metadata (FT-5)
|
|
344
|
+
// ---------------------------------------------------------------------------
|
|
345
|
+
export const LearnKindSchema = z
|
|
346
|
+
.enum(['starter', 'feature', 'sample-game', 'lesson-companion'])
|
|
347
|
+
.describe('Content kind in the FTUE taxonomy (§3): starter (minimal per-genre starting point), ' +
|
|
348
|
+
'feature (demonstrates a subsystem), sample-game (complete game as an architectural ' +
|
|
349
|
+
'reference), lesson-companion (exists to back a Learn-site lesson)');
|
|
350
|
+
export const LearnDifficultySchema = z
|
|
351
|
+
.enum(['beginner', 'intermediate', 'advanced'])
|
|
352
|
+
.describe('Learner-facing difficulty rating');
|
|
353
|
+
export const LearnMetadataSchema = z
|
|
354
|
+
.object({
|
|
355
|
+
kind: LearnKindSchema,
|
|
356
|
+
title: z.string().min(1).describe('Learner-facing display title (gallery card headline)'),
|
|
357
|
+
summary: z.string().min(1).describe('One-sentence learner-facing summary (gallery card body)'),
|
|
358
|
+
difficulty: LearnDifficultySchema,
|
|
359
|
+
features: z
|
|
360
|
+
.array(z.string().regex(/^[a-z0-9]+(-[a-z0-9]+)*$/, 'features tags must be kebab-case'))
|
|
361
|
+
.describe('Short kebab-case feature tags used as gallery/catalog filter facets'),
|
|
362
|
+
thumbnail: z
|
|
363
|
+
.string()
|
|
364
|
+
.optional()
|
|
365
|
+
.describe('Optional thumbnail image reference, PROJECT-relative (canonical path: ' +
|
|
366
|
+
'learn/thumbnail.png — the §3 schema path). Generated per FT-11 by the deterministic ' +
|
|
367
|
+
'render tooling (scripts/generate-learn-thumbnails.ts), never hand-made'),
|
|
368
|
+
preview: z
|
|
369
|
+
.string()
|
|
370
|
+
.optional()
|
|
371
|
+
.describe('Optional short preview video/loop reference, PROJECT-relative (canonical path: ' +
|
|
372
|
+
'learn/preview.mp4; generated per FT-11)'),
|
|
373
|
+
lesson: z
|
|
374
|
+
.string()
|
|
375
|
+
.optional()
|
|
376
|
+
.describe('Optional Learn-site lesson URL that teaches this project 1:1 ' +
|
|
377
|
+
'(e.g. https://vgai-learn.pages.dev/quick-starts/joints/)'),
|
|
378
|
+
})
|
|
379
|
+
.strict()
|
|
380
|
+
.describe('Learner-facing metadata (FT-5) — powers the example ' +
|
|
381
|
+
'gallery, New Project wizard, and Learn-site catalog. Registries are generated from this ' +
|
|
382
|
+
'block; there is no parallel hand-edited catalog.');
|
|
383
|
+
// ---------------------------------------------------------------------------
|
|
384
|
+
// Game manifest (vgai.project.json)
|
|
385
|
+
// ---------------------------------------------------------------------------
|
|
386
|
+
export const GameManifestSchema = z
|
|
387
|
+
.object({
|
|
388
|
+
$schema: z
|
|
389
|
+
.string()
|
|
390
|
+
.optional()
|
|
391
|
+
.describe('Optional JSON Schema URI for editor autocomplete and validation'),
|
|
392
|
+
manifestVersion: z
|
|
393
|
+
.literal(GAME_MANIFEST_VERSION)
|
|
394
|
+
.describe('Manifest file format version (v2 clean roots)'),
|
|
395
|
+
name: z.string().describe('Game display name'),
|
|
396
|
+
appId: z
|
|
397
|
+
.string()
|
|
398
|
+
.optional()
|
|
399
|
+
.describe('Stable reverse-domain application id used by packaged targets'),
|
|
400
|
+
version: z.string().describe("The game's own version (used for orphan detection)"),
|
|
401
|
+
engine: z
|
|
402
|
+
.object({
|
|
403
|
+
version: z
|
|
404
|
+
.string()
|
|
405
|
+
.describe('Exact @vgai/engine semver this game was scaffolded/last upgraded against — an ' +
|
|
406
|
+
'identity pin, not a range'),
|
|
407
|
+
})
|
|
408
|
+
.describe('Engine version pin'),
|
|
409
|
+
roots: z
|
|
410
|
+
.array(AdapterRootSchema)
|
|
411
|
+
.min(1)
|
|
412
|
+
.superRefine((roots, ctx) => {
|
|
413
|
+
// D-V6 (debt): root ids are described as unique above but that was
|
|
414
|
+
// describe-only at the SCHEMA level — only load.ts's loader-level
|
|
415
|
+
// cross-field check caught a collision, so any OTHER consumer of this
|
|
416
|
+
// schema (the generated JSON Schema, editor tooling) saw duplicate
|
|
417
|
+
// ids as legal. Enforced HERE instead, naming every colliding id (not
|
|
418
|
+
// just the first found) — a root id is the key every per-world editor
|
|
419
|
+
// surface is addressed by, so a silently-permitted duplicate would
|
|
420
|
+
// have two roots silently collide.
|
|
421
|
+
const counts = new Map();
|
|
422
|
+
for (const root of roots)
|
|
423
|
+
counts.set(root.id, (counts.get(root.id) ?? 0) + 1);
|
|
424
|
+
const duplicates = [...counts.entries()].filter(([, n]) => n > 1).map(([id]) => id);
|
|
425
|
+
if (duplicates.length > 0) {
|
|
426
|
+
const idsText = duplicates.map((id) => `"${id}"`).join(', ');
|
|
427
|
+
ctx.addIssue({
|
|
428
|
+
code: z.ZodIssueCode.custom,
|
|
429
|
+
message: duplicates.length === 1
|
|
430
|
+
? `Game manifest: duplicate root id ${idsText} — root ids must be unique across the manifest (enforced-unique).`
|
|
431
|
+
: `Game manifest: duplicate root ids: ${idsText} — root ids must be unique across the manifest (enforced-unique).`,
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
// A project has at most ONE world root per MEDIUM (owner-ratified).
|
|
435
|
+
// The medium is the surface (see `rootMedium`), so `three`, `dom` and
|
|
436
|
+
// the canvas surface are the three buckets — a first-party canvas
|
|
437
|
+
// world, a canvas ingest and a canvas module are the SAME medium.
|
|
438
|
+
//
|
|
439
|
+
// Enforced here rather than left to the reader because the editor
|
|
440
|
+
// mounts exactly one root per medium (`resolveFocusedThreejsRootId`
|
|
441
|
+
// is a `find`, and the design-time layer stack hosts the one dom
|
|
442
|
+
// root): a second root of the same medium parsed cleanly and was then
|
|
443
|
+
// silently never mounted, which is the failure mode this rejects.
|
|
444
|
+
//
|
|
445
|
+
// DEV LAYERS ARE COUNTED SEPARATELY. A `dev: true` root is not content
|
|
446
|
+
// competing for the medium — it is the game's dev GUI stacked above
|
|
447
|
+
// everything (`create-runtime.ts`'s stacking pass), and the editor
|
|
448
|
+
// mounts it as chrome, not as the one dom document. Counting it with
|
|
449
|
+
// the content roots would make the ratified shape — a game with a HUD
|
|
450
|
+
// and a dev panel, both `dom` — unrepresentable. The one-per-medium
|
|
451
|
+
// rule still applies WITHIN the dev band, for the same
|
|
452
|
+
// silently-never-mounted reason.
|
|
453
|
+
const idsByMedium = new Map();
|
|
454
|
+
for (const root of roots) {
|
|
455
|
+
const medium = `${root.dev ? 'dev ' : ''}${rootMedium(root)}`;
|
|
456
|
+
const ids = idsByMedium.get(medium);
|
|
457
|
+
if (ids)
|
|
458
|
+
ids.push(root.id);
|
|
459
|
+
else
|
|
460
|
+
idsByMedium.set(medium, [root.id]);
|
|
461
|
+
}
|
|
462
|
+
for (const [medium, ids] of idsByMedium) {
|
|
463
|
+
if (ids.length < 2)
|
|
464
|
+
continue;
|
|
465
|
+
ctx.addIssue({
|
|
466
|
+
code: z.ZodIssueCode.custom,
|
|
467
|
+
message: `Game manifest: a project has at most one ${medium} world root — ` +
|
|
468
|
+
`${ids.map((id) => `"${id}"`).join(', ')} all occupy the ${medium} surface. ` +
|
|
469
|
+
'Keep one and remove the rest, or move a root to a different medium ' +
|
|
470
|
+
"(three / canvas / dom); only one root per medium is ever mounted, so a second one's " +
|
|
471
|
+
'content would never appear.',
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
})
|
|
475
|
+
.describe("The Game's explicit, non-empty adapter-root composition. There is no implicit root. " +
|
|
476
|
+
'Root ids are unique, and a project declares at most ONE world root per medium — ' +
|
|
477
|
+
'one `three`, one `dom`, one canvas-surface root (first-party canvas, canvas ingest ' +
|
|
478
|
+
'and canvas module are the same medium). A `dev: true` root is counted in its own ' +
|
|
479
|
+
'band: a dev layer is chrome stacked above the game, not content competing for the ' +
|
|
480
|
+
'medium, so a game may declare a `dom` HUD and a `dom` dev layer — but not two of either.'),
|
|
481
|
+
authoring: z
|
|
482
|
+
.object({
|
|
483
|
+
hierarchy: z
|
|
484
|
+
.object({
|
|
485
|
+
rootLabels: z
|
|
486
|
+
.record(z.string(), z.string())
|
|
487
|
+
.optional()
|
|
488
|
+
.describe('Optional editor labels keyed by adapter-root id'),
|
|
489
|
+
groups: z
|
|
490
|
+
.array(z.object({
|
|
491
|
+
id: z.string().describe('Unique editor-only group id'),
|
|
492
|
+
label: z.string().describe('Editor-only group label'),
|
|
493
|
+
roots: z
|
|
494
|
+
.array(z.string())
|
|
495
|
+
.min(1)
|
|
496
|
+
.describe('Adapter-root ids shown under this editor-only group'),
|
|
497
|
+
}))
|
|
498
|
+
.optional()
|
|
499
|
+
.describe('Optional editor-only hierarchy groups'),
|
|
500
|
+
})
|
|
501
|
+
.optional()
|
|
502
|
+
.describe('Editor projection for native adapter roots'),
|
|
503
|
+
})
|
|
504
|
+
.optional()
|
|
505
|
+
.describe('Editor-only authoring metadata; never runtime ownership'),
|
|
506
|
+
server: z
|
|
507
|
+
.object({
|
|
508
|
+
room: z.string().describe('Colyseus room name'),
|
|
509
|
+
module: z
|
|
510
|
+
.string()
|
|
511
|
+
.optional()
|
|
512
|
+
.describe('Module path for the Colyseus room bootstrap; defaults to the scaffolded server bootstrap'),
|
|
513
|
+
relay: z
|
|
514
|
+
.object({
|
|
515
|
+
signalingUrl: z
|
|
516
|
+
.string()
|
|
517
|
+
.optional()
|
|
518
|
+
.describe('Managed relay signaling URL to prefer over the client default; omitted when the deploy did not pin one'),
|
|
519
|
+
accessToken: z
|
|
520
|
+
.string()
|
|
521
|
+
.describe('Room-scoped managed-relay access token minted at `vgai deploy` and read by the standalone client (main.ts)'),
|
|
522
|
+
expiresAt: z
|
|
523
|
+
.number()
|
|
524
|
+
.describe('Token expiry as epoch milliseconds; the client falls back to a tokenless join once elapsed'),
|
|
525
|
+
})
|
|
526
|
+
.strict()
|
|
527
|
+
.optional()
|
|
528
|
+
.describe('Deploy-baked managed-relay credentials. NEVER hand-authored in source — written only into the staged manifest by `vgai deploy` and fetched at runtime by the standalone client'),
|
|
529
|
+
})
|
|
530
|
+
.optional()
|
|
531
|
+
.describe('Multiplayer server config (Colyseus), if this game registers a room'),
|
|
532
|
+
resolution: z
|
|
533
|
+
.object({
|
|
534
|
+
width: z.number().describe('Canvas width in pixels'),
|
|
535
|
+
height: z.number().describe('Canvas height in pixels'),
|
|
536
|
+
})
|
|
537
|
+
.optional()
|
|
538
|
+
.describe('Canvas resolution'),
|
|
539
|
+
debug: z
|
|
540
|
+
.object({
|
|
541
|
+
allowInProduction: z
|
|
542
|
+
.boolean()
|
|
543
|
+
.describe('Allow the ?vgai-debug=1 introspection bridge and debug-command invocation in ' +
|
|
544
|
+
'production builds. Default false: the bridge only installs in dev builds. The ' +
|
|
545
|
+
'runtime reader is the debug-bridge installer (D18).'),
|
|
546
|
+
})
|
|
547
|
+
.optional()
|
|
548
|
+
.describe('Debug-bridge production gating (D18) — governs whether ?vgai-debug=1 installs ' +
|
|
549
|
+
'window.__vgai outside dev builds.'),
|
|
550
|
+
determinism: z
|
|
551
|
+
.object({
|
|
552
|
+
seededRandom: z
|
|
553
|
+
.boolean()
|
|
554
|
+
.describe('Declares that ALL gameplay RNG in this project flows through ctx.random (the ' +
|
|
555
|
+
'named-stream seeded PRNG) rather than raw ' +
|
|
556
|
+
'Math.random/Date.now/performance.now. Three runtime enforcers key off this flag: ' +
|
|
557
|
+
'the boot-time seeding reader (mount-manifest.ts seeds ctx.random from ' +
|
|
558
|
+
'defaultSeed/?vgai-seed=/explicit config, in that precedence, only when true), the ' +
|
|
559
|
+
'gameplay-rng-ban burn-down scan (test/gameplay-rng-ban.test.ts — lints this ' +
|
|
560
|
+
"project's src/ for raw RNG/wall-clock calls), and the dev-mode Math.random phase " +
|
|
561
|
+
'trap (runtime/gameplay-rng-trap.ts — warns once per call site during a gameplay ' +
|
|
562
|
+
'frame, never throws). Default false: an undeclared project gets no determinism ' +
|
|
563
|
+
'contract at all (that IS the opt-out — no dead field).'),
|
|
564
|
+
defaultSeed: z
|
|
565
|
+
.number()
|
|
566
|
+
.int()
|
|
567
|
+
.optional()
|
|
568
|
+
.describe('The seed ctx.random boots from when seededRandom is true, unless overridden by ' +
|
|
569
|
+
'?vgai-seed=<int> (the query param always wins over this manifest default) or an ' +
|
|
570
|
+
'even higher-precedence explicit config value a host passes directly. Optional — ' +
|
|
571
|
+
"omit to fall back to the runtime's own fixed default seed."),
|
|
572
|
+
})
|
|
573
|
+
.optional()
|
|
574
|
+
.describe('Seeded-RNG determinism contract (D15) — governs ' +
|
|
575
|
+
'whether ctx.random is boot-seeded from a reproducible seed and whether the ' +
|
|
576
|
+
'gameplay-rng-ban scan / dev-mode Math.random phase trap are active for this project.'),
|
|
577
|
+
budget: z
|
|
578
|
+
.object({
|
|
579
|
+
frameCpuMsP95: z
|
|
580
|
+
.number()
|
|
581
|
+
.positive()
|
|
582
|
+
.optional()
|
|
583
|
+
.describe('Maximum allowed p95 of per-frame CPU time (ms) across the measured frames of a ' +
|
|
584
|
+
'`vgai perf` seeded headless run. CPU-side only: headless runs rasterize under ' +
|
|
585
|
+
'SwiftShader, so this is main-thread frame cost, NOT real GPU frame time. ' +
|
|
586
|
+
'Machine-dependent — prefer the baseline-diff tolerance band for regression ' +
|
|
587
|
+
'gating and use this as a coarse absolute ceiling.'),
|
|
588
|
+
physicsMsP95: z
|
|
589
|
+
.number()
|
|
590
|
+
.positive()
|
|
591
|
+
.optional()
|
|
592
|
+
.describe("Maximum allowed p95 of the profiler's `physics` phase time (ms) per fixed-step " +
|
|
593
|
+
'frame in a `vgai perf` run. Same CPU-timing caveats as frameCpuMsP95.'),
|
|
594
|
+
maxEntities: z
|
|
595
|
+
.number()
|
|
596
|
+
.int()
|
|
597
|
+
.nonnegative()
|
|
598
|
+
.optional()
|
|
599
|
+
.describe('Maximum allowed entity-tagged scene-graph nodes (nodes carrying ' +
|
|
600
|
+
"userData.entityId) summed across the game's three/canvas worlds at the end " +
|
|
601
|
+
'of a `vgai perf` run. Exact and deterministic under a seed — no tolerance band.'),
|
|
602
|
+
maxDrawCalls: z
|
|
603
|
+
.number()
|
|
604
|
+
.int()
|
|
605
|
+
.positive()
|
|
606
|
+
.optional()
|
|
607
|
+
.describe('Maximum allowed renderer draw calls in any measured frame of a `vgai perf` run ' +
|
|
608
|
+
"(the profiler's per-frame render.drawCalls, from renderer.info). Exact and " +
|
|
609
|
+
'deterministic under a seed.'),
|
|
610
|
+
maxTriangles: z
|
|
611
|
+
.number()
|
|
612
|
+
.int()
|
|
613
|
+
.positive()
|
|
614
|
+
.optional()
|
|
615
|
+
.describe('Maximum allowed rendered triangles in any measured frame of a `vgai perf` run ' +
|
|
616
|
+
"(the profiler's per-frame render.triangles, from renderer.info). Exact and " +
|
|
617
|
+
'deterministic under a seed.'),
|
|
618
|
+
})
|
|
619
|
+
.refine((budget) => Object.values(budget).some((value) => value !== undefined), {
|
|
620
|
+
message: 'Game manifest: `budget` must set at least one metric (frameCpuMsP95, physicsMsP95, ' +
|
|
621
|
+
'maxEntities, maxDrawCalls, maxTriangles) — an empty budget block gates nothing ' +
|
|
622
|
+
'(the no-dead-fields policy).',
|
|
623
|
+
})
|
|
624
|
+
.optional()
|
|
625
|
+
.describe('Performance budget (W3d, F11 perf regression gates) asserted by ' +
|
|
626
|
+
'`vgai perf --assert-budget`: a seeded, fixed-step headless run samples the engine ' +
|
|
627
|
+
'profiler and fails (nonzero exit) when any metric here is exceeded. Only ' +
|
|
628
|
+
'headlessly-measurable metrics are budgetable; real GPU frame time is not (SwiftShader).'),
|
|
629
|
+
learn: LearnMetadataSchema.optional().describe('Optional learner-facing metadata (FT-5) — set on shipped example projects so the ' +
|
|
630
|
+
'gallery/wizard/Learn-catalog registries can be generated from the manifest itself'),
|
|
631
|
+
})
|
|
632
|
+
.strict()
|
|
633
|
+
.describe('Game manifest (vgai.project.json) — the complete v2 project configuration');
|