@volter/editor-game 0.5.66 → 0.5.68

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 (239) 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/build-player.document.tsx +95 -0
  5. package/contributions/canvas/component-board.service.ts +16 -0
  6. package/contributions/canvas/design-time-mount.service.ts +45 -0
  7. package/contributions/canvas-story-capture.service.ts +12 -0
  8. package/contributions/edit-mode-audio.service.ts +2 -2
  9. package/contributions/edit-mode-networking.service.ts +1 -1
  10. package/contributions/gameplay.command.ts +4 -4
  11. package/contributions/generation.service.ts +1 -1
  12. package/contributions/godot.style.ts +26 -6
  13. package/contributions/godot.view.ts +6 -0
  14. package/contributions/ingest.service.ts +2 -2
  15. package/contributions/instances.command.ts +1 -1
  16. package/contributions/navmesh.menu.ts +1 -1
  17. package/contributions/network-observer.service.ts +14 -0
  18. package/contributions/play.command.ts +10 -4
  19. package/contributions/react/component-board.service.ts +1 -1
  20. package/contributions/react/design-time-mount.service.ts +1 -1
  21. package/contributions/scene-document.service.ts +3 -3
  22. package/contributions/state-watch.menu.ts +1 -1
  23. package/contributions/state-watch.utility.tsx +1 -1
  24. package/contributions/team-playtest.service.ts +4 -4
  25. package/contributions/three/component-board.service.ts +1 -1
  26. package/contributions/three/component-verbs.command.ts +6 -6
  27. package/contributions/three/three-authoring.service.ts +8 -5
  28. package/contributions/three-story-capture.service.ts +12 -0
  29. package/contributions/unity.style.ts +17 -7
  30. package/contributions/unity.view.ts +6 -0
  31. package/contributions/unreal.style.ts +10 -2
  32. package/contributions/unreal.view.ts +5 -0
  33. package/package.json +21 -10
  34. package/src/asset-budget/AssetBudgetPanel.tsx +1 -1
  35. package/src/asset-budget/asset-budget-model.ts +1 -1
  36. package/src/audio/AudioDebuggerPanel.tsx +1 -1
  37. package/src/bridge/dispatch.ts +14 -14
  38. package/src/bridge/live-frames.ts +1 -1
  39. package/src/bridge/screenshot.ts +3 -3
  40. package/src/build/BuildProfilesPanel.tsx +14 -3
  41. package/src/build/build-session.ts +35 -0
  42. package/src/canvas/canvas-board/CanvasBoardDocument.tsx +749 -0
  43. package/src/canvas/canvas-board/canvas-board-model.ts +407 -0
  44. package/src/canvas/canvas-board/canvas-component-board.ts +56 -0
  45. package/src/canvas/canvas-design-mount.ts +524 -0
  46. package/src/canvas/design-time-canvas-mount.ts +79 -0
  47. package/src/coverage/live-authoring-surface.ts +5 -5
  48. package/src/coverage/live-project-verbs.ts +1 -1
  49. package/src/coverage/native-system-coverage.ts +5 -5
  50. package/src/coverage/root-coverage.ts +1 -1
  51. package/src/coverage/session-coverage.ts +3 -3
  52. package/src/design-system-stories/ApplicationChrome.stories.tsx +5 -5
  53. package/src/design-system-stories/InspectorNarrowBodies.stories.tsx +7 -7
  54. package/src/edit-mode/edit-mode-audio.ts +4 -4
  55. package/src/edit-mode/edit-mode-networking.ts +2 -2
  56. package/src/game-document/GameCaptureFrameButton.tsx +1 -1
  57. package/src/game-document/GameDocument.tsx +2 -2
  58. package/src/game-document/GamePanel.tsx +4 -4
  59. package/src/game-document/InstanceInspectorPicker.tsx +2 -2
  60. package/src/game-document/crowd-debug.ts +1 -1
  61. package/src/game-document/device-preview.ts +10 -11
  62. package/src/game-document/physics-debug.ts +1 -1
  63. package/src/generation/GenerationActivity.tsx +3 -3
  64. package/src/generation/generation-documents.tsx +5 -5
  65. package/src/generation/generation-jobs.ts +1 -1
  66. package/src/host/adapter-runtime-bindings.ts +96 -5
  67. package/src/host/authoring/babylon-authoring-adapter.ts +6 -6
  68. package/src/host/authoring/gesture-persist.ts +1 -1
  69. package/src/host/authoring/ingest-data-writer.ts +1 -1
  70. package/src/host/authoring/ingest-source-persistence.ts +4 -4
  71. package/src/host/authoring/mounted-authoring.ts +4 -4
  72. package/src/host/authoring/phaser-live-authoring-adapter.ts +4 -4
  73. package/src/host/authoring/pixi-authoring-adapter.ts +178 -31
  74. package/src/host/authoring/pixi-creatable-kinds.ts +62 -0
  75. package/src/host/authoring/pixi-creation-site-write-target.ts +2 -2
  76. package/src/host/authoring/pixi-live-write-target.ts +4 -4
  77. package/src/host/authoring/pixi-source-identity.ts +3 -3
  78. package/src/host/authoring/pixi-source-write-target.ts +1709 -0
  79. package/src/host/authoring/pixi-still-presentation.ts +1 -1
  80. package/src/host/authoring/pixi-structure-history.ts +2 -2
  81. package/src/host/authoring/pixi-transform-channels.ts +16 -14
  82. package/src/host/authoring/source-persistence-backend.ts +3 -3
  83. package/src/host/authoring/struct-write-pipe.ts +1 -1
  84. package/src/host/binding-resolver.ts +8 -9
  85. package/src/host/browser-transpile.ts +1 -1
  86. package/src/host/canvas-entry-runtime.ts +58 -47
  87. package/src/host/canvas-preview-frames.ts +482 -0
  88. package/src/host/components/CameraAuthoringOverlay.tsx +1 -1
  89. package/src/host/components/HeaderTelemetry.tsx +4 -4
  90. package/src/host/components/PixiIsolationSceneContent.tsx +11 -11
  91. package/src/host/components/ThreeIsolationSceneContent.tsx +3 -3
  92. package/src/host/components/frame-debugger-model.ts +2 -2
  93. package/src/host/components/header-telemetry-model.ts +2 -2
  94. package/src/host/components/scene-document.tsx +14 -14
  95. package/src/host/components/utility-view-state.ts +1 -1
  96. package/src/host/components/world-root-stage-binding.tsx +12 -12
  97. package/src/host/components/world-root-stage.ts +70 -49
  98. package/src/host/coverage/system-adapter-coverage.ts +3 -4
  99. package/src/host/design-system-stories/fixtures/editor-runtime.tsx +9 -11
  100. package/src/host/document-preview-three.ts +1 -1
  101. package/src/host/entry-adjudication.ts +6 -6
  102. package/src/host/game-css-scope-transform.ts +4 -0
  103. package/src/host/game-realm-page.ts +1 -1
  104. package/src/host/gameplay-export.ts +25 -14
  105. package/src/host/gameplay-recording.ts +5 -5
  106. package/src/host/gated-globals.ts +2 -2
  107. package/src/host/history/json-history-resource.ts +1 -1
  108. package/src/host/projection/pixi.ts +24 -2
  109. package/src/host/r3f-entry-runtime.ts +65 -34
  110. package/src/host/react-mount-runtime.ts +7 -48
  111. package/src/host/realm-services.ts +1 -1
  112. package/src/host/roots/canvas-root.tsx +373 -0
  113. package/src/host/roots/r3f-root.tsx +473 -0
  114. package/src/host/roots/react-root.ts +9 -43
  115. package/src/host/served-bundle-runtime-modules.ts +3 -19
  116. package/src/host/server-log-bridge.ts +2 -2
  117. package/src/host/stories/mounted-story-viewport-source.ts +1 -1
  118. package/src/host/stories/pixi-story-model.ts +30 -0
  119. package/src/host/stories/story-media-captures.ts +46 -0
  120. package/src/host/stories/story-media-presence.ts +3 -3
  121. package/src/host/stories/story-pixi-preview.ts +408 -0
  122. package/src/host/stories/story-three-preview.ts +806 -0
  123. package/src/host/stories/three-story-captures.ts +35 -0
  124. package/src/host/story-three-preview-runtime.ts +56 -0
  125. package/src/host/use-active-performance-source.ts +2 -2
  126. package/src/host/viewport-pose-memory.ts +1 -1
  127. package/src/host/viewport-root-presentation.ts +6 -5
  128. package/src/ingest/active-ingest.ts +1 -1
  129. package/src/ingest/authoring/ingest-dom-surface-authoring.ts +4 -4
  130. package/src/ingest/authoring/ingest-root-adapter.ts +8 -8
  131. package/src/ingest/deferred-ingest-play.ts +6 -6
  132. package/src/ingest/discovery-public-ingest.ts +2 -2
  133. package/src/ingest/ingest-boot-viewport.ts +2 -2
  134. package/src/ingest/ingest-canvas-scene-document.tsx +9 -9
  135. package/src/ingest/ingest-canvas-scene.ts +3 -3
  136. package/src/ingest/ingest-evidence-hook.ts +1 -1
  137. package/src/ingest/ingest-frame-snapshot.ts +1 -1
  138. package/src/ingest/ingest-play-control.ts +1 -1
  139. package/src/ingest/ingest-render-debug.ts +10 -10
  140. package/src/ingest/ingest-siblings.ts +13 -25
  141. package/src/ingest/module-mode.ts +14 -14
  142. package/src/ingest/mount-canvas-ingest-root.ts +21 -21
  143. package/src/ingest/mount-coverage.ts +2 -2
  144. package/src/ingest/mount-dom-ingest-root.ts +11 -11
  145. package/src/ingest/mount-ingest-root.ts +8 -8
  146. package/src/ingest/mount-three-ingest-root.ts +8 -8
  147. package/src/ingest/resolve-canvas.ts +1 -1
  148. package/src/ingest/served-html-boot.ts +1 -1
  149. package/src/ingest/surface-canvas.ts +1 -1
  150. package/src/ingest/unmount-ingest-root.ts +5 -5
  151. package/src/navmesh/navmesh-handler.ts +24 -16
  152. package/src/network/NetworkInspectorPanel.tsx +939 -37
  153. package/src/network/network-inspector-model.ts +20 -2
  154. package/src/play/play-log-events.ts +1 -1
  155. package/src/play/play-mode.ts +76 -133
  156. package/src/play/play-recording.ts +1 -1
  157. package/src/play/react-play-live-authoring.ts +3 -3
  158. package/src/play/run-selection.ts +93 -0
  159. package/src/play-bar/PlayBar.tsx +20 -39
  160. package/src/profiler/FrameDebuggerPanel.tsx +1 -1
  161. package/src/profiler/PerformancePanel.tsx +3 -3
  162. package/src/react/design-time-react-mount.ts +23 -65
  163. package/src/react/dom-authoring-adapter.ts +9 -9
  164. package/src/react/react-inspector-section.tsx +5 -5
  165. package/src/react/react-world-authoring-adapter.ts +11 -11
  166. package/src/react/story-documents/story-documents.tsx +9 -9
  167. package/src/react/ui-board-document.tsx +7 -7
  168. package/src/react/ui-component-board.ts +2 -2
  169. package/src/runtime/adapter/audio-meter.ts +21 -0
  170. package/src/runtime/adapter/first-party-audio-system.ts +230 -0
  171. package/src/runtime/adapter/ingest/contract-debug-adapter.ts +114 -0
  172. package/src/runtime/adapter/ingest/contract-system-adapters.ts +256 -0
  173. package/src/runtime/adapter/ingest/merge-debug-adapters.ts +197 -0
  174. package/src/runtime/adapter/ingest/observation-debug-adapter.ts +162 -0
  175. package/src/runtime/adapter/ingest/upstream-pin.ts +51 -0
  176. package/src/runtime/adapter/native-debug-module.ts +498 -0
  177. package/src/runtime/audio/bus-mixer.ts +161 -0
  178. package/src/runtime/audio/pose-guard.ts +80 -0
  179. package/src/runtime/core/frame-pacing.ts +126 -0
  180. package/src/runtime/core/game-loop.ts +225 -0
  181. package/src/runtime/core/game-scoped-slot.ts +28 -0
  182. package/src/runtime/core/seeded-random.ts +162 -0
  183. package/src/runtime/core/sim-clock.ts +391 -0
  184. package/src/runtime/core/system-runner.ts +269 -0
  185. package/src/runtime/core/types.ts +104 -0
  186. package/src/runtime/create-runtime.ts +1128 -0
  187. package/src/runtime/debug-bridge.ts +570 -0
  188. package/src/runtime/debug-registry.ts +899 -0
  189. package/src/runtime/dev/chrome-trace.ts +153 -0
  190. package/src/runtime/dev/instruments.ts +403 -0
  191. package/src/runtime/dev/logger.ts +119 -0
  192. package/src/runtime/dev/performance-profiler.ts +367 -0
  193. package/src/runtime/dev/register-render-vitals.ts +276 -0
  194. package/src/runtime/dev/render-census.ts +354 -0
  195. package/src/runtime/dev/render-debug-adapter.ts +218 -0
  196. package/src/runtime/dev/render-memory.ts +226 -0
  197. package/src/runtime/dev/render-vitals.ts +338 -0
  198. package/src/runtime/dev/static-batch-advisor.ts +188 -0
  199. package/src/runtime/dev/webgl-frame-capture.ts +366 -0
  200. package/src/runtime/dev/webgl-gpu-timer.ts +53 -0
  201. package/src/runtime/dev-build.ts +47 -0
  202. package/src/runtime/game.ts +1636 -0
  203. package/src/runtime/gameplay-rng-trap.ts +135 -0
  204. package/src/runtime/host-context.ts +64 -0
  205. package/src/runtime/input-router.ts +182 -0
  206. package/src/runtime/mount-manifest.ts +480 -0
  207. package/src/runtime/pixi/authoring.ts +706 -0
  208. package/src/runtime/pixi/ingest.ts +116 -0
  209. package/src/runtime/pixi/physics-registry.ts +49 -0
  210. package/src/runtime/pixi/render-pass-bracket.ts +117 -0
  211. package/src/runtime/pixi/scene-capture.ts +179 -0
  212. package/src/runtime/pixi/system-adapters.ts +69 -0
  213. package/src/runtime/playtest.ts +22 -0
  214. package/src/runtime/presentation.ts +141 -0
  215. package/src/runtime/render-control.ts +642 -0
  216. package/src/runtime/render-seed.ts +77 -0
  217. package/src/runtime/run-ticks-settled.ts +73 -0
  218. package/src/runtime/setup/setup-audio.ts +72 -0
  219. package/src/services/audio-pose-guard.ts +2 -2
  220. package/src/services/game-audio.ts +152 -0
  221. package/src/services/game-network.ts +767 -0
  222. package/src/services/game-physics.ts +334 -0
  223. package/src/state-watch/StateWatchPanel.tsx +1 -1
  224. package/src/three/authoring/camera-runtime-inspector-section.tsx +3 -2
  225. package/src/three/authoring/constraint-inspector-section.tsx +6 -5
  226. package/src/three/authoring/model-asset-inspector-section.tsx +7 -6
  227. package/src/three/authoring/oid-source-persistence.ts +7 -7
  228. package/src/three/authoring/r3f-design-session.ts +58 -54
  229. package/src/three/authoring/r3f-source-authoring-adapter.ts +95 -91
  230. package/src/three/authoring/reflection-probe-inspector-section.tsx +3 -2
  231. package/src/three/authoring/three-authoring-adapter.ts +29 -29
  232. package/src/three/component-verbs/extract-menu.ts +7 -6
  233. package/src/three/component-verbs/fork-menu.ts +7 -6
  234. package/src/three/component-verbs/internals-menu.ts +2 -2
  235. package/src/three/story-documents/three-story-documents.tsx +13 -13
  236. package/src/three/three-board/ThreeBoardDocument.tsx +13 -12
  237. package/src/three/three-board/board-scene.ts +6 -6
  238. package/src/three/three-board/three-component-board.ts +2 -2
  239. package/src/services/game-audio-unlock.ts +0 -48
