@vgai/engine 0.3.0 → 0.4.0-canary.20260715.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/package.json +8 -2
- package/schemas/engine-api.json +124 -0
- package/schemas/engine-api.md +53 -0
- package/schemas/engine-capabilities.json +124 -0
- package/schemas/inputmap.schema.json +314 -0
- package/schemas/mat.schema.json +286 -0
- package/schemas/prefab.schema.json +10148 -0
- package/schemas/scn2d.schema.json +475 -0
- package/schemas/vgai-game.schema.json +383 -0
- package/schemas/vscn.schema.json +11007 -0
- package/src/adapter/{world-kind.ts → adapter-surface.ts} +6 -6
- package/src/adapter/authoring.ts +67 -0
- package/src/adapter/game-adapter.ts +8 -8
- package/src/adapter/host-context.ts +2 -4
- package/src/adapter/index.ts +3 -1
- package/src/adapter/system-adapter.ts +73 -0
- package/src/adapter/vgai-scene-game-adapter.ts +239 -180
- package/src/animation/xstate-animation-binding.ts +300 -262
- package/src/animation/xstate-animation-meta.ts +50 -13
- package/src/character/cloth-sim.ts +533 -0
- package/src/character/spring-chain.ts +307 -0
- package/src/core/game-loop.ts +41 -3
- package/src/core/seeded-random.ts +161 -0
- package/src/core/system-runner.ts +20 -3
- package/src/core/types.ts +37 -0
- package/src/data/data-asset.ts +1 -1
- package/src/dev/performance-profiler.ts +213 -0
- package/src/dev/webgl-gpu-timer.ts +53 -0
- package/src/ecs/component-manager.ts +45 -12
- package/src/ecs/game-component.ts +95 -11
- package/src/humanoid/bake.operation.ts +326 -0
- package/src/humanoid/body.ts +663 -0
- package/src/humanoid/clips.ts +149 -0
- package/src/humanoid/compose.ts +209 -0
- package/src/humanoid/generate.ts +189 -0
- package/src/humanoid/index.ts +36 -0
- package/src/humanoid/schema.ts +108 -0
- package/src/humanoid/skeleton.ts +345 -0
- package/src/index.ts +5 -5
- package/src/input/input-manager.ts +701 -22
- package/src/input/input-types.ts +5 -2
- package/src/manifest/index.ts +5 -5
- package/src/manifest/load.ts +125 -72
- package/src/manifest/schema.ts +362 -255
- package/src/react/game-state.tsx +135 -32
- package/src/react/root-adapter.tsx +49 -0
- package/src/react/unmanaged-root-detector.ts +66 -0
- package/src/react/use-data.ts +12 -2
- package/src/runtime/create-runtime.ts +100 -282
- package/src/runtime/debug-bridge.ts +483 -0
- package/src/runtime/debug-registry.ts +856 -0
- package/src/runtime/game.ts +342 -93
- package/src/runtime/gameplay-rng-trap.ts +134 -0
- package/src/runtime/input-router.ts +7 -7
- package/src/runtime/mount-game.ts +40 -38
- package/src/runtime/mount-manifest.ts +169 -37
- package/src/runtime/render-control.ts +13 -13
- package/src/runtime/render-seed.ts +1 -1
- package/src/runtime/state-bridge.ts +24 -10
- package/src/runtime/types.ts +110 -28
- package/src/scene/asset-registry.ts +22 -0
- package/src/scene/component-registry.ts +14 -3
- package/src/scene/defaults.ts +1 -0
- package/src/scene/light-camera-factory.ts +11 -3
- package/src/scene/scene-apply.ts +55 -4
- package/src/scene/scene-loader.ts +10 -27
- package/src/scene/scene-types.ts +0 -1
- package/src/scene/schema/index.ts +0 -34
- package/src/scene/schema/light.ts +16 -1
- package/src/scene/schema/material.ts +96 -91
- package/src/scene/schema/scene-file.ts +1 -7
- package/src/scene/user-data.ts +14 -1
- package/src/setup/setup-renderer.ts +1 -1
- package/src/tools/define-tool.ts +50 -11
- package/src/world2d/authoring-2d.ts +17 -1
- package/src/world2d/collision-2d.ts +1 -1
- package/src/world2d/pixi-game-adapter.ts +19 -17
- package/src/world2d/scene2d-loader.ts +1 -0
- package/src/world2d/types.ts +8 -2
- package/dist/adapter/authoring.d.ts +0 -404
- package/dist/adapter/authoring.d.ts.map +0 -1
- package/dist/adapter/authoring.js +0 -22
- package/dist/adapter/colyseus-networking-adapter.d.ts +0 -43
- package/dist/adapter/colyseus-networking-adapter.d.ts.map +0 -1
- package/dist/adapter/colyseus-networking-adapter.js +0 -38
- package/dist/adapter/first-party-systems.d.ts +0 -38
- package/dist/adapter/first-party-systems.d.ts.map +0 -1
- package/dist/adapter/first-party-systems.js +0 -77
- package/dist/adapter/game-adapter.d.ts +0 -133
- package/dist/adapter/game-adapter.d.ts.map +0 -1
- package/dist/adapter/game-adapter.js +0 -10
- package/dist/adapter/host-context.d.ts +0 -73
- package/dist/adapter/host-context.d.ts.map +0 -1
- package/dist/adapter/host-context.js +0 -16
- package/dist/adapter/index.d.ts +0 -22
- package/dist/adapter/index.d.ts.map +0 -1
- package/dist/adapter/index.js +0 -15
- package/dist/adapter/ingest/game-contract.d.ts +0 -53
- package/dist/adapter/ingest/game-contract.d.ts.map +0 -1
- package/dist/adapter/ingest/game-contract.js +0 -30
- package/dist/adapter/ingest/overlay-applier.d.ts +0 -118
- package/dist/adapter/ingest/overlay-applier.d.ts.map +0 -1
- package/dist/adapter/ingest/overlay-applier.js +0 -132
- package/dist/adapter/ingest/overlay-apply.d.ts +0 -60
- package/dist/adapter/ingest/overlay-apply.d.ts.map +0 -1
- package/dist/adapter/ingest/overlay-apply.js +0 -101
- package/dist/adapter/ingest/overlay-file.d.ts +0 -79
- package/dist/adapter/ingest/overlay-file.d.ts.map +0 -1
- package/dist/adapter/ingest/overlay-file.js +0 -66
- package/dist/adapter/ingest/overlay-report.d.ts +0 -113
- package/dist/adapter/ingest/overlay-report.d.ts.map +0 -1
- package/dist/adapter/ingest/overlay-report.js +0 -103
- package/dist/adapter/ingest/scene-capture.d.ts +0 -97
- package/dist/adapter/ingest/scene-capture.d.ts.map +0 -1
- package/dist/adapter/ingest/scene-capture.js +0 -248
- package/dist/adapter/ingest/upstream-pin.d.ts +0 -47
- package/dist/adapter/ingest/upstream-pin.d.ts.map +0 -1
- package/dist/adapter/ingest/upstream-pin.js +0 -50
- package/dist/adapter/loop-gate-report.d.ts +0 -34
- package/dist/adapter/loop-gate-report.d.ts.map +0 -1
- package/dist/adapter/loop-gate-report.js +0 -37
- package/dist/adapter/rapier-physics-adapter.d.ts +0 -12
- package/dist/adapter/rapier-physics-adapter.d.ts.map +0 -1
- package/dist/adapter/rapier-physics-adapter.js +0 -46
- package/dist/adapter/system-adapter.d.ts +0 -133
- package/dist/adapter/system-adapter.d.ts.map +0 -1
- package/dist/adapter/system-adapter.js +0 -13
- package/dist/adapter/transform.d.ts +0 -18
- package/dist/adapter/transform.d.ts.map +0 -1
- package/dist/adapter/transform.js +0 -1
- package/dist/adapter/vgai-scene-game-adapter.d.ts +0 -116
- package/dist/adapter/vgai-scene-game-adapter.d.ts.map +0 -1
- package/dist/adapter/vgai-scene-game-adapter.js +0 -714
- package/dist/adapter/world-kind.d.ts +0 -30
- package/dist/adapter/world-kind.d.ts.map +0 -1
- package/dist/adapter/world-kind.js +0 -18
- package/dist/ai/navigation.d.ts +0 -64
- package/dist/ai/navigation.d.ts.map +0 -1
- package/dist/ai/navigation.js +0 -133
- package/dist/animation/anim-graph-types.d.ts +0 -25
- package/dist/animation/anim-graph-types.d.ts.map +0 -1
- package/dist/animation/anim-graph-types.js +0 -1
- package/dist/animation/animation-clock.d.ts +0 -213
- package/dist/animation/animation-clock.d.ts.map +0 -1
- package/dist/animation/animation-clock.js +0 -301
- package/dist/animation/blend-node.d.ts +0 -22
- package/dist/animation/blend-node.d.ts.map +0 -1
- package/dist/animation/blend-node.js +0 -97
- package/dist/animation/camera-ownership.d.ts +0 -250
- package/dist/animation/camera-ownership.d.ts.map +0 -1
- package/dist/animation/camera-ownership.js +0 -169
- package/dist/animation/cinematic-cues.d.ts +0 -200
- package/dist/animation/cinematic-cues.d.ts.map +0 -1
- package/dist/animation/cinematic-cues.js +0 -213
- package/dist/animation/clip-map.d.ts +0 -12
- package/dist/animation/clip-map.d.ts.map +0 -1
- package/dist/animation/clip-map.js +0 -37
- package/dist/animation/gsap-registration.d.ts +0 -119
- package/dist/animation/gsap-registration.d.ts.map +0 -1
- package/dist/animation/gsap-registration.js +0 -92
- package/dist/animation/theatre-clock-binding.d.ts +0 -89
- package/dist/animation/theatre-clock-binding.d.ts.map +0 -1
- package/dist/animation/theatre-clock-binding.js +0 -29
- package/dist/animation/theatre-director.d.ts +0 -242
- package/dist/animation/theatre-director.d.ts.map +0 -1
- package/dist/animation/theatre-director.js +0 -235
- package/dist/animation/theatre-object-binding.d.ts +0 -305
- package/dist/animation/theatre-object-binding.d.ts.map +0 -1
- package/dist/animation/theatre-object-binding.js +0 -351
- package/dist/animation/xstate-animation-binding.d.ts +0 -111
- package/dist/animation/xstate-animation-binding.d.ts.map +0 -1
- package/dist/animation/xstate-animation-binding.js +0 -307
- package/dist/animation/xstate-animation-meta.d.ts +0 -228
- package/dist/animation/xstate-animation-meta.d.ts.map +0 -1
- package/dist/animation/xstate-animation-meta.js +0 -221
- package/dist/assets.d.ts +0 -26
- package/dist/assets.d.ts.map +0 -1
- package/dist/assets.js +0 -55
- package/dist/audio/index.d.ts +0 -4
- package/dist/audio/index.d.ts.map +0 -1
- package/dist/audio/index.js +0 -24
- package/dist/audio/tone-clock-binding.d.ts +0 -75
- package/dist/audio/tone-clock-binding.d.ts.map +0 -1
- package/dist/audio/tone-clock-binding.js +0 -29
- package/dist/audio/tone-context.d.ts +0 -114
- package/dist/audio/tone-context.d.ts.map +0 -1
- package/dist/audio/tone-context.js +0 -39
- package/dist/audio/tone-offline-render.d.ts +0 -90
- package/dist/audio/tone-offline-render.d.ts.map +0 -1
- package/dist/audio/tone-offline-render.js +0 -56
- package/dist/audio/wav-encode.d.ts +0 -38
- package/dist/audio/wav-encode.d.ts.map +0 -1
- package/dist/audio/wav-encode.js +0 -97
- package/dist/core/game-loop.d.ts +0 -21
- package/dist/core/game-loop.d.ts.map +0 -1
- package/dist/core/game-loop.js +0 -130
- package/dist/core/system-runner.d.ts +0 -120
- package/dist/core/system-runner.d.ts.map +0 -1
- package/dist/core/system-runner.js +0 -286
- package/dist/core/types.d.ts +0 -58
- package/dist/core/types.d.ts.map +0 -1
- package/dist/core/types.js +0 -25
- package/dist/data/data-asset.d.ts +0 -101
- package/dist/data/data-asset.d.ts.map +0 -1
- package/dist/data/data-asset.js +0 -122
- package/dist/data/data-check-core.d.ts +0 -110
- package/dist/data/data-check-core.d.ts.map +0 -1
- package/dist/data/data-check-core.js +0 -178
- package/dist/data/data-ref.d.ts +0 -79
- package/dist/data/data-ref.d.ts.map +0 -1
- package/dist/data/data-ref.js +0 -130
- package/dist/data/vite-plugin-data.d.ts +0 -79
- package/dist/data/vite-plugin-data.d.ts.map +0 -1
- package/dist/data/vite-plugin-data.js +0 -217
- package/dist/dev/console-bridge.d.ts +0 -22
- package/dist/dev/console-bridge.d.ts.map +0 -1
- package/dist/dev/console-bridge.js +0 -71
- package/dist/dev/debug-draw.d.ts +0 -24
- package/dist/dev/debug-draw.d.ts.map +0 -1
- package/dist/dev/debug-draw.js +0 -73
- package/dist/dev/logger.d.ts +0 -30
- package/dist/dev/logger.d.ts.map +0 -1
- package/dist/dev/logger.js +0 -90
- package/dist/ecs/component-manager.d.ts +0 -189
- package/dist/ecs/component-manager.d.ts.map +0 -1
- package/dist/ecs/component-manager.js +0 -676
- package/dist/ecs/game-component.d.ts +0 -97
- package/dist/ecs/game-component.d.ts.map +0 -1
- package/dist/ecs/game-component.js +0 -80
- package/dist/ecs/hmr-swap-report.d.ts +0 -53
- package/dist/ecs/hmr-swap-report.d.ts.map +0 -1
- package/dist/ecs/hmr-swap-report.js +0 -55
- package/dist/index.d.ts +0 -37
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -30
- package/dist/input/input-manager.d.ts +0 -596
- package/dist/input/input-manager.d.ts.map +0 -1
- package/dist/input/input-manager.js +0 -1564
- package/dist/input/input-types.d.ts +0 -171
- package/dist/input/input-types.d.ts.map +0 -1
- package/dist/input/input-types.js +0 -1
- package/dist/input/prompt-labels.d.ts +0 -21
- package/dist/input/prompt-labels.d.ts.map +0 -1
- package/dist/input/prompt-labels.js +0 -121
- package/dist/input/rebind-controller.d.ts +0 -59
- package/dist/input/rebind-controller.d.ts.map +0 -1
- package/dist/input/rebind-controller.js +0 -85
- package/dist/input/schema.d.ts +0 -16
- package/dist/input/schema.d.ts.map +0 -1
- package/dist/input/schema.js +0 -228
- package/dist/loader.d.ts +0 -43
- package/dist/loader.d.ts.map +0 -1
- package/dist/loader.js +0 -59
- package/dist/manifest/index.d.ts +0 -5
- package/dist/manifest/index.d.ts.map +0 -1
- package/dist/manifest/index.js +0 -8
- package/dist/manifest/load-file.d.ts +0 -4
- package/dist/manifest/load-file.d.ts.map +0 -1
- package/dist/manifest/load-file.js +0 -14
- package/dist/manifest/load.d.ts +0 -117
- package/dist/manifest/load.d.ts.map +0 -1
- package/dist/manifest/load.js +0 -255
- package/dist/manifest/schema.d.ts +0 -173
- package/dist/manifest/schema.d.ts.map +0 -1
- package/dist/manifest/schema.js +0 -302
- package/dist/physics/collision-system.d.ts +0 -41
- package/dist/physics/collision-system.d.ts.map +0 -1
- package/dist/physics/collision-system.js +0 -64
- package/dist/physics/physics-registry.d.ts +0 -45
- package/dist/physics/physics-registry.d.ts.map +0 -1
- package/dist/physics/physics-registry.js +0 -65
- package/dist/physics/transform-writer.d.ts +0 -16
- package/dist/physics/transform-writer.d.ts.map +0 -1
- package/dist/physics/transform-writer.js +0 -38
- package/dist/physics/trigger-dispatch.d.ts +0 -24
- package/dist/physics/trigger-dispatch.d.ts.map +0 -1
- package/dist/physics/trigger-dispatch.js +0 -80
- package/dist/react/game-state.d.ts +0 -105
- package/dist/react/game-state.d.ts.map +0 -1
- package/dist/react/game-state.js +0 -144
- package/dist/react/use-data.d.ts +0 -60
- package/dist/react/use-data.d.ts.map +0 -1
- package/dist/react/use-data.js +0 -96
- package/dist/react/use-selection.d.ts +0 -75
- package/dist/react/use-selection.d.ts.map +0 -1
- package/dist/react/use-selection.js +0 -90
- package/dist/render/auto-batcher.d.ts +0 -34
- package/dist/render/auto-batcher.d.ts.map +0 -1
- package/dist/render/auto-batcher.js +0 -140
- package/dist/render/render-batch-system.d.ts +0 -33
- package/dist/render/render-batch-system.d.ts.map +0 -1
- package/dist/render/render-batch-system.js +0 -230
- package/dist/render/render-features.d.ts +0 -47
- package/dist/render/render-features.d.ts.map +0 -1
- package/dist/render/render-features.js +0 -105
- package/dist/render/render-settings.d.ts +0 -36
- package/dist/render/render-settings.d.ts.map +0 -1
- package/dist/render/render-settings.js +0 -51
- package/dist/runtime/create-runtime.d.ts +0 -280
- package/dist/runtime/create-runtime.d.ts.map +0 -1
- package/dist/runtime/create-runtime.js +0 -795
- package/dist/runtime/frame-selector-cache.d.ts +0 -41
- package/dist/runtime/frame-selector-cache.d.ts.map +0 -1
- package/dist/runtime/frame-selector-cache.js +0 -65
- package/dist/runtime/game.d.ts +0 -433
- package/dist/runtime/game.d.ts.map +0 -1
- package/dist/runtime/game.js +0 -569
- package/dist/runtime/input-router.d.ts +0 -78
- package/dist/runtime/input-router.d.ts.map +0 -1
- package/dist/runtime/input-router.js +0 -171
- package/dist/runtime/mount-game.d.ts +0 -129
- package/dist/runtime/mount-game.d.ts.map +0 -1
- package/dist/runtime/mount-game.js +0 -152
- package/dist/runtime/mount-manifest.d.ts +0 -119
- package/dist/runtime/mount-manifest.d.ts.map +0 -1
- package/dist/runtime/mount-manifest.js +0 -204
- package/dist/runtime/render-audio-control.d.ts +0 -110
- package/dist/runtime/render-audio-control.d.ts.map +0 -1
- package/dist/runtime/render-audio-control.js +0 -111
- package/dist/runtime/render-control.d.ts +0 -291
- package/dist/runtime/render-control.d.ts.map +0 -1
- package/dist/runtime/render-control.js +0 -264
- package/dist/runtime/render-seed.d.ts +0 -57
- package/dist/runtime/render-seed.d.ts.map +0 -1
- package/dist/runtime/render-seed.js +0 -74
- package/dist/runtime/scene-ui-bridge.d.ts +0 -69
- package/dist/runtime/scene-ui-bridge.d.ts.map +0 -1
- package/dist/runtime/scene-ui-bridge.js +0 -23
- package/dist/runtime/scene-ui-data.d.ts +0 -13
- package/dist/runtime/scene-ui-data.d.ts.map +0 -1
- package/dist/runtime/scene-ui-data.js +0 -92
- package/dist/runtime/state-bridge.d.ts +0 -47
- package/dist/runtime/state-bridge.d.ts.map +0 -1
- package/dist/runtime/state-bridge.js +0 -53
- package/dist/runtime/types.d.ts +0 -179
- package/dist/runtime/types.d.ts.map +0 -1
- package/dist/runtime/types.js +0 -1
- package/dist/scene/asset-loaders.d.ts +0 -79
- package/dist/scene/asset-loaders.d.ts.map +0 -1
- package/dist/scene/asset-loaders.js +0 -141
- package/dist/scene/asset-paths.d.ts +0 -11
- package/dist/scene/asset-paths.d.ts.map +0 -1
- package/dist/scene/asset-paths.js +0 -108
- package/dist/scene/asset-ref-check.d.ts +0 -88
- package/dist/scene/asset-ref-check.d.ts.map +0 -1
- package/dist/scene/asset-ref-check.js +0 -214
- package/dist/scene/asset-registry.d.ts +0 -30
- package/dist/scene/asset-registry.d.ts.map +0 -1
- package/dist/scene/asset-registry.js +0 -50
- package/dist/scene/collider-dimensions.d.ts +0 -63
- package/dist/scene/collider-dimensions.d.ts.map +0 -1
- package/dist/scene/collider-dimensions.js +0 -98
- package/dist/scene/component-registry.d.ts +0 -17
- package/dist/scene/component-registry.d.ts.map +0 -1
- package/dist/scene/component-registry.js +0 -28
- package/dist/scene/defaults.d.ts +0 -252
- package/dist/scene/defaults.d.ts.map +0 -1
- package/dist/scene/defaults.js +0 -151
- package/dist/scene/geometries/index.d.ts +0 -8
- package/dist/scene/geometries/index.d.ts.map +0 -1
- package/dist/scene/geometries/index.js +0 -7
- package/dist/scene/geometries/terrain.d.ts +0 -2
- package/dist/scene/geometries/terrain.d.ts.map +0 -1
- package/dist/scene/geometries/terrain.js +0 -37
- package/dist/scene/geometry-registry.d.ts +0 -24
- package/dist/scene/geometry-registry.d.ts.map +0 -1
- package/dist/scene/geometry-registry.js +0 -20
- package/dist/scene/instance-registry.d.ts +0 -36
- package/dist/scene/instance-registry.d.ts.map +0 -1
- package/dist/scene/instance-registry.js +0 -55
- package/dist/scene/instancers/grid.d.ts +0 -2
- package/dist/scene/instancers/grid.d.ts.map +0 -1
- package/dist/scene/instancers/grid.js +0 -36
- package/dist/scene/instancers/index.d.ts +0 -8
- package/dist/scene/instancers/index.d.ts.map +0 -1
- package/dist/scene/instancers/index.js +0 -7
- package/dist/scene/light-camera-factory.d.ts +0 -23
- package/dist/scene/light-camera-factory.d.ts.map +0 -1
- package/dist/scene/light-camera-factory.js +0 -68
- package/dist/scene/material-factory.d.ts +0 -17
- package/dist/scene/material-factory.d.ts.map +0 -1
- package/dist/scene/material-factory.js +0 -197
- package/dist/scene/material-registry.d.ts +0 -40
- package/dist/scene/material-registry.d.ts.map +0 -1
- package/dist/scene/material-registry.js +0 -44
- package/dist/scene/materials/index.d.ts +0 -8
- package/dist/scene/materials/index.d.ts.map +0 -1
- package/dist/scene/materials/index.js +0 -7
- package/dist/scene/materials/water.d.ts +0 -2
- package/dist/scene/materials/water.d.ts.map +0 -1
- package/dist/scene/materials/water.js +0 -54
- package/dist/scene/parse.d.ts +0 -23
- package/dist/scene/parse.d.ts.map +0 -1
- package/dist/scene/parse.js +0 -179
- package/dist/scene/particles-factory.d.ts +0 -33
- package/dist/scene/particles-factory.d.ts.map +0 -1
- package/dist/scene/particles-factory.js +0 -282
- package/dist/scene/scene-apply.d.ts +0 -109
- package/dist/scene/scene-apply.d.ts.map +0 -1
- package/dist/scene/scene-apply.js +0 -326
- package/dist/scene/scene-diff-schema.d.ts +0 -285
- package/dist/scene/scene-diff-schema.d.ts.map +0 -1
- package/dist/scene/scene-diff-schema.js +0 -92
- package/dist/scene/scene-diff-types.d.ts +0 -40
- package/dist/scene/scene-diff-types.d.ts.map +0 -1
- package/dist/scene/scene-diff-types.js +0 -14
- package/dist/scene/scene-loader.d.ts +0 -177
- package/dist/scene/scene-loader.d.ts.map +0 -1
- package/dist/scene/scene-loader.js +0 -1213
- package/dist/scene/scene-query.d.ts +0 -11
- package/dist/scene/scene-query.d.ts.map +0 -1
- package/dist/scene/scene-query.js +0 -63
- package/dist/scene/scene-types.d.ts +0 -10
- package/dist/scene/scene-types.d.ts.map +0 -1
- package/dist/scene/scene-types.js +0 -8
- package/dist/scene/scene-version.d.ts +0 -26
- package/dist/scene/scene-version.d.ts.map +0 -1
- package/dist/scene/scene-version.js +0 -34
- package/dist/scene/schema/animation.d.ts +0 -8
- package/dist/scene/schema/animation.d.ts.map +0 -1
- package/dist/scene/schema/animation.js +0 -42
- package/dist/scene/schema/audio.d.ts +0 -13
- package/dist/scene/schema/audio.d.ts.map +0 -1
- package/dist/scene/schema/audio.js +0 -22
- package/dist/scene/schema/camera.d.ts +0 -28
- package/dist/scene/schema/camera.d.ts.map +0 -1
- package/dist/scene/schema/camera.js +0 -17
- package/dist/scene/schema/collider.d.ts +0 -40
- package/dist/scene/schema/collider.d.ts.map +0 -1
- package/dist/scene/schema/collider.js +0 -55
- package/dist/scene/schema/entity-ref.d.ts +0 -31
- package/dist/scene/schema/entity-ref.d.ts.map +0 -1
- package/dist/scene/schema/entity-ref.js +0 -61
- package/dist/scene/schema/entity.d.ts +0 -1036
- package/dist/scene/schema/entity.d.ts.map +0 -1
- package/dist/scene/schema/entity.js +0 -153
- package/dist/scene/schema/environment.d.ts +0 -425
- package/dist/scene/schema/environment.d.ts.map +0 -1
- package/dist/scene/schema/environment.js +0 -357
- package/dist/scene/schema/index.d.ts +0 -39
- package/dist/scene/schema/index.d.ts.map +0 -1
- package/dist/scene/schema/index.js +0 -20
- package/dist/scene/schema/instances.d.ts +0 -14
- package/dist/scene/schema/instances.d.ts.map +0 -1
- package/dist/scene/schema/instances.js +0 -28
- package/dist/scene/schema/joint.d.ts +0 -23
- package/dist/scene/schema/joint.d.ts.map +0 -1
- package/dist/scene/schema/joint.js +0 -23
- package/dist/scene/schema/light.d.ts +0 -38
- package/dist/scene/schema/light.d.ts.map +0 -1
- package/dist/scene/schema/light.js +0 -26
- package/dist/scene/schema/material.d.ts +0 -199
- package/dist/scene/schema/material.d.ts.map +0 -1
- package/dist/scene/schema/material.js +0 -99
- package/dist/scene/schema/mesh.d.ts +0 -48
- package/dist/scene/schema/mesh.d.ts.map +0 -1
- package/dist/scene/schema/mesh.js +0 -82
- package/dist/scene/schema/particles.d.ts +0 -2178
- package/dist/scene/schema/particles.d.ts.map +0 -1
- package/dist/scene/schema/particles.js +0 -321
- package/dist/scene/schema/physics.d.ts +0 -56
- package/dist/scene/schema/physics.d.ts.map +0 -1
- package/dist/scene/schema/physics.js +0 -37
- package/dist/scene/schema/scene-file.d.ts +0 -304
- package/dist/scene/schema/scene-file.d.ts.map +0 -1
- package/dist/scene/schema/scene-file.js +0 -262
- package/dist/scene/schema/shadow.d.ts +0 -28
- package/dist/scene/schema/shadow.d.ts.map +0 -1
- package/dist/scene/schema/shadow.js +0 -20
- package/dist/scene/schema/spline.d.ts +0 -25
- package/dist/scene/schema/spline.d.ts.map +0 -1
- package/dist/scene/schema/spline.js +0 -15
- package/dist/scene/schema/tuples.d.ts +0 -12
- package/dist/scene/schema/tuples.d.ts.map +0 -1
- package/dist/scene/schema/tuples.js +0 -14
- package/dist/scene/schema/ui.d.ts +0 -880
- package/dist/scene/schema/ui.d.ts.map +0 -1
- package/dist/scene/schema/ui.js +0 -506
- package/dist/scene/user-data.d.ts +0 -171
- package/dist/scene/user-data.d.ts.map +0 -1
- package/dist/scene/user-data.js +0 -137
- package/dist/setup/setup-audio.d.ts +0 -20
- package/dist/setup/setup-audio.d.ts.map +0 -1
- package/dist/setup/setup-audio.js +0 -41
- package/dist/setup/setup-particles.d.ts +0 -17
- package/dist/setup/setup-particles.d.ts.map +0 -1
- package/dist/setup/setup-particles.js +0 -16
- package/dist/setup/setup-physics.d.ts +0 -25
- package/dist/setup/setup-physics.d.ts.map +0 -1
- package/dist/setup/setup-physics.js +0 -51
- package/dist/setup/setup-renderer.d.ts +0 -69
- package/dist/setup/setup-renderer.d.ts.map +0 -1
- package/dist/setup/setup-renderer.js +0 -363
- package/dist/tools/define-tool.d.ts +0 -105
- package/dist/tools/define-tool.d.ts.map +0 -1
- package/dist/tools/define-tool.js +0 -82
- package/dist/world2d/authoring-2d.d.ts +0 -76
- package/dist/world2d/authoring-2d.d.ts.map +0 -1
- package/dist/world2d/authoring-2d.js +0 -176
- package/dist/world2d/capture-to-scene2d.d.ts +0 -5
- package/dist/world2d/capture-to-scene2d.d.ts.map +0 -1
- package/dist/world2d/capture-to-scene2d.js +0 -49
- package/dist/world2d/collision-2d.d.ts +0 -52
- package/dist/world2d/collision-2d.d.ts.map +0 -1
- package/dist/world2d/collision-2d.js +0 -70
- package/dist/world2d/components-2d.d.ts +0 -47
- package/dist/world2d/components-2d.d.ts.map +0 -1
- package/dist/world2d/components-2d.js +0 -77
- package/dist/world2d/index.d.ts +0 -34
- package/dist/world2d/index.d.ts.map +0 -1
- package/dist/world2d/index.js +0 -32
- package/dist/world2d/ingest-iframe-2d.d.ts +0 -82
- package/dist/world2d/ingest-iframe-2d.d.ts.map +0 -1
- package/dist/world2d/ingest-iframe-2d.js +0 -166
- package/dist/world2d/ingest2d.d.ts +0 -97
- package/dist/world2d/ingest2d.d.ts.map +0 -1
- package/dist/world2d/ingest2d.js +0 -40
- package/dist/world2d/physics2d-registry.d.ts +0 -24
- package/dist/world2d/physics2d-registry.d.ts.map +0 -1
- package/dist/world2d/physics2d-registry.js +0 -38
- package/dist/world2d/pixi-game-adapter.d.ts +0 -107
- package/dist/world2d/pixi-game-adapter.d.ts.map +0 -1
- package/dist/world2d/pixi-game-adapter.js +0 -211
- package/dist/world2d/pixi-surface.d.ts +0 -39
- package/dist/world2d/pixi-surface.d.ts.map +0 -1
- package/dist/world2d/pixi-surface.js +0 -47
- package/dist/world2d/scene-capture-2d.d.ts +0 -43
- package/dist/world2d/scene-capture-2d.d.ts.map +0 -1
- package/dist/world2d/scene-capture-2d.js +0 -92
- package/dist/world2d/scene2d-loader.d.ts +0 -27
- package/dist/world2d/scene2d-loader.d.ts.map +0 -1
- package/dist/world2d/scene2d-loader.js +0 -274
- package/dist/world2d/schema/entity2d.d.ts +0 -102
- package/dist/world2d/schema/entity2d.d.ts.map +0 -1
- package/dist/world2d/schema/entity2d.js +0 -119
- package/dist/world2d/schema/physics2d.d.ts +0 -46
- package/dist/world2d/schema/physics2d.d.ts.map +0 -1
- package/dist/world2d/schema/physics2d.js +0 -45
- package/dist/world2d/schema/sprite.d.ts +0 -42
- package/dist/world2d/schema/sprite.d.ts.map +0 -1
- package/dist/world2d/schema/sprite.js +0 -63
- package/dist/world2d/schema/tilemap.d.ts +0 -15
- package/dist/world2d/schema/tilemap.d.ts.map +0 -1
- package/dist/world2d/schema/tilemap.js +0 -19
- package/dist/world2d/schema/tuples2d.d.ts +0 -20
- package/dist/world2d/schema/tuples2d.d.ts.map +0 -1
- package/dist/world2d/schema/tuples2d.js +0 -19
- package/dist/world2d/system-adapters-2d.d.ts +0 -16
- package/dist/world2d/system-adapters-2d.d.ts.map +0 -1
- package/dist/world2d/system-adapters-2d.js +0 -37
- package/dist/world2d/transform-writer-2d.d.ts +0 -16
- package/dist/world2d/transform-writer-2d.d.ts.map +0 -1
- package/dist/world2d/transform-writer-2d.js +0 -22
- package/dist/world2d/types.d.ts +0 -53
- package/dist/world2d/types.d.ts.map +0 -1
- package/dist/world2d/types.js +0 -1
- package/src/runtime/scene-ui-bridge.ts +0 -86
- package/src/runtime/scene-ui-data.ts +0 -119
- package/src/scene/schema/ui.ts +0 -602
|
@@ -15,8 +15,14 @@
|
|
|
15
15
|
import RAPIER from '@dimforge/rapier3d-compat';
|
|
16
16
|
import type { EffectComposer } from 'postprocessing';
|
|
17
17
|
import * as THREE from 'three';
|
|
18
|
+
import {
|
|
19
|
+
createSeededRandom,
|
|
20
|
+
DEFAULT_SEEDED_RANDOM_SEED,
|
|
21
|
+
getSeededRandom,
|
|
22
|
+
} from '../core/seeded-random';
|
|
18
23
|
import { createSystemRunner } from '../core/system-runner';
|
|
19
24
|
import { createDebugDraw } from '../dev/debug-draw';
|
|
25
|
+
import { createWebGLGpuTimer } from '../dev/webgl-gpu-timer';
|
|
20
26
|
import { createComponentManager } from '../ecs/component-manager';
|
|
21
27
|
import { InputManager } from '../input/input-manager';
|
|
22
28
|
import { setAssetPrefix } from '../loader';
|
|
@@ -26,14 +32,12 @@ import { createTransformWriter } from '../physics/transform-writer';
|
|
|
26
32
|
import { createTriggerDispatch } from '../physics/trigger-dispatch';
|
|
27
33
|
import { RenderBatchSystem } from '../render/render-batch-system';
|
|
28
34
|
import { type RenderScope, resolveRenderSettings } from '../render/render-settings';
|
|
29
|
-
import type { WorldFrameHooks } from '../runtime/game';
|
|
30
35
|
import {
|
|
31
|
-
|
|
32
|
-
type
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
} from '../runtime/
|
|
36
|
-
import { gameStateDataSource } from '../runtime/scene-ui-data';
|
|
36
|
+
createDebugRegistry,
|
|
37
|
+
type DebugRegistry,
|
|
38
|
+
getDebugRegistry,
|
|
39
|
+
} from '../runtime/debug-registry';
|
|
40
|
+
import type { WorldFrameHooks } from '../runtime/game';
|
|
37
41
|
import type { EditorPreview, GameCleanup, GameContext, GameSetupFn } from '../runtime/types';
|
|
38
42
|
import type { ComponentRegistry } from '../scene/component-registry';
|
|
39
43
|
import { tickCustomMaterials } from '../scene/material-registry';
|
|
@@ -88,24 +92,6 @@ export interface VgaiSceneConfig {
|
|
|
88
92
|
* that sets this today).
|
|
89
93
|
*/
|
|
90
94
|
componentRegistry?: ComponentRegistry | undefined;
|
|
91
|
-
/**
|
|
92
|
-
* The project's scene-UI registry (design/24-scene-ui.md D9/D11) —
|
|
93
|
-
* `components`/`transforms`/`strings` only, opaque records engine-side (the
|
|
94
|
-
* engine never imports `@vgai/scene-ui`'s real `ProjectUIRegistry` type;
|
|
95
|
-
* they're React things it never inspects). Threaded per-mount into the
|
|
96
|
-
* services `renderSceneUI` receives, mirroring `componentRegistry` above:
|
|
97
|
-
* the editor's default-three adapter resolver passes its cached project
|
|
98
|
-
* registry here for the editor-play path (D11); a standalone host that
|
|
99
|
-
* already registered a static registry via `registerSceneUIRenderer`
|
|
100
|
-
* typically omits this (registration-time registry is enough there).
|
|
101
|
-
*/
|
|
102
|
-
uiRegistry?:
|
|
103
|
-
| {
|
|
104
|
-
components?: Record<string, unknown>;
|
|
105
|
-
transforms?: Record<string, unknown>;
|
|
106
|
-
strings?: Record<string, Record<string, string>>;
|
|
107
|
-
}
|
|
108
|
-
| undefined;
|
|
109
95
|
/** Input map JSON path. Defaults to 'inputmaps/default.inputmap.json'. */
|
|
110
96
|
inputMapPath?: string | undefined;
|
|
111
97
|
/** URL prefix for relative asset paths. Defaults to '/'. */
|
|
@@ -139,10 +125,10 @@ export interface VgaiMountedGame extends MountedGame {
|
|
|
139
125
|
/**
|
|
140
126
|
* Phase-partitioned frame entry point (T7.1 slice 2,
|
|
141
127
|
* `docs/GAME-ROOT-DESIGN.md` §4) — wired onto this world's `WorldInstance`
|
|
142
|
-
* by `
|
|
128
|
+
* by `registerThreeWorld` (`create-runtime.ts`). `Game.runFrame` is
|
|
143
129
|
* the CANONICAL driver going forward: it calls `frame.runPhase` once per
|
|
144
130
|
* (phase, substep) for every world, then `frame.endFrame` once per
|
|
145
|
-
* substep after all
|
|
131
|
+
* substep after all roots finish all phases. `update` (below) remains
|
|
146
132
|
* the legacy/direct entry point to the exact same `SystemRunner` — direct
|
|
147
133
|
* callers (editor HMR, adapter conformance tests) keep using it unchanged.
|
|
148
134
|
*/
|
|
@@ -185,7 +171,6 @@ export class VgaiSceneGameAdapter implements GameAdapter {
|
|
|
185
171
|
scenePath,
|
|
186
172
|
sceneData,
|
|
187
173
|
componentRegistry,
|
|
188
|
-
uiRegistry,
|
|
189
174
|
inputMapPath = '/inputmaps/default.inputmap.json',
|
|
190
175
|
assetPrefix = '/',
|
|
191
176
|
} = this.config;
|
|
@@ -234,31 +219,69 @@ export class VgaiSceneGameAdapter implements GameAdapter {
|
|
|
234
219
|
// --- Particles (three.quarks BatchedRenderer) ---
|
|
235
220
|
const particles = setupParticles(scene);
|
|
236
221
|
|
|
237
|
-
// --- UI container (host-provided) ---
|
|
238
|
-
const uiContainer = host.ui as HTMLDivElement;
|
|
239
|
-
|
|
240
222
|
// --- Debug draw / assets ---
|
|
241
223
|
const debugDraw = createDebugDraw(scene);
|
|
242
224
|
const assets = host.assets;
|
|
225
|
+
// Test/headless adapters may provide the renderer surface needed by the
|
|
226
|
+
// runtime without a real WebGL context. GPU timing is optional diagnostics:
|
|
227
|
+
// degrade honestly when the renderer/context cannot expose extensions.
|
|
228
|
+
const rendererContext =
|
|
229
|
+
typeof renderer.getContext === 'function' ? renderer.getContext() : undefined;
|
|
230
|
+
const gpuTimer =
|
|
231
|
+
!headless && rendererContext && typeof rendererContext.getExtension === 'function'
|
|
232
|
+
? createWebGLGpuTimer(rendererContext)
|
|
233
|
+
: null;
|
|
243
234
|
|
|
244
235
|
// --- System runner (engine-level systems) ---
|
|
245
|
-
const systems = createSystemRunner();
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
236
|
+
const systems = createSystemRunner(host.game?.profiler.systemObserver, 'threejs');
|
|
237
|
+
// D15/T-D15.3/.5: pass the LIVE shared game tick (not a locally-counted
|
|
238
|
+
// one) into every `poll()` call — `debugRegistry` is declared further
|
|
239
|
+
// down in this same `mount()` (it needs `ctx`/`systemAdapters` to exist
|
|
240
|
+
// first), but this callback only ever executes during real frame
|
|
241
|
+
// ticks, long after `mount()` has fully returned and `debugRegistry` is
|
|
242
|
+
// initialized (a safe closure-over-a-later-const, not a genuine
|
|
243
|
+
// use-before-init). `host.game` gates it: a bare mount with no `Game`
|
|
244
|
+
// shell behind it (test harnesses predating T7.1) has no shared tick to
|
|
245
|
+
// key off, so `InputManager.poll()` falls back to its own internal
|
|
246
|
+
// self-incrementing counter instead (unchanged pre-D15 behavior) rather
|
|
247
|
+
// than being pinned to a constant `0` forever.
|
|
248
|
+
systems.add('input', () => input.poll(host.game ? debugRegistry.getGameTick() : undefined), {
|
|
249
|
+
name: 'input.poll',
|
|
251
250
|
});
|
|
252
|
-
systems.add('
|
|
253
|
-
|
|
254
|
-
tickCustomMaterials(scene, dt);
|
|
255
|
-
updateSceneLODs(scene, camera);
|
|
251
|
+
systems.add('physics', () => physics.rapierWorld.step(physics.eventQueue), {
|
|
252
|
+
name: 'physics.step',
|
|
256
253
|
});
|
|
254
|
+
systems.add(
|
|
255
|
+
'postPhysics',
|
|
256
|
+
() => {
|
|
257
|
+
collisions.drain();
|
|
258
|
+
writeTransforms();
|
|
259
|
+
},
|
|
260
|
+
{ name: 'physics.sync' },
|
|
261
|
+
);
|
|
262
|
+
systems.add(
|
|
263
|
+
'preRender',
|
|
264
|
+
(dt) => {
|
|
265
|
+
particles.batchedRenderer.update(dt);
|
|
266
|
+
tickCustomMaterials(scene, dt);
|
|
267
|
+
updateSceneLODs(scene, camera);
|
|
268
|
+
},
|
|
269
|
+
{ name: 'materials-and-particles' },
|
|
270
|
+
);
|
|
257
271
|
if (!headless) {
|
|
258
|
-
systems.add(
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
272
|
+
systems.add(
|
|
273
|
+
'render',
|
|
274
|
+
(dt) => {
|
|
275
|
+
if (host.game?.profiler.enabled) gpuTimer?.begin();
|
|
276
|
+
try {
|
|
277
|
+
composer.render(dt);
|
|
278
|
+
} finally {
|
|
279
|
+
gpuTimer?.end();
|
|
280
|
+
}
|
|
281
|
+
if (physics.debugEnabled) updatePhysicsDebug(physics.rapierWorld, physics.debugMesh);
|
|
282
|
+
},
|
|
283
|
+
{ name: 'three.render' },
|
|
284
|
+
);
|
|
262
285
|
}
|
|
263
286
|
|
|
264
287
|
// --- Debug toggle (browser only) ---
|
|
@@ -270,7 +293,18 @@ export class VgaiSceneGameAdapter implements GameAdapter {
|
|
|
270
293
|
};
|
|
271
294
|
if (!headless) window.addEventListener('keydown', onDebugToggle);
|
|
272
295
|
|
|
273
|
-
const postFrame = () =>
|
|
296
|
+
const postFrame = () => {
|
|
297
|
+
input.endFrame();
|
|
298
|
+
if (host.game?.profiler.enabled) {
|
|
299
|
+
host.game.profiler.reportRender({
|
|
300
|
+
gpuMs: gpuTimer?.poll() ?? null,
|
|
301
|
+
drawCalls: renderer.info.render.calls,
|
|
302
|
+
triangles: renderer.info.render.triangles,
|
|
303
|
+
geometries: renderer.info.memory.geometries,
|
|
304
|
+
textures: renderer.info.memory.textures,
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
};
|
|
274
308
|
|
|
275
309
|
// The mounted game's adapter surface (`mounted.systems`). Declared before
|
|
276
310
|
// ctx so `ctx.registerSystemAdapter` can close over it: the engine fills
|
|
@@ -280,17 +314,6 @@ export class VgaiSceneGameAdapter implements GameAdapter {
|
|
|
280
314
|
// late registrations are visible to its panels at read time.
|
|
281
315
|
const systemAdapters: SystemAdapters = {};
|
|
282
316
|
|
|
283
|
-
// Game-registered scene-UI services (design/24-scene-ui.md D2/D7) — a `let`
|
|
284
|
-
// bag mutated by `ctx.setSceneUIServices`, declared here (BEFORE `ctx` is
|
|
285
|
-
// built) so the closure below has something to capture: a GameComponent
|
|
286
|
-
// calling `ctx.setSceneUIServices` from its `init()` runs DURING
|
|
287
|
-
// `componentManager.initAll()` (scene-loader.ts), which is awaited before
|
|
288
|
-
// `loadScene`/`loadFromData` return below — well before `sceneUIHandle`
|
|
289
|
-
// exists — so early calls just accumulate here and are folded into the
|
|
290
|
-
// FIRST render (`buildSceneUIServices`, below) rather than routed through
|
|
291
|
-
// the late-update path.
|
|
292
|
-
let sceneUIServices: SceneUIGameServices = {};
|
|
293
|
-
|
|
294
317
|
// --- GameContext (the first-party runtime surface) ---
|
|
295
318
|
const ctx: GameContext = {
|
|
296
319
|
scene,
|
|
@@ -307,38 +330,20 @@ export class VgaiSceneGameAdapter implements GameAdapter {
|
|
|
307
330
|
assets,
|
|
308
331
|
systems,
|
|
309
332
|
components: null!,
|
|
310
|
-
uiContainer,
|
|
311
333
|
registerSystemAdapter: (kind, adapter) => {
|
|
312
334
|
systemAdapters[kind] = adapter;
|
|
313
335
|
},
|
|
314
|
-
setSceneUIServices: (incoming) => {
|
|
315
|
-
sceneUIServices = { ...sceneUIServices, ...incoming };
|
|
316
|
-
// Late call (after the initial mount already resolved a sceneInstance
|
|
317
|
-
// and rendered it): route to the live handle instead of just banking
|
|
318
|
-
// the services for a mount that already happened (D7).
|
|
319
|
-
if (sceneUIHandle && sceneInstance) {
|
|
320
|
-
const merged = buildSceneUIServices(sceneInstance);
|
|
321
|
-
if (sceneUIHandle.update) {
|
|
322
|
-
sceneUIHandle.update(merged);
|
|
323
|
-
} else {
|
|
324
|
-
sceneUIHandle.dispose();
|
|
325
|
-
sceneUIHandle = sceneInstance.ui
|
|
326
|
-
? renderSceneUI(uiContainer, sceneInstance.ui, merged)
|
|
327
|
-
: null;
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
},
|
|
331
336
|
};
|
|
332
337
|
// Game root (T7.1 slice 1): only present once the host has constructed a
|
|
333
338
|
// Game shell (createGameRuntime does this before mount; headless/foreign
|
|
334
|
-
// hosts may omit it — ctx.game/ctx.
|
|
335
|
-
// the documented zero-break behavior). `ctx.
|
|
339
|
+
// hosts may omit it — ctx.game/ctx.roots simply stay undefined, which is
|
|
340
|
+
// the documented zero-break behavior). `ctx.roots` is assigned the SAME
|
|
336
341
|
// live array `host.game` mutates via `registerWorld` (not a copy) — the
|
|
337
342
|
// default world is registered AFTER mount returns, and this reference
|
|
338
343
|
// must observe that later push.
|
|
339
344
|
if (host.game) {
|
|
340
345
|
ctx.game = host.game;
|
|
341
|
-
ctx.
|
|
346
|
+
ctx.roots = host.game.roots;
|
|
342
347
|
}
|
|
343
348
|
ctx.components = createComponentManager(ctx, physicsRegistry);
|
|
344
349
|
collisions.onCollision(
|
|
@@ -370,6 +375,85 @@ export class VgaiSceneGameAdapter implements GameAdapter {
|
|
|
370
375
|
// against the headless stand-in too (`headlessAudio()`'s plain
|
|
371
376
|
// `masterGain.gain` object) — this world's `pause()` mutes it harmlessly.
|
|
372
377
|
systemAdapters.audio = createAudioSystemAdapter(audio);
|
|
378
|
+
// Debug/synthetic-player seam (T1.1, docs/SYNTHETIC-PLAYER-SPEC.md §3.1):
|
|
379
|
+
// ONE registry per Game root, shared across every world that mounts onto
|
|
380
|
+
// it — `getDebugRegistry(host.game)` reaches the SAME accumulator
|
|
381
|
+
// `createGame` filed, so a second/third world's `ctx.debug` feeds it too
|
|
382
|
+
// (see debug-registry.ts's module doc for the provenance/id note). A
|
|
383
|
+
// mount with no Game shell at all (bare test harnesses predating T7.1)
|
|
384
|
+
// gets a private, mount-local registry instead — same absence precedent
|
|
385
|
+
// as `ctx.game`/`ctx.roots` above.
|
|
386
|
+
const debugRegistry: DebugRegistry =
|
|
387
|
+
(host.game ? getDebugRegistry(host.game) : null) ??
|
|
388
|
+
createDebugRegistry({ getTick: () => 0, getSimT: () => 0 });
|
|
389
|
+
systemAdapters.debug = debugRegistry.adapter;
|
|
390
|
+
ctx.debug = debugRegistry.forWorld(this.id);
|
|
391
|
+
// T1.2: the InputManager is a first-party per-world handle the registry
|
|
392
|
+
// has no other way to reach — wired as a lazy supplier (not a direct
|
|
393
|
+
// read here), scoped to THIS world's id, so the built-in `input.actions`
|
|
394
|
+
// provider always reflects the CURRENT action set, not a snapshot taken
|
|
395
|
+
// at mount time. Per-world (not a single last-writer-wins slot) since
|
|
396
|
+
// D15/T-D15.5 — see `debug-registry.ts`'s `setInputActionsSource` doc.
|
|
397
|
+
debugRegistry.setInputActionsSource(this.id, () =>
|
|
398
|
+
typeof input.actionNames === 'function'
|
|
399
|
+
? input.actionNames().map((name) => ({ name, valueType: input.getActionValueType(name) }))
|
|
400
|
+
: [],
|
|
401
|
+
);
|
|
402
|
+
// D15/T-D15.5 — same lazy-supplier pattern (and same headless-stand-in
|
|
403
|
+
// guard) as `setInputActionsSource` immediately above: the built-in
|
|
404
|
+
// `input.trace` provider always reads the CURRENT recorded trace, never
|
|
405
|
+
// a snapshot taken at mount time. `seed`/`fixedDt` are assembled here
|
|
406
|
+
// (not inside `InputManager`, which has no business knowing about
|
|
407
|
+
// `ctx.random` or the loop) — the two replay-critical metadata fields
|
|
408
|
+
// the design doc's format sketch (§2.c) calls for beside the raw
|
|
409
|
+
// per-tick deltas; `null` only absent a Game/ctx.random behind this
|
|
410
|
+
// mount, matching every other "no Game" fallback in this file.
|
|
411
|
+
debugRegistry.setInputTraceSource(this.id, () => {
|
|
412
|
+
const raw: { version: 1; ticks: unknown[] } =
|
|
413
|
+
typeof input.getInputTrace === 'function'
|
|
414
|
+
? input.getInputTrace()
|
|
415
|
+
: { version: 1, ticks: [] };
|
|
416
|
+
const seed = (host.game ? getSeededRandom(host.game) : null)?.seed ?? null;
|
|
417
|
+
const fixedDt = host.game?.loop.fixedDt ?? null;
|
|
418
|
+
return { version: raw.version, seed, fixedDt, ticks: raw.ticks };
|
|
419
|
+
});
|
|
420
|
+
// Task 2.1 — the same InputManager instance, wired as the debug bridge's
|
|
421
|
+
// actuation target (`runtime/debug-bridge.ts`'s `input.*` methods) at the
|
|
422
|
+
// same seed spot as `setInputActionsSource` above. Per-world (D15 review
|
|
423
|
+
// objection 2 fix) — see `debug-registry.ts`'s `setVirtualInputTarget`
|
|
424
|
+
// doc for why this used to be a single last-writer-wins slot.
|
|
425
|
+
debugRegistry.setVirtualInputTarget(this.id, {
|
|
426
|
+
setVirtualAction: (action, value) => input.setVirtualAction(action, value),
|
|
427
|
+
tapVirtualAction: (action) => input.tapVirtualAction(action),
|
|
428
|
+
clearVirtualActions: () => input.clearVirtualActions(),
|
|
429
|
+
scheduleActionAtTick: (tick, action, value) =>
|
|
430
|
+
input.scheduleActionAtTick(tick, action, value),
|
|
431
|
+
startInputRecording: () => input.startInputRecording(),
|
|
432
|
+
stopInputRecording: () => input.stopInputRecording(),
|
|
433
|
+
isInputRecording: () => input.isInputRecording(),
|
|
434
|
+
injectAxis: (sourceId, value) => input.injectAxis(sourceId, value),
|
|
435
|
+
injectVector2: (sourceId, value) => input.injectVector2(sourceId, value),
|
|
436
|
+
injectPointerDelta: (sourceId, delta) => input.injectPointerDelta(sourceId, delta),
|
|
437
|
+
injectPointerPosition: (sourceId, value) => input.injectPointerPosition(sourceId, value),
|
|
438
|
+
});
|
|
439
|
+
// R4-class fix — wire the InputManager's `'input.schedule.dropped'` sink
|
|
440
|
+
// to THIS world's debug registry, same seed spot/precedent as
|
|
441
|
+
// `setInputActionsSource`/`setVirtualInputTarget` above (typeof-guarded:
|
|
442
|
+
// a headless `InputManager` stand-in may have no `setDebugEmit`).
|
|
443
|
+
if (typeof input.setDebugEmit === 'function') {
|
|
444
|
+
input.setDebugEmit((event, detail) => ctx.debug?.emit(event, detail));
|
|
445
|
+
}
|
|
446
|
+
// D15 (T-D15.1) — same "ONE per Game root, shared across every world"
|
|
447
|
+
// pattern as the debug registry immediately above: `getSeededRandom
|
|
448
|
+
// (host.game)` reaches the SAME `SeededRandom` `createGame` filed (boot-
|
|
449
|
+
// seeded by the manifest-aware mount path, `mount-manifest.ts`, before
|
|
450
|
+
// ANY world's `mount()`/`setup()` runs — see `createGame`'s own doc
|
|
451
|
+
// comment), so every world's `ctx.random` is the identical instance, not
|
|
452
|
+
// a per-world copy. Same absence precedent as `ctx.debug`: a mount with
|
|
453
|
+
// no Game shell at all gets a private, mount-local surface instead.
|
|
454
|
+
ctx.random =
|
|
455
|
+
(host.game ? getSeededRandom(host.game) : null) ??
|
|
456
|
+
createSeededRandom(DEFAULT_SEEDED_RANDOM_SEED);
|
|
373
457
|
|
|
374
458
|
// Snapshot of the engine-owned adapter kinds, taken right after seeding
|
|
375
459
|
// and before any setup() has had a chance to run. `hotReload`/`disposeGame`
|
|
@@ -396,13 +480,7 @@ export class VgaiSceneGameAdapter implements GameAdapter {
|
|
|
396
480
|
c.traverse((n) => setUserData(n, 'engineInternal', true));
|
|
397
481
|
}
|
|
398
482
|
let currentCleanup: GameCleanup | null = null;
|
|
399
|
-
let sceneUIHandle: SceneUIHandle | null = null;
|
|
400
483
|
let batchSystem: RenderBatchSystem | null = null;
|
|
401
|
-
// The scenePath/sceneData branch's resolved SceneInstance, if either ran
|
|
402
|
-
// (stays undefined for a `setup`-based mount — see the `sceneUI` deriva-
|
|
403
|
-
// tion below). Single source of truth for both the scene-graph `ui` tree
|
|
404
|
-
// and (potentially, in future) other instance-derived wiring.
|
|
405
|
-
let sceneInstance: SceneInstance | undefined;
|
|
406
484
|
|
|
407
485
|
// Apply scene-level render settings + transparent auto-batching after a scene
|
|
408
486
|
// loads (GPU host only). Gated on the resolved `environment.rendering` cascade
|
|
@@ -441,61 +519,6 @@ export class VgaiSceneGameAdapter implements GameAdapter {
|
|
|
441
519
|
}
|
|
442
520
|
};
|
|
443
521
|
|
|
444
|
-
// Scratch vector for the D5 default worldProjector — reused across calls
|
|
445
|
-
// (one per bound world-tracked canvas per render), never allocated per-frame.
|
|
446
|
-
const _sceneUIProjectorTmp = new THREE.Vector3();
|
|
447
|
-
|
|
448
|
-
// The D4 default data source subscribes to game.state for its whole
|
|
449
|
-
// lifetime with no unsubscribe path, so it must be built at most ONCE per
|
|
450
|
-
// adapter mount — buildSceneUIServices runs again on every late
|
|
451
|
-
// setSceneUIServices call, and rebuilding it there would both leak a
|
|
452
|
-
// subscription and force every bound node to resubscribe to a fresh store.
|
|
453
|
-
let defaultSceneUIData: SceneUIDataSourceLike | undefined;
|
|
454
|
-
|
|
455
|
-
/**
|
|
456
|
-
* Assemble the services `renderSceneUI` receives (design/24-scene-ui.md
|
|
457
|
-
* D2): engine defaults (D4 data source, D5 worldProjector, D6 onEvent) <-
|
|
458
|
-
* the project's per-mount UI registry (D11, editor-play threading) <-
|
|
459
|
-
* game-registered services (`ctx.setSceneUIServices`) — per key, each
|
|
460
|
-
* later layer winning over the one before it.
|
|
461
|
-
*/
|
|
462
|
-
const buildSceneUIServices = (inst: SceneInstance): SceneUIGameServices => {
|
|
463
|
-
const defaults: SceneUIGameServices = {
|
|
464
|
-
onEvent: (handlerId) => {
|
|
465
|
-
console.warn(
|
|
466
|
-
`scene-ui: unhandled UI event "${handlerId}" — register onEvent via ctx.setSceneUIServices`,
|
|
467
|
-
);
|
|
468
|
-
},
|
|
469
|
-
worldProjector: (id) => {
|
|
470
|
-
const obj = inst.entities.get(id);
|
|
471
|
-
if (!obj) return null;
|
|
472
|
-
const projected = obj.getWorldPosition(_sceneUIProjectorTmp).project(camera);
|
|
473
|
-
if (projected.z > 1) return null; // behind the camera -> hidden
|
|
474
|
-
const w = uiContainer.clientWidth;
|
|
475
|
-
const h = uiContainer.clientHeight;
|
|
476
|
-
// Rounded (not sub-pixel) — matches CrtScreen's integer-rounding
|
|
477
|
-
// (crt-screen.ts), which exists specifically to stop an asymptotic
|
|
478
|
-
// camera lerp from shimmering a tracked canvas every frame.
|
|
479
|
-
return {
|
|
480
|
-
x: Math.round(((projected.x + 1) / 2) * w),
|
|
481
|
-
y: Math.round(((1 - projected.y) / 2) * h),
|
|
482
|
-
};
|
|
483
|
-
},
|
|
484
|
-
};
|
|
485
|
-
// Lazily and at-most-once; skipped entirely while the game supplies its
|
|
486
|
-
// own `data` service (no point subscribing a default nobody reads).
|
|
487
|
-
if (!sceneUIServices.data && ctx.game && componentRegistry) {
|
|
488
|
-
defaultSceneUIData ??= gameStateDataSource(ctx.game, componentRegistry);
|
|
489
|
-
defaults.data = defaultSceneUIData;
|
|
490
|
-
}
|
|
491
|
-
const registryPortion: SceneUIGameServices = {
|
|
492
|
-
...(uiRegistry?.components ? { components: uiRegistry.components } : {}),
|
|
493
|
-
...(uiRegistry?.transforms ? { transforms: uiRegistry.transforms } : {}),
|
|
494
|
-
...(uiRegistry?.strings ? { strings: uiRegistry.strings } : {}),
|
|
495
|
-
};
|
|
496
|
-
return { ...defaults, ...registryPortion, ...sceneUIServices };
|
|
497
|
-
};
|
|
498
|
-
|
|
499
522
|
const loadFromData = async (data: SceneFile): Promise<SceneInstance> => {
|
|
500
523
|
const inst = await loadSceneFromData(data, {
|
|
501
524
|
scene,
|
|
@@ -518,6 +541,9 @@ export class VgaiSceneGameAdapter implements GameAdapter {
|
|
|
518
541
|
if (headless) throw new Error('VgaiSceneGameAdapter: setup-based games require a GPU host');
|
|
519
542
|
currentCleanup = await setup(ctx, editorPreview);
|
|
520
543
|
} else if (scenePath) {
|
|
544
|
+
// #139: captured BEFORE load so adoptSceneCamera can tell whether a
|
|
545
|
+
// component (e.g. SceneCamera.init) already framed the camera.
|
|
546
|
+
const preLoadPose = captureCameraPose(camera);
|
|
521
547
|
const inst = await loadScene(scenePath, {
|
|
522
548
|
scene,
|
|
523
549
|
rapierWorld: ctx.rapierWorld,
|
|
@@ -529,11 +555,10 @@ export class VgaiSceneGameAdapter implements GameAdapter {
|
|
|
529
555
|
particleRenderer: ctx.particles.batchedRenderer,
|
|
530
556
|
...(headless ? {} : { renderer }),
|
|
531
557
|
});
|
|
532
|
-
applyEditorCamera(editorPreview, camera) || adoptSceneCamera(inst, camera);
|
|
558
|
+
applyEditorCamera(editorPreview, camera) || adoptSceneCamera(inst, camera, preLoadPose);
|
|
533
559
|
applySceneRendering(inst);
|
|
534
560
|
applySceneNavigation(inst);
|
|
535
561
|
ctx.systems.add('postPhysics', (dt) => inst.update(dt));
|
|
536
|
-
sceneInstance = inst;
|
|
537
562
|
// A pre-baked navmesh (sibling .navmesh file — see scene-loader.ts) holds
|
|
538
563
|
// live recast-navigation WASM handles that leak unless destroyed
|
|
539
564
|
// explicitly; dispose it alongside the scene instance on teardown.
|
|
@@ -544,9 +569,9 @@ export class VgaiSceneGameAdapter implements GameAdapter {
|
|
|
544
569
|
},
|
|
545
570
|
};
|
|
546
571
|
} else if (sceneData) {
|
|
572
|
+
const preLoadPose = captureCameraPose(camera);
|
|
547
573
|
const inst = await loadFromData(sceneData);
|
|
548
|
-
applyEditorCamera(editorPreview, camera) || adoptSceneCamera(inst, camera);
|
|
549
|
-
sceneInstance = inst;
|
|
574
|
+
applyEditorCamera(editorPreview, camera) || adoptSceneCamera(inst, camera, preLoadPose);
|
|
550
575
|
currentCleanup = {
|
|
551
576
|
dispose: () => {
|
|
552
577
|
inst.navMesh?.dispose(scene);
|
|
@@ -555,19 +580,6 @@ export class VgaiSceneGameAdapter implements GameAdapter {
|
|
|
555
580
|
};
|
|
556
581
|
}
|
|
557
582
|
|
|
558
|
-
// Render scene-graph UI (the `ui` tree) into the overlay via the injected React
|
|
559
|
-
// renderer (B1). Sourced from the loaded `SceneInstance` — the single source of
|
|
560
|
-
// truth for BOTH the scenePath and sceneData branches (R8 item 7 / B: previously
|
|
561
|
-
// only sceneData's raw `SceneFile.ui` was read via a `resolvedSceneData` special-
|
|
562
|
-
// case, so a scenePath mount's `ui` tree was silently dropped even though
|
|
563
|
-
// `loadScene` fully parses it). A `setup`-based mount has no `sceneInstance` at
|
|
564
|
-
// all — its game owns any UI mounting itself. No-op if no UI or no renderer
|
|
565
|
-
// registered. Engine stays React-free.
|
|
566
|
-
const sceneUI = sceneInstance?.ui;
|
|
567
|
-
if (sceneUI && sceneInstance && !headless) {
|
|
568
|
-
sceneUIHandle = renderSceneUI(uiContainer, sceneUI, buildSceneUIServices(sceneInstance));
|
|
569
|
-
}
|
|
570
|
-
|
|
571
583
|
// Idempotency guard for disposeGame — see below. Declared here (not inside
|
|
572
584
|
// disposeGame) so hotReload can also refuse to run on an already-disposed
|
|
573
585
|
// adapter.
|
|
@@ -654,13 +666,6 @@ export class VgaiSceneGameAdapter implements GameAdapter {
|
|
|
654
666
|
});
|
|
655
667
|
safeStep('clearAssetCaches', () => clearAssetCaches());
|
|
656
668
|
safeStep('debugDraw.clear', () => debugDraw.clear());
|
|
657
|
-
safeStep('sceneUIHandle.dispose', () => {
|
|
658
|
-
sceneUIHandle?.dispose();
|
|
659
|
-
sceneUIHandle = null;
|
|
660
|
-
});
|
|
661
|
-
safeStep('uiContainer reset', () => {
|
|
662
|
-
uiContainer.innerHTML = '';
|
|
663
|
-
});
|
|
664
669
|
|
|
665
670
|
// R8 item 7 (C) — disposeGame (Stop) used to skip both of these, unlike
|
|
666
671
|
// hotReload (warm restart), which already ran them: a game lifecycle
|
|
@@ -669,7 +674,7 @@ export class VgaiSceneGameAdapter implements GameAdapter {
|
|
|
669
674
|
// systemAdapters kind (e.g. a `setup`-registered 'networking') survived
|
|
670
675
|
// a Stop and would be visible on a STALE `mounted.systems` even though
|
|
671
676
|
// the game that owned it is gone. Same two steps, same relative
|
|
672
|
-
// ordering as hotReload (
|
|
677
|
+
// ordering as hotReload (before the
|
|
673
678
|
// engine-owned audio/input teardown below, which hotReload doesn't
|
|
674
679
|
// touch at all since it warm-restarts rather than tearing engine
|
|
675
680
|
// subsystems down).
|
|
@@ -679,6 +684,12 @@ export class VgaiSceneGameAdapter implements GameAdapter {
|
|
|
679
684
|
if (!engineAdapterKinds.has(kind)) delete systemAdapters[kind as keyof SystemAdapters];
|
|
680
685
|
}
|
|
681
686
|
});
|
|
687
|
+
// Defect 2 fix: a full Stop means the whole GAME is going away (every
|
|
688
|
+
// world it mounted, plus any react-door registrations from its HUDs)
|
|
689
|
+
// — unlike hotReload below (a SINGLE mount warm-restarting), so this is
|
|
690
|
+
// the one call site that legitimately wants strip()'s global, no-id
|
|
691
|
+
// form rather than scoping to `this.id`.
|
|
692
|
+
safeStep('debugRegistry.strip', () => debugRegistry.strip());
|
|
682
693
|
|
|
683
694
|
if (!headless) {
|
|
684
695
|
safeStep('audio teardown', () => {
|
|
@@ -689,6 +700,7 @@ export class VgaiSceneGameAdapter implements GameAdapter {
|
|
|
689
700
|
});
|
|
690
701
|
}
|
|
691
702
|
safeStep('input.dispose', () => input.dispose());
|
|
703
|
+
safeStep('gpuTimer.dispose', () => gpuTimer?.dispose());
|
|
692
704
|
};
|
|
693
705
|
|
|
694
706
|
const hotReload = async (
|
|
@@ -754,20 +766,6 @@ export class VgaiSceneGameAdapter implements GameAdapter {
|
|
|
754
766
|
scene.environment = null;
|
|
755
767
|
});
|
|
756
768
|
safeStep('debugDraw.clear', () => debugDraw.clear());
|
|
757
|
-
safeStep('sceneUIHandle.dispose', () => {
|
|
758
|
-
sceneUIHandle?.dispose();
|
|
759
|
-
sceneUIHandle = null;
|
|
760
|
-
});
|
|
761
|
-
// Strip game-registered scene-UI services back to none before the
|
|
762
|
-
// incoming game's setup/init runs (D7) — same contract as the
|
|
763
|
-
// systemAdapters strip below: a disposed game's onEvent/data/
|
|
764
|
-
// worldProjector must never leak onto the next mount.
|
|
765
|
-
safeStep('reset sceneUIServices', () => {
|
|
766
|
-
sceneUIServices = {};
|
|
767
|
-
});
|
|
768
|
-
safeStep('uiContainer reset', () => {
|
|
769
|
-
uiContainer.innerHTML = '';
|
|
770
|
-
});
|
|
771
769
|
|
|
772
770
|
// Bulk-remove every system the outgoing game registered (this restart's
|
|
773
771
|
// predecessor) so warm restarts never accumulate duplicate systems —
|
|
@@ -787,6 +785,16 @@ export class VgaiSceneGameAdapter implements GameAdapter {
|
|
|
787
785
|
if (!engineAdapterKinds.has(kind)) delete systemAdapters[kind as keyof SystemAdapters];
|
|
788
786
|
}
|
|
789
787
|
});
|
|
788
|
+
// Hot-reload re-seed (spec §3.1): the incoming game's setup (below)
|
|
789
|
+
// re-registers its providers/commands under the SAME worldId — strip()
|
|
790
|
+
// clears the outgoing game's registrations first so that re-seed is
|
|
791
|
+
// silent (no stale duplicate-name warning) rather than "replacing" a
|
|
792
|
+
// dead game's entries. Defect 2 fix: scoped to THIS mount's worldId
|
|
793
|
+
// (`this.id`) — a blind global strip() here wiped every OTHER live
|
|
794
|
+
// world's registrations on every warm restart of just this one, plus
|
|
795
|
+
// every react-door registration (whose `useEffect` cleanup never
|
|
796
|
+
// re-fires to restore them after someone else's strip).
|
|
797
|
+
safeStep('debugRegistry.strip', () => debugRegistry.strip(this.id));
|
|
790
798
|
|
|
791
799
|
currentCleanup = await newSetup(ctx, newEditorPreview);
|
|
792
800
|
};
|
|
@@ -833,17 +841,68 @@ function applyEditorCamera(
|
|
|
833
841
|
return true;
|
|
834
842
|
}
|
|
835
843
|
|
|
844
|
+
/** The pose `adoptSceneCamera` compares against to detect that a component
|
|
845
|
+
* already framed the runtime camera during scene load (#139). Capture with
|
|
846
|
+
* `captureCameraPose(camera)` immediately BEFORE `loadScene`. */
|
|
847
|
+
export interface CameraPose {
|
|
848
|
+
position: THREE.Vector3;
|
|
849
|
+
quaternion: THREE.Quaternion;
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
export function captureCameraPose(camera: THREE.PerspectiveCamera): CameraPose {
|
|
853
|
+
return { position: camera.position.clone(), quaternion: camera.quaternion.clone() };
|
|
854
|
+
}
|
|
855
|
+
|
|
836
856
|
export function adoptSceneCamera(
|
|
837
857
|
sceneInstance: SceneInstance,
|
|
838
858
|
runtimeCamera: THREE.PerspectiveCamera,
|
|
859
|
+
preLoadPose?: CameraPose,
|
|
839
860
|
): boolean {
|
|
840
861
|
const sceneCam = sceneInstance.cameras[0];
|
|
841
862
|
if (!sceneCam) return false;
|
|
863
|
+
// #133 (blind run #4): `camera.type: 'orthographic'` builds a real
|
|
864
|
+
// OrthographicCamera in the scene graph (`createCamera`), but the RUNTIME
|
|
865
|
+
// renders through a hardcoded PerspectiveCamera — the authored projection
|
|
866
|
+
// silently never reached the screen. Until ortho support is ranked
|
|
867
|
+
// (implement-vs-reject, owner call on #133), say so loudly instead of
|
|
868
|
+
// letting a coplanar game render in unexplained perspective.
|
|
869
|
+
if ((sceneCam as THREE.Camera & { isOrthographicCamera?: boolean }).isOrthographicCamera) {
|
|
870
|
+
console.warn(
|
|
871
|
+
"adoptSceneCamera (#133): this scene's camera is ORTHOGRAPHIC, but the runtime camera is " +
|
|
872
|
+
'perspective-only — the orthographic projection is NOT applied (only the pose is). ' +
|
|
873
|
+
'Use type: "perspective" (a long-lens fake: far position + small fov) until #133 lands.',
|
|
874
|
+
);
|
|
875
|
+
}
|
|
876
|
+
// #139 (blind run #5): if a GameComponent already positioned/oriented the
|
|
877
|
+
// runtime camera during scene load (`SceneCamera.init`'s
|
|
878
|
+
// `ctx.camera.position.set` + `lookAt` is the blessed shape), the camera
|
|
879
|
+
// ENTITY's transform must not stomp it — an unauthored `transform.rotation`
|
|
880
|
+
// is identity ("stare down −Z"), which silently blanked an entire correct
|
|
881
|
+
// game while every state-based probe spec passed. Components win the pose;
|
|
882
|
+
// the entity still contributes the LENS (fov/near/far below), which
|
|
883
|
+
// `SceneCamera` never sets.
|
|
884
|
+
const componentFramedCamera =
|
|
885
|
+
preLoadPose !== undefined &&
|
|
886
|
+
(!runtimeCamera.position.equals(preLoadPose.position) ||
|
|
887
|
+
!runtimeCamera.quaternion.equals(preLoadPose.quaternion));
|
|
842
888
|
const parent = sceneCam.parent;
|
|
843
|
-
if (parent) {
|
|
889
|
+
if (parent && !componentFramedCamera) {
|
|
844
890
|
parent.updateMatrixWorld(true);
|
|
845
891
|
runtimeCamera.position.copy(parent.getWorldPosition(new THREE.Vector3()));
|
|
846
|
-
|
|
892
|
+
const worldQuat = parent.getWorldQuaternion(new THREE.Quaternion());
|
|
893
|
+
runtimeCamera.quaternion.copy(worldQuat);
|
|
894
|
+
// Identity orientation on an adopted scene camera is almost never intent
|
|
895
|
+
// (it means "look at the horizon down −Z", not "look at my scene") — the
|
|
896
|
+
// exact silent-blank-viewport footgun above. Adopt it anyway (authored
|
|
897
|
+
// data is truth) but say so loudly, with the two blessed remedies.
|
|
898
|
+
if (Math.abs(1 - Math.abs(worldQuat.w)) < 1e-6) {
|
|
899
|
+
console.warn(
|
|
900
|
+
'adoptSceneCamera (#139): the scene camera entity has no rotation — the runtime camera ' +
|
|
901
|
+
'will stare horizontally down −Z and may show nothing. Either attach the SceneCamera ' +
|
|
902
|
+
'component (position + lookAt, no quaternion math) or author transform.rotation on ' +
|
|
903
|
+
'the camera entity.',
|
|
904
|
+
);
|
|
905
|
+
}
|
|
847
906
|
}
|
|
848
907
|
if (sceneCam instanceof THREE.PerspectiveCamera) {
|
|
849
908
|
runtimeCamera.fov = sceneCam.fov;
|