@volter/editor-game 0.5.66 → 0.5.67

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.
Files changed (236) hide show
  1. package/contributions/audio-unlock.service.ts +2 -2
  2. package/contributions/autoplay.service.ts +1 -1
  3. package/contributions/bridge.command.ts +3 -3
  4. package/contributions/canvas/component-board.service.ts +16 -0
  5. package/contributions/canvas/design-time-mount.service.ts +45 -0
  6. package/contributions/canvas-story-capture.service.ts +12 -0
  7. package/contributions/edit-mode-audio.service.ts +2 -2
  8. package/contributions/edit-mode-networking.service.ts +1 -1
  9. package/contributions/gameplay.command.ts +4 -4
  10. package/contributions/generation.service.ts +1 -1
  11. package/contributions/godot.style.ts +26 -6
  12. package/contributions/godot.view.ts +6 -0
  13. package/contributions/ingest.service.ts +2 -2
  14. package/contributions/instances.command.ts +1 -1
  15. package/contributions/navmesh.menu.ts +1 -1
  16. package/contributions/network-observer.service.ts +14 -0
  17. package/contributions/play.command.ts +10 -4
  18. package/contributions/react/component-board.service.ts +1 -1
  19. package/contributions/react/design-time-mount.service.ts +1 -1
  20. package/contributions/scene-document.service.ts +3 -3
  21. package/contributions/state-watch.menu.ts +1 -1
  22. package/contributions/state-watch.utility.tsx +1 -1
  23. package/contributions/team-playtest.service.ts +4 -4
  24. package/contributions/three/component-board.service.ts +1 -1
  25. package/contributions/three/component-verbs.command.ts +6 -6
  26. package/contributions/three/three-authoring.service.ts +8 -5
  27. package/contributions/three-story-capture.service.ts +12 -0
  28. package/contributions/unity.style.ts +17 -7
  29. package/contributions/unity.view.ts +6 -0
  30. package/contributions/unreal.style.ts +10 -2
  31. package/contributions/unreal.view.ts +5 -0
  32. package/package.json +20 -10
  33. package/src/asset-budget/AssetBudgetPanel.tsx +1 -1
  34. package/src/asset-budget/asset-budget-model.ts +1 -1
  35. package/src/audio/AudioDebuggerPanel.tsx +1 -1
  36. package/src/bridge/dispatch.ts +14 -14
  37. package/src/bridge/live-frames.ts +1 -1
  38. package/src/bridge/screenshot.ts +3 -3
  39. package/src/build/BuildProfilesPanel.tsx +3 -3
  40. package/src/canvas/canvas-board/CanvasBoardDocument.tsx +676 -0
  41. package/src/canvas/canvas-board/canvas-board-model.ts +407 -0
  42. package/src/canvas/canvas-board/canvas-component-board.ts +56 -0
  43. package/src/canvas/canvas-design-mount.ts +524 -0
  44. package/src/canvas/design-time-canvas-mount.ts +79 -0
  45. package/src/coverage/live-authoring-surface.ts +5 -5
  46. package/src/coverage/live-project-verbs.ts +1 -1
  47. package/src/coverage/native-system-coverage.ts +5 -5
  48. package/src/coverage/root-coverage.ts +1 -1
  49. package/src/coverage/session-coverage.ts +3 -3
  50. package/src/design-system-stories/ApplicationChrome.stories.tsx +5 -5
  51. package/src/design-system-stories/InspectorNarrowBodies.stories.tsx +7 -7
  52. package/src/edit-mode/edit-mode-audio.ts +4 -4
  53. package/src/edit-mode/edit-mode-networking.ts +2 -2
  54. package/src/game-document/GameCaptureFrameButton.tsx +1 -1
  55. package/src/game-document/GameDocument.tsx +2 -2
  56. package/src/game-document/GamePanel.tsx +4 -4
  57. package/src/game-document/InstanceInspectorPicker.tsx +2 -2
  58. package/src/game-document/crowd-debug.ts +1 -1
  59. package/src/game-document/device-preview.ts +10 -11
  60. package/src/game-document/physics-debug.ts +1 -1
  61. package/src/generation/GenerationActivity.tsx +3 -3
  62. package/src/generation/generation-documents.tsx +5 -5
  63. package/src/generation/generation-jobs.ts +1 -1
  64. package/src/host/adapter-runtime-bindings.ts +96 -5
  65. package/src/host/authoring/babylon-authoring-adapter.ts +6 -6
  66. package/src/host/authoring/gesture-persist.ts +1 -1
  67. package/src/host/authoring/ingest-data-writer.ts +1 -1
  68. package/src/host/authoring/ingest-source-persistence.ts +4 -4
  69. package/src/host/authoring/mounted-authoring.ts +4 -4
  70. package/src/host/authoring/phaser-live-authoring-adapter.ts +4 -4
  71. package/src/host/authoring/pixi-authoring-adapter.ts +40 -15
  72. package/src/host/authoring/pixi-creation-site-write-target.ts +2 -2
  73. package/src/host/authoring/pixi-live-write-target.ts +4 -4
  74. package/src/host/authoring/pixi-source-identity.ts +3 -3
  75. package/src/host/authoring/pixi-source-write-target.ts +1614 -0
  76. package/src/host/authoring/pixi-still-presentation.ts +1 -1
  77. package/src/host/authoring/pixi-structure-history.ts +2 -2
  78. package/src/host/authoring/pixi-transform-channels.ts +16 -14
  79. package/src/host/authoring/source-persistence-backend.ts +3 -3
  80. package/src/host/authoring/struct-write-pipe.ts +1 -1
  81. package/src/host/binding-resolver.ts +8 -9
  82. package/src/host/browser-transpile.ts +1 -1
  83. package/src/host/canvas-entry-runtime.ts +58 -47
  84. package/src/host/canvas-preview-frames.ts +482 -0
  85. package/src/host/components/CameraAuthoringOverlay.tsx +1 -1
  86. package/src/host/components/HeaderTelemetry.tsx +4 -4
  87. package/src/host/components/PixiIsolationSceneContent.tsx +10 -10
  88. package/src/host/components/ThreeIsolationSceneContent.tsx +3 -3
  89. package/src/host/components/frame-debugger-model.ts +2 -2
  90. package/src/host/components/header-telemetry-model.ts +2 -2
  91. package/src/host/components/scene-document.tsx +14 -14
  92. package/src/host/components/utility-view-state.ts +1 -1
  93. package/src/host/components/world-root-stage-binding.tsx +12 -12
  94. package/src/host/components/world-root-stage.ts +70 -49
  95. package/src/host/coverage/system-adapter-coverage.ts +3 -4
  96. package/src/host/design-system-stories/fixtures/editor-runtime.tsx +9 -11
  97. package/src/host/document-preview-three.ts +1 -1
  98. package/src/host/entry-adjudication.ts +6 -6
  99. package/src/host/game-css-scope-transform.ts +4 -0
  100. package/src/host/game-realm-page.ts +1 -1
  101. package/src/host/gameplay-export.ts +25 -14
  102. package/src/host/gameplay-recording.ts +5 -5
  103. package/src/host/gated-globals.ts +2 -2
  104. package/src/host/history/json-history-resource.ts +1 -1
  105. package/src/host/projection/pixi.ts +24 -2
  106. package/src/host/r3f-entry-runtime.ts +65 -34
  107. package/src/host/react-mount-runtime.ts +7 -48
  108. package/src/host/realm-services.ts +1 -1
  109. package/src/host/roots/canvas-root.tsx +361 -0
  110. package/src/host/roots/r3f-root.tsx +473 -0
  111. package/src/host/roots/react-root.ts +9 -43
  112. package/src/host/served-bundle-runtime-modules.ts +1 -19
  113. package/src/host/server-log-bridge.ts +2 -2
  114. package/src/host/stories/mounted-story-viewport-source.ts +1 -1
  115. package/src/host/stories/pixi-story-model.ts +30 -0
  116. package/src/host/stories/story-media-captures.ts +46 -0
  117. package/src/host/stories/story-media-presence.ts +3 -3
  118. package/src/host/stories/story-pixi-preview.ts +408 -0
  119. package/src/host/stories/story-three-preview.ts +806 -0
  120. package/src/host/stories/three-story-captures.ts +35 -0
  121. package/src/host/story-three-preview-runtime.ts +56 -0
  122. package/src/host/use-active-performance-source.ts +2 -2
  123. package/src/host/viewport-pose-memory.ts +1 -1
  124. package/src/host/viewport-root-presentation.ts +6 -5
  125. package/src/ingest/active-ingest.ts +1 -1
  126. package/src/ingest/authoring/ingest-dom-surface-authoring.ts +4 -4
  127. package/src/ingest/authoring/ingest-root-adapter.ts +8 -8
  128. package/src/ingest/deferred-ingest-play.ts +6 -6
  129. package/src/ingest/discovery-public-ingest.ts +2 -2
  130. package/src/ingest/ingest-boot-viewport.ts +2 -2
  131. package/src/ingest/ingest-canvas-scene-document.tsx +8 -8
  132. package/src/ingest/ingest-canvas-scene.ts +3 -3
  133. package/src/ingest/ingest-evidence-hook.ts +1 -1
  134. package/src/ingest/ingest-frame-snapshot.ts +1 -1
  135. package/src/ingest/ingest-play-control.ts +1 -1
  136. package/src/ingest/ingest-render-debug.ts +10 -10
  137. package/src/ingest/ingest-siblings.ts +13 -25
  138. package/src/ingest/module-mode.ts +14 -14
  139. package/src/ingest/mount-canvas-ingest-root.ts +21 -21
  140. package/src/ingest/mount-coverage.ts +2 -2
  141. package/src/ingest/mount-dom-ingest-root.ts +11 -11
  142. package/src/ingest/mount-ingest-root.ts +8 -8
  143. package/src/ingest/mount-three-ingest-root.ts +8 -8
  144. package/src/ingest/resolve-canvas.ts +1 -1
  145. package/src/ingest/served-html-boot.ts +1 -1
  146. package/src/ingest/surface-canvas.ts +1 -1
  147. package/src/ingest/unmount-ingest-root.ts +5 -5
  148. package/src/navmesh/navmesh-handler.ts +24 -16
  149. package/src/network/NetworkInspectorPanel.tsx +449 -14
  150. package/src/network/network-inspector-model.ts +14 -2
  151. package/src/play/play-log-events.ts +1 -1
  152. package/src/play/play-mode.ts +76 -133
  153. package/src/play/play-recording.ts +1 -1
  154. package/src/play/react-play-live-authoring.ts +3 -3
  155. package/src/play/run-selection.ts +93 -0
  156. package/src/play-bar/PlayBar.tsx +20 -39
  157. package/src/profiler/FrameDebuggerPanel.tsx +1 -1
  158. package/src/profiler/PerformancePanel.tsx +3 -3
  159. package/src/react/design-time-react-mount.ts +23 -65
  160. package/src/react/dom-authoring-adapter.ts +9 -9
  161. package/src/react/react-inspector-section.tsx +5 -5
  162. package/src/react/react-world-authoring-adapter.ts +11 -11
  163. package/src/react/story-documents/story-documents.tsx +9 -9
  164. package/src/react/ui-board-document.tsx +7 -7
  165. package/src/react/ui-component-board.ts +2 -2
  166. package/src/runtime/adapter/audio-meter.ts +21 -0
  167. package/src/runtime/adapter/first-party-audio-system.ts +230 -0
  168. package/src/runtime/adapter/ingest/contract-debug-adapter.ts +114 -0
  169. package/src/runtime/adapter/ingest/contract-system-adapters.ts +256 -0
  170. package/src/runtime/adapter/ingest/merge-debug-adapters.ts +197 -0
  171. package/src/runtime/adapter/ingest/observation-debug-adapter.ts +162 -0
  172. package/src/runtime/adapter/ingest/upstream-pin.ts +51 -0
  173. package/src/runtime/adapter/native-debug-module.ts +498 -0
  174. package/src/runtime/audio/bus-mixer.ts +161 -0
  175. package/src/runtime/audio/pose-guard.ts +80 -0
  176. package/src/runtime/core/frame-pacing.ts +126 -0
  177. package/src/runtime/core/game-loop.ts +225 -0
  178. package/src/runtime/core/game-scoped-slot.ts +28 -0
  179. package/src/runtime/core/seeded-random.ts +162 -0
  180. package/src/runtime/core/sim-clock.ts +391 -0
  181. package/src/runtime/core/system-runner.ts +269 -0
  182. package/src/runtime/core/types.ts +104 -0
  183. package/src/runtime/create-runtime.ts +1128 -0
  184. package/src/runtime/debug-bridge.ts +570 -0
  185. package/src/runtime/debug-registry.ts +899 -0
  186. package/src/runtime/dev/chrome-trace.ts +153 -0
  187. package/src/runtime/dev/instruments.ts +403 -0
  188. package/src/runtime/dev/logger.ts +119 -0
  189. package/src/runtime/dev/performance-profiler.ts +367 -0
  190. package/src/runtime/dev/register-render-vitals.ts +276 -0
  191. package/src/runtime/dev/render-census.ts +354 -0
  192. package/src/runtime/dev/render-debug-adapter.ts +218 -0
  193. package/src/runtime/dev/render-memory.ts +226 -0
  194. package/src/runtime/dev/render-vitals.ts +338 -0
  195. package/src/runtime/dev/static-batch-advisor.ts +188 -0
  196. package/src/runtime/dev/webgl-frame-capture.ts +366 -0
  197. package/src/runtime/dev/webgl-gpu-timer.ts +53 -0
  198. package/src/runtime/dev-build.ts +47 -0
  199. package/src/runtime/game.ts +1636 -0
  200. package/src/runtime/gameplay-rng-trap.ts +135 -0
  201. package/src/runtime/host-context.ts +64 -0
  202. package/src/runtime/input-router.ts +169 -0
  203. package/src/runtime/mount-manifest.ts +480 -0
  204. package/src/runtime/pixi/authoring.ts +706 -0
  205. package/src/runtime/pixi/ingest.ts +116 -0
  206. package/src/runtime/pixi/physics-registry.ts +49 -0
  207. package/src/runtime/pixi/render-pass-bracket.ts +117 -0
  208. package/src/runtime/pixi/scene-capture.ts +179 -0
  209. package/src/runtime/pixi/system-adapters.ts +69 -0
  210. package/src/runtime/playtest.ts +22 -0
  211. package/src/runtime/presentation.ts +141 -0
  212. package/src/runtime/render-control.ts +642 -0
  213. package/src/runtime/render-seed.ts +77 -0
  214. package/src/runtime/run-ticks-settled.ts +73 -0
  215. package/src/runtime/setup/setup-audio.ts +72 -0
  216. package/src/services/audio-pose-guard.ts +2 -2
  217. package/src/services/game-audio.ts +152 -0
  218. package/src/services/game-network.ts +657 -0
  219. package/src/services/game-physics.ts +334 -0
  220. package/src/state-watch/StateWatchPanel.tsx +1 -1
  221. package/src/three/authoring/camera-runtime-inspector-section.tsx +3 -2
  222. package/src/three/authoring/constraint-inspector-section.tsx +6 -5
  223. package/src/three/authoring/model-asset-inspector-section.tsx +7 -6
  224. package/src/three/authoring/oid-source-persistence.ts +7 -7
  225. package/src/three/authoring/r3f-design-session.ts +58 -54
  226. package/src/three/authoring/r3f-source-authoring-adapter.ts +95 -91
  227. package/src/three/authoring/reflection-probe-inspector-section.tsx +3 -2
  228. package/src/three/authoring/three-authoring-adapter.ts +29 -29
  229. package/src/three/component-verbs/extract-menu.ts +7 -6
  230. package/src/three/component-verbs/fork-menu.ts +7 -6
  231. package/src/three/component-verbs/internals-menu.ts +2 -2
  232. package/src/three/story-documents/three-story-documents.tsx +13 -13
  233. package/src/three/three-board/ThreeBoardDocument.tsx +13 -12
  234. package/src/three/three-board/board-scene.ts +6 -6
  235. package/src/three/three-board/three-component-board.ts +2 -2
  236. package/src/services/game-audio-unlock.ts +0 -48
