@vgai/editor 0.2.0 → 0.4.0-canary.20260715.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (430) hide show
  1. package/README.md +24 -0
  2. package/dist/assets/axe-C7YBtOuM.js +30 -0
  3. package/dist/assets/browserAll-DDtGGE48.js +1 -0
  4. package/dist/assets/create-runtime-DbTlBlKG.js +1 -0
  5. package/dist/assets/{game-BI111o5f.js → game-BE0r7DMI.js} +3 -3
  6. package/dist/assets/game-BdTHR2_X.js +1 -0
  7. package/dist/assets/{game-pt_1lQLv.js → game-C3iQGSqo.js} +1 -1
  8. package/dist/assets/game-CcHfYxjP.js +1 -0
  9. package/dist/assets/game-Cqzj_lpD.js +1 -0
  10. package/dist/assets/game-DSZdeCHu.js +1 -0
  11. package/dist/assets/game-Dch9sAPc.js +1 -0
  12. package/dist/assets/{game-xsOho_wg.js → game-SAFn90pA.js} +3 -3
  13. package/dist/assets/game-loop-DMIgSMV-.js +1 -0
  14. package/dist/assets/{game-source-CvidN7AB.js → game-source-Dk83w26t.js} +1 -1
  15. package/dist/assets/{index-Bp5cecD6.js → index-4idIsHHJ.js} +2 -2
  16. package/dist/assets/{index-DL7RcQ0n.js → index-C-LhOTBN.js} +1 -1
  17. package/dist/assets/{index-Cs8xwv3e.js → index-CDkxceqE.js} +1 -1
  18. package/dist/assets/index-CQEfi217.js +15412 -0
  19. package/dist/assets/index-Dvi-V0NE.css +1 -0
  20. package/dist/assets/ingest-siblings-s0P5I1Ub.js +1 -0
  21. package/dist/assets/mount-manifest-DXMOlF79.js +1 -0
  22. package/dist/assets/react-18-C9eHn8x1.js +1 -0
  23. package/dist/assets/webworkerAll-Fn0e-ouF.js +1 -0
  24. package/dist/assets/world-documents-GM0a9Kv7.js +1 -0
  25. package/dist/index.html +15 -13
  26. package/dist/ingest/racing-game/vgai.game.json +5 -4
  27. package/dist/ingest/simcity/vgai.game.json +5 -4
  28. package/dist/ingest/tanks/vgai.game.json +5 -4
  29. package/dist/project-scripts.bundle.js +3917 -0
  30. package/dist/scenes/untitled.vscn.json +2 -0
  31. package/dist-server/packaged.mjs +7697 -3435
  32. package/package.json +31 -4
  33. package/scripts/probe-reporter.ts +349 -0
  34. package/scripts/run-probe.ts +2260 -0
  35. package/server/asset-catalog-audit.ts +268 -0
  36. package/server/asset-catalog-v2.ts +146 -0
  37. package/server/asset-library-routes.ts +276 -58
  38. package/server/canonical-path.ts +1 -1
  39. package/server/dev.ts +148 -44
  40. package/server/editor-server.ts +888 -61
  41. package/server/editor-sse.ts +115 -4
  42. package/server/harness-chat-service.ts +796 -0
  43. package/server/local-asset-catalog.ts +157 -22
  44. package/server/packaged.ts +51 -21
  45. package/server/process-shutdown.ts +136 -0
  46. package/server/prod.ts +9 -6
  47. package/server/project-hmr-files.ts +41 -0
  48. package/server/project-operations.ts +343 -0
  49. package/server/project-optimize-deps-entries.ts +4 -4
  50. package/server/project-output-writer.ts +156 -0
  51. package/server/project-validation.ts +140 -0
  52. package/server/project-view.ts +8 -50
  53. package/server/server-utils.ts +75 -10
  54. package/server/session-registry.ts +12 -0
  55. package/src/EditorContext.tsx +107 -3
  56. package/src/action-registry.ts +115 -17
  57. package/src/adapter-resolver.ts +213 -478
  58. package/src/asset-events.ts +64 -1
  59. package/src/asset-preview.ts +906 -0
  60. package/src/asset-selection.ts +121 -0
  61. package/src/asset-workflow/asset-capabilities.ts +259 -0
  62. package/src/asset-workflow/asset-editor-errors.ts +46 -0
  63. package/src/asset-workflow/asset-import-pipeline.ts +176 -0
  64. package/src/asset-workflow/asset-library-query.ts +107 -0
  65. package/src/asset-workflow/asset-types.ts +192 -0
  66. package/src/asset-workflow/asset-workflow-quality.ts +65 -0
  67. package/src/asset-workflow/import-contract.ts +113 -0
  68. package/src/asset-workflow/model-conversion.ts +126 -0
  69. package/src/asset-workflow/model-inspection.ts +185 -0
  70. package/src/asset-workflow/project-asset-commands.ts +23 -0
  71. package/src/asset-workflow/project-asset-health.ts +153 -0
  72. package/src/asset-workflow/project-asset-operations.ts +119 -0
  73. package/src/asset-workflow/thumbnail-system.ts +172 -0
  74. package/src/authoring/active-systems.ts +15 -0
  75. package/src/authoring/boundary-authoring-adapter.ts +16 -5
  76. package/src/authoring/composite-authoring-adapter.ts +305 -124
  77. package/src/authoring/design-time-layers.ts +300 -117
  78. package/src/authoring/edit-mode-authoring.ts +278 -293
  79. package/src/authoring/embed-only-adapter.ts +4 -2
  80. package/src/authoring/first-party-hierarchy-menu.ts +7 -2
  81. package/src/authoring/first-party-inspector/AddSectionMenu.tsx +5 -12
  82. package/src/authoring/first-party-inspector/EnvironmentSection.tsx +53 -126
  83. package/src/authoring/first-party-inspector/HeaderSection.tsx +54 -65
  84. package/src/authoring/first-party-inspector/is-first-party-selection.ts +30 -11
  85. package/src/authoring/first-party-inspector/register.tsx +13 -2
  86. package/src/authoring/ingest-authoring-adapter.ts +142 -45
  87. package/src/authoring/mount-failure-report.ts +5 -5
  88. package/src/authoring/provenance.ts +41 -0
  89. package/src/authoring/react-dom-authoring-adapter.ts +92 -92
  90. package/src/authoring/react-inspector-section.tsx +489 -51
  91. package/src/authoring/react-world-authoring-adapter.ts +541 -306
  92. package/src/authoring/story-overlay.ts +1 -1
  93. package/src/authoring/story-types.ts +11 -0
  94. package/src/authoring/vgai-scene-authoring-adapter.ts +54 -25
  95. package/src/authoring/viewport-tool-context.ts +78 -0
  96. package/src/authoring/world-canvas-viewport-state.ts +35 -0
  97. package/src/authoring/world-hidden-viewport.ts +186 -0
  98. package/src/authoring/world-pan-state.ts +33 -17
  99. package/src/authoring/world-session-state.ts +1 -1
  100. package/src/authoring/world2d-authoring-adapter.ts +109 -52
  101. package/src/availability-tick.ts +56 -0
  102. package/src/browser-play-entry.ts +5 -5
  103. package/src/browser-project-scripts.ts +1 -0
  104. package/src/build-identity.ts +15 -0
  105. package/src/command-listener.ts +893 -19
  106. package/src/components/AlignToolbar.tsx +74 -63
  107. package/src/components/AppRoot.tsx +193 -26
  108. package/src/components/ApplicationMenus.tsx +272 -0
  109. package/src/components/AssetBrowser.tsx +1450 -293
  110. package/src/components/AssetEditorShell.tsx +141 -0
  111. package/src/components/AssetImportDetails.tsx +218 -0
  112. package/src/components/AssetLibraryPanel.tsx +14 -0
  113. package/src/components/CameraInfo.tsx +11 -20
  114. package/src/components/CenterDocuments.tsx +585 -0
  115. package/src/components/CommandPalette.tsx +75 -30
  116. package/src/components/ConsolePanel.css +55 -0
  117. package/src/components/ConsolePanel.tsx +57 -112
  118. package/src/components/DebugConsolePanel.tsx +461 -0
  119. package/src/components/DebuggerPanel.tsx +165 -0
  120. package/src/components/DefaultEditorLayout.tsx +167 -231
  121. package/src/components/GameHierarchy.tsx +873 -290
  122. package/src/components/GamePerformanceOverlay.tsx +46 -0
  123. package/src/components/HarnessChatPanel.tsx +2352 -0
  124. package/src/components/HistoryPanel.tsx +226 -0
  125. package/src/components/Inspector.tsx +153 -99
  126. package/src/components/InspectorToolSection.tsx +6 -4
  127. package/src/components/MountFailureBanner.tsx +31 -48
  128. package/src/components/NetworkSection.tsx +25 -14
  129. package/src/components/OnlineAssetBrowser.tsx +794 -343
  130. package/src/components/OverlayReportBanner.tsx +38 -64
  131. package/src/components/PerformancePanel.tsx +206 -0
  132. package/src/components/PlayBar.tsx +93 -263
  133. package/src/components/PrefabSaveDialog.tsx +55 -127
  134. package/src/components/ProjectHeader.css +60 -0
  135. package/src/components/ProjectHeader.tsx +170 -105
  136. package/src/components/ProjectScreen.tsx +246 -184
  137. package/src/components/ReactCanvasControls.tsx +185 -0
  138. package/src/components/ResolutionPicker.tsx +85 -0
  139. package/src/components/RootActivateDialog.tsx +39 -68
  140. package/src/components/SaveDialog.tsx +55 -127
  141. package/src/components/SaveStatus.tsx +11 -29
  142. package/src/components/StartupLoadingScreen.tsx +96 -0
  143. package/src/components/StateWatchPanel.tsx +302 -0
  144. package/src/components/StatsOverlay.tsx +12 -5
  145. package/src/components/StatusBar.tsx +64 -0
  146. package/src/components/ThemeManagerDialog.css +89 -0
  147. package/src/components/ThemeManagerDialog.tsx +371 -0
  148. package/src/components/ToolHost.tsx +26 -15
  149. package/src/components/Toolbar.tsx +117 -214
  150. package/src/components/VgaiVoxelLogo.tsx +89 -0
  151. package/src/components/ViewportOverlay.tsx +97 -172
  152. package/src/components/ViewportPanel.tsx +130 -31
  153. package/src/components/WorkspaceDock.tsx +891 -0
  154. package/src/components/WorldSelectionOverlay.tsx +51 -63
  155. package/src/components/WorldTextEditor.tsx +9 -5
  156. package/src/components/asset-documents.tsx +390 -0
  157. package/src/components/asset-editor-persistence.ts +44 -0
  158. package/src/components/asset-selection-section.tsx +338 -0
  159. package/src/components/asset-viewers/AudioViewer.tsx +73 -21
  160. package/src/components/asset-viewers/GenericJsonViewer.tsx +26 -11
  161. package/src/components/asset-viewers/ImageViewer.tsx +43 -11
  162. package/src/components/asset-viewers/InputMapViewer.tsx +512 -134
  163. package/src/components/asset-viewers/MaterialAssetEditor.tsx +540 -0
  164. package/src/components/asset-viewers/ModelViewer.tsx +805 -121
  165. package/src/components/asset-viewers/OnlineAssetDetail.tsx +177 -60
  166. package/src/components/asset-viewers/SourceAssetViewer.tsx +121 -0
  167. package/src/components/asset-workflow.css +506 -0
  168. package/src/components/build-documents.tsx +696 -0
  169. package/src/components/core-utilities.tsx +75 -0
  170. package/src/components/data-documents.tsx +364 -0
  171. package/src/components/{DataPanel.tsx → data-editor.tsx} +138 -288
  172. package/src/components/debugger-panel-state.ts +57 -0
  173. package/src/components/inspector-widgets/AlignmentGrid.tsx +8 -14
  174. package/src/components/inspector-widgets/BorderEditor.tsx +41 -33
  175. package/src/components/inspector-widgets/ColorPicker.tsx +39 -39
  176. package/src/components/inspector-widgets/FontPicker.tsx +13 -21
  177. package/src/components/inspector-widgets/GradientEditor.tsx +11 -19
  178. package/src/components/inspector-widgets/ScrubbableInput.tsx +6 -3
  179. package/src/components/inspector-widgets/ShadowEditor.tsx +20 -33
  180. package/src/components/inspector-widgets/shared.tsx +90 -49
  181. package/src/components/inspectors/AnimationSection.tsx +39 -40
  182. package/src/components/inspectors/AudioSection.tsx +28 -39
  183. package/src/components/inspectors/BoneAttachmentSection.tsx +19 -24
  184. package/src/components/inspectors/CameraSection.tsx +14 -23
  185. package/src/components/inspectors/ComponentsSection.tsx +39 -43
  186. package/src/components/inspectors/JointsSection.tsx +34 -43
  187. package/src/components/inspectors/LightSection.tsx +90 -35
  188. package/src/components/inspectors/MaterialSection.tsx +137 -174
  189. package/src/components/inspectors/MeshSection.tsx +9 -17
  190. package/src/components/inspectors/NavigationSection.tsx +8 -15
  191. package/src/components/inspectors/ParticleSection.tsx +91 -76
  192. package/src/components/inspectors/PhysicsSection.tsx +42 -46
  193. package/src/components/inspectors/PostProcessingSection.tsx +28 -36
  194. package/src/components/inspectors/RenderingSection.tsx +12 -20
  195. package/src/components/inspectors/ShadowSection.tsx +7 -8
  196. package/src/components/inspectors/SplineSection.tsx +31 -42
  197. package/src/components/inspectors/TransformSection.tsx +14 -22
  198. package/src/components/patterns/Dialog.tsx +95 -0
  199. package/src/components/patterns/Fields.tsx +44 -0
  200. package/src/components/patterns/List.tsx +25 -0
  201. package/src/components/patterns/StateSurface.tsx +40 -0
  202. package/src/components/patterns/Surfaces.tsx +115 -0
  203. package/src/components/patterns/Tabs.tsx +80 -0
  204. package/src/components/patterns/Toolbar.tsx +51 -0
  205. package/src/components/patterns/Tree.tsx +72 -0
  206. package/src/components/primitives/Button.tsx +46 -0
  207. package/src/components/primitives/ColorInput.tsx +11 -47
  208. package/src/components/primitives/EditorIcon.tsx +99 -0
  209. package/src/components/primitives/FormControls.tsx +71 -0
  210. package/src/components/primitives/JsonInput.tsx +15 -2
  211. package/src/components/primitives/Layout.tsx +100 -0
  212. package/src/components/primitives/Menu.tsx +105 -0
  213. package/src/components/primitives/NumberInput.tsx +8 -35
  214. package/src/components/primitives/Panel.tsx +49 -44
  215. package/src/components/primitives/SectionHeader.tsx +10 -28
  216. package/src/components/primitives/Text.tsx +46 -0
  217. package/src/components/primitives/Tooltip.tsx +20 -12
  218. package/src/components/primitives/Vec3Input.tsx +3 -0
  219. package/src/components/primitives/banner-tones.ts +33 -0
  220. package/src/components/primitives/editor-icons.ts +102 -0
  221. package/src/components/primitives/panel-header-styles.ts +30 -0
  222. package/src/components/project-operation-documents.tsx +226 -0
  223. package/src/components/status-contributions.tsx +175 -0
  224. package/src/components/story-documents-register.ts +15 -0
  225. package/src/components/story-documents.tsx +1185 -0
  226. package/src/components/tool-documents.tsx +110 -0
  227. package/src/components/workspace-dock.css +293 -0
  228. package/src/components/workspace-history.ts +33 -0
  229. package/src/components/world-documents.tsx +145 -0
  230. package/src/components/xstate-documents.tsx +209 -0
  231. package/src/composite-screenshot.ts +248 -0
  232. package/src/design-system/index.ts +70 -0
  233. package/src/design-system-stories/Foundation.stories.tsx +183 -0
  234. package/src/design-system-stories/Patterns.stories.tsx +251 -0
  235. package/src/design-system-stories/Workspace.stories.tsx +538 -0
  236. package/src/doctor/report.ts +57 -13
  237. package/src/editor-api.ts +295 -31
  238. package/src/editor-compatibility.ts +200 -0
  239. package/src/editor-console.ts +35 -17
  240. package/src/editor-hotkeys.ts +85 -33
  241. package/src/editor-store.ts +538 -233
  242. package/src/editor-viewport.ts +160 -34
  243. package/src/entity-factory.ts +14 -3
  244. package/src/gizmo-registry.ts +21 -5
  245. package/src/harness-chat-editor-context.ts +37 -0
  246. package/src/harness-chat-indicator.ts +68 -0
  247. package/src/harness-chat-layout.ts +53 -0
  248. package/src/harness-chat-lifecycle.ts +170 -0
  249. package/src/harness-chat-reconnect.ts +85 -0
  250. package/src/harness-chat-types.ts +409 -0
  251. package/src/hierarchy-drop.ts +50 -0
  252. package/src/hierarchy-expansion-state.ts +100 -0
  253. package/src/hierarchy-menu-registry.ts +1 -1
  254. package/src/hierarchy-projection.ts +76 -0
  255. package/src/history/editor-session.ts +21 -0
  256. package/src/history/history-commands.ts +147 -0
  257. package/src/history/history-service.ts +904 -0
  258. package/src/history/json-history-resource.ts +165 -0
  259. package/src/history/persistence-coordinator.ts +35 -0
  260. package/src/history/project-file-history.ts +266 -0
  261. package/src/history/project-root-history-backends.ts +53 -0
  262. package/src/history/resource-registry.ts +209 -0
  263. package/src/history/snapshot-store.ts +108 -0
  264. package/src/history/source-history-backend.ts +374 -0
  265. package/src/history/types.ts +100 -0
  266. package/src/hmr-registration-group.ts +67 -0
  267. package/src/hmr-stable-react-context.ts +23 -0
  268. package/src/hosted-example.ts +12 -2
  269. package/src/hotkeys.ts +89 -18
  270. package/src/ingest/discovery-react.ts +9 -10
  271. package/src/ingest/discovery.ts +4 -4
  272. package/src/ingest/discovery2d.ts +5 -5
  273. package/src/ingest/games/bloom-composer/vgai.game.json +3 -3
  274. package/src/ingest/games/embed-bundle/vgai.game.json +3 -3
  275. package/src/ingest/games/games-fps/vgai.game.json +3 -3
  276. package/src/ingest/games/iframe-reachable/vgai.game.json +3 -3
  277. package/src/ingest/games/interactive-cubes/vgai.game.json +3 -3
  278. package/src/ingest/games/mismatched-three/vgai.game.json +3 -3
  279. package/src/ingest/games/own-three-bundled/vgai.game.json +3 -3
  280. package/src/ingest/games/pointerlock-maze/vgai.game.json +7 -4
  281. package/src/ingest/games-2d/bubbo-bubbo/vgai.game.json +3 -3
  282. package/src/ingest/games-2d/bunnymark/vgai.game.json +3 -3
  283. package/src/ingest/games-2d/flappy/vgai.game.json +3 -3
  284. package/src/ingest/games-2d/flappy-pixi/vgai.game.json +3 -3
  285. package/src/ingest/games-2d/puzzling-potions/vgai.game.json +3 -3
  286. package/src/ingest/games-2d/tilemap-camera/vgai.game.json +3 -3
  287. package/src/ingest/games-react/react-rpg/vgai.game.json +3 -3
  288. package/src/ingest/types.ts +1 -1
  289. package/src/ingest-mode.ts +47 -52
  290. package/src/ingest-siblings.ts +23 -33
  291. package/src/initial-scene.ts +1 -2
  292. package/src/main.tsx +16 -8
  293. package/src/manifest-project.ts +10 -12
  294. package/src/model-thumbnail.ts +261 -26
  295. package/src/module-mode.ts +44 -50
  296. package/src/play-log-events.ts +26 -0
  297. package/src/play-mode.ts +495 -401
  298. package/src/play-scene-adoption.ts +23 -0
  299. package/src/playground/main.ts +68 -24
  300. package/src/playwright-shim.ts +473 -0
  301. package/src/project-manager.ts +90 -10
  302. package/src/project-operations.ts +112 -0
  303. package/src/project-story-discovery.ts +25 -0
  304. package/src/project-tool-discovery.ts +43 -0
  305. package/src/scene-serializer.ts +0 -6
  306. package/src/scene-sync.ts +7 -2
  307. package/src/script-loader.ts +3 -3
  308. package/src/skeleton-helper.ts +57 -0
  309. package/src/storage/seed.ts +68 -8
  310. package/src/stories/StoryPreviewMount.tsx +265 -0
  311. package/src/stories/action-stories.fixture.tsx +44 -0
  312. package/src/stories/button-stories.fixture.tsx +50 -0
  313. package/src/stories/compose-project-stories.ts +182 -0
  314. package/src/stories/loader-stories.fixture.tsx +53 -0
  315. package/src/stories/story-discovery.ts +130 -0
  316. package/src/stories/story-registry.ts +146 -0
  317. package/src/theme-css.ts +1049 -0
  318. package/src/theme-library.ts +238 -0
  319. package/src/theme-preference.ts +130 -0
  320. package/src/theme.ts +527 -0
  321. package/src/tool-loader.ts +80 -24
  322. package/src/ui-source/inspect.ts +27 -4
  323. package/src/ui-source/source-write-backend.ts +83 -22
  324. package/src/widgets/index.ts +9 -18
  325. package/src/workspace-aux-commands.ts +11 -0
  326. package/src/workspace-dock-controller.ts +64 -0
  327. package/src/workspace-document-ids.ts +5 -0
  328. package/src/workspace-document-registry.ts +367 -0
  329. package/src/workspace-state-persistence.ts +455 -0
  330. package/src/workspace-status-registry.ts +110 -0
  331. package/src/workspace-utility-commands.ts +49 -0
  332. package/src/workspace-utility-registry.ts +161 -0
  333. package/src/world-document-routing.ts +16 -0
  334. package/src/xstate-inspect/XStateMachineInspector.tsx +544 -0
  335. package/src/xstate-inspect/character-animation-machine.fixture.ts +74 -0
  336. package/src/xstate-inspect/use-live-actor-state.ts +39 -0
  337. package/src/xstate-inspect/xstate-graph.ts +265 -0
  338. package/src/xstate-inspect/xstate-layout.ts +76 -0
  339. package/src/z-index.ts +26 -0
  340. package/template/.claude/skills/editor/SKILL.md +129 -90
  341. package/template/AGENTS.md +1110 -0
  342. package/template/CLAUDE.md +1 -512
  343. package/template/IDIOMS.md +50 -0
  344. package/template/check-idioms.ts +706 -0
  345. package/template/manifest-entry-modules-plugin.ts +53 -0
  346. package/template/package.json +13 -4
  347. package/template/public/scenes/default.scn2d.json +6 -0
  348. package/template/public/scenes/default.vscn.json +7 -1
  349. package/template/public/scenes/untitled.vscn.json +10 -0
  350. package/template/scripts/playtest.ts +40 -0
  351. package/template/server/loopback.ts +75 -0
  352. package/template/server/rooms/arena-room.ts +69 -1
  353. package/template/server/rooms/game-room.ts +68 -1
  354. package/template/src/data/README.md +9 -4
  355. package/template/src/data/data-ref.ts +35 -0
  356. package/template/src/data/tuning.schema.ts +1 -1
  357. package/template/src/main.ts +41 -62
  358. package/template/src/manifest-entry-modules.d.ts +3 -0
  359. package/template/src/operations/README.md +88 -0
  360. package/template/src/runtime/pixi-adapter.ts +24 -0
  361. package/template/src/scripts/components/data-spinner.ts +43 -2
  362. package/template/src/scripts/components/spin-lap-math.ts +27 -0
  363. package/template/src/tools/README.md +5 -3
  364. package/template/src/tools/example.tool.tsx +13 -7
  365. package/template/src/ui/Button.stories.tsx +66 -0
  366. package/template/src/ui/RebindPanel.tsx +2 -6
  367. package/template/src/ui/game.tsx +17 -0
  368. package/template/tests/acceptance/example.spec.ts +64 -0
  369. package/template/tests/logic/example.test.ts +31 -0
  370. package/template/tests/logic/room.test.ts +100 -0
  371. package/template/tests/tsconfig.json +30 -0
  372. package/template/validate-manifest.ts +5 -5
  373. package/template/validate-scenes.ts +50 -18
  374. package/template/vgai.game.json +20 -13
  375. package/template/vite.config.ts +77 -16
  376. package/vite-plugin-ui-oid.ts +261 -17
  377. package/dist/assets/CCDIKSolver-Dz-ysxZF.js +0 -1
  378. package/dist/assets/SelectionBox-BXsv_6aH.js +0 -1
  379. package/dist/assets/browser-project-scripts-DOru4L1x.js +0 -2
  380. package/dist/assets/browserAll-CEkWYlFk.js +0 -1
  381. package/dist/assets/create-runtime-DYIWr3va.js +0 -1
  382. package/dist/assets/data-asset-Bb9sIM7i.js +0 -5
  383. package/dist/assets/game-8SDZPPgH.js +0 -1
  384. package/dist/assets/game-CevorxyV.js +0 -1
  385. package/dist/assets/game-Di7XlywD.js +0 -1
  386. package/dist/assets/game-DjnCaw8R.js +0 -1
  387. package/dist/assets/game-Q9A0aXSV.js +0 -1
  388. package/dist/assets/index-CPVV6pjw.js +0 -1
  389. package/dist/assets/index-CpOnYyeD.js +0 -213
  390. package/dist/assets/index-Dr8H_6Rl.js +0 -1
  391. package/dist/assets/index-_bCaipUk.js +0 -13650
  392. package/dist/assets/ingest-siblings-Dz8eEqrV.js +0 -1
  393. package/dist/assets/mount-manifest-Bhk0ohsl.js +0 -1
  394. package/dist/assets/scene-query-BivAHhJu.js +0 -1
  395. package/dist/assets/webworkerAll-BLrH0F6F.js +0 -1
  396. package/dist/assets/xstate-animation-binding-1NGLmw6y.js +0 -1
  397. package/dist/assets/xstate.esm-BgUD33nl.js +0 -3
  398. package/src/authoring/scene-ui-layer.ts +0 -485
  399. package/src/authoring/ui-authoring-adapter.ts +0 -325
  400. package/src/authoring/ui-hierarchy-menu.ts +0 -40
  401. package/src/authoring/ui-inspector-sections.tsx +0 -156
  402. package/src/authoring/undo-timeline.ts +0 -145
  403. package/src/components/BottomPanel.tsx +0 -326
  404. package/src/components/BuildPanel.tsx +0 -455
  405. package/src/components/FolderTree.tsx +0 -179
  406. package/src/components/RightPanel.tsx +0 -166
  407. package/src/components/WorldContextMenu.tsx +0 -257
  408. package/src/components/asset-viewers/AssetViewer.tsx +0 -38
  409. package/src/ingest/games-react/react-rpg/src/ui/game-state.tsx +0 -129
  410. package/src/scene-ui-mode/active-scene-ui.ts +0 -58
  411. package/src/scene-ui-mode/scene-ui-palette-panel.tsx +0 -152
  412. package/src/scene-ui-mode/scene-ui-timeline-tab.tsx +0 -29
  413. package/src/scene-ui-mode/ui-prefab-dialog-host.tsx +0 -74
  414. package/src/scene-ui-mode/ui-prefab-hierarchy-menu.ts +0 -49
  415. package/src/scene-ui-mode/ui-prefab-io.ts +0 -76
  416. package/src/ui-editor/inspector.tsx +0 -563
  417. package/src/ui-editor/node-ops.ts +0 -266
  418. package/src/ui-editor/overlay.tsx +0 -380
  419. package/src/ui-editor/palette.tsx +0 -114
  420. package/src/ui-editor/react-store.ts +0 -78
  421. package/src/ui-editor/timeline-panel.tsx +0 -443
  422. package/src/ui-editor/ui-edit-store.ts +0 -552
  423. package/src/ui-editor/ui-prefab.ts +0 -95
  424. package/template/project.json +0 -9
  425. package/template/src/scripts/main.ts +0 -94
  426. package/template/src/ui/DefaultHud.tsx +0 -40
  427. package/template/src/ui/game-state.tsx +0 -37
  428. package/template/src/ui/mount-default-hud.tsx +0 -19
  429. package/template/src/ui/mount-ui.ts +0 -15
  430. package/vite-plugin-react-world-provider.ts +0 -81