@@ -9,8 +9,8 @@
9
9
  * pause/filter, the sparkline sample history, and the polyline geometry —
10
10
  * lives here.
11
11
  *
12
- * Editor code never imports Colyseus (net-import-ban) — only the
13
- * `NetworkingAdapter` interface.
12
+ * The inspector reads only the `NetworkingAdapter` interface; decoding a
13
+ * game's Colyseus rooms is the observer's (`services/game-network.ts`).
14
14
  */
15
15
 
16
16
  import type {
@@ -82,6 +82,18 @@ export interface NetworkCapabilityMap {
82
82
  /** The adapter can SET the local identity (`setPlayerIdentity`) — the
83
83
  * inspector shows an EDITABLE name field. Implies `identity`. */
84
84
  identitySettable: boolean;
85
+ /** Traffic per message type (`getTrafficByType`). */
86
+ traffic: boolean;
87
+ /** Sending a message into the room as this client (`sendMessage`). */
88
+ send: boolean;
89
+ /** Measuring a round trip (`ping`). */
90
+ ping: boolean;
91
+ /** The room server's own view (`inspectServer`). */
92
+ server: boolean;
93
+ /** Traffic per replicated entity (`getTrafficByEntity`). */
94
+ entityTraffic: boolean;
95
+ /** Tallying that can be started and stopped (`isRecording`/`setRecording`). */
96
+ recording: boolean;
85
97
  }
86
98
 
87
99
  export function deriveNetworkCapabilities(
@@ -103,6 +115,12 @@ export function deriveNetworkCapabilities(
103
115
  stats: typeof adapter.getReplicationStats === 'function',
104
116
  identity: typeof adapter.getPlayerIdentity === 'function',
105
117
  identitySettable: typeof adapter.setPlayerIdentity === 'function',
118
+ traffic: typeof adapter.getTrafficByType === 'function',
119
+ send: typeof adapter.sendMessage === 'function',
120
+ ping: typeof adapter.ping === 'function',
121
+ server: typeof adapter.inspectServer === 'function',
122
+ entityTraffic: typeof adapter.getTrafficByEntity === 'function',
123
+ recording: typeof adapter.isRecording === 'function' && typeof adapter.setRecording === 'function',
106
124
  };
107
125
  }
108
126
 
@@ -1,4 +1,4 @@
1
- import type { LogEntry } from '@volter/editor-core/editor-api';
1
+ import type { LogEntry } from '@volter/editor-sdk/kit/editor-api';
2
2
  import type { TickStampedEvent } from '@volter/editor-project/adapter/system-adapter';
3
3
 
4
4
  /** Convert newly observed game-authored debug events into persistent JSONL entries. */
@@ -15,19 +15,19 @@ import { editorHost } from '@volter/editor-sdk/host';
15
15
  */
16
16
 
17
17
  import { installAdapterRuntimeBindings } from '../host/adapter-runtime-bindings';
18
- import { getAuthoringOverride, setActiveAuthoring } from '@volter/editor-core/authoring/active-adapter';
18
+ import { getAuthoringOverride, setActiveAuthoring } from '@volter/editor-sdk/kit/authoring/active-adapter';
19
19
  import {
20
20
  getActiveNetworking,
21
21
  inspectedInstanceId,
22
22
  setActiveSystems,
23
23
  setInspectedInstance,
24
24
  updateInstanceSystems,
25
- } from '@volter/editor-core/authoring/active-systems';
26
- import { BoundaryAuthoringAdapter } from '@volter/editor-core/authoring/boundary-authoring-adapter';
25
+ } from '@volter/editor-sdk/kit/authoring/active-systems';
26
+ import { BoundaryAuthoringAdapter } from '@volter/editor-sdk/kit/authoring/boundary-authoring-adapter';
27
27
  import {
28
28
  CompositeAuthoringAdapter,
29
29
  type CompositeChild,
30
- } from '@volter/editor-core/authoring/composite-authoring-adapter';
30
+ } from '@volter/editor-sdk/kit/authoring/composite-authoring-adapter';
31
31
  import { createEphemeralPersistence } from '../host/authoring/ephemeral-persistence';