@@ -61,36 +61,39 @@ import { onAssetReload } from '@volter/editor-sdk/kit/project-asset-refresh';
61
61
  * published), and the returned disposer.
62
62
  */
63
63
 
64
- import { setActiveSystems, updateInstanceSystems } from '@volter/editor-core/authoring/active-systems';
64
+ import { setActiveSystems, updateInstanceSystems } from '@volter/editor-sdk/kit/authoring/active-systems';
65
65
  import {
66
66
  BoundaryAuthoringAdapter,
67
67
  type BoundaryRootInfo,
68
- } from '@volter/editor-core/authoring/boundary-authoring-adapter';
69
- import type { CompositeAuthoringAdapter } from '@volter/editor-core/authoring/composite-authoring-adapter';
68
+ } from '@volter/editor-sdk/kit/authoring/boundary-authoring-adapter';
69
+ import type { CompositeAuthoringAdapter } from '@volter/editor-sdk/kit/authoring/composite-authoring-adapter';
70
70
  import {
71
71
  collaborationSnapshot,
72
72
  subscribeCollaborationRevision,
73
- } from '@volter/editor-core/collaboration-client';
73
+ } from '@volter/editor-sdk/kit/collaboration-client';
74
74
  import { editorConsole } from '@volter/editor-sdk/kit/editor-console';