@@ -1,10 +1,20 @@
1
1
  import { resolveUrl } from '@engine/loader';
2
2
  import { parsePrefabFile, parseSceneFile } from '@engine/scene/parse';
3
3
  import type { PrefabFile, SceneFile } from '@engine/scene/scene-types';
4
- import { use, useCallback, useEffect, useRef, useState, useSyncExternalStore } from 'react';
4
+ import { use, useCallback, useEffect, useState, useSyncExternalStore } from 'react';
5
5
  import { createPortal } from 'react-dom';
6
- import { connectAssetEvents, connectSceneEvents } from '../asset-events';
6
+ import {
7
+ connectAssetEvents,
8
+ connectSceneEvents,
9
+ decideExternalSceneChangeAction,
10
+ } from '../asset-events';
11
+ import { installAssetSelectionAutoClear } from '../asset-selection';
7
12
  import { getActiveAuthoring, hasAuthoringOverride } from '../authoring/active-adapter';
13
+ import {
14
+ switchFocusedWorld,
15
+ WORLD_FOCUS_REQUEST_EVENT,
16
+ type WorldFocusRequest,
17
+ } from '../authoring/edit-mode-authoring';
8
18
  import {
9
19
  findOwningRootGroupId,
10
20
  ROOT_ACTIVATION_REQUEST_EVENT,
@@ -12,24 +22,30 @@ import {
12
22
  requestRootActivation,
13
23
  } from '../authoring/root-activation';
14
24
  import { watchExternalSceneChanges } from '../browser-external-watch';
15
- import { useEditorInit, useEditorStore } from '../EditorContext';
25
+ import { themeVars } from '../design-system';
26
+ import { useEditorInit, useEditorStore, useHistoryService } from '../EditorContext';
16
27
  import { readProjectTextFile, saveFile } from '../editor-api';
17
28
  import { editorConsole } from '../editor-console';
18
29
  import { getEditorMode } from '../editor-mode';
19
- import { resizeGame, setGameContainer } from '../play-mode';
20
- import { SceneUIPalettePanel } from '../scene-ui-mode/scene-ui-palette-panel';
21
- import { UIPrefabDialogHost } from '../scene-ui-mode/ui-prefab-dialog-host';
30
+ import type { HistoryService } from '../history/history-service';
31
+ import { getProjectFileHistory } from '../history/project-file-history';
22
32
  import { getStorageBackend } from '../storage';
23
- import { BottomPanel } from './BottomPanel';
24
- import { GameHierarchy } from './GameHierarchy';
33
+ import { installAuxiliaryEvents } from '../workspace-aux-commands';
34
+ import { installUtilityAutoOpen, installUtilityEvents } from '../workspace-utility-commands';
35
+ import { ensureBuildContributionsRegistered } from './build-documents';
36
+ import { useCenterDocuments } from './CenterDocuments';
37
+ import { CommandPalette } from './CommandPalette';
38
+ import { ensureCoreUtilitiesRegistered } from './core-utilities';
39
+ import { configureDataDocumentStore, startDataAssetDiscovery } from './data-documents';
25
40
  import { MountFailureBanner } from './MountFailureBanner';
26
- import { NetworkSection } from './NetworkSection';
27
- import { PlayBar, type Resolution } from './PlayBar';
28
41
  import { PrefabSaveDialog } from './PrefabSaveDialog';
29
42
  import { ProjectHeader } from './ProjectHeader';
30
- import { RightPanel } from './RightPanel';
31
43
  import { RootActivateDialog } from './RootActivateDialog';
32
- import { ViewportPanel } from './ViewportPanel';
44
+ import { StatusBar } from './StatusBar';
45
+ import { ensureCoreStatusContributionsRegistered } from './status-contributions';
46
+ import { WorkspaceDock } from './WorkspaceDock';
47
+ import { setWorkspaceHistoryService } from './workspace-history';
48
+ import { configureXStateInspector } from './xstate-documents';
33
49
 
34
50
  /** Load a scene from a URL into the store. */
35
51
  export async function openSceneFromAsset(
@@ -52,14 +68,33 @@ export async function openSceneFromAsset(
52
68
  export async function saveMaterialToServer(
53
69
  material: import('@engine/scene/scene-types').MaterialFile,
54
70
  path: string,
71
+ history?: HistoryService,
55
72
  ): Promise<boolean> {
56
73
  const content = JSON.stringify(material, null, 2);
74
+ if (history) {
75
+ return getProjectFileHistory(history).write(path, content, {
76
+ label: `Edit ${path.split('/').pop() ?? 'Material'}`,
77
+ kind: 'material',
78
+ contentType: 'application/json',
79
+ });
80
+ }
57
81
  return saveFile(path, content);
58
82
  }
59
83
 
60
84
  /** Save a PrefabFile to disk via the editor server API. */
61
- export async function savePrefabToServer(prefab: PrefabFile, path: string): Promise<boolean> {
85
+ export async function savePrefabToServer(
86
+ prefab: PrefabFile,
87
+ path: string,
88
+ history?: HistoryService,
89
+ ): Promise<boolean> {
62
90
  const content = JSON.stringify(prefab, null, 2);
91
+ if (history) {
92
+ return getProjectFileHistory(history).write(path, content, {
93
+ label: `Save ${path.split('/').pop() ?? 'Prefab'}`,
94
+ kind: 'prefab',
95
+ contentType: 'application/json',
96
+ });
97
+ }
63
98
  return saveFile(path, content);
64
99
  }
65
100
 
@@ -91,165 +126,48 @@ export async function fetchPrefabFile(url: string): Promise<PrefabFile | null> {
91
126
  }
92
127
  }
93
128
 
94
- /** Game panel — a container div that play-mode.ts fills with a canvas. */
95
- function GamePanel({ style }: { style?: React.CSSProperties }) {
96
- const store = useEditorStore();
97
- const outerRef = useRef<HTMLDivElement>(null);
98
- const [resolution, setResolution] = useState<Resolution>({
99
- label: 'Fill',
100
- width: null,
101
- height: null,
102
- });
103
- const [containerSize, setContainerSize] = useState({ width: 0, height: 0 });
104
-
105
- // Callback ref so setGameContainer is called even when the element swaps (fill ↔ device)
106
- const prevRef = useRef<HTMLDivElement | null>(null);
107
- const canvasRef = useCallback((el: HTMLDivElement | null) => {
108
- if (el === prevRef.current) return;
109
- // Move game canvas to new container
110
- if (prevRef.current && el) {
111
- while (prevRef.current.firstChild) el.appendChild(prevRef.current.firstChild);
112
- }
113
- prevRef.current = el;
114
- setGameContainer(el);
115
- }, []);
116
-
117
- // Track outer container size for scale calculation
118
- useEffect(() => {
119
- const el = outerRef.current;
120
- if (!el) return;
121
- const observer = new ResizeObserver(([entry]) => {
122
- if (!entry) return;
123
- setContainerSize({ width: entry.contentRect.width, height: entry.contentRect.height });
124
- });
125
- observer.observe(el);
126
- return () => observer.disconnect();
127
- }, []);
128
-
129
- // Resize the game renderer when resolution or container size changes
130
- const isFill = resolution.width === null;
131
- useEffect(() => {
132
- if (isFill) {
133
- // Fill mode: resize to match available container space
134
- if (containerSize.width > 0 && containerSize.height > 0) {
135
- resizeGame(containerSize.width, containerSize.height);
136
- }
137
- } else {
138
- resizeGame(resolution.width!, resolution.height!);
139
- }
140
- }, [isFill, resolution.width, resolution.height, containerSize.width, containerSize.height]);
141
-
142
- // Scale: fit the device resolution into the available space, never upscale
143
- let scale = 1;
144
- if (!isFill && containerSize.width > 0 && containerSize.height > 0) {
145
- const scaleX = containerSize.width / resolution.width!;
146
- const scaleY = containerSize.height / resolution.height!;
147
- scale = Math.min(scaleX, scaleY, 1);
148
- }
149
-
150
- return (
151
- <div style={{ overflow: 'hidden', position: 'relative', flexDirection: 'column', ...style }}>
152
- <div
153
- ref={outerRef}
154
- style={{
155
- flex: 1,
156
- overflow: 'hidden',
157
- display: 'flex',
158
- alignItems: 'center',
159
- justifyContent: 'center',
160
- position: 'relative',
161
- }}
162
- >
163
- {isFill ? (
164
- <div ref={canvasRef} aria-hidden="true" style={{ position: 'absolute', inset: 0 }} />
165
- ) : (
166
- /* Wrapper sized to the scaled dimensions so flexbox centering works.
167
- The inner canvasRef is full device resolution, CSS-scaled down. */
168
- <div
169
- style={{
170
- width: resolution.width! * scale,
171
- height: resolution.height! * scale,
172
- overflow: 'hidden',
173
- }}
174
- >
175
- <div
176
- ref={canvasRef}
177
- aria-hidden="true"
178
- style={{
179
- width: resolution.width!,
180
- height: resolution.height!,
181
- transformOrigin: 'top left',
182
- transform: `scale(${scale})`,
183
- }}
184
- />
185
- </div>
186
- )}
187
- {/* Same overlay ViewportPanel renders on the Scene tab (T-R1a #6) — the
188
- Game tab is where play auto-switches to, so it must render here too,
189
- not only on the Scene-tab viewport it would otherwise be hidden behind. */}
190
- {store.playState !== 'stopped' && <NetworkSection />}
191
- </div>
192
- <PlayBar resolution={resolution} onResolutionChange={setResolution} scale={scale} />
193
- </div>
194
- );
195
- }
196
-
197
- function ViewportTabBar({
198
- active,
199
- onChange,
200
- showGame,
201
- }: {
202
- active: 'scene' | 'game';
203
- onChange: (tab: 'scene' | 'game') => void;
204
- showGame: boolean;
205
- }) {
206
- const tabStyle = (isActive: boolean): React.CSSProperties => ({
207
- background: 'none',
208
- border: 'none',
209
- padding: '4px 8px',
210
- cursor: 'pointer',
211
- fontSize: 11,
212
- fontWeight: 600,
213
- textTransform: 'uppercase',
214
- color: isActive ? '#c5c8ce' : '#666',
215
- borderBottom: isActive ? '2px solid #579eff' : '2px solid transparent',
216
- marginBottom: -1,
217
- pointerEvents: 'auto',
218
- });
219
- return (
220
- <div
221
- style={{
222
- display: 'flex',
223
- gap: 2,
224
- background: '#2c2c2c',
225
- borderBottom: '1px solid #333',
226
- flexShrink: 0,
227
- pointerEvents: 'auto',
228
- }}
229
- >
230
- <button type="button" style={tabStyle(active === 'scene')} onClick={() => onChange('scene')}>
231
- Viewport
232
- </button>
233
- {showGame && (
234
- <button type="button" style={tabStyle(active === 'game')} onClick={() => onChange('game')}>
235
- Game
236
- </button>
237
- )}
238
- </div>
239
- );
240
- }
241
-
242
129
  export function DefaultEditorLayout({
243
130
  onReturnToProjectScreen,
244
131
  }: {
245
132
  onReturnToProjectScreen?: (() => void) | undefined;
246
133
  }) {
247
134
  const store = useEditorStore();
135
+ const history = useHistoryService();
248
136
  use(useEditorInit()); // suspends until project is detected
249
137
 
250
138
  // Subscribe to store changes
251
139
  useSyncExternalStore(store.subscribe, store.getSnapshot);
252
- const isPlaying = store.playState !== 'stopped';
140
+ // W1 — install the center workspace documents (scene + Game) and keep the
141
+ // document registry synced with the store's activeViewportTab (T6.3 gate).
142
+ useCenterDocuments(store);
143
+ // W3 (workspace-shell §9/W3) — the shell contributions the new center
144
+ // documents ride on:
145
+ // - data-asset discovery (folder-scan store behind the per-file data
146
+ // documents + the palette's Open Data Asset actions), plus the store
147
+ // bridge the Data Assets navigation document opens siblings through;
148
+ // - the XState selected-live-entity Inspector section (§4.3 — matches
149
+ // ONLY a real live `bindXStateAnimation` binding; no demo anywhere);
150
+ // - the Build Output utility + build-progress status contribution
151
+ // (server mode only — builds spawn npm scripts server-side).
152
+ // W4 (workspace-shell §9/W4) — status-bar contributions register BEFORE the
153
+ // build ensure below so the order-0 items sequence save-status first; the
154
+ // utility auto-open watcher (save/build failure → the correct Dockview
155
+ // panel) is per-store. Core utilities register before the host reconciles.
156
+ useEffect(() => ensureCoreStatusContributionsRegistered(), []);
157
+ useEffect(() => ensureCoreUtilitiesRegistered(), []);
158
+ useEffect(() => installUtilityAutoOpen(store), [store]);
159
+ useEffect(() => installUtilityEvents(), []);
160
+ useEffect(() => installAuxiliaryEvents(), []);
161
+ useEffect(() => startDataAssetDiscovery(), []);
162
+ useEffect(() => configureDataDocumentStore(store), [store]);
163
+ useEffect(() => setWorkspaceHistoryService(history), [history]);
164
+ useEffect(() => configureXStateInspector(store), [store]);
165
+ useEffect(() => {
166
+ if (getEditorMode() === 'server') ensureBuildContributionsRegistered();
167
+ }, []);
168
+ // W2 (§5.1) — an ENTITY selection change drops the asset selection, so the
169
+ // Inspector goes back to being purely entity-contextual (asset-selection.ts).
170
+ useEffect(() => installAssetSelectionAutoClear(store), [store]);
253
171
  const [prefabSaveState, setPrefabSaveState] = useState<{ entityId: string; name: string } | null>(
254
172
  null,
255
173
  );
@@ -270,6 +188,20 @@ export function DefaultEditorLayout({
270
188
  return () => window.removeEventListener(ROOT_ACTIVATION_REQUEST_EVENT, handler);
271
189
  }, []);
272
190
 
191
+ // A4 (focus-switch) — the world-focus twin of the root-activation dialog
192
+ // above: `requestWorldFocus` dispatches this when the store is dirty; the
193
+ // same RootActivateDialog renders with world copy, and confirm runs the
194
+ // actual switch.
195
+ const [pendingWorldFocus, setPendingWorldFocus] = useState<WorldFocusRequest | null>(null);
196
+
197
+ useEffect(() => {
198
+ const handler = (e: Event) => {
199
+ setPendingWorldFocus((e as CustomEvent<WorldFocusRequest>).detail);
200
+ };
201
+ window.addEventListener(WORLD_FOCUS_REQUEST_EVENT, handler);
202
+ return () => window.removeEventListener(WORLD_FOCUS_REQUEST_EVENT, handler);
203
+ }, []);
204
+
273
205
  // Listen for "save as prefab" events from the hierarchy context menu
274
206
  useEffect(() => {
275
207
  const handler = (e: Event) => {
@@ -288,15 +220,24 @@ export function DefaultEditorLayout({
288
220
  setPrefabSaveState(null);
289
221
  return;
290
222
  }
291
- savePrefabToServer(prefab, path).then((ok) => {
223
+ const save = history
224
+ ? store.savePrefabAndConvertInstance(
225
+ prefabSaveState.entityId,
226
+ path,
227
+ JSON.stringify(prefab, null, 2),
228
+ )
229
+ : savePrefabToServer(prefab, path);
230
+ save.then((ok) => {
292
231
  if (ok) {
293
- const servingPath = `/${path}`;
294
- store.convertToPrefabInstance(prefabSaveState.entityId, servingPath);
232
+ if (!history) {
233
+ const servingPath = `/${path}`;
234
+ store.convertToPrefabInstance(prefabSaveState.entityId, servingPath);
235
+ }
295
236
  }
296
237
  setPrefabSaveState(null);
297
238
  });
298
239
  },
299
- [store, prefabSaveState],
240
+ [store, prefabSaveState, history],
300
241
  );
301
242
 
302
243
  // A4 (D8) — the SINGLE choke point for the asset-browser's scene/prefab
@@ -339,10 +280,13 @@ export function DefaultEditorLayout({
339
280
 
340
281
  // Subscribe to server-sent asset move events (file watcher)
341
282
  useEffect(() => {
342
- return connectAssetEvents((event) => {
343
- store.applyAssetMove(event.oldPath, event.newPath);
344
- window.dispatchEvent(new CustomEvent('editor:assets-changed'));
345
- });
283
+ return connectAssetEvents(
284
+ (event) => {
285
+ store.applyAssetMove(event.oldPath, event.newPath);
286
+ window.dispatchEvent(new CustomEvent('editor:assets-changed'));
287
+ },
288
+ () => window.dispatchEvent(new CustomEvent('editor:assets-changed')),
289
+ );
346
290
  }, [store]);
347
291
 
348
292
  // Subscribe to server-sent scene file changes (live sync from disk). This channel
@@ -358,15 +302,41 @@ export function DefaultEditorLayout({
358
302
  // ITS `applyExternal` would feed a foreign `SceneFile` into e.g. an ingest
359
303
  // overlay's apply, so fall back to `store.applyExternalUpdate` directly there,
360
304
  // preserving its existing play-state-guarded queueing behavior unchanged.
305
+ //
306
+ // run-3 friction #1: a hand edit landing while the editor holds UNSAVED
307
+ // first-party changes used to be silently diff-merged into the live scene —
308
+ // a real external edit and the user's own in-flight edits would interleave
309
+ // with no warning. Own-echo (this editor's own autosave reflected back
310
+ // through the watcher) is checked FIRST via `isOwnEchoContent` so a plain
311
+ // echo never triggers the notice; only a GENUINE external change while
312
+ // dirty is held back, with a loud (never blocking — no window.prompt)
313
+ // console notice telling the user how to pick it up. Clean documents keep
314
+ // applying automatically, same as before. Scoped to the non-override path
315
+ // only — ingest/world2d/UI overrides have their own dirty/reload contracts.
361
316
  const onSceneChanged = useCallback(
362
317
  (event: { path: string; content: string }) => {
363
318
  const currentPath = store.savePath;
364
- if (!currentPath) return;
365
- const eventPath = event.path.startsWith('/') ? event.path.slice(1) : event.path;
366
- if (eventPath !== currentPath) return;
319
+ const hasOverride = hasAuthoringOverride();
320
+ const action = decideExternalSceneChangeAction({
321
+ currentPath,
322
+ eventPath: event.path,
323
+ isDirty: store.isDirty,
324
+ isOwnEcho: store.isOwnEchoContent(event.content),
325
+ hasOverride,
326
+ });
327
+ if (action === 'skip') return;
328
+ if (action === 'notice') {
329
+ editorConsole.warn(
330
+ `${currentPath} changed on disk while you have unsaved changes — ` +
331
+ 'it will NOT auto-reload over unsaved work. Save (Ctrl/Cmd+S) or ' +
332
+ 'discard your edits to pick up the external change.',
333
+ 'scene',
334
+ );
335
+ return;
336
+ }
367
337
  try {
368
338
  const doc = parseSceneFile(JSON.parse(event.content));
369
- if (hasAuthoringOverride()) {
339
+ if (hasOverride) {
370
340
  store.applyExternalUpdate(doc, event.content);
371
341
  } else {
372
342
  getActiveAuthoring(store).persistence?.applyExternal?.(doc, event.content);
@@ -399,6 +369,9 @@ export function DefaultEditorLayout({
399
369
  return (
400
370
  <>
401
371
  <div
372
+ className="vgai-editor-shell"
373
+ data-editor-hotkey-scope="workspace"
374
+ data-editor-hotkey-fallback
402
375
  style={{
403
376
  position: 'absolute',
404
377
  top: 0,
@@ -408,9 +381,9 @@ export function DefaultEditorLayout({
408
381
  display: 'flex',
409
382
  flexDirection: 'column',
410
383
  pointerEvents: 'none',
411
- fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
384
+ fontFamily: themeVars.typography.sans,
412
385
  fontSize: '13px',
413
- color: '#c5c8ce',
386
+ color: themeVars.content.primary,
414
387
  }}
415
388
  >
416
389
  <ProjectHeader onReturnToProjectScreen={onReturnToProjectScreen} />
@@ -429,56 +402,7 @@ export function DefaultEditorLayout({
429
402
  minHeight: 0,
430
403
  }}
431
404
  >
432
- {/* A2 — ONE contract-only hierarchy panel drives every session shape
433
- (bare single-scene edit, ingested game, multi-world composite):
434
- `hasAuthoringOverride()` no longer selects between two panels. */}
435
- <GameHierarchy />
436
- {/* E1.a (spec-27 §7 E1) — the scene-UI palette (+ prefab
437
- instantiate list), visible only while a scene-UI child is
438
- installed (renders null otherwise — the component's own gate). */}
439
- <SceneUIPalettePanel />
440
- {/* Viewport + Game area — two independent panels, tab-switched */}
441
- <div
442
- style={{
443
- flex: 1,
444
- display: 'flex',
445
- flexDirection: 'column',
446
- position: 'relative',
447
- pointerEvents: 'none',
448
- }}
449
- >
450
- <ViewportTabBar
451
- active={store.activeViewportTab}
452
- onChange={(tab) => store.setActiveViewportTab(tab)}
453
- showGame={isPlaying}
454
- />
455
- {/* Viewport panel (editor) — all overlays are inside ViewportPanel */}
456
- <div
457
- style={{
458
- flex: 1,
459
- position: 'relative',
460
- display: store.activeViewportTab === 'scene' ? 'block' : 'none',
461
- }}
462
- >
463
- <ViewportPanel />
464
- </div>
465
- {/* Game panel — always mounted, hidden when not playing/active */}
466
- <GamePanel
467
- style={{
468
- flex: 1,
469
- position: 'relative',
470
- display: isPlaying && store.activeViewportTab === 'game' ? 'flex' : 'none',
471
- flexDirection: 'column',
472
- pointerEvents: 'auto',
473
- ...(isPlaying && store.playState === 'playing'
474
- ? { outline: '2px solid #4ec9b0', outlineOffset: -2 }
475
- : isPlaying
476
- ? { outline: '2px solid #dcdcaa', outlineOffset: -2 }
477
- : {}),
478
- }}
479
- />
480
- </div>
481
- <RightPanel />
405
+ <WorkspaceDock onOpenScene={handleOpenScene} />
482
406
  </div>
483
407
  {prefabSaveState && (
484
408
  <PrefabSaveDialog
@@ -487,10 +411,6 @@ export function DefaultEditorLayout({
487
411
  onCancel={() => setPrefabSaveState(null)}
488
412
  />
489
413
  )}
490
- {/* E1.c (spec-27 §7 E1) — the scene-UI "Save as Prefab" dialog
491
- (hierarchy context-menu, `ui-prefab-hierarchy-menu.ts`); a
492
- self-contained host, renders nothing until that menu item fires. */}
493
- <UIPrefabDialogHost />
494
414
  {pendingRootActivation && (
495
415
  <RootActivateDialog
496
416
  label={pendingRootActivation.label}
@@ -502,8 +422,24 @@ export function DefaultEditorLayout({
502
422
  onCancel={() => setPendingRootActivation(null)}
503
423
  />
504
424
  )}
425
+ {pendingWorldFocus && (
426
+ <RootActivateDialog
427
+ label={pendingWorldFocus.worldId}
428
+ title="Switch focused world?"
429
+ onConfirm={() => {
430
+ const { worldId, scenePath } = pendingWorldFocus;
431
+ setPendingWorldFocus(null);
432
+ void switchFocusedWorld(store, worldId, scenePath);
433
+ }}
434
+ onCancel={() => setPendingWorldFocus(null)}
435
+ />
436
+ )}
437
+ {/* Global command surface: this must live at the shell root. Mounting
438
+ it inside the Scene document made Cmd/Ctrl+K invisible whenever
439
+ Game, Story, asset, data, or tool documents were active. */}
440
+ {store.commandPaletteOpen && <CommandPalette onClose={() => store.closeCommandPalette()} />}
505
441
  </div>
506
- {bottomEl && createPortal(<BottomPanel onOpenScene={handleOpenScene} />, bottomEl)}
442
+ {bottomEl && createPortal(<StatusBar />, bottomEl)}
507
443
  </>
508
444
  );
509
445
  }