@vgai/engine 0.5.0 → 0.5.1
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 +1 -1
- package/schemas/engine-capabilities.json +4 -4
- package/schemas/vgai-game.schema.json +2 -2
- package/src/adapter/authoring.ts +42 -0
- package/src/adapter/index.ts +3 -0
- package/src/adapter/ingest/overlay-apply.ts +50 -6
- package/src/adapter/ingest/scene-capture.ts +51 -2
- package/src/adapter/vgai-scene-game-adapter.ts +24 -0
- package/src/manifest/schema.ts +7 -3
- package/src/runtime/create-runtime.ts +97 -0
- package/src/runtime/game.ts +11 -1
- package/src/scene/asset-ref-check.ts +1 -1
- package/src/scene/scene-loader.ts +2 -2
- package/src/scene/user-data.ts +18 -0
- package/src/world3d-react/behavior.tsx +19 -11
- package/src/world3d-react/r3f-adapter.tsx +8 -0
- package/dist/adapter/adapter-surface.d.ts +0 -30
- package/dist/adapter/adapter-surface.d.ts.map +0 -1
- package/dist/adapter/adapter-surface.js +0 -18
- package/dist/adapter/authoring.d.ts +0 -461
- 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 -71
- 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 -206
- 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 -108
- package/dist/adapter/vgai-scene-game-adapter.d.ts.map +0 -1
- package/dist/adapter/vgai-scene-game-adapter.js +0 -762
- 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 -56
- package/dist/animation/xstate-animation-binding.d.ts.map +0 -1
- package/dist/animation/xstate-animation-binding.js +0 -331
- package/dist/animation/xstate-animation-meta.d.ts +0 -266
- package/dist/animation/xstate-animation-meta.d.ts.map +0 -1
- package/dist/animation/xstate-animation-meta.js +0 -252
- 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/character/cloth-sim.d.ts +0 -179
- package/dist/character/cloth-sim.d.ts.map +0 -1
- package/dist/character/cloth-sim.js +0 -334
- package/dist/character/spring-chain.d.ts +0 -135
- package/dist/character/spring-chain.d.ts.map +0 -1
- package/dist/character/spring-chain.js +0 -165
- package/dist/core/game-loop.d.ts +0 -42
- package/dist/core/game-loop.d.ts.map +0 -1
- package/dist/core/game-loop.js +0 -167
- package/dist/core/seeded-random.d.ts +0 -69
- package/dist/core/seeded-random.d.ts.map +0 -1
- package/dist/core/seeded-random.js +0 -121
- 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 -297
- package/dist/core/types.d.ts +0 -92
- 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/dev/performance-profiler.d.ts +0 -60
- package/dist/dev/performance-profiler.d.ts.map +0 -1
- package/dist/dev/performance-profiler.js +0 -181
- package/dist/dev/webgl-gpu-timer.d.ts +0 -8
- package/dist/dev/webgl-gpu-timer.d.ts.map +0 -1
- package/dist/dev/webgl-gpu-timer.js +0 -52
- package/dist/ecs/component-manager.d.ts +0 -205
- package/dist/ecs/component-manager.d.ts.map +0 -1
- package/dist/ecs/component-manager.js +0 -706
- package/dist/ecs/game-component.d.ts +0 -146
- package/dist/ecs/game-component.d.ts.map +0 -1
- package/dist/ecs/game-component.js +0 -141
- 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/humanoid/bake.operation.d.ts +0 -119
- package/dist/humanoid/bake.operation.d.ts.map +0 -1
- package/dist/humanoid/bake.operation.js +0 -228
- package/dist/humanoid/body.d.ts +0 -101
- package/dist/humanoid/body.d.ts.map +0 -1
- package/dist/humanoid/body.js +0 -530
- package/dist/humanoid/clips.d.ts +0 -62
- package/dist/humanoid/clips.d.ts.map +0 -1
- package/dist/humanoid/clips.js +0 -121
- package/dist/humanoid/compose.d.ts +0 -75
- package/dist/humanoid/compose.d.ts.map +0 -1
- package/dist/humanoid/compose.js +0 -176
- package/dist/humanoid/generate.d.ts +0 -92
- package/dist/humanoid/generate.d.ts.map +0 -1
- package/dist/humanoid/generate.js +0 -124
- package/dist/humanoid/index.d.ts +0 -24
- package/dist/humanoid/index.d.ts.map +0 -1
- package/dist/humanoid/index.js +0 -18
- package/dist/humanoid/schema.d.ts +0 -35
- package/dist/humanoid/schema.d.ts.map +0 -1
- package/dist/humanoid/schema.js +0 -87
- package/dist/humanoid/skeleton.d.ts +0 -103
- package/dist/humanoid/skeleton.d.ts.map +0 -1
- package/dist/humanoid/skeleton.js +0 -289
- 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 -945
- package/dist/input/input-manager.d.ts.map +0 -1
- package/dist/input/input-manager.js +0 -2207
- package/dist/input/input-types.d.ts +0 -174
- 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 -144
- package/dist/manifest/load.d.ts.map +0 -1
- package/dist/manifest/load.js +0 -273
- package/dist/manifest/schema.d.ts +0 -230
- package/dist/manifest/schema.d.ts.map +0 -1
- package/dist/manifest/schema.js +0 -394
- 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 -156
- package/dist/react/game-state.d.ts.map +0 -1
- package/dist/react/game-state.js +0 -222
- package/dist/react/root-adapter.d.ts +0 -11
- package/dist/react/root-adapter.d.ts.map +0 -1
- package/dist/react/root-adapter.js +0 -41
- package/dist/react/unmanaged-root-detector.d.ts +0 -12
- package/dist/react/unmanaged-root-detector.d.ts.map +0 -1
- package/dist/react/unmanaged-root-detector.js +0 -45
- 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 -101
- 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 -249
- package/dist/runtime/create-runtime.d.ts.map +0 -1
- package/dist/runtime/create-runtime.js +0 -641
- package/dist/runtime/debug-bridge.d.ts +0 -257
- package/dist/runtime/debug-bridge.d.ts.map +0 -1
- package/dist/runtime/debug-bridge.js +0 -224
- package/dist/runtime/debug-registry.d.ts +0 -288
- package/dist/runtime/debug-registry.d.ts.map +0 -1
- package/dist/runtime/debug-registry.js +0 -513
- 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 -496
- package/dist/runtime/game.d.ts.map +0 -1
- package/dist/runtime/game.js +0 -741
- package/dist/runtime/gameplay-rng-trap.d.ts +0 -48
- package/dist/runtime/gameplay-rng-trap.d.ts.map +0 -1
- package/dist/runtime/gameplay-rng-trap.js +0 -96
- 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 -173
- package/dist/runtime/mount-manifest.d.ts.map +0 -1
- package/dist/runtime/mount-manifest.js +0 -297
- 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/state-bridge.d.ts +0 -61
- package/dist/runtime/state-bridge.d.ts.map +0 -1
- package/dist/runtime/state-bridge.js +0 -63
- package/dist/runtime/types.d.ts +0 -253
- 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 -38
- package/dist/scene/asset-registry.d.ts.map +0 -1
- package/dist/scene/asset-registry.js +0 -66
- 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 -22
- package/dist/scene/component-registry.d.ts.map +0 -1
- package/dist/scene/component-registry.js +0 -37
- 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 -370
- 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 -167
- package/dist/scene/scene-loader.d.ts.map +0 -1
- package/dist/scene/scene-loader.js +0 -1211
- 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 -37
- package/dist/scene/schema/index.d.ts.map +0 -1
- package/dist/scene/schema/index.js +0 -19
- 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 -103
- 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 -303
- package/dist/scene/schema/scene-file.d.ts.map +0 -1
- package/dist/scene/schema/scene-file.js +0 -256
- 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/user-data.d.ts +0 -185
- package/dist/scene/user-data.d.ts.map +0 -1
- package/dist/scene/user-data.js +0 -144
- 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 -130
- package/dist/tools/define-tool.d.ts.map +0 -1
- package/dist/tools/define-tool.js +0 -96
- package/dist/world2d/authoring-2d.d.ts +0 -80
- package/dist/world2d/authoring-2d.d.ts.map +0 -1
- package/dist/world2d/authoring-2d.js +0 -195
- 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 -210
- 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 -275
- 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 -59
- package/dist/world2d/types.d.ts.map +0 -1
- package/dist/world2d/types.js +0 -1
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@vgai/engine",
|
|
3
3
|
"author": "Volter AI, Inc.",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
|
-
"version": "0.5.
|
|
5
|
+
"version": "0.5.1",
|
|
6
6
|
"description": "Readable TypeScript game engine and universal host for Three.js, PixiJS, and React games.",
|
|
7
7
|
"keywords": ["game-engine", "three.js", "pixijs", "react", "ai-agents"],
|
|
8
8
|
"type": "module",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
],
|
|
17
17
|
"notes": "Grepped packages/engine/src for ccd/CCD/setCcdEnabled: zero matches, 2D and 3D. No call ever sets a ccd flag. Workaround: keep dynamic-body per-step travel small relative to the thinnest collider, or add intermediate colliders.",
|
|
18
18
|
"evidenceHashes": {
|
|
19
|
-
"packages/engine/src/scene/scene-loader.ts": "
|
|
19
|
+
"packages/engine/src/scene/scene-loader.ts": "07fb9086e95959fd84e71ccc57581bb00d1f6eca1137853492b6a569755e8db5",
|
|
20
20
|
"packages/engine/src/world2d/scene2d-loader.ts": "f0f74eefd9cce16bbe7826225a52f2b0407ab141641dcdd370bcff1d091bce69"
|
|
21
21
|
}
|
|
22
22
|
},
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"notes": "Grepped for maxBodies/MAX_ENTITIES/entity limit/body limit/entityCount: no matches. No invented numbers — nothing caps entity/body count and no perf test here establishes a safe ceiling. Treat large counts (hundreds+ dynamic bodies) as unvalidated, not 'supported at scale'.",
|
|
33
33
|
"evidenceHashes": {
|
|
34
34
|
"packages/engine/src/setup/setup-physics.ts": "0540c502f420018b24dac8b77c486f30f905f0a05b02ead7ed3899e5aa612ee5",
|
|
35
|
-
"packages/engine/src/scene/scene-loader.ts": "
|
|
35
|
+
"packages/engine/src/scene/scene-loader.ts": "07fb9086e95959fd84e71ccc57581bb00d1f6eca1137853492b6a569755e8db5"
|
|
36
36
|
}
|
|
37
37
|
},
|
|
38
38
|
{
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
],
|
|
92
92
|
"notes": "Track P shipped 2026-07-03; proven: bubbo-bubbo/puzzling-potions/flappy-pixi. Tiers/limits: docs/CAPABILITY-TIERS.md, docs/PIXI-INGEST-LANDING-DESIGN.md.",
|
|
93
93
|
"evidenceHashes": {
|
|
94
|
-
"docs/BACKBONE-TASKS.md": "
|
|
94
|
+
"docs/BACKBONE-TASKS.md": "4d58398e22ed0261ec246668cac115ec9cfdde9881920070e95ee642f1323eb1"
|
|
95
95
|
}
|
|
96
96
|
},
|
|
97
97
|
{
|
|
@@ -104,7 +104,7 @@
|
|
|
104
104
|
],
|
|
105
105
|
"notes": "Scope is native-DOM React ONLY (D-N1): R3F/@pixi/react games are canvas games and ride the three.js/pixi seams instead. Generality limit: ONE proven game (react-rpg — menu-to-dungeon e2e under React 19; both game-2 candidates rejected on evidence, R-N7). Game deps must be host-installed root deps (D-N6). Open R-N6: vendored react games' raw window listeners bypass the play-mode input gate. Design: docs/REACT-INGEST-LANDING-DESIGN.md.",
|
|
106
106
|
"evidenceHashes": {
|
|
107
|
-
"docs/BACKBONE-TASKS.md": "
|
|
107
|
+
"docs/BACKBONE-TASKS.md": "4d58398e22ed0261ec246668cac115ec9cfdde9881920070e95ee642f1323eb1"
|
|
108
108
|
}
|
|
109
109
|
},
|
|
110
110
|
{
|
|
@@ -446,11 +446,11 @@
|
|
|
446
446
|
"description": "Short kebab-case feature tags used as gallery/catalog filter facets"
|
|
447
447
|
},
|
|
448
448
|
"thumbnail": {
|
|
449
|
-
"description": "Optional thumbnail image reference
|
|
449
|
+
"description": "Optional thumbnail image reference, PROJECT-relative (canonical path: learn/thumbnail.png — the §3 schema path). Generated per FT-11 by the deterministic render tooling (scripts/generate-learn-thumbnails.ts), never hand-made",
|
|
450
450
|
"type": "string"
|
|
451
451
|
},
|
|
452
452
|
"preview": {
|
|
453
|
-
"description": "Optional short preview video/loop reference (generated per FT-11)",
|
|
453
|
+
"description": "Optional short preview video/loop reference, PROJECT-relative (canonical path: learn/preview.mp4; generated per FT-11)",
|
|
454
454
|
"type": "string"
|
|
455
455
|
},
|
|
456
456
|
"lesson": {
|
package/src/adapter/authoring.ts
CHANGED
|
@@ -89,6 +89,7 @@ export type EditorNodeRole =
|
|
|
89
89
|
| 'document'
|
|
90
90
|
| 'story'
|
|
91
91
|
| 'component'
|
|
92
|
+
| 'instance'
|
|
92
93
|
| 'element'
|
|
93
94
|
| 'entity'
|
|
94
95
|
| 'boundary';
|
|
@@ -153,6 +154,34 @@ export interface HierarchyProvider {
|
|
|
153
154
|
export interface SelectionProvider {
|
|
154
155
|
get(): string[];
|
|
155
156
|
set(ids: string[]): void;
|
|
157
|
+
/** Resolve a raw native/render hit to the semantic authoring subject. The
|
|
158
|
+
* shell must not infer ownership from ancestry or substrate-specific kinds.
|
|
159
|
+
* Older adapters may omit this; raw ids then remain the selection ids. */
|
|
160
|
+
resolve?(
|
|
161
|
+
rawId: string,
|
|
162
|
+
options?: { intent?: 'normal' | 'deep'; scopeId?: string | null },
|
|
163
|
+
): SelectionResolution | null;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** Adapter-owned result of semantic selection resolution. Separate ids keep
|
|
167
|
+
* selection, inspection, and manipulation from becoming accidental aliases. */
|
|
168
|
+
export interface SelectionResolution {
|
|
169
|
+
/** Hierarchy selection and default Inspector subject. */
|
|
170
|
+
id: string;
|
|
171
|
+
/** Optional alternate Inspector subject. Defaults to {@link id}. */
|
|
172
|
+
inspectorId?: string;
|
|
173
|
+
/** Native transform subject. `null` means the selection is non-spatial. */
|
|
174
|
+
transformId?: string | null;
|
|
175
|
+
/** Nearest closed component/prefab/assembly boundary, when any. */
|
|
176
|
+
boundaryId?: string | null;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export type TransformChannel = 'position' | 'rotation' | 'scale';
|
|
180
|
+
|
|
181
|
+
export interface TransformEditability {
|
|
182
|
+
writable: boolean;
|
|
183
|
+
/** Human-facing explanation for a disabled gizmo/field. */
|
|
184
|
+
reason?: string;
|
|
156
185
|
}
|
|
157
186
|
|
|
158
187
|
export interface TransformProvider {
|
|
@@ -160,6 +189,10 @@ export interface TransformProvider {
|
|
|
160
189
|
dimensions?(id: string): '2d' | '3d' | null;
|
|
161
190
|
get(id: string): Transform;
|
|
162
191
|
owner(id: string): TransformOwner;
|
|
192
|
+
/** Pre-gesture persistence check. Omitted means the adapter's transform
|
|
193
|
+
* capability applies uniformly. A false result must suppress manipulation
|
|
194
|
+
* before the live object is moved, never discover refusal at drag end. */
|
|
195
|
+
editability?(id: string, channel: TransformChannel): TransformEditability;
|
|
163
196
|
/** Pause whatever controller fights the gizmo (physics/script) for editing. */
|
|
164
197
|
beginEdit(id: string): void;
|
|
165
198
|
apply(id: string, t: Transform): void;
|
|
@@ -237,6 +270,15 @@ export interface StructureProvider {
|
|
|
237
270
|
* `wrap`). Absent ⇒ the shell's context menu shows no Unwrap item for this
|
|
238
271
|
* adapter. */
|
|
239
272
|
unwrap?(id: string): void;
|
|
273
|
+
/** Group sibling authoring objects beneath one new spatial parent. The
|
|
274
|
+
* adapter owns transform preservation, persistence, and undo semantics.
|
|
275
|
+
* Returns the new group id, or null when the selection cannot be grouped. */
|
|
276
|
+
group?(ids: readonly string[]): string | null;
|
|
277
|
+
/** Dissolve a plain spatial group and return the ids of its promoted
|
|
278
|
+
* children. Absent means this adapter has no lossless ungroup operation. */
|
|
279
|
+
ungroup?(id: string): string[];
|
|
280
|
+
/** Preflight for an Ungroup affordance. Omit when ungroup is never offered. */
|
|
281
|
+
canUngroup?(id: string): boolean;
|
|
240
282
|
/**
|
|
241
283
|
* D4.R2 (spec27 §6 D4 reopen) — remove every id in `ids` as ONE undoable
|
|
242
284
|
* op (a single Ctrl+Z restores the whole batch), instead of the caller
|
package/src/adapter/index.ts
CHANGED
|
@@ -39,6 +39,7 @@ export type {
|
|
|
39
39
|
RootGroup,
|
|
40
40
|
RootGroupsProvider,
|
|
41
41
|
SelectionProvider,
|
|
42
|
+
SelectionResolution,
|
|
42
43
|
SpriteAtlas2D,
|
|
43
44
|
SpriteAtlasFrame2D,
|
|
44
45
|
SpriteFrames2DDescriptor,
|
|
@@ -50,6 +51,8 @@ export type {
|
|
|
50
51
|
TilemapCell,
|
|
51
52
|
TilemapEditGrid,
|
|
52
53
|
TilemapEditProvider,
|
|
54
|
+
TransformChannel,
|
|
55
|
+
TransformEditability,
|
|
53
56
|
TransformProvider,
|
|
54
57
|
} from './authoring';
|
|
55
58
|
export {
|
|
@@ -26,6 +26,24 @@ import type { IngestOverlay } from './overlay-file';
|
|
|
26
26
|
/** Fixed id for the captured render camera (not a scene child, so no structural path). */
|
|
27
27
|
export const CAMERA_ID = 'ingest:camera';
|
|
28
28
|
|
|
29
|
+
/**
|
|
30
|
+
* The editor parks its OWN objects — grid, its two lights, the particle
|
|
31
|
+
* BatchedRenderer, every TransformControls/gizmo helper — on layer 31
|
|
32
|
+
* (`packages/editor/src/editor-layers.ts`'s `EDITOR_LAYER`) so the game camera
|
|
33
|
+
* never sees them. In ingest mode those objects are added to the GAME'S OWN
|
|
34
|
+
* scene, which is the same tree this walk indexes.
|
|
35
|
+
*/
|
|
36
|
+
const EDITOR_ONLY_LAYER_MASK = 1 << 31;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Editor furniture, not game content. Excluded from the walk entirely — see
|
|
40
|
+
* {@link assignStructuralIds} for why that exclusion is what makes the id
|
|
41
|
+
* scheme's central promise true.
|
|
42
|
+
*/
|
|
43
|
+
function isEditorOnly(o: THREE.Object3D): boolean {
|
|
44
|
+
return (o.layers.mask & EDITOR_ONLY_LAYER_MASK) !== 0;
|
|
45
|
+
}
|
|
46
|
+
|
|
29
47
|
/** The single (non-array) standard-ish material of a mesh, if it has a color. */
|
|
30
48
|
export function colorMaterialOf(o: THREE.Object3D): THREE.MeshStandardMaterial | null {
|
|
31
49
|
const mat = (o as THREE.Mesh).material;
|
|
@@ -49,6 +67,28 @@ export interface StructuralIdWalk {
|
|
|
49
67
|
* (position + type + name) — the prerequisite for overlay reapplication
|
|
50
68
|
* across an independent fresh walk (editor reload, or a shipped build that
|
|
51
69
|
* never ran the editor at all).
|
|
70
|
+
*
|
|
71
|
+
* EDITOR FURNITURE IS EXCLUDED, and that exclusion is load-bearing rather than
|
|
72
|
+
* cosmetic. In ingest mode the editor adds its grid, lights, particle
|
|
73
|
+
* BatchedRenderer and TransformControls gizmo to the GAME'S OWN scene, and
|
|
74
|
+
* they arrive asynchronously — some before the walk, some after. Indexing them
|
|
75
|
+
* made a game object's path depend on how much editor furniture happened to be
|
|
76
|
+
* attached at walk time, which broke the two promises above:
|
|
77
|
+
*
|
|
78
|
+
* • Across a RELOAD, the same mesh changed id. Observed in the games-fps
|
|
79
|
+
* overlay-persistence e2e: an object saved as `ingest:106/0/0/0:…` came
|
|
80
|
+
* back as `ingest:102/0:Mesh:Cube004` — four root slots earlier, exactly
|
|
81
|
+
* the grid + two editor lights + BatchedRenderer — so the persisted
|
|
82
|
+
* override landed on nothing and was reported as an orphan.
|
|
83
|
+
* • A SHIPPED build (no editor, so no furniture at all) minted a different
|
|
84
|
+
* id set than the editor that authored the overlay — i.e. the ship path
|
|
85
|
+
* this module exists to serve could not reliably consume its own output.
|
|
86
|
+
*
|
|
87
|
+
* Skipping the furniture entirely — not merely declining to give it an id —
|
|
88
|
+
* is what fixes both: the game's own children occupy 0..N-1 whatever else is
|
|
89
|
+
* parented alongside them. It also keeps gizmo handles and the grid out of the
|
|
90
|
+
* hierarchy/inspector projections built on this walk, where they were
|
|
91
|
+
* selectable and colorable as if they were game content.
|
|
52
92
|
*/
|
|
53
93
|
export function assignStructuralIds(
|
|
54
94
|
scene: THREE.Object3D,
|
|
@@ -68,13 +108,17 @@ export function assignStructuralIds(
|
|
|
68
108
|
count++;
|
|
69
109
|
if (o.isLight) lights++;
|
|
70
110
|
else if (o.isMesh) meshes++;
|
|
71
|
-
o
|
|
72
|
-
|
|
73
|
-
|
|
111
|
+
visitChildren(o, path);
|
|
112
|
+
};
|
|
113
|
+
const visitChildren = (o: THREE.Object3D, path: string): void => {
|
|
114
|
+
let i = 0;
|
|
115
|
+
for (const c of o.children) {
|
|
116
|
+
if (isEditorOnly(c)) continue;
|
|
117
|
+
visit(c, path ? `${path}/${i}` : `${i}`);
|
|
118
|
+
i++;
|
|
119
|
+
}
|
|
74
120
|
};
|
|
75
|
-
scene
|
|
76
|
-
visit(c, `${i}`);
|
|
77
|
-
});
|
|
121
|
+
visitChildren(scene, '');
|
|
78
122
|
if (camera) {
|
|
79
123
|
setUserData(camera, 'entityId', CAMERA_ID);
|
|
80
124
|
byId.set(CAMERA_ID, camera);
|
|
@@ -59,6 +59,32 @@ export interface CapturedRuntime {
|
|
|
59
59
|
renderer: THREE.WebGLRenderer;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
/** Options for {@link installSceneCapture}. */
|
|
63
|
+
export interface SceneCaptureOptions {
|
|
64
|
+
/**
|
|
65
|
+
* True when `renderer` is one the HOST constructed for its own drawing.
|
|
66
|
+
*
|
|
67
|
+
* The trap lives on the shared `WebGLRenderer.prototype` — that sharing is
|
|
68
|
+
* the whole mechanism — so the host's renders arrive here too, and the trap
|
|
69
|
+
* captures the first scene it sees. Any host renderer built after the trap
|
|
70
|
+
* installs (the editor bakes model thumbnails and asset previews on demand,
|
|
71
|
+
* each with its own offscreen renderer and its own little light rig) is a
|
|
72
|
+
* candidate to be captured AS THE GAME.
|
|
73
|
+
*
|
|
74
|
+
* That is what made `cov-mismatched-three` — the spec for "a game bundling
|
|
75
|
+
* its own three is DETECTED and degrades to embed-only, never silently" —
|
|
76
|
+
* pass or fail on timing alone: whether a thumbnail happened to bake inside
|
|
77
|
+
* the game's 2.5s capture window. When it did, the editor adopted its own
|
|
78
|
+
* preview scene as the game and `captureFailed` never fired.
|
|
79
|
+
*
|
|
80
|
+
* Identity, not shape, is the discriminator: a host renderer and a game
|
|
81
|
+
* renderer are the same class, both built after install, both drawing real
|
|
82
|
+
* scenes. The host is the only party that knows which is which, so it says
|
|
83
|
+
* so (`packages/editor/src/host-renderers.ts`).
|
|
84
|
+
*/
|
|
85
|
+
isHostRenderer?: (renderer: unknown) => boolean;
|
|
86
|
+
}
|
|
87
|
+
|
|
62
88
|
/** Handle returned by {@link installSceneCapture}. */
|
|
63
89
|
export interface SceneCaptureHandle {
|
|
64
90
|
/** The captured runtime, or null until the game renders its first frame. */
|
|
@@ -120,6 +146,7 @@ interface EffectComposerCtorLike {
|
|
|
120
146
|
export function installSceneCapture(
|
|
121
147
|
threeNamespace: unknown,
|
|
122
148
|
effectComposerCtor?: unknown,
|
|
149
|
+
opts?: SceneCaptureOptions,
|
|
123
150
|
): SceneCaptureHandle {
|
|
124
151
|
const THREE_NS = threeNamespace as ThreeLike;
|
|
125
152
|
const proto = THREE_NS.WebGLRenderer.prototype;
|
|
@@ -173,8 +200,30 @@ export function installSceneCapture(
|
|
|
173
200
|
const self = this;
|
|
174
201
|
return function render(this: unknown, ...args: unknown[]) {
|
|
175
202
|
const [scene, camera] = args;
|
|
176
|
-
|
|
177
|
-
|
|
203
|
+
// Attribute the draw to the GAME, not to whoever shares this prototype.
|
|
204
|
+
// The trap patches `WebGLRenderer.prototype.render` on the editor's own
|
|
205
|
+
// three, so the EDITOR viewport's renders land here too. Counting them
|
|
206
|
+
// made `getDrawCount()` climb while the ingested game was paused, which
|
|
207
|
+
// is what the pause assertions in `14-ingest-feature-matrix` were
|
|
208
|
+
// measuring — the loop gate was doing its job (both games use
|
|
209
|
+
// `setAnimationLoop`, so they ARE gateable) and the instrument was
|
|
210
|
+
// reporting someone else's frames. Before capture every render still
|
|
211
|
+
// counts: that is how the first game frame is detected at all.
|
|
212
|
+
if (!captured || (self as unknown) === captured.renderer) drawCount++;
|
|
213
|
+
// Never capture a scene the HOST owns. The trap sits on the shared
|
|
214
|
+
// `WebGLRenderer.prototype`, so the editor's own viewport renders
|
|
215
|
+
// arrive here too — and when a game bundles its own MISMATCHED three
|
|
216
|
+
// (the case this whole degrade-to-embed-only path exists for), the
|
|
217
|
+
// editor's scene is then the only thing that ever reaches the trap.
|
|
218
|
+
// It was duly "captured" as the game: the editor got a hierarchy of
|
|
219
|
+
// its own GridHelper, BatchedRenderer and viewport lights presented as
|
|
220
|
+
// the ingested game's content, and `captureFailed` — the signal the
|
|
221
|
+
// whole graceful-degradation contract is built on — never fired.
|
|
222
|
+
// Whether that happened at all came down to whether the editor
|
|
223
|
+
// rendered a frame inside the game's capture window, so the same
|
|
224
|
+
// session could pass or fail on timing alone.
|
|
225
|
+
const isHostRender = opts?.isHostRenderer?.(self) === true;
|
|
226
|
+
if (!captured && !isHostRender && scene && (scene as { isScene?: boolean }).isScene) {
|
|
178
227
|
captured = {
|
|
179
228
|
scene: scene as THREE.Scene,
|
|
180
229
|
camera: camera as THREE.Camera,
|
|
@@ -668,6 +668,30 @@ export class VgaiSceneGameAdapter implements GameAdapter {
|
|
|
668
668
|
};
|
|
669
669
|
}
|
|
670
670
|
|
|
671
|
+
// Warm the GPU program cache before the first visible frame. A mount gets
|
|
672
|
+
// a fresh WebGL context, so without this every scene material compiles
|
|
673
|
+
// lazily INSIDE the first draw calls — measured as ~0.5s of main-thread
|
|
674
|
+
// driver stalls on every editor play press. Gated on
|
|
675
|
+
// KHR_parallel_shader_compile: with the extension, compileAsync overlaps
|
|
676
|
+
// the compiles with the play transition; WITHOUT it (software
|
|
677
|
+
// rasterizers — SwiftShader in CI) compileAsync degenerates into one big
|
|
678
|
+
// synchronous compile that delays mount by whole seconds, strictly worse
|
|
679
|
+
// than the lazy first-draw path it was replacing. Best-effort: lazy
|
|
680
|
+
// compilation stays correct if it throws, and test hosts pass renderer
|
|
681
|
+
// stubs without these methods.
|
|
682
|
+
const glContext = typeof renderer.getContext === 'function' ? renderer.getContext() : undefined;
|
|
683
|
+
const parallelCompile =
|
|
684
|
+
!!glContext &&
|
|
685
|
+
typeof glContext.getExtension === 'function' &&
|
|
686
|
+
!!glContext.getExtension('KHR_parallel_shader_compile');
|
|
687
|
+
if (!headless && parallelCompile && typeof renderer.compileAsync === 'function') {
|
|
688
|
+
try {
|
|
689
|
+
await renderer.compileAsync(scene, camera);
|
|
690
|
+
} catch {
|
|
691
|
+
// Fall back to lazy compilation.
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
|
|
671
695
|
// Idempotency guard for disposeGame — see below. Declared here (not inside
|
|
672
696
|
// disposeGame) so hotReload can also refuse to run on an already-disposed
|
|
673
697
|
// adapter.
|
package/src/manifest/schema.ts
CHANGED
|
@@ -346,13 +346,17 @@ export const LearnMetadataSchema = z
|
|
|
346
346
|
.string()
|
|
347
347
|
.optional()
|
|
348
348
|
.describe(
|
|
349
|
-
'Optional thumbnail image reference
|
|
350
|
-
'
|
|
349
|
+
'Optional thumbnail image reference, PROJECT-relative (canonical path: ' +
|
|
350
|
+
'learn/thumbnail.png — the §3 schema path). Generated per FT-11 by the deterministic ' +
|
|
351
|
+
'render tooling (scripts/generate-learn-thumbnails.ts), never hand-made',
|
|
351
352
|
),
|
|
352
353
|
preview: z
|
|
353
354
|
.string()
|
|
354
355
|
.optional()
|
|
355
|
-
.describe(
|
|
356
|
+
.describe(
|
|
357
|
+
'Optional short preview video/loop reference, PROJECT-relative (canonical path: ' +
|
|
358
|
+
'learn/preview.mp4; generated per FT-11)',
|
|
359
|
+
),
|
|
356
360
|
lesson: z
|
|
357
361
|
.string()
|
|
358
362
|
.optional()
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
type WorldInstance,
|
|
26
26
|
} from './game';
|
|
27
27
|
import { createInputRouter, type RouterAdapterRoot, stackOrder } from './input-router';
|
|
28
|
+
import { installRenderControlHarness, isRenderModeRequested } from './render-control';
|
|
28
29
|
|
|
29
30
|
// Re-export the camera-precedence helper from its new home so existing importers
|
|
30
31
|
// (`import { adoptSceneCamera } from '@engine/runtime/create-runtime'`) keep working.
|
|
@@ -393,6 +394,23 @@ export interface WorldsRuntimeConfig {
|
|
|
393
394
|
* (a test, a bespoke host) may also set it directly. Omitting it falls
|
|
394
395
|
* back to `createGame`'s own fixed default. */
|
|
395
396
|
seed?: number | undefined;
|
|
397
|
+
/**
|
|
398
|
+
* G3/FT-11 (docs/FTUE-LEARN-SYSTEM-DESIGN.md §8 G3) — test-only overrides
|
|
399
|
+
* for the render-control seam this host now wires up for EVERY session
|
|
400
|
+
* (see `createWorldsGameRuntime`): `location` is where `?vgai-render=1`
|
|
401
|
+
* is read from (defaults to the real `window.location`; a Node test has
|
|
402
|
+
* no `window` and must inject one to exercise the seam), `target` is
|
|
403
|
+
* where the harness publishes (defaults to the real `window` — override
|
|
404
|
+
* in a unit test to avoid touching the global object; mirrors
|
|
405
|
+
* `RenderControlHarnessOptions.target`/`.location` and the
|
|
406
|
+
* `debugBridge.url` override precedent in `mount-manifest.ts`).
|
|
407
|
+
*/
|
|
408
|
+
renderControl?:
|
|
409
|
+
| {
|
|
410
|
+
readonly location?: { readonly search: string } | undefined;
|
|
411
|
+
readonly target?: Record<string, unknown> | undefined;
|
|
412
|
+
}
|
|
413
|
+
| undefined;
|
|
396
414
|
}
|
|
397
415
|
|
|
398
416
|
/**
|
|
@@ -818,6 +836,57 @@ async function mountAllWorldSpecs(
|
|
|
818
836
|
return { mountedEntries, routerEntries };
|
|
819
837
|
}
|
|
820
838
|
|
|
839
|
+
/**
|
|
840
|
+
* G3/FT-11 — publish the render-control harness (`render-control.ts`) for a
|
|
841
|
+
* live session, returning its retraction (wired into the session's own
|
|
842
|
+
* `stop()`, same leave-nothing-live rule as the debug bridge's `uninstall()`
|
|
843
|
+
* in mount-manifest.ts — render-control has no uninstall surface of its own,
|
|
844
|
+
* a render page being a single-load host by design, so the retraction is
|
|
845
|
+
* the publication's inverse). Split out of `createWorldsGameRuntime` purely
|
|
846
|
+
* to keep that function's cyclomatic complexity down (the same reason
|
|
847
|
+
* `mountAllWorldSpecs`/`installDefaultWorldDevGlobals` are split out).
|
|
848
|
+
*
|
|
849
|
+
* The clock is a documented no-op: a manifest-mounted game has no global
|
|
850
|
+
* cinematic AnimationClock to seek (a cinematic fixture that HAS one
|
|
851
|
+
* installs its own harness with the real clock, e.g.
|
|
852
|
+
* packages/engine/e2e/render-cinematic/main.ts) — the meaningful advance
|
|
853
|
+
* path for a plain game is `simulateSubsteps` (I5 `--simulate`), which
|
|
854
|
+
* drives `game.runFrame`.
|
|
855
|
+
*/
|
|
856
|
+
function installSessionRenderHarness(
|
|
857
|
+
game: GameInternal,
|
|
858
|
+
location: { readonly search: string },
|
|
859
|
+
targetOverride: Record<string, unknown> | undefined,
|
|
860
|
+
): (() => void) | undefined {
|
|
861
|
+
const target =
|
|
862
|
+
targetOverride ??
|
|
863
|
+
(typeof window !== 'undefined' ? (window as unknown as Record<string, unknown>) : undefined);
|
|
864
|
+
if (target === undefined) return undefined;
|
|
865
|
+
installRenderControlHarness({
|
|
866
|
+
game,
|
|
867
|
+
clock: {
|
|
868
|
+
seek() {
|
|
869
|
+
/* no global cinematic clock on a manifest-mounted game — see above */
|
|
870
|
+
},
|
|
871
|
+
seekFrame() {
|
|
872
|
+
/* intentional no-op, as seek() */
|
|
873
|
+
},
|
|
874
|
+
},
|
|
875
|
+
readiness: {
|
|
876
|
+
// Mount is complete by the time this harness exists (the install site
|
|
877
|
+
// in `createWorldsGameRuntime` is after `mountAllWorldSpecs`
|
|
878
|
+
// resolved) — the hook resolving immediately IS the readiness
|
|
879
|
+
// statement, not an assumption.
|
|
880
|
+
scene() {},
|
|
881
|
+
},
|
|
882
|
+
location,
|
|
883
|
+
target,
|
|
884
|
+
});
|
|
885
|
+
return () => {
|
|
886
|
+
delete target['__vgaiRender'];
|
|
887
|
+
};
|
|
888
|
+
}
|
|
889
|
+
|
|
821
890
|
async function createWorldsGameRuntime(config: WorldsRuntimeConfig): Promise<GameSession> {
|
|
822
891
|
const { container, roots: specs, width, height, headless = false, seed } = config;
|
|
823
892
|
if (specs.length === 0) {
|
|
@@ -896,10 +965,27 @@ async function createWorldsGameRuntime(config: WorldsRuntimeConfig): Promise<Gam
|
|
|
896
965
|
return () => extraUpdaters.delete(fn);
|
|
897
966
|
},
|
|
898
967
|
};
|
|
968
|
+
// G3/FT-11 (docs/FTUE-LEARN-SYSTEM-DESIGN.md §8 G3): every manifest/host-
|
|
969
|
+
// mounted game is a deterministic-capture candidate — the render-control
|
|
970
|
+
// seam (`?vgai-render=1`, render-control.ts) is wired HERE, at the one
|
|
971
|
+
// host every boot path shares (mountGameFromManifest, mountManifestWorlds,
|
|
972
|
+
// and direct createGameRuntime callers all reach this function), instead
|
|
973
|
+
// of asking every project's entry page to install it the way the e2e
|
|
974
|
+
// fixtures do. Production-protected twice over: `isRenderModeRequested`
|
|
975
|
+
// gates on the query param, and `installRenderControlHarness` re-checks it
|
|
976
|
+
// internally (its AC 4), so a normal gameplay page sees zero change.
|
|
977
|
+
const renderModeLocation =
|
|
978
|
+
config.renderControl?.location ?? (typeof window !== 'undefined' ? window.location : undefined);
|
|
979
|
+
const renderMode = renderModeLocation !== undefined && isRenderModeRequested(renderModeLocation);
|
|
899
980
|
let started = false;
|
|
900
981
|
const loop = createGameLoop({
|
|
901
982
|
fixedTimestep: 1 / 60,
|
|
902
983
|
maxSubSteps: 8,
|
|
984
|
+
// Render mode runs the loop in EXTERNAL-DRIVE mode (game-loop.ts, I2):
|
|
985
|
+
// no RAF is ever armed, so nothing advances gameplay between the capture
|
|
986
|
+
// host's explicit `simulateSubsteps`/`renderOnce` calls — wall-clock time
|
|
987
|
+
// passing while a screenshot is taken must not move the world.
|
|
988
|
+
externalDrive: renderMode,
|
|
903
989
|
update: (dt) => {
|
|
904
990
|
if (started) game.runFrame(dt);
|
|
905
991
|
for (const fn of extraUpdaters) fn(dt);
|
|
@@ -942,6 +1028,16 @@ async function createWorldsGameRuntime(config: WorldsRuntimeConfig): Promise<Gam
|
|
|
942
1028
|
// purely to keep this function's own cyclomatic complexity down.
|
|
943
1029
|
const retractDevGlobals = installDefaultWorldDevGlobals(game);
|
|
944
1030
|
|
|
1031
|
+
// G3/FT-11 — publish `window.__vgaiRender` for the deterministic capture
|
|
1032
|
+
// host. Installed at the TAIL of the mount (same position as
|
|
1033
|
+
// mount-manifest.ts's debug bridge): every world's `mount()`/`setup()` has
|
|
1034
|
+
// resolved by now, so the harness's `scene` readiness hook reporting ready
|
|
1035
|
+
// is truthful. See `installSessionRenderHarness` below.
|
|
1036
|
+
const retractRenderHarness =
|
|
1037
|
+
renderMode && renderModeLocation !== undefined
|
|
1038
|
+
? installSessionRenderHarness(game, renderModeLocation, config.renderControl?.target)
|
|
1039
|
+
: undefined;
|
|
1040
|
+
|
|
945
1041
|
function fullCleanup(): void {
|
|
946
1042
|
loop.stop();
|
|
947
1043
|
router.dispose();
|
|
@@ -964,6 +1060,7 @@ async function createWorldsGameRuntime(config: WorldsRuntimeConfig): Promise<Gam
|
|
|
964
1060
|
}
|
|
965
1061
|
game.dispose();
|
|
966
1062
|
retractDevGlobals();
|
|
1063
|
+
retractRenderHarness?.();
|
|
967
1064
|
}
|
|
968
1065
|
|
|
969
1066
|
return {
|
package/src/runtime/game.ts
CHANGED
|
@@ -1262,7 +1262,17 @@ export function createGame(opts: {
|
|
|
1262
1262
|
// "no state bridge" warning at registration (probe: every real react
|
|
1263
1263
|
// world mount), eroding the signal for a genuinely un-observable
|
|
1264
1264
|
// ingested world.
|
|
1265
|
-
|
|
1265
|
+
// A mount exposing the engine's real ComponentManager (notably the R3F
|
|
1266
|
+
// first-party adapter) is observable through Game.queryByComponent +
|
|
1267
|
+
// Game.state even though it does not carry the classic scene adapter's
|
|
1268
|
+
// `firstParty` brand. Requiring a foreign-world `observe` bridge there
|
|
1269
|
+
// produces a false warning while the canonical bridge is already live.
|
|
1270
|
+
if (
|
|
1271
|
+
!isFirstPartyMounted(world.mounted) &&
|
|
1272
|
+
!world.mounted.components &&
|
|
1273
|
+
world.kind !== 'react' &&
|
|
1274
|
+
!world.mounted.observe
|
|
1275
|
+
) {
|
|
1266
1276
|
console.warn(
|
|
1267
1277
|
`[game] world "${world.id}" (kind: ${world.kind}, adapter: "${world.adapter.id}"): ` +
|
|
1268
1278
|
'no state bridge — this mounted game has no `observe` (WorldStateObserver); ' +
|
|
@@ -189,7 +189,7 @@ function formatIssues(issues: { path: PropertyKey[]; message: string }[]): strin
|
|
|
189
189
|
* structured errors (empty = every new reference resolved and validated) —
|
|
190
190
|
* never throws; callers decide how to present/escalate a non-empty result
|
|
191
191
|
* (the CLI folds these into one `ApplyDiffCliError` message, the SDK raises
|
|
192
|
-
* a declared `ASSET_REF_INVALID` `
|
|
192
|
+
* a declared `ASSET_REF_INVALID` `ToolError`).
|
|
193
193
|
*/
|
|
194
194
|
export function dereferenceNewAssetRefs(
|
|
195
195
|
inputScene: SceneFile,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type RAPIER from '@dimforge/rapier3d-compat';
|
|
2
2
|
import * as THREE from 'three';
|
|
3
|
-
import {
|
|
3
|
+
import { HDRLoader } from 'three/addons/loaders/HDRLoader.js';
|
|
4
4
|
import type { BatchedRenderer } from 'three.quarks';
|
|
5
5
|
import { initNavigation, NavMeshManager } from '../ai/navigation';
|
|
6
6
|
import { buildClipMap } from '../animation/clip-map';
|
|
@@ -148,7 +148,7 @@ async function loadEnvTexture(
|
|
|
148
148
|
const ext = path.split('.').pop()?.toLowerCase();
|
|
149
149
|
const rawTexture =
|
|
150
150
|
ext === 'hdr'
|
|
151
|
-
? await new
|
|
151
|
+
? await new HDRLoader(loadingManager).loadAsync(resolveUrl(path))
|
|
152
152
|
: await new THREE.TextureLoader(loadingManager).loadAsync(resolveUrl(path));
|
|
153
153
|
rawTexture.mapping = THREE.EquirectangularReflectionMapping;
|
|
154
154
|
const envMap = pmremGenerator.fromEquirectangular(rawTexture).texture;
|
package/src/scene/user-data.ts
CHANGED
|
@@ -73,6 +73,16 @@
|
|
|
73
73
|
* surfaced in the play-mode hierarchy with a *synthetic*
|
|
74
74
|
* descriptor (it has no `.vscn` record). Marks it as
|
|
75
75
|
* ephemeral: selectable/movable for testing, never saved.
|
|
76
|
+
* - `authoringRoot` — explicit opt-in for a runtime descendant to become
|
|
77
|
+
* its own authoring object instead of a part of the
|
|
78
|
+
* nearest ancestor owner.
|
|
79
|
+
* - `authoringInstance` — source OID of the custom-component callsite that
|
|
80
|
+
* rendered this existing Object3D. Used to group
|
|
81
|
+
* implementation parts without adding wrappers.
|
|
82
|
+
* - `authoringLabel` — authored literal name (or component tag fallback)
|
|
83
|
+
* for that source-backed component instance.
|
|
84
|
+
* - `behaviorType` — registry key on the compatibility R3F Behavior
|
|
85
|
+
* attachment group; authoring projects it as a component.
|
|
76
86
|
* - `editorHelper` — `true` for editor-only helper objects (gizmos, wireframes).
|
|
77
87
|
* - `editorHelperType` — which kind of helper (lights/particles/pivot/navmesh/...).
|
|
78
88
|
* - `editorIcon` — `true` for editor billboard icon sprites.
|
|
@@ -145,6 +155,10 @@ export interface UserDataSchema {
|
|
|
145
155
|
__ingestNextId: number;
|
|
146
156
|
engineInternal: boolean;
|
|
147
157
|
liveObject: boolean;
|
|
158
|
+
authoringRoot: boolean;
|
|
159
|
+
authoringInstance: string;
|
|
160
|
+
authoringLabel: string;
|
|
161
|
+
behaviorType: string;
|
|
148
162
|
editorHelper: boolean;
|
|
149
163
|
editorHelperType: EditorHelperType;
|
|
150
164
|
editorIcon: boolean;
|
|
@@ -190,6 +204,10 @@ export const UserDataKeys = {
|
|
|
190
204
|
__ingestNextId: '__ingestNextId',
|
|
191
205
|
engineInternal: 'engineInternal',
|
|
192
206
|
liveObject: 'liveObject',
|
|
207
|
+
authoringRoot: 'authoringRoot',
|
|
208
|
+
authoringInstance: 'authoringInstance',
|
|
209
|
+
authoringLabel: 'authoringLabel',
|
|
210
|
+
behaviorType: 'behaviorType',
|
|
193
211
|
editorHelper: 'editorHelper',
|
|
194
212
|
editorHelperType: 'editorHelperType',
|
|
195
213
|
editorIcon: 'editorIcon',
|
|
@@ -22,12 +22,11 @@
|
|
|
22
22
|
* byte-identical to an un-wrapped mesh. `cloneElement` would have to
|
|
23
23
|
* merge a ref without clobbering an authored one — fragile across
|
|
24
24
|
* forwardRef/ref-as-prop shapes — and adds nothing the group doesn't.
|
|
25
|
-
* - The wrapper
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* the
|
|
30
|
-
* other JSX prop.
|
|
25
|
+
* - The wrapper carries the `<Behavior>` call site's `userData-oid` stamp so
|
|
26
|
+
* its config stays source-addressable. It is an INTERNAL attachment node,
|
|
27
|
+
* not an independent spatial authoring object: the R3F authoring adapter
|
|
28
|
+
* projects this config onto the wrapped object's Inspector and promotes
|
|
29
|
+
* the child through the hierarchy.
|
|
31
30
|
* - Transform semantics: the group stays at identity, so the child's
|
|
32
31
|
* authored `position`/`rotation`/`scale` are unchanged by wrapping.
|
|
33
32
|
*
|
|
@@ -43,7 +42,7 @@
|
|
|
43
42
|
// their fiber import — project entry files importing this module keep their
|
|
44
43
|
// own `@react-three/fiber` import for the scene itself.
|
|
45
44
|
import type { ThreeElements } from '@react-three/fiber';
|
|
46
|
-
import { createElement, useContext, useEffect, useRef } from 'react';
|
|
45
|
+
import { createElement, useContext, useEffect, useLayoutEffect, useRef } from 'react';
|
|
47
46
|
import type { Group } from 'three';
|
|
48
47
|
import type { GameComponent } from '../ecs/game-component';
|
|
49
48
|
import { type BehaviorRegistry, EngineBridge, resolveBehaviorClass } from './engine-bridge';
|
|
@@ -70,7 +69,11 @@ export function Behavior<Reg extends BehaviorRegistry = BehaviorRegistry>(
|
|
|
70
69
|
// The live instance the config-reapply effect targets (never re-attach).
|
|
71
70
|
const liveRef = useRef<GameComponent | null>(null);
|
|
72
71
|
|
|
73
|
-
|
|
72
|
+
// Attachment is part of the committed world, not deferred follow-up work.
|
|
73
|
+
// A layout effect runs before `createR3FAdapter.mount()` resolves its first
|
|
74
|
+
// committed tree, so deterministic hosts can begin stepping immediately
|
|
75
|
+
// without losing every warm-up tick to an unflushed passive effect.
|
|
76
|
+
useLayoutEffect(() => {
|
|
74
77
|
if (!bridge?.registry) {
|
|
75
78
|
// Loud degrade, never a crash: a mount without the adapter's bridge
|
|
76
79
|
// (e.g. a foreign harness rendering this tree directly) — or a bridge
|
|
@@ -123,13 +126,18 @@ export function Behavior<Reg extends BehaviorRegistry = BehaviorRegistry>(
|
|
|
123
126
|
// OID stamper rewrites JSX syntax only, so a JSX `<group>` here would get
|
|
124
127
|
// behavior.tsx's OWN stamp AND the forwarded call-site oid (a duplicate
|
|
125
128
|
// `userData-oid` attribute). The wrapper group must carry exactly ONE
|
|
126
|
-
// identity — the `<Behavior>` CALL SITE's oid — so the editor
|
|
127
|
-
//
|
|
129
|
+
// identity — the `<Behavior>` CALL SITE's oid — so the editor can edit the
|
|
130
|
+
// config while projecting the wrapper as a component of its child.
|
|
128
131
|
return createElement(
|
|
129
132
|
'group',
|
|
130
133
|
{
|
|
131
134
|
ref: groupRef,
|
|
132
|
-
|
|
135
|
+
// `Behavior: ` WITH the space: the editor's R3F adapter labels this node
|
|
136
|
+
// `Behavior: ${behaviorType}` when it projects it as an entity, but falls
|
|
137
|
+
// back to this `name` when the same node is projected as a component
|
|
138
|
+
// boundary. Without the space the hierarchy showed one of two different
|
|
139
|
+
// labels for the identical concept depending on which branch ran.
|
|
140
|
+
name: `Behavior: ${type}`,
|
|
133
141
|
'userData-oid': oid,
|
|
134
142
|
'userData-behaviorType': type,
|
|
135
143
|
},
|