75
75
  import {
76
76
  describeModuleFetch,
77
77
  diagnoseModuleFetch,
78
78
  failedImportEntry,
79
79
  } from '@volter/editor-sdk/kit/module-fetch-diagnosis';
80
- import type { EditorShellStore } from '@volter/editor-core/editor-shell-store';
80
+ import type { EditorShellStore } from '@volter/editor-threejs/kit/editor-shell-store';
81
+ import { withObservedPhysics } from '../../host/adapter-runtime-bindings';
82
+ import { whenRapierWorldMounts } from '../../services/game-physics';
81
83
  import { adjudicateThreeEntry } from '../../host/entry-adjudication';
82
- import { onPlayTransitionSettled } from '@volter/editor-core/live-transition';
83
- import { fetchRawGameManifest } from '@volter/editor-core/manifest-project';
84
- import { getCurrentProject } from '@volter/editor-core/project-manager';
84
+ import { onPlayTransitionSettled } from '@volter/editor-sdk/kit/live-transition';
85
+ import { fetchRawGameManifest } from '@volter/editor-sdk/kit/manifest-project';
86
+ import { getCurrentProject } from '@volter/editor-sdk/kit/active-project';
85
87
  import { activeRealmServices } from '../../host/realm-services';
86
- import { pickGameCamera } from '@volter/editor-core/scene-framing';
87
- import { tierSourceWriteBackend } from '@volter/editor-core/ui-source/tier-source-write-backend';
88
+ import { pickGameCamera } from '@volter/editor-threejs/kit/scene-framing';
89
+ import { tierSourceWriteBackend } from '@volter/editor-sdk/kit/ui-source/tier-source-write-backend';
88
90
  import type {
89
91
  MountedThreeRoot,
90
92
  RootAdapter,
91
93
  SystemAdapters,
92
94
  } from '@volter/editor-project/adapter';
