@vgai/engine 0.2.0 → 0.3.0
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/README.md +3 -1
- package/dist/adapter/authoring.d.ts +404 -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 +43 -0
- package/dist/adapter/colyseus-networking-adapter.d.ts.map +1 -0
- package/dist/adapter/colyseus-networking-adapter.js +38 -0
- package/dist/adapter/first-party-systems.d.ts +38 -0
- package/dist/adapter/first-party-systems.d.ts.map +1 -0
- package/dist/adapter/first-party-systems.js +77 -0
- package/dist/adapter/game-adapter.d.ts +133 -0
- package/dist/adapter/game-adapter.d.ts.map +1 -0
- package/dist/adapter/game-adapter.js +10 -0
- package/dist/adapter/host-context.d.ts +73 -0
- package/dist/adapter/host-context.d.ts.map +1 -0
- package/dist/adapter/host-context.js +16 -0
- package/dist/adapter/index.d.ts +22 -0
- package/dist/adapter/index.d.ts.map +1 -0
- package/dist/adapter/index.js +15 -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/overlay-applier.d.ts +118 -0
- package/dist/adapter/ingest/overlay-applier.d.ts.map +1 -0
- package/dist/adapter/ingest/overlay-applier.js +132 -0
- package/dist/adapter/ingest/overlay-apply.d.ts +60 -0
- package/dist/adapter/ingest/overlay-apply.d.ts.map +1 -0
- package/dist/adapter/ingest/overlay-apply.js +101 -0
- package/dist/adapter/ingest/overlay-file.d.ts +79 -0
- package/dist/adapter/ingest/overlay-file.d.ts.map +1 -0
- package/dist/adapter/ingest/overlay-file.js +66 -0
- package/dist/adapter/ingest/overlay-report.d.ts +113 -0
- package/dist/adapter/ingest/overlay-report.d.ts.map +1 -0
- package/dist/adapter/ingest/overlay-report.js +103 -0
- package/dist/adapter/ingest/scene-capture.d.ts +97 -0
- package/dist/adapter/ingest/scene-capture.d.ts.map +1 -0
- package/dist/adapter/ingest/scene-capture.js +248 -0
- package/dist/adapter/ingest/upstream-pin.d.ts +47 -0
- package/dist/adapter/ingest/upstream-pin.d.ts.map +1 -0
- package/dist/adapter/ingest/upstream-pin.js +50 -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 +12 -0
- package/dist/adapter/rapier-physics-adapter.d.ts.map +1 -0
- package/dist/adapter/rapier-physics-adapter.js +46 -0
- package/dist/adapter/system-adapter.d.ts +133 -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/adapter/vgai-scene-game-adapter.d.ts +116 -0
- package/dist/adapter/vgai-scene-game-adapter.d.ts.map +1 -0
- package/dist/adapter/vgai-scene-game-adapter.js +714 -0
- package/dist/adapter/world-kind.d.ts +30 -0
- package/dist/adapter/world-kind.d.ts.map +1 -0
- package/dist/adapter/world-kind.js +18 -0
- package/dist/ai/navigation.d.ts +64 -0
- package/dist/ai/navigation.d.ts.map +1 -0
- package/dist/ai/navigation.js +133 -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 +250 -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 +37 -0
- package/dist/animation/gsap-registration.d.ts +119 -0
- package/dist/animation/gsap-registration.d.ts.map +1 -0
- package/dist/animation/gsap-registration.js +92 -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 +242 -0
- package/dist/animation/theatre-director.d.ts.map +1 -0
- package/dist/animation/theatre-director.js +235 -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 +111 -0
- package/dist/animation/xstate-animation-binding.d.ts.map +1 -0
- package/dist/animation/xstate-animation-binding.js +307 -0
- package/dist/animation/xstate-animation-meta.d.ts +228 -0
- package/dist/animation/xstate-animation-meta.d.ts.map +1 -0
- package/dist/animation/xstate-animation-meta.js +221 -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/index.d.ts +4 -0
- package/dist/audio/index.d.ts.map +1 -0
- package/dist/audio/index.js +24 -0
- package/dist/audio/tone-clock-binding.d.ts +75 -0
- package/dist/audio/tone-clock-binding.d.ts.map +1 -0
- package/dist/audio/tone-clock-binding.js +29 -0
- package/dist/audio/tone-context.d.ts +114 -0
- package/dist/audio/tone-context.d.ts.map +1 -0
- package/dist/audio/tone-context.js +39 -0
- package/dist/audio/tone-offline-render.d.ts +90 -0
- package/dist/audio/tone-offline-render.d.ts.map +1 -0
- package/dist/audio/tone-offline-render.js +56 -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/core/game-loop.d.ts +21 -0
- package/dist/core/game-loop.d.ts.map +1 -0
- package/dist/core/game-loop.js +130 -0
- package/dist/core/system-runner.d.ts +120 -0
- package/dist/core/system-runner.d.ts.map +1 -0
- package/dist/core/system-runner.js +286 -0
- package/dist/core/types.d.ts +58 -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 +110 -0
- package/dist/data/data-check-core.d.ts.map +1 -0
- package/dist/data/data-check-core.js +178 -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/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/logger.d.ts +30 -0
- package/dist/dev/logger.d.ts.map +1 -0
- package/dist/dev/logger.js +90 -0
- package/dist/ecs/component-manager.d.ts +189 -0
- package/dist/ecs/component-manager.d.ts.map +1 -0
- package/dist/ecs/component-manager.js +676 -0
- package/dist/ecs/game-component.d.ts +97 -0
- package/dist/ecs/game-component.d.ts.map +1 -0
- package/dist/ecs/game-component.js +80 -0
- package/dist/ecs/hmr-swap-report.d.ts +53 -0
- package/dist/ecs/hmr-swap-report.d.ts.map +1 -0
- package/dist/ecs/hmr-swap-report.js +55 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/input/input-manager.d.ts +596 -0
- package/dist/input/input-manager.d.ts.map +1 -0
- package/dist/input/input-manager.js +1564 -0
- package/dist/input/input-types.d.ts +171 -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 +43 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +59 -0
- package/dist/manifest/index.d.ts +5 -0
- package/dist/manifest/index.d.ts.map +1 -0
- package/dist/manifest/index.js +8 -0
- package/dist/manifest/load-file.d.ts +4 -0
- package/dist/manifest/load-file.d.ts.map +1 -0
- package/dist/manifest/load-file.js +14 -0
- package/dist/manifest/load.d.ts +117 -0
- package/dist/manifest/load.d.ts.map +1 -0
- package/dist/manifest/load.js +255 -0
- package/dist/manifest/schema.d.ts +173 -0
- package/dist/manifest/schema.d.ts.map +1 -0
- package/dist/manifest/schema.js +302 -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/physics/trigger-dispatch.d.ts +24 -0
- package/dist/physics/trigger-dispatch.d.ts.map +1 -0
- package/dist/physics/trigger-dispatch.js +80 -0
- package/dist/react/game-state.d.ts +105 -0
- package/dist/react/game-state.d.ts.map +1 -0
- package/dist/react/game-state.js +144 -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 +96 -0
- package/dist/react/use-selection.d.ts +75 -0
- package/dist/react/use-selection.d.ts.map +1 -0
- package/dist/react/use-selection.js +90 -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/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 +230 -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 +36 -0
- package/dist/render/render-settings.d.ts.map +1 -0
- package/dist/render/render-settings.js +51 -0
- package/dist/runtime/create-runtime.d.ts +280 -0
- package/dist/runtime/create-runtime.d.ts.map +1 -0
- package/dist/runtime/create-runtime.js +795 -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 +433 -0
- package/dist/runtime/game.d.ts.map +1 -0
- package/dist/runtime/game.js +569 -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 +129 -0
- package/dist/runtime/mount-game.d.ts.map +1 -0
- package/dist/runtime/mount-game.js +152 -0
- package/dist/runtime/mount-manifest.d.ts +119 -0
- package/dist/runtime/mount-manifest.d.ts.map +1 -0
- package/dist/runtime/mount-manifest.js +204 -0
- package/dist/runtime/render-audio-control.d.ts +110 -0
- package/dist/runtime/render-audio-control.d.ts.map +1 -0
- package/dist/runtime/render-audio-control.js +111 -0
- package/dist/runtime/render-control.d.ts +291 -0
- package/dist/runtime/render-control.d.ts.map +1 -0
- package/dist/runtime/render-control.js +264 -0
- package/dist/runtime/render-seed.d.ts +57 -0
- package/dist/runtime/render-seed.d.ts.map +1 -0
- package/dist/runtime/render-seed.js +74 -0
- package/dist/runtime/scene-ui-bridge.d.ts +69 -0
- package/dist/runtime/scene-ui-bridge.d.ts.map +1 -0
- package/dist/runtime/scene-ui-bridge.js +23 -0
- package/dist/runtime/scene-ui-data.d.ts +13 -0
- package/dist/runtime/scene-ui-data.d.ts.map +1 -0
- package/dist/runtime/scene-ui-data.js +92 -0
- package/dist/runtime/state-bridge.d.ts +47 -0
- package/dist/runtime/state-bridge.d.ts.map +1 -0
- package/dist/runtime/state-bridge.js +53 -0
- package/dist/runtime/types.d.ts +179 -0
- package/dist/runtime/types.d.ts.map +1 -0
- package/dist/runtime/types.js +1 -0
- package/dist/scene/asset-loaders.d.ts +79 -0
- package/dist/scene/asset-loaders.d.ts.map +1 -0
- package/dist/scene/asset-loaders.js +141 -0
- package/dist/scene/asset-paths.d.ts +11 -0
- package/dist/scene/asset-paths.d.ts.map +1 -0
- package/dist/scene/asset-paths.js +108 -0
- package/dist/scene/asset-ref-check.d.ts +88 -0
- package/dist/scene/asset-ref-check.d.ts.map +1 -0
- package/dist/scene/asset-ref-check.js +214 -0
- package/dist/scene/asset-registry.d.ts +30 -0
- package/dist/scene/asset-registry.d.ts.map +1 -0
- package/dist/scene/asset-registry.js +50 -0
- package/dist/scene/collider-dimensions.d.ts +63 -0
- package/dist/scene/collider-dimensions.d.ts.map +1 -0
- package/dist/scene/collider-dimensions.js +98 -0
- package/dist/scene/component-registry.d.ts +17 -0
- package/dist/scene/component-registry.d.ts.map +1 -0
- package/dist/scene/component-registry.js +28 -0
- package/dist/scene/defaults.d.ts +252 -0
- package/dist/scene/defaults.d.ts.map +1 -0
- package/dist/scene/defaults.js +151 -0
- package/dist/scene/geometries/index.d.ts +8 -0
- package/dist/scene/geometries/index.d.ts.map +1 -0
- package/dist/scene/geometries/index.js +7 -0
- package/dist/scene/geometries/terrain.d.ts +2 -0
- package/dist/scene/geometries/terrain.d.ts.map +1 -0
- package/dist/scene/geometries/terrain.js +37 -0
- package/dist/scene/geometry-registry.d.ts +24 -0
- package/dist/scene/geometry-registry.d.ts.map +1 -0
- package/dist/scene/geometry-registry.js +20 -0
- package/dist/scene/instance-registry.d.ts +36 -0
- package/dist/scene/instance-registry.d.ts.map +1 -0
- package/dist/scene/instance-registry.js +55 -0
- package/dist/scene/instancers/grid.d.ts +2 -0
- package/dist/scene/instancers/grid.d.ts.map +1 -0
- package/dist/scene/instancers/grid.js +36 -0
- package/dist/scene/instancers/index.d.ts +8 -0
- package/dist/scene/instancers/index.d.ts.map +1 -0
- package/dist/scene/instancers/index.js +7 -0
- package/dist/scene/light-camera-factory.d.ts +23 -0
- package/dist/scene/light-camera-factory.d.ts.map +1 -0
- package/dist/scene/light-camera-factory.js +68 -0
- package/dist/scene/material-factory.d.ts +17 -0
- package/dist/scene/material-factory.d.ts.map +1 -0
- package/dist/scene/material-factory.js +197 -0
- package/dist/scene/material-registry.d.ts +40 -0
- package/dist/scene/material-registry.d.ts.map +1 -0
- package/dist/scene/material-registry.js +44 -0
- package/dist/scene/materials/index.d.ts +8 -0
- package/dist/scene/materials/index.d.ts.map +1 -0
- package/dist/scene/materials/index.js +7 -0
- package/dist/scene/materials/water.d.ts +2 -0
- package/dist/scene/materials/water.d.ts.map +1 -0
- package/dist/scene/materials/water.js +54 -0
- package/dist/scene/parse.d.ts +23 -0
- package/dist/scene/parse.d.ts.map +1 -0
- package/dist/scene/parse.js +179 -0
- package/dist/scene/particles-factory.d.ts +33 -0
- package/dist/scene/particles-factory.d.ts.map +1 -0
- package/dist/scene/particles-factory.js +282 -0
- package/dist/scene/scene-apply.d.ts +109 -0
- package/dist/scene/scene-apply.d.ts.map +1 -0
- package/dist/scene/scene-apply.js +326 -0
- package/dist/scene/scene-diff-schema.d.ts +285 -0
- package/dist/scene/scene-diff-schema.d.ts.map +1 -0
- package/dist/scene/scene-diff-schema.js +92 -0
- package/dist/scene/scene-diff-types.d.ts +40 -0
- package/dist/scene/scene-diff-types.d.ts.map +1 -0
- package/dist/scene/scene-diff-types.js +14 -0
- package/dist/scene/scene-loader.d.ts +177 -0
- package/dist/scene/scene-loader.d.ts.map +1 -0
- package/dist/scene/scene-loader.js +1213 -0
- package/dist/scene/scene-query.d.ts +11 -0
- package/dist/scene/scene-query.d.ts.map +1 -0
- package/dist/scene/scene-query.js +63 -0
- package/dist/scene/scene-types.d.ts +10 -0
- package/dist/scene/scene-types.d.ts.map +1 -0
- package/dist/scene/scene-types.js +8 -0
- package/dist/scene/scene-version.d.ts +26 -0
- package/dist/scene/scene-version.d.ts.map +1 -0
- package/dist/scene/scene-version.js +34 -0
- package/dist/scene/schema/animation.d.ts +8 -0
- package/dist/scene/schema/animation.d.ts.map +1 -0
- package/dist/scene/schema/animation.js +42 -0
- package/dist/scene/schema/audio.d.ts +13 -0
- package/dist/scene/schema/audio.d.ts.map +1 -0
- package/dist/scene/schema/audio.js +22 -0
- package/dist/scene/schema/camera.d.ts +28 -0
- package/dist/scene/schema/camera.d.ts.map +1 -0
- package/dist/scene/schema/camera.js +17 -0
- package/dist/scene/schema/collider.d.ts +40 -0
- package/dist/scene/schema/collider.d.ts.map +1 -0
- package/dist/scene/schema/collider.js +55 -0
- package/dist/scene/schema/entity-ref.d.ts +31 -0
- package/dist/scene/schema/entity-ref.d.ts.map +1 -0
- package/dist/scene/schema/entity-ref.js +61 -0
- package/dist/scene/schema/entity.d.ts +1036 -0
- package/dist/scene/schema/entity.d.ts.map +1 -0
- package/dist/scene/schema/entity.js +153 -0
- package/dist/scene/schema/environment.d.ts +425 -0
- package/dist/scene/schema/environment.d.ts.map +1 -0
- package/dist/scene/schema/environment.js +357 -0
- package/dist/scene/schema/index.d.ts +39 -0
- package/dist/scene/schema/index.d.ts.map +1 -0
- package/dist/scene/schema/index.js +20 -0
- package/dist/scene/schema/instances.d.ts +14 -0
- package/dist/scene/schema/instances.d.ts.map +1 -0
- package/dist/scene/schema/instances.js +28 -0
- package/dist/scene/schema/joint.d.ts +23 -0
- package/dist/scene/schema/joint.d.ts.map +1 -0
- package/dist/scene/schema/joint.js +23 -0
- package/dist/scene/schema/light.d.ts +38 -0
- package/dist/scene/schema/light.d.ts.map +1 -0
- package/dist/scene/schema/light.js +26 -0
- package/dist/scene/schema/material.d.ts +199 -0
- package/dist/scene/schema/material.d.ts.map +1 -0
- package/dist/scene/schema/material.js +99 -0
- package/dist/scene/schema/mesh.d.ts +48 -0
- package/dist/scene/schema/mesh.d.ts.map +1 -0
- package/dist/scene/schema/mesh.js +82 -0
- package/dist/scene/schema/particles.d.ts +2178 -0
- package/dist/scene/schema/particles.d.ts.map +1 -0
- package/dist/scene/schema/particles.js +321 -0
- package/dist/scene/schema/physics.d.ts +56 -0
- package/dist/scene/schema/physics.d.ts.map +1 -0
- package/dist/scene/schema/physics.js +37 -0
- package/dist/scene/schema/scene-file.d.ts +304 -0
- package/dist/scene/schema/scene-file.d.ts.map +1 -0
- package/dist/scene/schema/scene-file.js +262 -0
- package/dist/scene/schema/shadow.d.ts +28 -0
- package/dist/scene/schema/shadow.d.ts.map +1 -0
- package/dist/scene/schema/shadow.js +20 -0
- package/dist/scene/schema/spline.d.ts +25 -0
- package/dist/scene/schema/spline.d.ts.map +1 -0
- package/dist/scene/schema/spline.js +15 -0
- package/dist/scene/schema/tuples.d.ts +12 -0
- package/dist/scene/schema/tuples.d.ts.map +1 -0
- package/dist/scene/schema/tuples.js +14 -0
- package/dist/scene/schema/ui.d.ts +880 -0
- package/dist/scene/schema/ui.d.ts.map +1 -0
- package/dist/scene/schema/ui.js +506 -0
- package/dist/scene/user-data.d.ts +171 -0
- package/dist/scene/user-data.d.ts.map +1 -0
- package/dist/scene/user-data.js +137 -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 +69 -0
- package/dist/setup/setup-renderer.d.ts.map +1 -0
- package/dist/setup/setup-renderer.js +363 -0
- package/dist/tools/define-tool.d.ts +105 -0
- package/dist/tools/define-tool.d.ts.map +1 -0
- package/dist/tools/define-tool.js +82 -0
- package/dist/world2d/authoring-2d.d.ts +76 -0
- package/dist/world2d/authoring-2d.d.ts.map +1 -0
- package/dist/world2d/authoring-2d.js +176 -0
- package/dist/world2d/capture-to-scene2d.d.ts +5 -0
- package/dist/world2d/capture-to-scene2d.d.ts.map +1 -0
- package/dist/world2d/capture-to-scene2d.js +49 -0
- package/dist/world2d/collision-2d.d.ts +52 -0
- package/dist/world2d/collision-2d.d.ts.map +1 -0
- package/dist/world2d/collision-2d.js +70 -0
- package/dist/world2d/components-2d.d.ts +47 -0
- package/dist/world2d/components-2d.d.ts.map +1 -0
- package/dist/world2d/components-2d.js +77 -0
- package/dist/world2d/index.d.ts +34 -0
- package/dist/world2d/index.d.ts.map +1 -0
- package/dist/world2d/index.js +32 -0
- package/dist/world2d/ingest-iframe-2d.d.ts +82 -0
- package/dist/world2d/ingest-iframe-2d.d.ts.map +1 -0
- package/dist/world2d/ingest-iframe-2d.js +166 -0
- package/dist/world2d/ingest2d.d.ts +97 -0
- package/dist/world2d/ingest2d.d.ts.map +1 -0
- package/dist/world2d/ingest2d.js +40 -0
- package/dist/world2d/physics2d-registry.d.ts +24 -0
- package/dist/world2d/physics2d-registry.d.ts.map +1 -0
- package/dist/world2d/physics2d-registry.js +38 -0
- package/dist/world2d/pixi-game-adapter.d.ts +107 -0
- package/dist/world2d/pixi-game-adapter.d.ts.map +1 -0
- package/dist/world2d/pixi-game-adapter.js +211 -0
- package/dist/world2d/pixi-surface.d.ts +39 -0
- package/dist/world2d/pixi-surface.d.ts.map +1 -0
- package/dist/world2d/pixi-surface.js +47 -0
- package/dist/world2d/scene-capture-2d.d.ts +43 -0
- package/dist/world2d/scene-capture-2d.d.ts.map +1 -0
- package/dist/world2d/scene-capture-2d.js +92 -0
- package/dist/world2d/scene2d-loader.d.ts +27 -0
- package/dist/world2d/scene2d-loader.d.ts.map +1 -0
- package/dist/world2d/scene2d-loader.js +274 -0
- package/dist/world2d/schema/entity2d.d.ts +102 -0
- package/dist/world2d/schema/entity2d.d.ts.map +1 -0
- package/dist/world2d/schema/entity2d.js +119 -0
- package/dist/world2d/schema/physics2d.d.ts +46 -0
- package/dist/world2d/schema/physics2d.d.ts.map +1 -0
- package/dist/world2d/schema/physics2d.js +45 -0
- package/dist/world2d/schema/sprite.d.ts +42 -0
- package/dist/world2d/schema/sprite.d.ts.map +1 -0
- package/dist/world2d/schema/sprite.js +63 -0
- package/dist/world2d/schema/tilemap.d.ts +15 -0
- package/dist/world2d/schema/tilemap.d.ts.map +1 -0
- package/dist/world2d/schema/tilemap.js +19 -0
- package/dist/world2d/schema/tuples2d.d.ts +20 -0
- package/dist/world2d/schema/tuples2d.d.ts.map +1 -0
- package/dist/world2d/schema/tuples2d.js +19 -0
- package/dist/world2d/system-adapters-2d.d.ts +16 -0
- package/dist/world2d/system-adapters-2d.d.ts.map +1 -0
- package/dist/world2d/system-adapters-2d.js +37 -0
- package/dist/world2d/transform-writer-2d.d.ts +16 -0
- package/dist/world2d/transform-writer-2d.d.ts.map +1 -0
- package/dist/world2d/transform-writer-2d.js +22 -0
- package/dist/world2d/types.d.ts +53 -0
- package/dist/world2d/types.d.ts.map +1 -0
- package/dist/world2d/types.js +1 -0
- package/package.json +18 -4
- package/src/adapter/authoring.ts +10 -0
- package/src/adapter/first-party-systems.ts +23 -34
- package/src/adapter/index.ts +1 -3
- package/src/adapter/system-adapter.ts +15 -22
- package/src/adapter/vgai-scene-game-adapter.ts +5 -14
- package/src/animation/anim-graph-types.ts +12 -43
- package/src/animation/animation-clock.ts +479 -0
- package/src/animation/camera-ownership.ts +467 -0
- package/src/animation/cinematic-cues.ts +451 -0
- package/src/animation/clip-map.ts +41 -0
- package/src/animation/gsap-registration.ts +184 -0
- package/src/animation/theatre-clock-binding.ts +111 -0
- package/src/animation/theatre-director.ts +347 -0
- package/src/animation/theatre-object-binding.ts +661 -0
- package/src/animation/xstate-animation-binding.ts +398 -0
- package/src/animation/xstate-animation-meta.ts +282 -0
- package/src/audio/index.ts +39 -7
- package/src/audio/tone-clock-binding.ts +98 -0
- package/src/audio/tone-context.ts +129 -0
- package/src/audio/tone-offline-render.ts +167 -0
- package/src/audio/wav-encode.ts +119 -0
- package/src/core/game-loop.ts +17 -0
- package/src/core/types.ts +13 -0
- package/src/data/data-asset.ts +167 -0
- package/src/data/data-check-core.ts +242 -0
- package/src/data/data-ref.ts +145 -0
- package/src/data/vite-plugin-data.ts +290 -0
- package/src/index.ts +48 -0
- package/src/input/input-manager.ts +1206 -32
- package/src/input/input-types.ts +155 -3
- package/src/input/prompt-labels.ts +122 -0
- package/src/input/rebind-controller.ts +105 -0
- package/src/input/schema.ts +206 -52
- package/src/react/use-data.ts +114 -0
- package/src/react/use-selection.tsx +135 -0
- package/src/runtime/create-runtime.ts +30 -9
- package/src/runtime/render-audio-control.ts +168 -0
- package/src/runtime/render-control.ts +522 -0
- package/src/runtime/render-seed.ts +79 -0
- package/src/runtime/types.ts +0 -5
- package/src/scene/asset-loaders.ts +10 -36
- package/src/scene/asset-paths.ts +0 -2
- package/src/scene/asset-ref-check.ts +248 -0
- package/src/scene/parse.ts +133 -0
- package/src/scene/scene-loader.ts +81 -96
- package/src/scene/schema/animation.ts +30 -79
- package/src/scene/schema/entity.ts +20 -0
- package/src/scene/schema/index.ts +2 -12
- package/src/scene/user-data.ts +8 -9
- package/src/setup/setup-renderer.ts +9 -2
- package/src/tools/define-tool.ts +152 -0
- package/src/animation/anim-graph.ts +0 -406
- package/src/animation/anim-system.ts +0 -28
- package/src/animation/property-track.ts +0 -178
- package/src/animation/schema.ts +0 -204
- package/src/audio/ambient.ts +0 -300
- package/src/audio/impacts.ts +0 -212
- package/src/audio/movement.ts +0 -140
- package/src/audio/musical.ts +0 -200
- package/src/audio/ui-sounds.ts +0 -171
- package/src/audio/vehicle.ts +0 -235
- package/src/audio/weapons.ts +0 -152
|
@@ -0,0 +1,714 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VgaiSceneGameAdapter — the FIRST-PARTY implementer of {@link GameAdapter}.
|
|
3
|
+
*
|
|
4
|
+
* This is where `.vscn` + `GameComponent` + Rapier live now: the host no longer
|
|
5
|
+
* knows about any of them. `mount(host)` builds the full first-party runtime
|
|
6
|
+
* (the body that used to live inline in `create-runtime.ts`) from a neutral
|
|
7
|
+
* {@link HostContext}, runs the game's `setup`/scene load, and returns a
|
|
8
|
+
* {@link MountedGame}. First-party content is now just one implementer of the
|
|
9
|
+
* same interface an unmodified external game implements (Phase B).
|
|
10
|
+
*
|
|
11
|
+
* `GameSetupFn` / `GameContext` are imported ONLY here (and in the example
|
|
12
|
+
* `fromSetup` wrappers) — never by the host. That confinement is the inversion.
|
|
13
|
+
*/
|
|
14
|
+
import RAPIER from '@dimforge/rapier3d-compat';
|
|
15
|
+
import * as THREE from 'three';
|
|
16
|
+
import { createSystemRunner } from '../core/system-runner';
|
|
17
|
+
import { createDebugDraw } from '../dev/debug-draw';
|
|
18
|
+
import { createComponentManager } from '../ecs/component-manager';
|
|
19
|
+
import { InputManager } from '../input/input-manager';
|
|
20
|
+
import { setAssetPrefix } from '../loader';
|
|
21
|
+
import { createCollisionSystem } from '../physics/collision-system';
|
|
22
|
+
import { createPhysicsRegistry } from '../physics/physics-registry';
|
|
23
|
+
import { createTransformWriter } from '../physics/transform-writer';
|
|
24
|
+
import { createTriggerDispatch } from '../physics/trigger-dispatch';
|
|
25
|
+
import { RenderBatchSystem } from '../render/render-batch-system';
|
|
26
|
+
import { resolveRenderSettings } from '../render/render-settings';
|
|
27
|
+
import { renderSceneUI, } from '../runtime/scene-ui-bridge';
|
|
28
|
+
import { gameStateDataSource } from '../runtime/scene-ui-data';
|
|
29
|
+
import { tickCustomMaterials } from '../scene/material-registry';
|
|
30
|
+
import { clearAssetCaches, loadScene, loadSceneFromData, updateSceneLODs, } from '../scene/scene-loader';
|
|
31
|
+
import { hasUserData, setUserData } from '../scene/user-data';
|
|
32
|
+
import { setupAudio } from '../setup/setup-audio';
|
|
33
|
+
import { setupParticles } from '../setup/setup-particles';
|
|
34
|
+
import { setupPhysics, updatePhysicsDebug } from '../setup/setup-physics';
|
|
35
|
+
import { applyRendererSettings, applyScenePostProcessing, createSceneView, } from '../setup/setup-renderer';
|
|
36
|
+
import { createAudioSystemAdapter, createInputManagerAdapter, createNavigationAdapter, createVgaiAssetAdapter, } from './first-party-systems';
|
|
37
|
+
import { createRapierPhysicsAdapter } from './rapier-physics-adapter';
|
|
38
|
+
/** Minimal stand-in for the GPU composer when mounting headlessly. */
|
|
39
|
+
function headlessComposer(renderer) {
|
|
40
|
+
return {
|
|
41
|
+
render: () => { },
|
|
42
|
+
setSize: () => { },
|
|
43
|
+
dispose: () => { },
|
|
44
|
+
addPass: () => { },
|
|
45
|
+
removeAllPasses: () => { },
|
|
46
|
+
passes: [],
|
|
47
|
+
getRenderer: () => renderer,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Wrap a first-party `setup` function as a {@link GameAdapter}. This is how every
|
|
52
|
+
* first-party example becomes an implementer of the same interface an external
|
|
53
|
+
* game implements — with no change to the setup's body.
|
|
54
|
+
*/
|
|
55
|
+
export function fromSetup(id, setup) {
|
|
56
|
+
return new VgaiSceneGameAdapter({ id, setup });
|
|
57
|
+
}
|
|
58
|
+
export class VgaiSceneGameAdapter {
|
|
59
|
+
config;
|
|
60
|
+
id;
|
|
61
|
+
constructor(config = {}) {
|
|
62
|
+
this.config = config;
|
|
63
|
+
this.id = config.id ?? 'vgai-scene';
|
|
64
|
+
}
|
|
65
|
+
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: one cohesive first-party bootstrap (moved verbatim from create-runtime); splitting it would obscure the ordering contract
|
|
66
|
+
async mount(host) {
|
|
67
|
+
const { setup, editorPreview, scenePath, sceneData, componentRegistry, uiRegistry, inputMapPath = '/inputmaps/default.inputmap.json', assetPrefix = '/', } = this.config;
|
|
68
|
+
const headless = host.headless === true;
|
|
69
|
+
const { width, height } = host.surface;
|
|
70
|
+
const renderer = host.renderer;
|
|
71
|
+
setAssetPrefix(assetPrefix);
|
|
72
|
+
// --- Scene view (scene/camera/composer). Browser: the canonical builder, so
|
|
73
|
+
// behavior is byte-identical to the old create-runtime. Headless: plain
|
|
74
|
+
// scene/camera + a no-op composer (no GPU). ---
|
|
75
|
+
let scene;
|
|
76
|
+
let camera;
|
|
77
|
+
let composer;
|
|
78
|
+
if (headless) {
|
|
79
|
+
scene = new THREE.Scene();
|
|
80
|
+
scene.background = new THREE.Color(0x1a1a2e);
|
|
81
|
+
camera = new THREE.PerspectiveCamera(60, width / height || 1, 0.1, 1000);
|
|
82
|
+
camera.position.set(0, 5, 10);
|
|
83
|
+
camera.lookAt(0, 0, 0);
|
|
84
|
+
composer = headlessComposer(renderer);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
const view = createSceneView(renderer, width, height);
|
|
88
|
+
scene = view.scene;
|
|
89
|
+
camera = view.camera;
|
|
90
|
+
composer = view.composer;
|
|
91
|
+
}
|
|
92
|
+
// --- Rapier physics ---
|
|
93
|
+
await RAPIER.init();
|
|
94
|
+
const physics = setupPhysics(RAPIER, scene);
|
|
95
|
+
const physicsRegistry = createPhysicsRegistry();
|
|
96
|
+
const writeTransforms = createTransformWriter(physicsRegistry, scene);
|
|
97
|
+
// --- Input (InputManager attaches window listeners; stub it headlessly) ---
|
|
98
|
+
const input = headless ? headlessInput() : new InputManager();
|
|
99
|
+
if (!headless)
|
|
100
|
+
await input.loadMap(inputMapPath);
|
|
101
|
+
// --- Collision system ---
|
|
102
|
+
const collisions = createCollisionSystem(physics.rapierWorld, physics.eventQueue);
|
|
103
|
+
// --- Audio (Web Audio — browser only) ---
|
|
104
|
+
const audio = headless ? headlessAudio() : setupAudio(camera);
|
|
105
|
+
// --- Particles (three.quarks BatchedRenderer) ---
|
|
106
|
+
const particles = setupParticles(scene);
|
|
107
|
+
// --- UI container (host-provided) ---
|
|
108
|
+
const uiContainer = host.ui;
|
|
109
|
+
// --- Debug draw / assets ---
|
|
110
|
+
const debugDraw = createDebugDraw(scene);
|
|
111
|
+
const assets = host.assets;
|
|
112
|
+
// --- System runner (engine-level systems) ---
|
|
113
|
+
const systems = createSystemRunner();
|
|
114
|
+
systems.add('input', () => input.poll());
|
|
115
|
+
systems.add('physics', () => physics.rapierWorld.step(physics.eventQueue));
|
|
116
|
+
systems.add('postPhysics', () => {
|
|
117
|
+
collisions.drain();
|
|
118
|
+
writeTransforms();
|
|
119
|
+
});
|
|
120
|
+
systems.add('preRender', (dt) => {
|
|
121
|
+
particles.batchedRenderer.update(dt);
|
|
122
|
+
tickCustomMaterials(scene, dt);
|
|
123
|
+
updateSceneLODs(scene, camera);
|
|
124
|
+
});
|
|
125
|
+
if (!headless) {
|
|
126
|
+
systems.add('render', (dt) => {
|
|
127
|
+
composer.render(dt);
|
|
128
|
+
if (physics.debugEnabled)
|
|
129
|
+
updatePhysicsDebug(physics.rapierWorld, physics.debugMesh);
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
// --- Debug toggle (browser only) ---
|
|
133
|
+
const onDebugToggle = (e) => {
|
|
134
|
+
if (e.code === 'KeyP') {
|
|
135
|
+
physics.debugEnabled = !physics.debugEnabled;
|
|
136
|
+
physics.debugMesh.visible = physics.debugEnabled;
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
if (!headless)
|
|
140
|
+
window.addEventListener('keydown', onDebugToggle);
|
|
141
|
+
const postFrame = () => input.endFrame();
|
|
142
|
+
// The mounted game's adapter surface (`mounted.systems`). Declared before
|
|
143
|
+
// ctx so `ctx.registerSystemAdapter` can close over it: the engine fills
|
|
144
|
+
// the first-party entries below; GAME-owned capabilities (networking,
|
|
145
|
+
// navigation) are registered by the game's setup through the ctx hook.
|
|
146
|
+
// The editor holds this same object reference (setActiveSystems), so
|
|
147
|
+
// late registrations are visible to its panels at read time.
|
|
148
|
+
const systemAdapters = {};
|
|
149
|
+
// Game-registered scene-UI services (design/24-scene-ui.md D2/D7) — a `let`
|
|
150
|
+
// bag mutated by `ctx.setSceneUIServices`, declared here (BEFORE `ctx` is
|
|
151
|
+
// built) so the closure below has something to capture: a GameComponent
|
|
152
|
+
// calling `ctx.setSceneUIServices` from its `init()` runs DURING
|
|
153
|
+
// `componentManager.initAll()` (scene-loader.ts), which is awaited before
|
|
154
|
+
// `loadScene`/`loadFromData` return below — well before `sceneUIHandle`
|
|
155
|
+
// exists — so early calls just accumulate here and are folded into the
|
|
156
|
+
// FIRST render (`buildSceneUIServices`, below) rather than routed through
|
|
157
|
+
// the late-update path.
|
|
158
|
+
let sceneUIServices = {};
|
|
159
|
+
// --- GameContext (the first-party runtime surface) ---
|
|
160
|
+
const ctx = {
|
|
161
|
+
scene,
|
|
162
|
+
camera,
|
|
163
|
+
rapierWorld: physics.rapierWorld,
|
|
164
|
+
rapier: RAPIER,
|
|
165
|
+
physics: physicsRegistry,
|
|
166
|
+
input,
|
|
167
|
+
collisions,
|
|
168
|
+
composer,
|
|
169
|
+
audio,
|
|
170
|
+
particles,
|
|
171
|
+
debugDraw,
|
|
172
|
+
assets,
|
|
173
|
+
systems,
|
|
174
|
+
components: null,
|
|
175
|
+
uiContainer,
|
|
176
|
+
registerSystemAdapter: (kind, adapter) => {
|
|
177
|
+
systemAdapters[kind] = adapter;
|
|
178
|
+
},
|
|
179
|
+
setSceneUIServices: (incoming) => {
|
|
180
|
+
sceneUIServices = { ...sceneUIServices, ...incoming };
|
|
181
|
+
// Late call (after the initial mount already resolved a sceneInstance
|
|
182
|
+
// and rendered it): route to the live handle instead of just banking
|
|
183
|
+
// the services for a mount that already happened (D7).
|
|
184
|
+
if (sceneUIHandle && sceneInstance) {
|
|
185
|
+
const merged = buildSceneUIServices(sceneInstance);
|
|
186
|
+
if (sceneUIHandle.update) {
|
|
187
|
+
sceneUIHandle.update(merged);
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
sceneUIHandle.dispose();
|
|
191
|
+
sceneUIHandle = sceneInstance.ui
|
|
192
|
+
? renderSceneUI(uiContainer, sceneInstance.ui, merged)
|
|
193
|
+
: null;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
|
+
// Game root (T7.1 slice 1): only present once the host has constructed a
|
|
199
|
+
// Game shell (createGameRuntime does this before mount; headless/foreign
|
|
200
|
+
// hosts may omit it — ctx.game/ctx.worlds simply stay undefined, which is
|
|
201
|
+
// the documented zero-break behavior). `ctx.worlds` is assigned the SAME
|
|
202
|
+
// live array `host.game` mutates via `registerWorld` (not a copy) — the
|
|
203
|
+
// default world is registered AFTER mount returns, and this reference
|
|
204
|
+
// must observe that later push.
|
|
205
|
+
if (host.game) {
|
|
206
|
+
ctx.game = host.game;
|
|
207
|
+
ctx.worlds = host.game.worlds;
|
|
208
|
+
}
|
|
209
|
+
ctx.components = createComponentManager(ctx, physicsRegistry);
|
|
210
|
+
collisions.onCollision(createTriggerDispatch(physicsRegistry, ctx.components, physics.rapierWorld, ctx));
|
|
211
|
+
// Everything registered above (engine systems + the ComponentManager's
|
|
212
|
+
// per-phase tick, just wired in) is "engine" and must survive a warm
|
|
213
|
+
// restart. Everything a game (setup()/scenePath/sceneData, below) adds
|
|
214
|
+
// from here on is "game" content that `hotReload` bulk-removes via
|
|
215
|
+
// `systems.removeAllNonEngine()` on every restart (T1.7).
|
|
216
|
+
systems.markEngineBoundary();
|
|
217
|
+
// First-party System adapters over the real subsystems — seeded HERE,
|
|
218
|
+
// BEFORE setup()/scene load runs below, so that a game which registers any
|
|
219
|
+
// of these kinds during its own setup (via `ctx.registerSystemAdapter`)
|
|
220
|
+
// always wins over the engine's first-party entry (see
|
|
221
|
+
// registerSystemAdapter's docstring in runtime/types.ts). `navigation` is
|
|
222
|
+
// ALSO first-party now (R8 item 7): `createNavigationAdapter` wraps the
|
|
223
|
+
// real `NavMeshManager` a scenePath/sceneData scene load may produce (see
|
|
224
|
+
// `applySceneNavigation` below) — it is wired once that scene instance
|
|
225
|
+
// resolves, not here (no NavMeshManager exists yet at this point in the
|
|
226
|
+
// mount). `networking` remains the one game-owned capability with no
|
|
227
|
+
// first-party implementer; it simply starts absent here.
|
|
228
|
+
systemAdapters.physics = createRapierPhysicsAdapter(physicsRegistry, physics.debugMesh);
|
|
229
|
+
systemAdapters.input = createInputManagerAdapter(input);
|
|
230
|
+
systemAdapters.assets = createVgaiAssetAdapter();
|
|
231
|
+
// D10/T7.6: the audio seam `Game.play.pause()` silences on pause. Works
|
|
232
|
+
// against the headless stand-in too (`headlessAudio()`'s plain
|
|
233
|
+
// `masterGain.gain` object) — this world's `pause()` mutes it harmlessly.
|
|
234
|
+
systemAdapters.audio = createAudioSystemAdapter(audio);
|
|
235
|
+
// Snapshot of the engine-owned adapter kinds, taken right after seeding
|
|
236
|
+
// and before any setup() has had a chance to run. `hotReload`/`disposeGame`
|
|
237
|
+
// use this to strip every GAME-registered kind (including an override of a
|
|
238
|
+
// first-party kind) left over from the outgoing game, so a warm restart or
|
|
239
|
+
// a full stop never exposes a disposed game's networking/etc. adapter to
|
|
240
|
+
// the next setup.
|
|
241
|
+
const engineAdapterKinds = new Set(Object.keys(systemAdapters));
|
|
242
|
+
// 'navigation' is engine-owned too (R8 item 7), but the scene load that
|
|
243
|
+
// populates it (below, `applySceneNavigation`) happens AFTER this
|
|
244
|
+
// snapshot — add it explicitly so the generic "strip every non-engine
|
|
245
|
+
// kind" step (hotReload/disposeGame) never mistakes a first-party
|
|
246
|
+
// navigation adapter for game-registered content and deletes it. (The
|
|
247
|
+
// adapter is still kept in sync with the CURRENT scene's NavMeshManager
|
|
248
|
+
// via the dedicated `clear navigation adapter` teardown step below, which
|
|
249
|
+
// runs independently of this snapshot.)
|
|
250
|
+
engineAdapterKinds.add('navigation');
|
|
251
|
+
// --- Scene / game setup ---
|
|
252
|
+
const engineSceneChildren = new Set(scene.children.slice());
|
|
253
|
+
// Tag engine-owned infra (particle BatchedRenderer, debug-draw + subtrees) so
|
|
254
|
+
// the editor's play-mode hierarchy skips them — they're not game entities.
|
|
255
|
+
for (const c of engineSceneChildren) {
|
|
256
|
+
c.traverse((n) => setUserData(n, 'engineInternal', true));
|
|
257
|
+
}
|
|
258
|
+
let currentCleanup = null;
|
|
259
|
+
let sceneUIHandle = null;
|
|
260
|
+
let batchSystem = null;
|
|
261
|
+
// The scenePath/sceneData branch's resolved SceneInstance, if either ran
|
|
262
|
+
// (stays undefined for a `setup`-based mount — see the `sceneUI` deriva-
|
|
263
|
+
// tion below). Single source of truth for both the scene-graph `ui` tree
|
|
264
|
+
// and (potentially, in future) other instance-derived wiring.
|
|
265
|
+
let sceneInstance;
|
|
266
|
+
// Apply scene-level render settings + transparent auto-batching after a scene
|
|
267
|
+
// loads (GPU host only). Gated on the resolved `environment.rendering` cascade
|
|
268
|
+
// (defaults preserve prior behavior when a scene omits `rendering`).
|
|
269
|
+
const applySceneRendering = (inst) => {
|
|
270
|
+
if (headless)
|
|
271
|
+
return;
|
|
272
|
+
const scope = inst.environment?.rendering;
|
|
273
|
+
const settings = resolveRenderSettings(scope);
|
|
274
|
+
// live renderer settings (shadows, resolution scale)
|
|
275
|
+
applyRendererSettings(renderer, scope);
|
|
276
|
+
// post-processing master switch: (re)build when the scene defines effects OR
|
|
277
|
+
// the master is off (to strip the default bloom pass down to a plain scene).
|
|
278
|
+
if (inst.environment?.postProcessing || !settings['postProcessing']) {
|
|
279
|
+
applyScenePostProcessing(composer, renderer, scene, camera, inst.environment);
|
|
280
|
+
}
|
|
281
|
+
// transparent batching: collapse static/mover meshes sharing a signature
|
|
282
|
+
if (settings['autoBatch']) {
|
|
283
|
+
batchSystem = new RenderBatchSystem(scene, settings);
|
|
284
|
+
batchSystem.build();
|
|
285
|
+
ctx.systems.add('preRender', () => batchSystem?.update());
|
|
286
|
+
if (import.meta.env?.DEV)
|
|
287
|
+
window.__vgaiBatch = batchSystem;
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
// Wire the (first-party) navigation system adapter to whichever
|
|
291
|
+
// NavMeshManager the CURRENT scene instance carries — reassigned on every
|
|
292
|
+
// scene load, and explicitly cleared (not just left stale) when the new
|
|
293
|
+
// scene has none, so `mounted.systems.navigation` never lingers pointing
|
|
294
|
+
// at a manager a later teardown step disposes (R8 item 7).
|
|
295
|
+
const applySceneNavigation = (inst) => {
|
|
296
|
+
if (inst.navMesh) {
|
|
297
|
+
systemAdapters.navigation = createNavigationAdapter(inst.navMesh);
|
|
298
|
+
}
|
|
299
|
+
else {
|
|
300
|
+
delete systemAdapters.navigation;
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
// Scratch vector for the D5 default worldProjector — reused across calls
|
|
304
|
+
// (one per bound world-tracked canvas per render), never allocated per-frame.
|
|
305
|
+
const _sceneUIProjectorTmp = new THREE.Vector3();
|
|
306
|
+
// The D4 default data source subscribes to game.state for its whole
|
|
307
|
+
// lifetime with no unsubscribe path, so it must be built at most ONCE per
|
|
308
|
+
// adapter mount — buildSceneUIServices runs again on every late
|
|
309
|
+
// setSceneUIServices call, and rebuilding it there would both leak a
|
|
310
|
+
// subscription and force every bound node to resubscribe to a fresh store.
|
|
311
|
+
let defaultSceneUIData;
|
|
312
|
+
/**
|
|
313
|
+
* Assemble the services `renderSceneUI` receives (design/24-scene-ui.md
|
|
314
|
+
* D2): engine defaults (D4 data source, D5 worldProjector, D6 onEvent) <-
|
|
315
|
+
* the project's per-mount UI registry (D11, editor-play threading) <-
|
|
316
|
+
* game-registered services (`ctx.setSceneUIServices`) — per key, each
|
|
317
|
+
* later layer winning over the one before it.
|
|
318
|
+
*/
|
|
319
|
+
const buildSceneUIServices = (inst) => {
|
|
320
|
+
const defaults = {
|
|
321
|
+
onEvent: (handlerId) => {
|
|
322
|
+
console.warn(`scene-ui: unhandled UI event "${handlerId}" — register onEvent via ctx.setSceneUIServices`);
|
|
323
|
+
},
|
|
324
|
+
worldProjector: (id) => {
|
|
325
|
+
const obj = inst.entities.get(id);
|
|
326
|
+
if (!obj)
|
|
327
|
+
return null;
|
|
328
|
+
const projected = obj.getWorldPosition(_sceneUIProjectorTmp).project(camera);
|
|
329
|
+
if (projected.z > 1)
|
|
330
|
+
return null; // behind the camera -> hidden
|
|
331
|
+
const w = uiContainer.clientWidth;
|
|
332
|
+
const h = uiContainer.clientHeight;
|
|
333
|
+
// Rounded (not sub-pixel) — matches CrtScreen's integer-rounding
|
|
334
|
+
// (crt-screen.ts), which exists specifically to stop an asymptotic
|
|
335
|
+
// camera lerp from shimmering a tracked canvas every frame.
|
|
336
|
+
return {
|
|
337
|
+
x: Math.round(((projected.x + 1) / 2) * w),
|
|
338
|
+
y: Math.round(((1 - projected.y) / 2) * h),
|
|
339
|
+
};
|
|
340
|
+
},
|
|
341
|
+
};
|
|
342
|
+
// Lazily and at-most-once; skipped entirely while the game supplies its
|
|
343
|
+
// own `data` service (no point subscribing a default nobody reads).
|
|
344
|
+
if (!sceneUIServices.data && ctx.game && componentRegistry) {
|
|
345
|
+
defaultSceneUIData ??= gameStateDataSource(ctx.game, componentRegistry);
|
|
346
|
+
defaults.data = defaultSceneUIData;
|
|
347
|
+
}
|
|
348
|
+
const registryPortion = {
|
|
349
|
+
...(uiRegistry?.components ? { components: uiRegistry.components } : {}),
|
|
350
|
+
...(uiRegistry?.transforms ? { transforms: uiRegistry.transforms } : {}),
|
|
351
|
+
...(uiRegistry?.strings ? { strings: uiRegistry.strings } : {}),
|
|
352
|
+
};
|
|
353
|
+
return { ...defaults, ...registryPortion, ...sceneUIServices };
|
|
354
|
+
};
|
|
355
|
+
const loadFromData = async (data) => {
|
|
356
|
+
const inst = await loadSceneFromData(data, {
|
|
357
|
+
scene,
|
|
358
|
+
rapierWorld: ctx.rapierWorld,
|
|
359
|
+
rapier: ctx.rapier,
|
|
360
|
+
physics: ctx.physics,
|
|
361
|
+
audioListener: ctx.audio.listener,
|
|
362
|
+
...(componentRegistry ? { componentRegistry } : {}),
|
|
363
|
+
componentManager: ctx.components,
|
|
364
|
+
particleRenderer: ctx.particles.batchedRenderer,
|
|
365
|
+
...(headless ? {} : { renderer }),
|
|
366
|
+
});
|
|
367
|
+
applySceneRendering(inst);
|
|
368
|
+
applySceneNavigation(inst);
|
|
369
|
+
ctx.systems.add('postPhysics', (dt) => inst.update(dt));
|
|
370
|
+
return inst;
|
|
371
|
+
};
|
|
372
|
+
if (setup) {
|
|
373
|
+
if (headless)
|
|
374
|
+
throw new Error('VgaiSceneGameAdapter: setup-based games require a GPU host');
|
|
375
|
+
currentCleanup = await setup(ctx, editorPreview);
|
|
376
|
+
}
|
|
377
|
+
else if (scenePath) {
|
|
378
|
+
const inst = await loadScene(scenePath, {
|
|
379
|
+
scene,
|
|
380
|
+
rapierWorld: ctx.rapierWorld,
|
|
381
|
+
rapier: ctx.rapier,
|
|
382
|
+
physics: ctx.physics,
|
|
383
|
+
audioListener: ctx.audio.listener,
|
|
384
|
+
...(componentRegistry ? { componentRegistry } : {}),
|
|
385
|
+
componentManager: ctx.components,
|
|
386
|
+
particleRenderer: ctx.particles.batchedRenderer,
|
|
387
|
+
...(headless ? {} : { renderer }),
|
|
388
|
+
});
|
|
389
|
+
applyEditorCamera(editorPreview, camera) || adoptSceneCamera(inst, camera);
|
|
390
|
+
applySceneRendering(inst);
|
|
391
|
+
applySceneNavigation(inst);
|
|
392
|
+
ctx.systems.add('postPhysics', (dt) => inst.update(dt));
|
|
393
|
+
sceneInstance = inst;
|
|
394
|
+
// A pre-baked navmesh (sibling .navmesh file — see scene-loader.ts) holds
|
|
395
|
+
// live recast-navigation WASM handles that leak unless destroyed
|
|
396
|
+
// explicitly; dispose it alongside the scene instance on teardown.
|
|
397
|
+
currentCleanup = {
|
|
398
|
+
dispose: () => {
|
|
399
|
+
inst.navMesh?.dispose(scene);
|
|
400
|
+
inst.dispose();
|
|
401
|
+
},
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
else if (sceneData) {
|
|
405
|
+
const inst = await loadFromData(sceneData);
|
|
406
|
+
applyEditorCamera(editorPreview, camera) || adoptSceneCamera(inst, camera);
|
|
407
|
+
sceneInstance = inst;
|
|
408
|
+
currentCleanup = {
|
|
409
|
+
dispose: () => {
|
|
410
|
+
inst.navMesh?.dispose(scene);
|
|
411
|
+
inst.dispose();
|
|
412
|
+
},
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
// Render scene-graph UI (the `ui` tree) into the overlay via the injected React
|
|
416
|
+
// renderer (B1). Sourced from the loaded `SceneInstance` — the single source of
|
|
417
|
+
// truth for BOTH the scenePath and sceneData branches (R8 item 7 / B: previously
|
|
418
|
+
// only sceneData's raw `SceneFile.ui` was read via a `resolvedSceneData` special-
|
|
419
|
+
// case, so a scenePath mount's `ui` tree was silently dropped even though
|
|
420
|
+
// `loadScene` fully parses it). A `setup`-based mount has no `sceneInstance` at
|
|
421
|
+
// all — its game owns any UI mounting itself. No-op if no UI or no renderer
|
|
422
|
+
// registered. Engine stays React-free.
|
|
423
|
+
const sceneUI = sceneInstance?.ui;
|
|
424
|
+
if (sceneUI && sceneInstance && !headless) {
|
|
425
|
+
sceneUIHandle = renderSceneUI(uiContainer, sceneUI, buildSceneUIServices(sceneInstance));
|
|
426
|
+
}
|
|
427
|
+
// Idempotency guard for disposeGame — see below. Declared here (not inside
|
|
428
|
+
// disposeGame) so hotReload can also refuse to run on an already-disposed
|
|
429
|
+
// adapter.
|
|
430
|
+
let disposed = false;
|
|
431
|
+
// Run one teardown step in isolation: a throwing step (e.g. a
|
|
432
|
+
// GameComponent's dispose() misbehaving, or a WASM free() panicking) must
|
|
433
|
+
// not abort the remaining steps — otherwise a single bad component leaks
|
|
434
|
+
// the Rapier world and skips input.dispose() with no way to retry (a
|
|
435
|
+
// second call is a no-op once `disposed` is set). Logs and continues.
|
|
436
|
+
const safeStep = (label, fn) => {
|
|
437
|
+
try {
|
|
438
|
+
fn();
|
|
439
|
+
}
|
|
440
|
+
catch (err) {
|
|
441
|
+
console.error(`VgaiSceneGameAdapter: teardown step "${label}" threw (continuing)`, err);
|
|
442
|
+
}
|
|
443
|
+
};
|
|
444
|
+
const disposeGame = () => {
|
|
445
|
+
// A second stop() must be a safe no-op — do NOT double-free the Rapier
|
|
446
|
+
// world/EventQueue (WASM handles panic/throw on a second free) or
|
|
447
|
+
// double-run teardown side effects.
|
|
448
|
+
if (disposed)
|
|
449
|
+
return;
|
|
450
|
+
disposed = true;
|
|
451
|
+
safeStep('batchSystem.teardown', () => {
|
|
452
|
+
batchSystem?.teardown(); // re-attach detached sources before scene teardown
|
|
453
|
+
batchSystem = null;
|
|
454
|
+
});
|
|
455
|
+
safeStep('currentCleanup.dispose', () => {
|
|
456
|
+
currentCleanup?.dispose();
|
|
457
|
+
currentCleanup = null;
|
|
458
|
+
});
|
|
459
|
+
// The scene instance's NavMeshManager (if any) was just disposed above
|
|
460
|
+
// (currentCleanup.dispose calls `inst.navMesh?.dispose(scene)`) — clear
|
|
461
|
+
// the wrapper too, or `mounted.systems.navigation` would keep pointing
|
|
462
|
+
// at a freed manager (R8 item 7). Unconditional: harmless if navigation
|
|
463
|
+
// was never set.
|
|
464
|
+
safeStep('clear navigation adapter', () => {
|
|
465
|
+
delete systemAdapters.navigation;
|
|
466
|
+
});
|
|
467
|
+
if (!headless) {
|
|
468
|
+
safeStep('removeEventListener(keydown)', () => window.removeEventListener('keydown', onDebugToggle));
|
|
469
|
+
}
|
|
470
|
+
// Components BEFORE the physics world is freed/bodies are removed: a
|
|
471
|
+
// GameComponent's dispose() may read `this.rigidBody`/`this.collider`
|
|
472
|
+
// (see game-component.ts) — freeing the world first would make those
|
|
473
|
+
// dangling WASM references. Isolated: a throwing component dispose must
|
|
474
|
+
// not prevent the world/eventQueue frees or input.dispose() below.
|
|
475
|
+
safeStep('components.clear', () => ctx.components.clear());
|
|
476
|
+
safeStep('remove rigid bodies', () => {
|
|
477
|
+
const handles = [];
|
|
478
|
+
physics.rapierWorld.forEachRigidBody((b) => handles.push(b.handle));
|
|
479
|
+
for (const h of handles) {
|
|
480
|
+
const b = physics.rapierWorld.getRigidBody(h);
|
|
481
|
+
if (b)
|
|
482
|
+
physics.rapierWorld.removeRigidBody(b);
|
|
483
|
+
}
|
|
484
|
+
});
|
|
485
|
+
safeStep('rapierWorld.free', () => physics.rapierWorld.free());
|
|
486
|
+
safeStep('eventQueue.free', () => physics.eventQueue.free()); // WASM handle — must be freed manually
|
|
487
|
+
safeStep('physicsRegistry.clear', () => physicsRegistry.clear());
|
|
488
|
+
safeStep('scene children dispose', () => {
|
|
489
|
+
for (const obj of [...scene.children]) {
|
|
490
|
+
scene.remove(obj);
|
|
491
|
+
obj.traverse((node) => {
|
|
492
|
+
if (node instanceof THREE.Mesh) {
|
|
493
|
+
if (!hasUserData(node, '__sharedGeometry'))
|
|
494
|
+
node.geometry?.dispose();
|
|
495
|
+
if (Array.isArray(node.material))
|
|
496
|
+
node.material.forEach((m) => {
|
|
497
|
+
m.dispose();
|
|
498
|
+
});
|
|
499
|
+
else
|
|
500
|
+
node.material?.dispose();
|
|
501
|
+
}
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
scene.fog = null;
|
|
505
|
+
scene.background = null;
|
|
506
|
+
scene.environment = null;
|
|
507
|
+
});
|
|
508
|
+
safeStep('clearAssetCaches', () => clearAssetCaches());
|
|
509
|
+
safeStep('debugDraw.clear', () => debugDraw.clear());
|
|
510
|
+
safeStep('sceneUIHandle.dispose', () => {
|
|
511
|
+
sceneUIHandle?.dispose();
|
|
512
|
+
sceneUIHandle = null;
|
|
513
|
+
});
|
|
514
|
+
safeStep('uiContainer reset', () => {
|
|
515
|
+
uiContainer.innerHTML = '';
|
|
516
|
+
});
|
|
517
|
+
// R8 item 7 (C) — disposeGame (Stop) used to skip both of these, unlike
|
|
518
|
+
// hotReload (warm restart), which already ran them: a game lifecycle
|
|
519
|
+
// system registered via `ctx.systems.register(...)` never had its
|
|
520
|
+
// `dispose()` hook called on a full Stop, and a game-registered
|
|
521
|
+
// systemAdapters kind (e.g. a `setup`-registered 'networking') survived
|
|
522
|
+
// a Stop and would be visible on a STALE `mounted.systems` even though
|
|
523
|
+
// the game that owned it is gone. Same two steps, same relative
|
|
524
|
+
// ordering as hotReload (right after `uiContainer reset`, before the
|
|
525
|
+
// engine-owned audio/input teardown below, which hotReload doesn't
|
|
526
|
+
// touch at all since it warm-restarts rather than tearing engine
|
|
527
|
+
// subsystems down).
|
|
528
|
+
safeStep('systems.removeAllNonEngine', () => systems.removeAllNonEngine());
|
|
529
|
+
safeStep('strip game-registered systemAdapters', () => {
|
|
530
|
+
for (const kind of Object.keys(systemAdapters)) {
|
|
531
|
+
if (!engineAdapterKinds.has(kind))
|
|
532
|
+
delete systemAdapters[kind];
|
|
533
|
+
}
|
|
534
|
+
});
|
|
535
|
+
if (!headless) {
|
|
536
|
+
safeStep('audio teardown', () => {
|
|
537
|
+
audio.masterGain.gain.value = 0;
|
|
538
|
+
audio.listener.context.suspend();
|
|
539
|
+
camera.remove(audio.listener);
|
|
540
|
+
composer.dispose();
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
safeStep('input.dispose', () => input.dispose());
|
|
544
|
+
};
|
|
545
|
+
const hotReload = async (newSetup, newEditorPreview) => {
|
|
546
|
+
if (disposed) {
|
|
547
|
+
throw new Error('VgaiSceneGameAdapter: cannot hotReload after dispose()/stop()');
|
|
548
|
+
}
|
|
549
|
+
// Full parity with disposeGame for the parts a warm restart rebuilds:
|
|
550
|
+
// batch-render teardown, game cleanup, component batch teardown (in that
|
|
551
|
+
// ordering, BEFORE bodies are pulled from the world — see disposeGame),
|
|
552
|
+
// scene-UI dispose (React root unmount), and bulk system removal. Each
|
|
553
|
+
// step isolated the same way as disposeGame — one throwing step (e.g. a
|
|
554
|
+
// component dispose) must not abort the rest of the warm restart.
|
|
555
|
+
safeStep('batchSystem.teardown', () => {
|
|
556
|
+
batchSystem?.teardown(); // re-attach detached sources before scene teardown
|
|
557
|
+
batchSystem = null;
|
|
558
|
+
});
|
|
559
|
+
safeStep('currentCleanup.dispose', () => {
|
|
560
|
+
currentCleanup?.dispose();
|
|
561
|
+
currentCleanup = null;
|
|
562
|
+
});
|
|
563
|
+
// Same reasoning as disposeGame: the outgoing scene instance's
|
|
564
|
+
// NavMeshManager was just disposed above, and `hotReload`'s `newSetup`
|
|
565
|
+
// (below) never auto-wires a replacement (that only happens for THIS
|
|
566
|
+
// adapter's own scenePath/sceneData mount, once, at initial mount) — so
|
|
567
|
+
// clear the stale wrapper here. A `newSetup` that wants navigation may
|
|
568
|
+
// register its own via `ctx.registerSystemAdapter('navigation', ...)`.
|
|
569
|
+
safeStep('clear navigation adapter', () => {
|
|
570
|
+
delete systemAdapters.navigation;
|
|
571
|
+
});
|
|
572
|
+
safeStep('components.clear', () => ctx.components.clear());
|
|
573
|
+
safeStep('remove rigid bodies', () => {
|
|
574
|
+
const handles = [];
|
|
575
|
+
physics.rapierWorld.forEachRigidBody((b) => handles.push(b.handle));
|
|
576
|
+
for (const h of handles) {
|
|
577
|
+
const b = physics.rapierWorld.getRigidBody(h);
|
|
578
|
+
if (b)
|
|
579
|
+
physics.rapierWorld.removeRigidBody(b);
|
|
580
|
+
}
|
|
581
|
+
physicsRegistry.clear();
|
|
582
|
+
});
|
|
583
|
+
safeStep('scene children dispose', () => {
|
|
584
|
+
for (const obj of [...scene.children]) {
|
|
585
|
+
if (engineSceneChildren.has(obj))
|
|
586
|
+
continue;
|
|
587
|
+
scene.remove(obj);
|
|
588
|
+
obj.traverse((node) => {
|
|
589
|
+
if (node instanceof THREE.Mesh) {
|
|
590
|
+
if (!hasUserData(node, '__sharedGeometry'))
|
|
591
|
+
node.geometry?.dispose();
|
|
592
|
+
if (Array.isArray(node.material))
|
|
593
|
+
node.material.forEach((m) => {
|
|
594
|
+
m.dispose();
|
|
595
|
+
});
|
|
596
|
+
else
|
|
597
|
+
node.material?.dispose();
|
|
598
|
+
}
|
|
599
|
+
});
|
|
600
|
+
}
|
|
601
|
+
scene.fog = null;
|
|
602
|
+
scene.background = null;
|
|
603
|
+
scene.environment = null;
|
|
604
|
+
});
|
|
605
|
+
safeStep('debugDraw.clear', () => debugDraw.clear());
|
|
606
|
+
safeStep('sceneUIHandle.dispose', () => {
|
|
607
|
+
sceneUIHandle?.dispose();
|
|
608
|
+
sceneUIHandle = null;
|
|
609
|
+
});
|
|
610
|
+
// Strip game-registered scene-UI services back to none before the
|
|
611
|
+
// incoming game's setup/init runs (D7) — same contract as the
|
|
612
|
+
// systemAdapters strip below: a disposed game's onEvent/data/
|
|
613
|
+
// worldProjector must never leak onto the next mount.
|
|
614
|
+
safeStep('reset sceneUIServices', () => {
|
|
615
|
+
sceneUIServices = {};
|
|
616
|
+
});
|
|
617
|
+
safeStep('uiContainer reset', () => {
|
|
618
|
+
uiContainer.innerHTML = '';
|
|
619
|
+
});
|
|
620
|
+
// Bulk-remove every system the outgoing game registered (this restart's
|
|
621
|
+
// predecessor) so warm restarts never accumulate duplicate systems —
|
|
622
|
+
// engine systems registered before mount()'s boundary mark are untouched.
|
|
623
|
+
safeStep('systems.removeAllNonEngine', () => systems.removeAllNonEngine());
|
|
624
|
+
// Strip every GAME-registered systemAdapters kind left by the outgoing
|
|
625
|
+
// game (including any override of a first-party kind) so the disposed
|
|
626
|
+
// game's networking/etc. adapter is never exposed to the next setup —
|
|
627
|
+
// see registerSystemAdapter's docstring in runtime/types.ts. ('navigation'
|
|
628
|
+
// is engine-kind and is NOT touched here — it's a first-party adapter now,
|
|
629
|
+
// kept in sync with the current scene's NavMeshManager by the dedicated
|
|
630
|
+
// `clear navigation adapter` step above instead.) The new setup below
|
|
631
|
+
// either re-registers a kind or it stays absent.
|
|
632
|
+
safeStep('strip game-registered systemAdapters', () => {
|
|
633
|
+
for (const kind of Object.keys(systemAdapters)) {
|
|
634
|
+
if (!engineAdapterKinds.has(kind))
|
|
635
|
+
delete systemAdapters[kind];
|
|
636
|
+
}
|
|
637
|
+
});
|
|
638
|
+
currentCleanup = await newSetup(ctx, newEditorPreview);
|
|
639
|
+
};
|
|
640
|
+
return {
|
|
641
|
+
kind: 'threejs',
|
|
642
|
+
scene,
|
|
643
|
+
camera,
|
|
644
|
+
firstParty: true,
|
|
645
|
+
drivesOwnLoop: false,
|
|
646
|
+
update: (dt) => {
|
|
647
|
+
systems.run(dt);
|
|
648
|
+
postFrame();
|
|
649
|
+
},
|
|
650
|
+
resize: (w, h) => {
|
|
651
|
+
const safeWidth = Math.max(1, w);
|
|
652
|
+
const safeHeight = Math.max(1, h);
|
|
653
|
+
composer.setSize(safeWidth, safeHeight);
|
|
654
|
+
camera.aspect = safeWidth / safeHeight;
|
|
655
|
+
camera.updateProjectionMatrix();
|
|
656
|
+
},
|
|
657
|
+
dispose: disposeGame,
|
|
658
|
+
systems: systemAdapters,
|
|
659
|
+
ctx,
|
|
660
|
+
composer: headless ? null : composer,
|
|
661
|
+
hotReload,
|
|
662
|
+
frame: {
|
|
663
|
+
runPhase: (phase, dt) => systems.runPhase(phase, dt),
|
|
664
|
+
endFrame: postFrame,
|
|
665
|
+
},
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
// --- Camera precedence helpers (moved from create-runtime, unchanged) ---
|
|
670
|
+
function applyEditorCamera(editor, runtimeCamera) {
|
|
671
|
+
if (!editor?.viewportCamera)
|
|
672
|
+
return false;
|
|
673
|
+
runtimeCamera.position.fromArray(editor.viewportCamera.position);
|
|
674
|
+
runtimeCamera.quaternion.fromArray(editor.viewportCamera.quaternion);
|
|
675
|
+
return true;
|
|
676
|
+
}
|
|
677
|
+
export function adoptSceneCamera(sceneInstance, runtimeCamera) {
|
|
678
|
+
const sceneCam = sceneInstance.cameras[0];
|
|
679
|
+
if (!sceneCam)
|
|
680
|
+
return false;
|
|
681
|
+
const parent = sceneCam.parent;
|
|
682
|
+
if (parent) {
|
|
683
|
+
parent.updateMatrixWorld(true);
|
|
684
|
+
runtimeCamera.position.copy(parent.getWorldPosition(new THREE.Vector3()));
|
|
685
|
+
runtimeCamera.quaternion.copy(parent.getWorldQuaternion(new THREE.Quaternion()));
|
|
686
|
+
}
|
|
687
|
+
if (sceneCam instanceof THREE.PerspectiveCamera) {
|
|
688
|
+
runtimeCamera.fov = sceneCam.fov;
|
|
689
|
+
runtimeCamera.near = sceneCam.near;
|
|
690
|
+
runtimeCamera.far = sceneCam.far;
|
|
691
|
+
runtimeCamera.updateProjectionMatrix();
|
|
692
|
+
}
|
|
693
|
+
return true;
|
|
694
|
+
}
|
|
695
|
+
/** Headless input stand-in — `InputManager` attaches `window` listeners in its
|
|
696
|
+
* constructor, which Node lacks. The scene-data path never reads input. */
|
|
697
|
+
function headlessInput() {
|
|
698
|
+
return {
|
|
699
|
+
poll: () => { },
|
|
700
|
+
endFrame: () => { },
|
|
701
|
+
dispose: () => { },
|
|
702
|
+
loadMap: async () => { },
|
|
703
|
+
isPressed: () => false,
|
|
704
|
+
getAxis: () => 0,
|
|
705
|
+
};
|
|
706
|
+
}
|
|
707
|
+
/** Headless audio stand-in (no Web Audio). Only the fields the loader/cleanup
|
|
708
|
+
* touch are present; setup-based games never mount headlessly. */
|
|
709
|
+
function headlessAudio() {
|
|
710
|
+
return {
|
|
711
|
+
listener: undefined,
|
|
712
|
+
masterGain: { gain: { value: 1 } },
|
|
713
|
+
};
|
|
714
|
+
}
|