32
32
  import {
33
33
  EPHEMERAL_DESTINATION,
@@ -36,8 +36,8 @@ import {
36
36
  type WriteAck,
37
37
  } from '@volter/editor-sdk/kit/write-pipe';
38
38
  import { resolveAllRootEntries } from '../host/binding-resolver';
39
- import type { LogEntry } from '@volter/editor-core/editor-api';
40
- import { endLogSession, flushLogEntries, startLogSession } from '@volter/editor-core/editor-api';
39
+ import type { LogEntry } from '@volter/editor-sdk/kit/editor-api';
40
+ import { endLogSession, flushLogEntries, startLogSession } from '@volter/editor-sdk/kit/editor-api';
41
41
  import type { ConsoleEntry } from '@volter/editor-sdk/kit/editor-console';
42
42
  import {
43
43
  editorConsole,
@@ -45,15 +45,15 @@ import {
45
45
  resumeEditorConsoleCapture,
46
46
  suspendEditorConsoleCapture,
47
47
  } from '@volter/editor-sdk/kit/editor-console';
48
- import { EDITOR_PARTICIPANT_ID, sendControl } from '@volter/editor-core/editor-presence';
48
+ import { EDITOR_PARTICIPANT_ID, sendControl } from '@volter/editor-sdk/kit/editor-presence';
49
49
  import {
50
50
  isEditorPresentationActive,
51
51
  subscribeEditorPresentationActivity,
52
52
  } from '@volter/editor-sdk/kit/editor-presentation-activity';
53
- import type { EditorShellStore } from '@volter/editor-core/editor-shell-store';
53
+ import type { EditorShellStore } from '@volter/editor-threejs/kit/editor-shell-store';
54
54
  import { GAME_SURFACE_CONTAINMENT_CSS } from '../host/game-realm-page';
55
55
  import { reclaimGameRealm } from '../host/game-realm-reclaim';
56
- import { toolContributionRecording } from '@volter/editor-core/gameplay-sessions';
56
+ import { toolContributionRecording } from '@volter/editor-sdk/kit/gameplay-sessions';
57
57
  import {
58
58
  clearGameSurface,
59
59
  currentGameRealmMountId,
@@ -64,18 +64,18 @@ import {
64
64
  import { hierarchyProjectionFromProjectConfig } from '@volter/editor-sdk/kit/hierarchy-projection';
65
65
  import { type JournalSubject, playJournal } from '../host/history/json-history-resource';
66
66
  import { isEditableTarget, setActiveScope } from '@volter/editor-sdk/kit/hotkeys';
67
- import { projectBootstrapSettled } from '@volter/editor-core/initial-project';
68
- import { registerGameNullSubject } from '@volter/editor-core/inspection/game-subject';
69
- import { fetchGameManifest } from '@volter/editor-core/manifest-project';
70
- import { registerPerformanceSource } from '@volter/editor-core/performance-sources';
67
+ import { projectBootstrapSettled } from '@volter/editor-sdk/kit/initial-project';
68
+ import { registerGameNullSubject } from '@volter/editor-sdk/kit/inspection/game-subject';
69
+ import { fetchGameManifest } from '@volter/editor-sdk/kit/manifest-project';
70
+ import { registerPerformanceSource } from '@volter/editor-sdk/kit/performance-sources';
71
71
  import {
72
72
  beginPlayBoot,
73
73
  endPlayBoot,
74
74
  markPlayBootPhase,
75
75
  type PlayBootPhase,
76
- } from '@volter/editor-core/play-boot-phase';
76
+ } from '@volter/editor-sdk/kit/play-boot-phase';
77
77
  import { presentationSurface } from '@volter/editor-sdk/kit/presentation-surface';
78
- import { getCurrentProject } from '@volter/editor-core/project-manager';
78
+ import { getCurrentProject } from '@volter/editor-sdk/kit/active-project';
79
79
  import {
80
80
  beginProjectModuleSplitWatch,
81
81
  clearProjectModuleSplitReports,
@@ -83,31 +83,30 @@ import {
83
83
  formatProjectModuleSplitMessage,
84
84
  } from '@volter/editor-sdk/kit/project-module-split';
85
85
  import { clearRootReadiness, recordRootReadiness } from '@volter/editor-sdk/kit/readiness';
86
- import { onThreeStore } from '@volter/editor-core/shell-store-door';
87
- import { mountedStoryHasPixiContent } from '@volter/editor-core/stories/pixi-story-model';
86
+ import { mountedStoryHasPixiContent } from '../host/stories/pixi-story-model';
88
87
  import { domHasRenderableContent, threeSceneHasRenderableContent } from '../host/surface-content';
89
- import { subscribeSurfaceKeyboard, surfaceHoldsKeyboard } from '@volter/editor-sdk/kit/surface-keyboard';
90
- import { publishToolContributionPlay } from '@volter/editor-core/tool-contribution-play';
88
+ import { surfaceHoldsKeyboard } from '@volter/editor-sdk/kit/surface-keyboard';
89
+ import { publishToolContributionPlay } from '@volter/editor-sdk/kit/tool-contribution-play';
91
90
  import { liveWorldId, presentThreeRoots } from '../host/viewport-root-presentation';
92
91
  import {
93
92
  cancelPendingWorkspacePlayUtilities,
94
93
  revealWorkspacePlayUtilities,
95
- } from '@volter/editor-core/workspace-play-utilities';
94
+ } from '@volter/editor-sdk/kit/workspace-play-utilities';
96
95
  import { markGameCssScope } from '@volter/editor-sdk/session/game-css-scope';
97
96
  import type { EntrypointSelectionOverride } from '@volter/editor-sdk/session/project-module-url';
98
97
  import { isEditorLanePath } from '@volter/editor-sdk/session/tool-contribution-convention';
99
- import { getSeededRandom, type SeededRandom } from '@volter/game-runtime/core/seeded-random';
100
- import { _engineLogActive } from '@volter/game-runtime/dev/logger';
101
- import type { PerformanceProfiler } from '@volter/game-runtime/dev/performance-profiler';
102
- import type { GameSession } from '@volter/game-runtime/runtime/create-runtime';
98
+ import { getSeededRandom, type SeededRandom } from '../runtime/core/seeded-random';
99
+ import { _engineLogActive } from '../runtime/dev/logger';
100
+ import type { PerformanceProfiler } from '../runtime/dev/performance-profiler';
101
+ import type { GameSession } from '../runtime/create-runtime';
103
102
  import {
104
103
  type DebugVirtualInputTarget,
105
104
  getDebugRegistry,
106
105
  type RunTicksOptions,
107
- } from '@volter/game-runtime/runtime/debug-registry';
108
- import type { GameLoop, RootInstance } from '@volter/game-runtime/runtime/game';
109
- import type { PlaytestContext } from '@volter/game-runtime/runtime/playtest';
110
- import { runTicksWhenSettled } from '@volter/game-runtime/runtime/run-ticks-settled';
106
+ } from '../runtime/debug-registry';
107
+ import type { GameLoop, RootInstance } from '../runtime/game';
108
+ import type { PlaytestContext } from '../runtime/playtest';
109
+ import { runTicksWhenSettled } from '../runtime/run-ticks-settled';
111
110
  import {
112
111
  type AuthoringAdapter,
113
112
  type InspectorProvider,
@@ -119,6 +118,7 @@ import { declaredRoots, rootById } from '@volter/editor-project/adapter/manifest
119
118
  import { readOidSourceAnchors } from '../three/authoring/oid-source-persistence';
120
119
  import { oidThree, structuralThree } from '../three/authoring/three-authoring-adapter';
121
120
  import type * as THREE from 'three';
121
+ import { threeRoot } from '@volter/editor-threejs/adapter/three-contract';
122
122
  import { deviceEmulatedPixelRatio } from '../game-document/device-preview';
123
123
  import { exitDeferredIngestPlay, mountDeferredIngestForPlay } from '../ingest/deferred-ingest-play';
124
124
  import { getIngestPlayControl } from '../ingest/ingest-play-control';
@@ -126,6 +126,8 @@ import { withPlayBootStallGuard } from './play-boot-stall';
126
126
  import { debugEventsToLogEntries } from './play-log-events';
127
127
  import { bindPlayRecordingStop, endPlayRecording } from './play-recording';
128
128
  import { createReactPlayAuthoringAdapter } from './react-play-live-authoring';
129
+ import { onThreeStore } from '@volter/editor-threejs/kit/three-state';
130
+ import { presentViewportRoots } from '@volter/editor-threejs/viewport-door';
129
131
 
130
132
  /** Context needed by the orchestrator (passed from the world root's stage). */
131
133
  export interface PlayModeContext {
@@ -251,8 +253,8 @@ let _hostMountedReadyRootIds: readonly string[] = [];
251
253
  // id) resolves to the primary, so the default — and the single-instance case —
252
254
  // is "the primary has the keyboard", exactly as before split screen existed.
253
255
  // A click on an instance's viewport routes the keyboard to it
254
- // (`setFocusedInstance`); the input gate + InputManager for every instance read
255
- // this, so exactly the focused one is live and the rest are inert.
256
+ // (`setFocusedInstance`); every instance's input gate reads this, so exactly
257
+ // the focused one is live and the rest are inert.
256
258
  let _focusedInstanceId: string | null = null;
257
259
  const focusListeners = new Set<() => void>();
258
260
 
@@ -293,7 +295,6 @@ export function setFocusedInstance(id: string): void {
293
295
  setInspectedInstance(id);
294
296
  if (focusedInstanceId() === id) return;
295
297
  _focusedInstanceId = id;
296
- resyncInstanceInputs();
297
298
  notifyFocusedInstance();
298
299
  }
299
300
 
@@ -301,59 +302,23 @@ export function setFocusedInstance(id: string): void {
301
302
  * Game tab is active, this instance holds keyboard focus, AND our surface
302
303
  * holds the keyboard.
303
304
  *
304
- * The fourth term is U2's, and it exists for the engine's `InputManager`
305
- * specifically. `gated-globals.ts` already ANDs the same predicate into every
306
- * raw `window`/`document` listener a PROJECT module registers, but
307
- * `InputManager` is `@volter/game-runtime`'s — a dependency, not a project module, so
308
- * the dev server's lexical shadow never covers it and it attaches to the real
309
- * `window`. Under the Code-OSS frame that window also carries Monaco, so
310
- * without this a keystroke meant for the source file beside the running game
311
- * moves the game too. Standalone it is a constant true and nothing changes.
312
- * See `@editor/surface-keyboard`. */
305
+ * The fourth term is U2's: `gated-globals.ts` ANDs this predicate into every
306
+ * raw `window`/`document` listener a project module registers, and under the
307
+ * Code-OSS frame that window also carries Monaco, so without it a keystroke
308
+ * meant for the source file beside the running game moves the game too.
309
+ * Standalone it is a constant true and nothing changes. See
310
+ * `@editor/surface-keyboard`. */
313
311
  function instanceInputActive(id: string): boolean {
314
312
  if (!_ctx) return false;
315
313
  const { store } = _ctx;
316
314
  return (
317
- store.playState === 'playing' &&
318
- store.activeViewportTab === 'play' &&
315
+ store.shell.playState === 'playing' &&
316
+ store.shell.activeViewportTab === 'play' &&
319
317
  focusedInstanceId() === id &&
320
318
  surfaceHoldsKeyboard()
321
319
  );
322
320
  }
323
321
 
324
- /** The first-party `InputManager` for an instance, or `undefined` — a session's
325
- * game handle may lack one (an ingest mount, a partial double), so resolve it
326
- * defensively. */
327
- function instanceInput(inst: PlayInstance): { setEnabled(on: boolean): void } | undefined {
328
- try {
329
- return inst.session?.game?.input;
330
- } catch {
331
- return undefined;
332
- }
333
- }
334
-
335
- /** Re-apply the enabled/disabled state of every live instance's InputManager
336
- * from the current play/tab/focus predicate. Called whenever any of those
337
- * change (store subscription, focus switch, an instance mounting). The raw
338
- * window/document gates are closures over `instanceInputActive`, so they need
339
- * no re-registration — they re-read focus on every event. */
340
- function resyncInstanceInputs(): void {
341
- if (_instance.id) instanceInput(_instance)?.setEnabled(instanceInputActive(_instance.id));
342
- for (const inst of _additional) instanceInput(inst)?.setEnabled(instanceInputActive(inst.id));
343
- }
344
-
345
- /**
346
- * THE SURFACE TERM'S OWN EDGE. The store subscription re-gates on play/tab
347
- * changes and `setFocusedInstance` on focus changes, but the fourth term above
348
- * moves on neither: a person clicks into Monaco and nothing in the editor's own
349
- * state has changed. `InputManager` is a LATCHED `setEnabled`, so unlike the
350
- * raw gates (closures re-read per event) it has to be told. Module scope and
351
- * never unsubscribed on purpose — the notification is a no-op with no instances
352
- * mounted, and a lane-scoped subscription would have to be rebuilt on every
353
- * mount for a predicate that is process-wide.
354
- */
355
- subscribeSurfaceKeyboard(resyncInstanceInputs);
356
-
357
322
  let _ctx: PlayModeContext | null = null;
358
323
  const playModeBindingWaiters = new Set<() => void>();
359
324
 
@@ -513,7 +478,6 @@ export async function runWarmRestartPauseBracket(
513
478
  if (!wasPaused) session.resume();
514
479
  }
515
480
  }
516
- let _unsubStore: (() => void) | null = null;
517
481
  /** Browser-mode component-source watch (Phase A2); null in server mode / stopped. */
518
482
  /**
519
483
  * The authoring override that was active before THIS play session installed its
@@ -658,7 +622,7 @@ async function installPlayRootAuthoring(
658
622
  children.push({
659
623
  worldId: world.id,
660
624
  kind: world.kind,
661
- adapter: new BoundaryAuthoringAdapter(store, {
625
+ adapter: new BoundaryAuthoringAdapter(store.shell, {
662
626
  id: world.id,
663
627
  kind: world.kind,
664
628
  adapter: declaration.adapter.identity,
@@ -672,24 +636,25 @@ async function installPlayRootAuthoring(
672
636
  }
673
637
  const mounted = world.mounted;
674
638
  if (mounted.kind === 'three') {
639
+ const scene = threeRoot(mounted).scene;
675
640
  // The presented subject uses OID identity so Edit→Play selection stays
676
641
  // continuous. A headless or non-Three host can omit presentation; its
677
642
  // mounted tree still gets an honest structural live projection.
678
643
  // `frameControl: 'host'` on the structural branch follows from the same
679
644
  // tick-ownership fact: play's own loop drives the root and this adapter
680
645
  // holds no handle that can stop it for a gesture.
681
- const isPresentedSubject = world.id === presentedWorldId && mounted.scene === store.scene;
646
+ const isPresentedSubject = world.id === presentedWorldId && scene === store.scene;
682
647
  const sourceAnchor = isPresentedSubject ? await readOidSourceAnchors() : undefined;
683
648
  if (!isCurrentGeneration()) {
684
649
  abandon();
685
650
  return;
686
651
  }
687
652
  const adapter = isPresentedSubject
688
- ? oidThree(store, mounted.scene, liveWorldId(world.id), playRunJournal(world.id), {
653
+ ? oidThree(store, scene, liveWorldId(world.id), playRunJournal(world.id), {
689
654
  explicitSourceCommit: true,
690
655
  sourceAnchor,
691
656
  })
692
- : structuralThree(store, mounted.scene, {
657
+ : structuralThree(store, scene, {
693
658
  frameControl: 'host',
694
659
  journal: playRunJournal(world.id),
695
660
  });
@@ -734,7 +699,7 @@ async function installPlayRootAuthoring(
734
699
  }
735
700
  if (mounted.substrate.name !== 'pixi') {
736
701
  const adapter = new BoundaryAuthoringAdapter(
737
- store,
702
+ store.shell,
738
703
  {
739
704
  id: world.id,
740
705
  kind: world.kind,
@@ -752,8 +717,8 @@ async function installPlayRootAuthoring(
752
717
  const stage = mounted.substrate.root as import('pixi.js').Container;
753
718
  const [physicsRegistry, physicsAdapters, pixiAuthoring, pixiWriteTarget, canvasRuntime] =
754
719
  await Promise.all([
755
- import('@volter/game-runtime/pixi/physics-registry'),
756
- import('@volter/game-runtime/pixi/system-adapters'),
720
+ import('../runtime/pixi/physics-registry'),
721
+ import('../runtime/pixi/system-adapters'),
757
722
  import('../host/authoring/pixi-authoring-adapter'),
758
723
  import('../host/authoring/pixi-live-write-target'),
759
724
  import('../host/canvas-entry-runtime'),
@@ -827,7 +792,7 @@ async function installPlayRootAuthoring(
827
792
  // the left hierarchy panel only re-checks `hasAuthoringOverride()` when the
828
793
  // store notifies (same reason `ingest/mount-ingest-root.ts` calls this right after
829
794
  // installing its own override).
830
- store.notifyIngestEdit();
795
+ store.shell.notifyIngestEdit();
831
796
 
832
797
  // Dev/e2e diagnostic handle — the SAME pattern `ingest/mount-ingest-root.ts`'s
833
798
  // `window.__vgaiIngest`/`window.__vgaiIngest2D` use:
@@ -869,7 +834,7 @@ function exitPlayRootAuthoring(store: EditorShellStore): void {
869
834
  // Play edits are session-local by architecture: nothing this run journaled
870
835
  // may still be undoable once the run is over.
871
836
  if (_instance.journalSession) {
872
- store.projectHistory?.expireSession(_instance.journalSession);
837
+ store.shell.projectHistory?.expireSession(_instance.journalSession);
873
838
  _instance.journalSession = '';
874
839
  }
875
840
  if (import.meta.env.DEV) {
@@ -1047,9 +1012,9 @@ export function bindPlayMode(store: EditorShellStore): void {
1047
1012
  // game's, and what decides is the workbench: our stage actions carry a
1048
1013
  // `when` clause over `vgai.stage.focused`/`vgai.play`, so a bare key reaches
1049
1014
  // the game rather than a shell binding, and a ⌘-chord stays the workbench's.
1050
- // The engine's own `InputManager` gate tracks the same predicate
1051
- // independently (`gated-globals.ts` and `surface-keyboard.ts`), which is what
1052
- // keeps a game's raw `window.addEventListener('keydown')` gated too.
1015
+ // The realm gate tracks the same predicate independently (`gated-globals.ts`
1016
+ // and `surface-keyboard.ts`), which is what keeps a game's raw
1017
+ // `window.addEventListener('keydown')` gated too.
1053
1018
  // The idle auto-stop needs a way to end play without `play-recording.ts`
1054
1019
  // importing the play lifecycle it is driven BY. Handed over here rather than
1055
1020
  // at module scope so the two directions of the edge stay one-way.
@@ -1063,7 +1028,7 @@ export function isPlayModeActive(): boolean {
1063
1028
  }
1064
1029
 
1065
1030
  /**
1066
- * Narrow relay accessor — the live play session's `InputManager`(s)
1031
+ * Narrow relay accessor — the live play session's virtual input targets
1067
1032
  * and the Game root's loop, for `command-listener.ts`'s
1068
1033
  * `inject-input`/`set-time-scale`/`set-seed` cases. This is exactly the
1069
1034
  * accessor the vgai-sdk honest-gap jsdocs prescribed
@@ -1073,13 +1038,7 @@ export function isPlayModeActive(): boolean {
1073
1038
  * `setActiveSystems`/`getActiveSystems` instead.
1074
1039
  *
1075
1040
  * `getInputTarget(worldId?)` (D15/T-D15.5 — review objection 2's fix)
1076
- * REPLACES what used to be a plain `input: Game['input'] | null` field —
1077
- * `Game.input` always resolves to the DEFAULT world's `InputManager` only,
1078
- * while the debug bridge's `window.__vgai.input.*` reached whichever world's
1079
- * `InputManager` last called `DebugRegistry.setVirtualInputTarget` (a
1080
- * SEPARATE, last-writer-wins slot). In a multi-world project those two could
1081
- * name DIFFERENT roots — the exact closed-PR review objection. Now both
1082
- * doors call the SAME `getDebugRegistry(game).getVirtualInputTarget(worldId)`
1041
+ * is one resolution for every input door: both the SAME `getDebugRegistry(game).getVirtualInputTarget(worldId)`
1083
1042
  * — one resolution function (`debug-registry.ts`'s `resolveInputRootId`),
1084
1043
  * so `inject-input` (this accessor) and `window.__vgai.input.*`
1085
1044
  * (`debug-bridge.ts`) can never disagree about which world an unqualified
@@ -1135,7 +1094,7 @@ export function getPlayRuntimeAccess(): {
1135
1094
  /** Get the running game's scene (for editor Scene tab rendering). */
1136
1095
  export function getGameScene(): THREE.Scene | null {
1137
1096
  const mounted = _instance.session?.game.defaultRoot.mounted;
1138
- return mounted?.kind === 'three' ? mounted.scene : null;
1097
+ return mounted?.kind === 'three' ? threeRoot(mounted).scene : null;
1139
1098
  }
1140
1099
 
1141
1100
  export interface GameRootSurfaceFact {
@@ -1152,7 +1111,7 @@ export function gameRootSurfaceFacts(): readonly GameRootSurfaceFact[] {
1152
1111
  const mounted = root.mounted;
1153
1112
  let hasRenderableContent = false;
1154
1113
  if (mounted.kind === 'three') {
1155
- hasRenderableContent = threeSceneHasRenderableContent(mounted.scene);
1114
+ hasRenderableContent = threeSceneHasRenderableContent(threeRoot(mounted).scene);
1156
1115
  } else if (mounted.kind === 'canvas') {
1157
1116
  try {
1158
1117
  hasRenderableContent =
@@ -1651,7 +1610,7 @@ async function enterPlayModeInner(
1651
1610
  editorHost().viewport.transition.begin();
1652
1611
 
1653
1612
  // setPlayState auto-switches to Game tab
1654
- store.setPlayState('playing');
1613
+ store.shell.setPlayState('playing');
1655
1614
  // THE GAME TAKES THE KEYBOARD AS PLAY STARTS. Until the player clicks the
1656
1615
  // pane, focus stays on the transport button they pressed and the hotkey
1657
1616
  // scope on the workspace — so the next Enter or Space activates that
@@ -1663,7 +1622,7 @@ async function enterPlayModeInner(
1663
1622
  editorConsole.log('Play mode started', 'play-mode');
1664
1623
  // Apply the project's adapter-declared utilities after transient Play chrome settles.
1665
1624
  editorHost().viewport.transition.onSettled(() => {
1666
- if (epoch === _playEpoch && store.playState === 'playing') revealWorkspacePlayUtilities();
1625
+ if (epoch === _playEpoch && store.shell.playState === 'playing') revealWorkspacePlayUtilities();
1667
1626
  });
1668
1627
 
1669
1628
  // WHAT THIS BOOT CREATED, BEFORE ANYTHING ELSE CAN REACH IT. `_instance.id`
@@ -1746,7 +1705,7 @@ async function enterPlayModeInner(
1746
1705
  // MEASURED at N=20000: the block that ate three command budgets started
1747
1706
  // here and ran for 199.5s with nothing anywhere able to name it.
1748
1707
  markPlayBootPhase('mounting the runtime roots');
1749
- const { mountManifestRoots } = await import('@volter/game-runtime/runtime/mount-manifest');
1708
+ const { mountManifestRoots } = await import('../runtime/mount-manifest');
1750
1709
  session = await mountManifestRoots({
1751
1710
  manifest,
1752
1711
  container: gameContainer,
@@ -1818,7 +1777,7 @@ async function enterPlayModeInner(
1818
1777
  }
1819
1778
  notifySessionListeners();
1820
1779
  // D19: play edits are session-local regardless of world count.
1821
- store.setPlayEditRegime('ephemeral');
1780
+ store.shell.setPlayEditRegime('ephemeral');
1822
1781
 
1823
1782
  // Swap store to game scene so hierarchy/inspector show game entities.
1824
1783
  // liveHierarchy: first-party play mode is the ONLY adoption path that may
@@ -1828,7 +1787,7 @@ async function enterPlayModeInner(
1828
1787
  // are the whole layout), Play still adopts its roots, so the hierarchy door and every
1829
1788
  // inspector reach the live objects exactly as they do beside a Scene tab.
1830
1789
  _instance.presentation =
1831
- editorHost().viewport.presentRoots(session.game.roots) ??
1790
+ presentViewportRoots(session.game.roots) ??
1832
1791
  presentThreeRoots(store, session.game.roots);
1833
1792
  markPlayBootPhase('installing play authoring for each root');
1834
1793
  await installPlayRootAuthoring(
@@ -1878,8 +1837,7 @@ async function enterPlayModeInner(
1878
1837
  }) ?? null;
1879
1838
 
1880
1839
  // T6.3: gate game input (raw `window`/`document` listeners in game code via
1881
- // gated-globals, AND the default world's first-party InputManager) to only
1882
- // fire while play is actually running AND the Game tab is the focused
1840
+ // gated-globals) to only fire while play is actually running AND the Game tab is the focused
1883
1841
  // viewport — so keystrokes typed into the editor (Scene tab, inspector
1884
1842
  // fields) don't leak into the running game.
1885
1843
  // The gate is FOCUS-AWARE (`instanceInputActive`): input flows only while
@@ -1892,19 +1850,10 @@ async function enterPlayModeInner(
1892
1850
  // the modules find the default realm's gate instead of their own.
1893
1851
  setGameInputGate(() => instanceInputActive(mountId), mountId);
1894
1852
  // THE DEFAULT REALM follows the focused instance too. Module-lifetime code
1895
- // that no mount id reaches lives there — a game's own `InputManager`
1896
- // (`@volter/game-runtime`'s input, served through the realm shadow) — and
1897
- // the stop path leaves it open, so a key aimed at a Model document while
1898
- // the game played still reached it.
1853
+ // that no mount id reaches lives there — a game's own input store,
1854
+ // attached at module load — and the stop path leaves it open, so a key
1855
+ // aimed at a Model document while the game played still reached it.
1899
1856
  setGameInputGate(() => instanceInputActive(focusedInstanceId()));
1900
- // Sync EVERY live instance's first-party InputManager from the play/tab/
1901
- // focus predicate whenever the store changes (a tab switch flips the active
1902
- // viewport for all of them). `resyncInstanceInputs` resolves each
1903
- // instance's `game.input` defensively — a session whose game handle has no
1904
- // first-party InputManager (an ingest mount, a partial double) has only the
1905
- // raw window/document gate above.
1906
- resyncInstanceInputs();
1907
- _unsubStore = store.subscribe(resyncInstanceInputs);
1908
1857
 
1909
1858
  // Node-id keyed only: `setEcsSyncTransform` hands this an editor node id
1910
1859
  // and a THREE `Transform`, which a display-keyed carrier has no values for.
@@ -2019,7 +1968,7 @@ export async function mountAdditionalInstance(
2019
1968
  }
2020
1969
  markGameCssScope(container);
2021
1970
  setGameSurface(container, mountId);
2022
- const { mountManifestRoots } = await import('@volter/game-runtime/runtime/mount-manifest');
1971
+ const { mountManifestRoots } = await import('../runtime/mount-manifest');
2023
1972
  const session = await mountManifestRoots({
2024
1973
  manifest,
2025
1974
  container,
@@ -2070,15 +2019,12 @@ export async function mountAdditionalInstance(
2070
2019
  }) ?? null;
2071
2020
  // FOCUS-AWARE input, exactly like the primary: this instance takes the shared
2072
2021
  // keyboard only while it holds focus. It mounts UNFOCUSED (the primary keeps
2073
- // focus), so its gate is closed and its InputManager is disabled until a click
2022
+ // focus), so its gate is closed until a click
2074
2023
  // on its viewport routes focus here (`setFocusedInstance`). This is what stops
2075
2024
  // the pre-focus bug where every seat took the same keystroke, AND what lets
2076
2025
  // you drive a chosen seat manually rather than only via autoplay.
2077
2026
  setGameInputGate(() => instanceInputActive(mountId), mountId);
2078
2027
  _additional.push(inst);
2079
- // Now that it is in `_additional`, sync its (and every) InputManager to the
2080
- // current focus — disabled here, since the primary is focused.
2081
- resyncInstanceInputs();
2082
2028
 
2083
2029
  // `setActiveSystems` moved editor focus (`getActiveSystems`) onto the newer
2084
2030
  // mount. The user is still authoring the PRIMARY, so restore its focus
@@ -2153,11 +2099,10 @@ export function unmountAdditionalInstance(id: string): void {
2153
2099
  inst.container = null;
2154
2100
  inst.session = null;
2155
2101
  // If the removed instance held keyboard focus, focus falls back to the primary
2156
- // (`focusedInstanceId` already resolves a stale id to it); re-sync so the
2157
- // primary's InputManager re-enables, and notify the viewport highlight.
2102
+ // (`focusedInstanceId` already resolves a stale id to it); notify the
2103
+ // viewport highlight.
2158
2104
  if (_focusedInstanceId === id) {
2159
2105
  _focusedInstanceId = null;
2160
- resyncInstanceInputs();
2161
2106
  notifyFocusedInstance();
2162
2107
  }
2163
2108
  notifySessionListeners();
@@ -2310,7 +2255,7 @@ export function exitPlayMode(): void {
2310
2255
  exitPlayRootAuthoring(store);
2311
2256
  restorePriorAuthoring();
2312
2257
  // Readout-only — clear the regime the moment play is no longer active.
2313
- store.setPlayEditRegime(null);
2258
+ store.shell.setPlayEditRegime(null);
2314
2259
 
2315
2260
  // Always null _instance.session even if stop() throws — otherwise enterPlayMode's
2316
2261
  // `if (_instance.session) return` guard would permanently block re-entering play mode.
@@ -2339,11 +2284,9 @@ export function exitPlayMode(): void {
2339
2284
  _hostMountedReadyRootIds = [];
2340
2285
 
2341
2286
  // Cleanup subscriptions
2342
- _unsubStore?.();
2343
- _unsubStore = null;
2344
2287
 
2345
- // T6.3: no game running — game input (raw window/document listeners AND the
2346
- // InputManager sync above) should never be suppressed again until the next
2288
+ // T6.3: no game running — game input (raw window/document listeners) should
2289
+ // never be suppressed again until the next
2347
2290
  // play session re-gates it. The mount's own gate is DROPPED rather than set
2348
2291
  // to always-true: its id is never reused, so overwriting would retain one
2349
2292
  // dead closure per play run.
@@ -2392,7 +2335,7 @@ export function exitPlayMode(): void {
2392
2335
  // that FAILED before ever flipping the store to 'playing' never produces
2393
2336
  // that edge, so release directly too — `releaseGameDocument` is the one
2394
2337
  // idempotent teardown path either way (`game-document.ts`).
2395
- store.setPlayState('stopped');
2338
+ store.shell.setPlayState('stopped');
2396
2339
  editorHost().workspace.liveDocument.release();
2397
2340
  // LAST — the run's error window closes only once teardown is done, so every
2398
2341
  // error this teardown itself logged still belongs to the run that caused it
@@ -2417,7 +2360,7 @@ export function pausePlayMode(): void {
2417
2360
  // Freeze EVERY seat, not just the primary — a paused split with the extras
2418
2361
  // still ticking is not paused.
2419
2362
  for (const inst of allLiveInstances()) inst.session?.pause();
2420
- _ctx.store.setPlayState('paused');
2363
+ _ctx.store.shell.setPlayState('paused');
2421
2364
 
2422
2365
  editorConsole.log('Play mode paused', 'play-mode');
2423
2366
  }
@@ -2429,7 +2372,7 @@ export function resumePlayMode(): void {
2429
2372
  if (!_instance.session || !_ctx) return;
2430
2373
 
2431
2374
  for (const inst of allLiveInstances()) inst.session?.resume();
2432
- _ctx.store.setPlayState('playing');
2375
+ _ctx.store.shell.setPlayState('playing');
2433
2376
 
2434
2377
  editorConsole.log('Play mode resumed', 'play-mode');
2435
2378
  }
@@ -37,7 +37,7 @@
37
37
  * recorder's stream never sees, so nothing about the evidence changes.
38
38
  */
39
39
 
40
- import { isRootCanvas } from '@volter/editor-core/composite-screenshot';
40
+ import { isRootCanvas } from '@volter/editor-sdk/kit/composite-screenshot';
41
41
  import { editorConsole } from '@volter/editor-sdk/kit/editor-console';
42
42
  import {
43
43
  type GameplayRecordingCapture,
@@ -44,8 +44,8 @@
44
44
  * three gizmo drag during play. That is the regime, not a defect.
45
45
  */
46
46
 
47
- import type { EditorShellStore } from '@volter/editor-core/editor-shell-store';
48
- import type { SourceWriteBackend } from '@volter/editor-core/ui-source/source-write-backend';
47
+ import type { EditorShellStore } from '@volter/editor-threejs/kit/editor-shell-store';
48
+ import type { SourceWriteBackend } from '@volter/editor-sdk/kit/ui-source/source-write-backend';
49
49
  import {
50
50
  type OidElementLike,
51
51
  ReactRootAuthoringAdapter,
@@ -158,7 +158,7 @@ export function createReactPlayAuthoringAdapter(
158
158
  root: OidElementLike,
159
159
  store: EditorShellStore,
160
160
  ): ReactRootAuthoringAdapter {
161
- return new ReactRootAuthoringAdapter(root, store, {
161
+ return new ReactRootAuthoringAdapter(root, store.shell, {
162
162
  writeBackend: createEphemeralDomWriteBackend(root),
163
163
  provenance: EPHEMERAL_DOM_PROVENANCE,
164
164
  });