93
- import type { GameThreeHostContext } from '@volter/game-runtime/runtime/host-context';
95
+ import type { GameThreeHostContext } from '../../runtime/host-context';
96
+ import type { ThreeMountedRoot } from '@volter/editor-threejs/adapter/three-contract';
94
97
  import { nodeKeyedPhysics } from '@volter/editor-project/adapter';
95
98
  import { declaredRoots, rootById } from '@volter/editor-project/adapter/manifest-interpreter';
96
99
  import {
@@ -100,11 +103,11 @@ import {
100
103
  type NativeSystemsBinding,
101
104
  nativeDebugBindingFromEntryModule,
102
105
  nativeSystemsBindingFromEntryModule,
103
- } from '@volter/game-runtime/adapter/native-debug-module';
106
+ } from '../../runtime/adapter/native-debug-module';
104
107
  import { createAssetCache } from '@volter/threejs-runtime/assets';
105
- import { createGameLoop } from '@volter/game-runtime/core/game-loop';
106
- import { registerThreeRoot } from '@volter/game-runtime/runtime/create-runtime';
107
- import { createGame, type GameInternal } from '@volter/game-runtime/runtime/game';
108
+ import { createGameLoop } from '../../runtime/core/game-loop';
109
+ import { registerThreeRoot } from '../../runtime/create-runtime';
110
+ import { createGame, type GameInternal } from '../../runtime/game';
108
111
  import {
109
112
  beginProjectMountEpoch,
110
113
  viteUpdateImportPath,
@@ -136,7 +139,7 @@ import {
136
139
  type EditModeRootSpec,
137
140
  parseEditModeManifest,
138
141
  queueEditModeRebuild,
139
- } from '@volter/editor-core/authoring/edit-mode-authoring';
142
+ } from '@volter/editor-sdk/kit/authoring/edit-mode-authoring';
140
143
  import { liveGestureActive, whenLiveGestureIdle } from '@volter/editor-sdk/kit/live-gesture-lock';
141
144
  import {
142
145
  addMountFailureReport,
@@ -234,7 +237,8 @@ export function registerR3FDesignRoot(
234
237
  ): void {
235
238
  registerThreeRoot(game, adapter, mounted, { id: worldId });
236
239
  installNativeDebugBindings(game, entryDebug ? [entryDebug] : []);
237
- installNativeSystemsBindings(game, entrySystems ? [entrySystems] : []);
240
+ // The design world's own `@react-three/rapier` world is observed the way Play's is.
241
+ installNativeSystemsBindings(game, withObservedPhysics(game, entrySystems ? [entrySystems] : []));
238
242
  }
239
243
 
240
244
  /**
@@ -253,10 +257,6 @@ export function registerR3FDesignRoot(
253
257
  * promises. It also gets its OWN debug registry (registries are game-scoped),
254
258
  * so design-time providers can't collide with the play game's.
255
259
  *
256
- * Input is explicitly DISABLED: `new InputManager()` binds window-level
257
- * keyboard/mouse listeners in its constructor, and design time is not play
258
- * (T6.3's invariant). `dispose()` unbinds them — the caller must call it.
259
- *
260
260
  * Its renderer is `createDesignTimeRenderer`, which isolates Fiber configuration
261
261
  * and permits real offscreen work without transferring canvas ownership.
262
262
  */
@@ -269,7 +269,6 @@ function createDesignHost(renderer: THREE.WebGLRenderer): {
269
269
  const borrowedRenderer = createDesignTimeRenderer(canvas, renderer);
270
270
  const assets = createAssetCache();
271
271
  const game = createGame({ loop: createGameLoop({ update: () => {} }), assets });
272
- game.input.setEnabled(false);
273
272
  return {
274
273
  game,
275
274
  host: {
@@ -299,11 +298,11 @@ function rebuildWhenPlayStops(store: EditorShellStore): () => void {
299
298
  let disposed = false;
300
299
  let requested = false;
301
300
  const request = () => {
302
- if (disposed || requested || store.playState !== 'stopped') return;
301
+ if (disposed || requested || store.shell.playState !== 'stopped') return;
303
302
  requested = true;
304
303
  queueEditModeRebuild();
305
304
  };
306
- const unsubscribe = store.subscribe(request);
305
+ const unsubscribe = store.shell.subscribe(request);
307
306
  request();
308
307
  return () => {
309
308
  disposed = true;
@@ -340,7 +339,7 @@ export async function mountR3FDesignSession(
340
339
 
341
340
  // Mirror design-time-layers' entry guard: while play is already running,
342
341
  // mount nothing and wait for Stop's rebuild.
343
- if (store.playState !== 'stopped') {
342
+ if (store.shell.playState !== 'stopped') {
344
343
  return rebuildWhenPlayStops(store);
345
344
  }
346
345
 
@@ -403,7 +402,7 @@ export async function mountR3FDesignSession(
403
402
  * design world is mounted, this session is live, and play is stopped. */
404
403
  const publishPlane = (): void => {
405
404
  if (publishedSystems || !designGame) return;
406
- if (torndown || suspended || store.playState !== 'stopped') return;
405
+ if (torndown || suspended || store.shell.playState !== 'stopped') return;
407
406
  publishedSystems = designGame.systemAdapters;
408
407
  setActiveSystems(publishedSystems);
409
408
  };
@@ -479,7 +478,7 @@ export async function mountR3FDesignSession(
479
478
  * Ownership is `adoptMount`'s, and only after `disposeMounted`.
480
479
  */
481
480
  interface DesignMount {
482
- root: MountedThreeRoot;
481
+ root: ThreeMountedRoot;
483
482
  game: GameInternal;
484
483
  disposeHost: () => void;
485
484
  }
@@ -508,7 +507,7 @@ export async function mountR3FDesignSession(
508
507
  // (Rapier, game debug providers, and future native systems) on
509
508
  // `mounted.systems` even though the component registered successfully.
510
509
  registerR3FDesignRoot(hostGame, adapterExport, result, worldId, entryDebug, entrySystems);
511
- return { root: result, game: hostGame, disposeHost };
510
+ return { root: result as ThreeMountedRoot, game: hostGame, disposeHost };
512
511
  };
513
512
 
514
513
  /** Install a freshly-mounted design world as THE live one. The previous one
@@ -530,7 +529,7 @@ export async function mountR3FDesignSession(
530
529
  publishedSystems = systems;
531
530
  updateInstanceSystems(systems);
532
531
  }
533
- store.notifyIngestEdit();
532
+ store.shell.notifyIngestEdit();
534
533
  });
535
534
  // The design Game outlives `mount()` (the world holds its ctx) and must go
536
535
  // down with the mount, or every HMR remount leaks another window-listener
@@ -580,21 +579,21 @@ export async function mountR3FDesignSession(
580
579
  composite.replaceChild(
581
580
  worldId,
582
581
  new BoundaryAuthoringAdapter(
583
- store,
582
+ store.shell,
584
583
  boundaryInfo(world),
585
584
  'R3F design session suspended by play mode — Stop restores it.',
586
585
  ),
587
586
  );
588
- store.notifyIngestEdit();
587
+ store.shell.notifyIngestEdit();
589
588
  };
590
589
 
591
590
  const failToBoundary = (err: unknown): void => {
592
591
  const message = reportDesignMountFailure(worldId, err);
593
592
  composite.replaceChild(
594
593
  worldId,
595
- new BoundaryAuthoringAdapter(store, boundaryInfo(world), message),
594
+ new BoundaryAuthoringAdapter(store.shell, boundaryInfo(world), message),
596
595
  );
597
- store.notifyIngestEdit();
596
+ store.shell.notifyIngestEdit();
598
597
  };
599
598
 
600
599
  // ---------------------------------------------------------- initial mount
@@ -629,10 +628,10 @@ export async function mountR3FDesignSession(
629
628
  }
630
629
  if (torndown) return () => {};
631
630
  // Restart can enter Play while this design import is in flight.
632
- if (store.playState !== 'stopped') return rebuildWhenPlayStops(store);
631
+ if (store.shell.playState !== 'stopped') return rebuildWhenPlayStops(store);
633
632
  const first = await mountRoot(loaded.adapter, loaded.entryDebug, loaded.entrySystems);
634
633
  adoptMount(first);
635
- if (torndown || store.playState !== 'stopped') {
634
+ if (torndown || store.shell.playState !== 'stopped') {
636
635
  disposeMounted();
637
636
  return torndown ? () => {} : rebuildWhenPlayStops(store);
638
637
  }
@@ -643,12 +642,17 @@ export async function mountR3FDesignSession(
643
642
  physics: () => nodeKeyedPhysics(designGame?.systemAdapters.physics),
644
643
  });
645
644
  composite.replaceChild(worldId, adapter);
645
+ // A body's colliders appear once the world's `<Physics>` has loaded Rapier;
646
+ // panels that already read it are told to read again.
647
+ void whenRapierWorldMounts(first.root.scene as THREE.Object3D).then((mounted) => {
648
+ if (mounted && !torndown) store.shell.notifyIngestEdit();
649
+ });
646
650
  // The hierarchy can become interactive as soon as the composite child is
647
651
  // replaced, while this async mount is still completing. Preserve a user
648
652
  // selection made in that window across enterPlayScene(), which clears the
649
653
  // store selection while adopting the mounted scene. OID-signature ids are
650
654
  // stable across the boundary, so only restore ids the new composite owns.
651
- const selectedIds = selectionRemountHandoff.take(store, store.selectedEntityIds);
655
+ const selectedIds = selectionRemountHandoff.take(store, store.shell.selectedEntityIds);
652
656
  // The world's own colour pipeline travels WITH the adoption: this session
653
657
  // mounted it against a renderer that draws nothing, so the declaration has
654
658
  // to reach the viewport's renderer through the adoption instead (see
@@ -681,10 +685,10 @@ export async function mountR3FDesignSession(
681
685
  // from under them on every save. A first look is opened once.
682
686
  store.focusOnScene(() => pickGameCamera(null, first.root.scene));
683
687
  const alive = selectedIds.filter((id) => composite.hierarchy.node(id) !== null);
684
- if (alive.length > 0) store.selectMultiple(alive);
688
+ if (alive.length > 0) store.shell.selectMultiple(alive);
685
689
  clearMountFailureReport(worldId);
686
690
  publishPlane();
687
- store.notifyIngestEdit();
691
+ store.shell.notifyIngestEdit();
688
692
  editorConsole.log(
689
693
  `[r3f-design] world "${worldId}" mounted for design-time authoring (${entry})`,
690
694
  'authoring',
@@ -750,12 +754,12 @@ export async function mountR3FDesignSession(
750
754
  // ---------------------------------------------------------------- remount
751
755
  const remount = async (): Promise<void> => {
752
756
  if (torndown || suspended) return;
753
- const selectedIds = [...store.selectedEntityIds];
757
+ const selectedIds = [...store.shell.selectedEntityIds];
754
758
  // Same stall watchdog as the initial mount, per stage: after a crashed
755
759
  // mount the NEXT remount was observed to hang silently — no "mounted", no
756
760
  // "failed" — leaving the world Unavailable with a clean console.
757
761
  const startedAtWriteStamp = writeStamp;
758
- const historyBusyAtStart = store.projectHistory?.getSnapshot().busy === true;
762
+ const historyBusyAtStart = store.shell.projectHistory?.getSnapshot().busy === true;
759
763
  let stage: 'importing' | 'mounting' = 'importing';
760
764
  const stallTimer = setTimeout(() => {
761
765
  editorConsole.warn(
@@ -798,7 +802,7 @@ export async function mountR3FDesignSession(
798
802
  for (let settle = 0; settle < 50; settle += 1) {
799
803
  await whenLiveGestureIdle();
800
804
  await whenProjectHistoryIdle();
801
- if (!liveGestureActive() && store.projectHistory?.getSnapshot().busy !== true) break;
805
+ if (!liveGestureActive() && store.shell.projectHistory?.getSnapshot().busy !== true) break;
802
806
  }
803
807
  settledAt = performance.now();
804
808
  if (!torndown && !suspended && writeStamp !== startedAtWriteStamp) {
@@ -834,7 +838,7 @@ export async function mountR3FDesignSession(
834
838
  // selection snapped back to A 255 ms after the adopt (Opus
835
839
  // reproduction on preview-b53, 2/2 with a non-reverting control; the
836
840
  // human typed their Position X into the wrong tree — runhuman pass 128).
837
- const selectionAtSwap = new Set(store.selectedEntityIds);
841
+ const selectionAtSwap = new Set(store.shell.selectedEntityIds);
838
842
  restoreEditorScene();
839
843
  // The OUTGOING world goes down first, with its OWN host — then the
840
844
  // incoming one is adopted. Reversing these disposes the incoming Game.
@@ -895,7 +899,7 @@ export async function mountR3FDesignSession(
895
899
  // objects (exitPlayScene cleared the store selection; restore it).
896
900
  const restoreIds = selectionChangedMidRemount ? [...selectionAtSwap] : selectedIds;
897
901
  const alive = restoreIds.filter((id) => adapter?.hierarchy.node(id) !== null);
898
- if (alive.length > 0) store.selectMultiple(alive);
902
+ if (alive.length > 0) store.shell.selectMultiple(alive);
899
903
  // PD-1: this world is mounted again — retract its failure report so the
900
904
  // status item (and `vgai status`) can go back to healthy.
901
905
  clearMountFailureReport(worldId);
@@ -903,7 +907,7 @@ export async function mountR3FDesignSession(
903
907
  // one's), so a stat added by the edit that triggered this remount is
904
908
  // readable without entering play.
905
909
  publishPlane();
906
- store.notifyIngestEdit();
910
+ store.shell.notifyIngestEdit();
907
911
  reportSlowRemount(worldId, remountStartedAt, importedAt, mountedAt, settledAt);
908
912
  refreshRevisions.mounted();
909
913
  clearTimeout(revisionFallback);
@@ -950,7 +954,7 @@ export async function mountR3FDesignSession(
950
954
  * in-flight work — bounded, so a wedged pipeline degrades to the stale-drop
951
955
  * guard instead of holding the swap forever. */
952
956
  const whenProjectHistoryIdle = async (): Promise<void> => {
953
- const history = store.projectHistory;
957
+ const history = store.shell.projectHistory;
954
958
  if (!history) return;
955
959
  const deadline = Date.now() + 10_000;
956
960
  while (history.getSnapshot().busy && Date.now() < deadline) {
@@ -1000,7 +1004,7 @@ export async function mountR3FDesignSession(
1000
1004
  );
1001
1005
  return;
1002
1006
  }
1003
- const history = store.projectHistory;
1007
+ const history = store.shell.projectHistory;
1004
1008
  if (!history) return;
1005
1009
  const snapshot = history.getSnapshot();
1006
1010
  const last = snapshot.canUndo ? snapshot.transactions[snapshot.cursor - 1] : undefined;
@@ -1095,7 +1099,7 @@ export async function mountR3FDesignSession(
1095
1099
  if (!refreshRevisions.needsRemount()) clearTimeout(revisionFallback);
1096
1100
  // The native adapter observes child additions/removals. Property-only
1097
1101
  // refreshes still need an inspector/viewport notification.
1098
- store.notifyIngestEdit();
1102
+ store.shell.notifyIngestEdit();
1099
1103
  };
1100
1104
  hot.on('vgai:r3f-entry-update', onUpdate);
1101
1105
  hot.on('vgai:r3f-refresh-source', onSource);
@@ -1133,16 +1137,16 @@ export async function mountR3FDesignSession(
1133
1137
  // ------------------------------------------------------------ play handoff
1134
1138
  let stopRebuildRequested = false;
1135
1139
  let suspendQueued = false;
1136
- unsubStore = store.subscribe(() => {
1140
+ unsubStore = store.shell.subscribe(() => {
1137
1141
  if (torndown) return;
1138
1142
  // Seat handover, BEFORE the deferred visual suspend below: play mode
1139
1143
  // registers under its own mount id, so holding both seats would make an
1140
1144
  // unaddressed `vgai eval` ambiguous. This fires at
1141
1145
  // `store.setPlayState('playing')`, which precedes play's own
1142
1146
  // `setActiveSystems` — so the two never overlap in either direction.
1143
- if (store.playState === 'stopped') publishPlane();
1147
+ if (store.shell.playState === 'stopped') publishPlane();
1144
1148
  else withdrawPlane();
1145
- if (!suspended && !suspendQueued && store.playState !== 'stopped') {
1149
+ if (!suspended && !suspendQueued && store.shell.playState !== 'stopped') {
1146
1150
  // Keep the adopted design scene alive UNDER the play-entry transition.
1147
1151
  // Suspending at the playState flip swapped the viewport back to the
1148
1152
  // placeholder editor scene mid-flight — the whole screen flashed the
@@ -1154,12 +1158,12 @@ export async function mountR3FDesignSession(
1154
1158
  suspendQueued = true;
1155
1159
  onPlayTransitionSettled(() => {
1156
1160
  suspendQueued = false;
1157
- if (torndown || suspended || store.playState === 'stopped') return;
1161
+ if (torndown || suspended || store.shell.playState === 'stopped') return;
1158
1162
  suspendForPlay();
1159
1163
  });
1160
1164
  return;
1161
1165
  }
1162
- if (suspended && !stopRebuildRequested && store.playState === 'stopped') {
1166
+ if (suspended && !stopRebuildRequested && store.shell.playState === 'stopped') {
1163
1167
  stopRebuildRequested = true;
1164
1168
  queueEditModeRebuild();
1165
1169
  }
@@ -1179,8 +1183,8 @@ export async function mountR3FDesignSession(
1179
1183
  // changes) should preserve editor-global selection. Play suspension is a
1180
1184
  // different scene lifecycle and deliberately keeps exitPlayScene's normal
1181
1185
  // clearing semantics.
1182
- if (!suspended && store.playState === 'stopped' && store.selectedEntityIds.size > 0) {
1183
- selectionRemountHandoff.remember(store, store.selectedEntityIds);
1186
+ if (!suspended && store.shell.playState === 'stopped' && store.shell.selectedEntityIds.size > 0) {
1187
+ selectionRemountHandoff.remember(store, store.shell.selectedEntityIds);
1184
1188
  }
1185
1189
  restoreEditorScene();
1186
1190
  disposeMounted();