@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
@@ -0,0 +1,200 @@
1
+ import { GAME_MANIFEST_VERSION } from '../../engine/src/manifest/schema';
2
+
3
+ export interface EditorServerCompatibility {
4
+ apiVersion: 1;
5
+ engineVersion: string | null;
6
+ manifestVersion: number;
7
+ startedAt: string;
8
+ source:
9
+ | { state: 'current' }
10
+ | { state: 'restart-required'; changedPath: string; changedAt: string };
11
+ }
12
+
13
+ export type StartupRecovery =
14
+ | {
15
+ kind: 'retry-editor';
16
+ title: 'Editor server unavailable';
17
+ guidance: string;
18
+ command: 'vgai edit .';
19
+ }
20
+ | {
21
+ kind: 'restart-editor';
22
+ title: 'Restart this editor';
23
+ guidance: string;
24
+ command: 'vgai close . && vgai edit .';
25
+ }
26
+ | {
27
+ kind: 'upgrade-project';
28
+ title: 'Upgrade this project';
29
+ guidance: string;
30
+ command: 'vgai upgrade .';
31
+ }
32
+ | {
33
+ kind: 'use-compatible-editor';
34
+ title: 'Use a compatible editor';
35
+ guidance: string;
36
+ };
37
+
38
+ export class ProjectCompatibilityError extends Error {
39
+ readonly recovery: StartupRecovery;
40
+
41
+ constructor(message: string, recovery: StartupRecovery) {
42
+ super(message);
43
+ this.name = 'ProjectCompatibilityError';
44
+ this.recovery = recovery;
45
+ }
46
+ }
47
+
48
+ export function editorServerUnavailableError(detail?: string): ProjectCompatibilityError {
49
+ return new ProjectCompatibilityError(
50
+ `Could not reach the local editor server${detail ? `: ${detail}` : '.'}`,
51
+ {
52
+ kind: 'retry-editor',
53
+ title: 'Editor server unavailable',
54
+ guidance: 'Make sure the local editor is running, then retry this operation.',
55
+ command: 'vgai edit .',
56
+ },
57
+ );
58
+ }
59
+
60
+ export function isStartupRecovery(value: unknown): value is StartupRecovery {
61
+ if (!value || typeof value !== 'object') return false;
62
+ const candidate = value as Record<string, unknown>;
63
+ if (typeof candidate['title'] !== 'string' || typeof candidate['guidance'] !== 'string') {
64
+ return false;
65
+ }
66
+ switch (candidate['kind']) {
67
+ case 'retry-editor':
68
+ return candidate['command'] === 'vgai edit .';
69
+ case 'restart-editor':
70
+ return candidate['command'] === 'vgai close . && vgai edit .';
71
+ case 'upgrade-project':
72
+ return candidate['command'] === 'vgai upgrade .';
73
+ case 'use-compatible-editor':
74
+ return candidate['command'] === undefined;
75
+ default:
76
+ return false;
77
+ }
78
+ }
79
+
80
+ interface ProjectIdentity {
81
+ manifestVersion?: unknown;
82
+ engine?: { version?: unknown } | undefined;
83
+ }
84
+
85
+ const EXACT_SEMVER = /^(\d+)\.(\d+)\.(\d+)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
86
+
87
+ function compareSemver(a: string, b: string): -1 | 0 | 1 | null {
88
+ const aMatch = EXACT_SEMVER.exec(a);
89
+ const bMatch = EXACT_SEMVER.exec(b);
90
+ if (!aMatch || !bMatch) return null;
91
+ for (let index = 1; index <= 3; index++) {
92
+ const aPart = Number(aMatch[index]);
93
+ const bPart = Number(bMatch[index]);
94
+ if (aPart < bPart) return -1;
95
+ if (aPart > bPart) return 1;
96
+ }
97
+ return 0;
98
+ }
99
+
100
+ export function missingCompatibilityError(): ProjectCompatibilityError {
101
+ return new ProjectCompatibilityError(
102
+ 'The editor page is newer than its local server. The running server does not expose the compatibility handshake this page expects.',
103
+ {
104
+ kind: 'restart-editor',
105
+ title: 'Restart this editor',
106
+ guidance: 'From the project folder, restart the local editor and then reopen this page.',
107
+ command: 'vgai close . && vgai edit .',
108
+ },
109
+ );
110
+ }
111
+
112
+ /** Verify that the browser bundle and its long-running local server still agree. */
113
+ export function assertEditorCompatibility(identity: EditorServerCompatibility): void {
114
+ if (identity.source.state === 'restart-required') {
115
+ throw new ProjectCompatibilityError(
116
+ `The local editor server is stale. ${identity.source.changedPath} changed after this server started at ${identity.startedAt}.`,
117
+ {
118
+ kind: 'restart-editor',
119
+ title: 'Restart this editor',
120
+ guidance:
121
+ 'The browser has newer source than the running Node process. From the project folder, restart the editor before retrying.',
122
+ command: 'vgai close . && vgai edit .',
123
+ },
124
+ );
125
+ }
126
+
127
+ if (identity.manifestVersion !== GAME_MANIFEST_VERSION) {
128
+ throw new ProjectCompatibilityError(
129
+ `The editor page supports project format v${GAME_MANIFEST_VERSION}, but its local server supports v${identity.manifestVersion}.`,
130
+ {
131
+ kind: 'restart-editor',
132
+ title: 'Restart this editor',
133
+ guidance: 'The browser and server are from different editor builds. Restart them together.',
134
+ command: 'vgai close . && vgai edit .',
135
+ },
136
+ );
137
+ }
138
+ }
139
+
140
+ /** Verify the lightweight identity fields before full Zod manifest parsing. */
141
+ export function assertProjectCompatibility(
142
+ project: ProjectIdentity,
143
+ editor: EditorServerCompatibility,
144
+ ): void {
145
+ if (
146
+ typeof project.manifestVersion === 'number' &&
147
+ project.manifestVersion !== GAME_MANIFEST_VERSION
148
+ ) {
149
+ if (project.manifestVersion < GAME_MANIFEST_VERSION) {
150
+ throw new ProjectCompatibilityError(
151
+ `This project uses manifest format v${project.manifestVersion}; this editor requires v${GAME_MANIFEST_VERSION}.`,
152
+ {
153
+ kind: 'upgrade-project',
154
+ title: 'Upgrade this project',
155
+ guidance:
156
+ 'Run the upgrade from the project folder. VGAI reports changes before updating scaffold-managed files.',
157
+ command: 'vgai upgrade .',
158
+ },
159
+ );
160
+ }
161
+ throw new ProjectCompatibilityError(
162
+ `This project uses manifest format v${project.manifestVersion}, which is newer than this editor's v${GAME_MANIFEST_VERSION} format.`,
163
+ {
164
+ kind: 'use-compatible-editor',
165
+ title: 'Use a compatible editor',
166
+ guidance: 'Open this project with the newer VGAI checkout or installation that created it.',
167
+ },
168
+ );
169
+ }
170
+
171
+ const projectEngine = project.engine?.version;
172
+ const editorEngine = editor.engineVersion;
173
+ if (typeof projectEngine !== 'string' || !editorEngine || projectEngine === editorEngine) return;
174
+
175
+ const comparison = compareSemver(projectEngine, editorEngine);
176
+ if (comparison === -1) {
177
+ throw new ProjectCompatibilityError(
178
+ `This project is pinned to @vgai/engine ${projectEngine}, but this editor is running ${editorEngine}.`,
179
+ {
180
+ kind: 'upgrade-project',
181
+ title: 'Upgrade this project',
182
+ guidance:
183
+ 'Run the upgrade from the project folder to review template changes and re-pin the engine.',
184
+ command: 'vgai upgrade .',
185
+ },
186
+ );
187
+ }
188
+
189
+ throw new ProjectCompatibilityError(
190
+ `This project is pinned to @vgai/engine ${projectEngine}, but this editor is running ${editorEngine}.`,
191
+ {
192
+ kind: 'use-compatible-editor',
193
+ title: 'Use a compatible editor',
194
+ guidance:
195
+ comparison === 1
196
+ ? 'This project targets a newer engine. Open it from the matching newer VGAI checkout or installation.'
197
+ : 'The engine identities differ. Open the project with the exact VGAI version it is pinned to.',
198
+ },
199
+ );
200
+ }
@@ -123,8 +123,17 @@ export const editorConsole = new EditorConsole();
123
123
  // anticipates: direct read access to console entries without DOM-scraping
124
124
  // `ConsolePanel` (which has no per-entry testids). Same ad-hoc `window.__vgai*`
125
125
  // convention as every other dev-only hook in `test-window.ts`.
126
- (window as unknown as { __vgaiEditorConsole?: EditorConsole })['__vgaiEditorConsole'] =
127
- editorConsole;
126
+ //
127
+ // Guarded on `window`: this module is now imported by `ingest-authoring-adapter.ts`
128
+ // (to report a failed history journal loudly), which is exercised by node-env
129
+ // vitest suites where `window` does not exist. A bare module-scope reference
130
+ // throws `ReferenceError: window is not defined` at COLLECTION time — before any
131
+ // test body runs — so the guard belongs here at the source rather than as a
132
+ // `vi.mock` repeated in every importing test file.
133
+ if (typeof window !== 'undefined') {
134
+ (window as unknown as { __vgaiEditorConsole?: EditorConsole })['__vgaiEditorConsole'] =
135
+ editorConsole;
136
+ }
128
137
 
129
138
  /**
130
139
  * Listen for `console-bridge` postMessage events from game iframes (or self)
@@ -146,22 +155,31 @@ const ENGINE_LEVEL_MAP: Record<string, ConsoleLevel> = {
146
155
  fatal: 'error',
147
156
  };
148
157
 
149
- window.addEventListener('message', (e: MessageEvent) => {
150
- // Structured engine-log messages (from engine logger)
151
- if (e.data?.type === 'engine-log') {
152
- const level = ENGINE_LEVEL_MAP[e.data.level];
153
- if (!level) return;
154
- editorConsole.logStructured(level, e.data.message, 'engine', e.data.subsystem, e.data.metadata);
155
- return;
156
- }
158
+ // Same `window` guard as the test hook above — see the comment there.
159
+ if (typeof window !== 'undefined') {
160
+ window.addEventListener('message', (e: MessageEvent) => {
161
+ // Structured engine-log messages (from engine logger)
162
+ if (e.data?.type === 'engine-log') {
163
+ const level = ENGINE_LEVEL_MAP[e.data.level];
164
+ if (!level) return;
165
+ editorConsole.logStructured(
166
+ level,
167
+ e.data.message,
168
+ 'engine',
169
+ e.data.subsystem,
170
+ e.data.metadata,
171
+ );
172
+ return;
173
+ }
157
174
 
158
- // Plain console-bridge messages (from game code)
159
- if (e.data?.type === 'console-bridge') {
160
- const level = BRIDGE_LEVEL_MAP[e.data.level];
161
- if (!level) return;
162
- editorConsole[level === 'info' ? 'log' : level](e.data.message, 'engine');
163
- }
164
- });
175
+ // Plain console-bridge messages (from game code)
176
+ if (e.data?.type === 'console-bridge') {
177
+ const level = BRIDGE_LEVEL_MAP[e.data.level];
178
+ if (!level) return;
179
+ editorConsole[level === 'info' ? 'log' : level](e.data.message, 'engine');
180
+ }
181
+ });
182
+ }
165
183
 
166
184
  /**
167
185
  * Connect to the editor SSE endpoint and pipe `server-log` events
@@ -3,7 +3,6 @@ import {
3
3
  getActiveAuthoring,
4
4
  hasAuthoringOverride,
5
5
  } from './authoring/active-adapter';
6
- import { timelineRedo, timelineUndo } from './authoring/undo-timeline';
7
6
  import { resetWorldPan } from './authoring/world-pan-state';
8
7
  import {
9
8
  boxEditForId,
@@ -13,7 +12,12 @@ import {
13
12
  } from './components/world-overlay-gestures';
14
13
  import type { EditorStore } from './editor-store';
15
14
  import type { EditorViewport } from './editor-viewport';
15
+ import type { HistoryCommands } from './history/history-commands';
16
16
  import { installHotkeys, registerHotkeys, setActiveScope } from './hotkeys';
17
+ import { toggleWorkspaceFocus } from './workspace-dock-controller';
18
+ import { saveActiveWorkspaceDocument } from './workspace-document-registry';
19
+
20
+ const AUTHORING_SELECTION_SCOPES = ['viewport', 'hierarchy'] as const;
17
21
 
18
22
  /**
19
23
  * D4 (spec27 §6 D4, §8 "Keyboard / undo / pan-zoom" row) — RECONCILED by the
@@ -62,6 +66,17 @@ import { installHotkeys, registerHotkeys, setActiveScope } from './hotkeys';
62
66
  // capability-gate behavior (structure/boxEdit absent -> no-op) directly
63
67
  // against them, without needing a full `EditorViewport`/canvas fixture.
64
68
 
69
+ /** Copy is shared with the browser. Claim Cmd/Ctrl+C only when the current
70
+ * selection is copyable by the scene clipboard and the user is not selecting
71
+ * DOM text. Returning false lets the native copy event continue untouched. */
72
+ export function shouldHandleEditorCopy(store: EditorStore): boolean {
73
+ const selection = window.getSelection();
74
+ const hasTextSelection = Boolean(
75
+ selection && !selection.isCollapsed && selection.toString().length > 0,
76
+ );
77
+ return store.selectedEntities.length > 0 && !hasTextSelection;
78
+ }
79
+
65
80
  /**
66
81
  * D4 (spec27 §6 D4 "Ctrl+D duplicate, Del/Backspace delete — route through
67
82
  * adapter.structure.* (capability-gated)"): the pre-D4 `'d'`/`'delete'`/
@@ -213,46 +228,47 @@ export function registerEditorHotkeys(
213
228
  store: EditorStore,
214
229
  viewport: EditorViewport,
215
230
  canvas: HTMLCanvasElement,
231
+ history: HistoryCommands,
216
232
  ): () => void {
217
233
  const unregister = registerHotkeys([
218
234
  // --- Global (fire regardless of active panel) ---
219
- // Undo/redo (T3.2 slice 2): dispatch through the editor-global undo TIMELINE,
220
- // NOT `hasAuthoringOverride() ? adapter : store` — the timeline pops whichever
221
- // adapter (first-party store / ingest / UI) recorded the MOST RECENT op,
222
- // globally, regardless of which one is currently active (docs/
223
- // PERSISTENCE-PROVIDER-DESIGN.md §3). Ctrl+Y mirrors Ctrl+Shift+Z (Windows
224
- // convention) — see `undo-timeline.ts`.
235
+ // H2: one project-scoped async command queue owns shell undo/redo. Ctrl+Y
236
+ // mirrors Ctrl+Shift+Z (Windows convention).
225
237
  {
226
238
  key: 'z',
227
239
  mod: true,
228
240
  shift: true,
229
241
  scope: 'global',
230
- action: () => timelineRedo(),
242
+ action: () => void history.redo(),
231
243
  },
232
244
  {
233
245
  key: 'y',
234
246
  mod: true,
235
247
  scope: 'global',
236
- action: () => timelineRedo(),
248
+ action: () => void history.redo(),
237
249
  },
238
250
  {
239
251
  key: 'z',
240
252
  mod: true,
241
253
  scope: 'global',
242
- action: () => timelineUndo(),
254
+ action: () => void history.undo(),
243
255
  },
244
256
  {
245
257
  key: 'c',
246
258
  mod: true,
247
- scope: 'global',
248
- action: () => {
249
- if (store.selectedEntityIds.size > 0) store.copyEntities();
250
- },
259
+ scope: AUTHORING_SELECTION_SCOPES,
260
+ // Native text copy wins whenever the user has selected text in a log,
261
+ // source preview, path label, or other non-input surface. Previously
262
+ // this binding matched first and called preventDefault() even when no
263
+ // entity was selected, which made Copy appear to fail at random across
264
+ // Dockview panels.
265
+ when: () => shouldHandleEditorCopy(store),
266
+ action: () => store.copyEntities(),
251
267
  },
252
268
  {
253
269
  key: 'x',
254
270
  mod: true,
255
- scope: 'global',
271
+ scope: AUTHORING_SELECTION_SCOPES,
256
272
  action: () => {
257
273
  if (store.selectedEntityIds.size > 0) store.cutEntities();
258
274
  },
@@ -260,7 +276,7 @@ export function registerEditorHotkeys(
260
276
  {
261
277
  key: 'v',
262
278
  mod: true,
263
- scope: 'global',
279
+ scope: AUTHORING_SELECTION_SCOPES,
264
280
  action: () => {
265
281
  if (store.hasClipboard) store.pasteEntities();
266
282
  },
@@ -268,7 +284,7 @@ export function registerEditorHotkeys(
268
284
  {
269
285
  key: 'd',
270
286
  mod: true,
271
- scope: 'global',
287
+ scope: AUTHORING_SELECTION_SCOPES,
272
288
  action: () => duplicateSelection(store),
273
289
  },
274
290
  // D4 — wrap/unwrap (override-only, capability-gated — see
@@ -277,34 +293,44 @@ export function registerEditorHotkeys(
277
293
  key: 'g',
278
294
  mod: true,
279
295
  alt: true,
280
- scope: 'global',
296
+ scope: AUTHORING_SELECTION_SCOPES,
281
297
  action: () => wrapSelection(store),
282
298
  },
283
299
  {
284
300
  key: 'g',
285
301
  mod: true,
286
302
  shift: true,
287
- scope: 'global',
303
+ scope: AUTHORING_SELECTION_SCOPES,
288
304
  action: () => unwrapSelection(store),
289
305
  },
290
306
  // D4 — arrow-nudge (↑↓←→, Shift=×10 — see `nudgeSelection`'s doc comment).
291
- { key: 'arrowup', scope: 'global', action: () => nudgeSelection(store, 0, -1) },
292
- { key: 'arrowup', shift: true, scope: 'global', action: () => nudgeSelection(store, 0, -10) },
293
- { key: 'arrowdown', scope: 'global', action: () => nudgeSelection(store, 0, 1) },
294
- { key: 'arrowdown', shift: true, scope: 'global', action: () => nudgeSelection(store, 0, 10) },
295
- { key: 'arrowleft', scope: 'global', action: () => nudgeSelection(store, -1, 0) },
296
- { key: 'arrowleft', shift: true, scope: 'global', action: () => nudgeSelection(store, -10, 0) },
297
- { key: 'arrowright', scope: 'global', action: () => nudgeSelection(store, 1, 0) },
307
+ { key: 'arrowup', scope: 'viewport', action: () => nudgeSelection(store, 0, -1) },
308
+ { key: 'arrowup', shift: true, scope: 'viewport', action: () => nudgeSelection(store, 0, -10) },
309
+ { key: 'arrowdown', scope: 'viewport', action: () => nudgeSelection(store, 0, 1) },
310
+ {
311
+ key: 'arrowdown',
312
+ shift: true,
313
+ scope: 'viewport',
314
+ action: () => nudgeSelection(store, 0, 10),
315
+ },
316
+ { key: 'arrowleft', scope: 'viewport', action: () => nudgeSelection(store, -1, 0) },
317
+ {
318
+ key: 'arrowleft',
319
+ shift: true,
320
+ scope: 'viewport',
321
+ action: () => nudgeSelection(store, -10, 0),
322
+ },
323
+ { key: 'arrowright', scope: 'viewport', action: () => nudgeSelection(store, 1, 0) },
298
324
  {
299
325
  key: 'arrowright',
300
326
  shift: true,
301
- scope: 'global',
327
+ scope: 'viewport',
302
328
  action: () => nudgeSelection(store, 10, 0),
303
329
  },
304
330
  {
305
331
  key: 'a',
306
332
  mod: true,
307
- scope: 'global',
333
+ scope: AUTHORING_SELECTION_SCOPES,
308
334
  action: () => {
309
335
  if (hasAuthoringOverride()) {
310
336
  const a = getActiveAuthoring(store);
@@ -312,27 +338,39 @@ export function registerEditorHotkeys(
312
338
  } else store.selectAll();
313
339
  },
314
340
  },
315
- { key: 's', mod: true, scope: 'global', action: () => void store.saveNow() },
341
+ {
342
+ key: 's',
343
+ mod: true,
344
+ scope: 'global',
345
+ allowInEditable: true,
346
+ action: () => {
347
+ void saveActiveWorkspaceDocument().then((handled) => {
348
+ // Scene/Game and legacy documents have no document-local editor.
349
+ // Preserve the established scene save path for those surfaces.
350
+ if (handled === null) void store.saveNow();
351
+ });
352
+ },
353
+ },
316
354
  // D4 (spec27 §8 "space-pan" row) — Ctrl+0, the conventional "reset
317
355
  // zoom/pan to 100%" shortcut (browsers/design tools alike), resets the
318
356
  // DOM/react overlay's shared pan translate (`world-pan-state.ts`) back to
319
357
  // `(0, 0)`. A no-op when already at rest or when the active surface has
320
358
  // no pan-capable world (there is nothing for it to affect either way —
321
359
  // `resetWorldPan()` itself no-ops at `(0,0)`).
322
- { key: '0', mod: true, scope: 'global', action: () => resetWorldPan() },
360
+ { key: '0', mod: true, scope: 'viewport', action: () => resetWorldPan() },
323
361
  {
324
362
  key: 'delete',
325
- scope: 'global',
363
+ scope: AUTHORING_SELECTION_SCOPES,
326
364
  action: () => void deleteSelection(store),
327
365
  },
328
366
  {
329
367
  key: 'backspace',
330
- scope: 'global',
368
+ scope: AUTHORING_SELECTION_SCOPES,
331
369
  action: () => void deleteSelection(store),
332
370
  },
333
371
  {
334
372
  key: 'escape',
335
- scope: 'global',
373
+ scope: AUTHORING_SELECTION_SCOPES,
336
374
  // While playing, Escape is owned by play-mode (stop on Escape) — don't also
337
375
  // clear the editor selection out from under the running game.
338
376
  action: () => {
@@ -350,6 +388,20 @@ export function registerEditorHotkeys(
350
388
  scope: 'global',
351
389
  action: () => window.dispatchEvent(new CustomEvent('editor:toggle-console')),
352
390
  },
391
+ // W5 (§6.2 focus/maximize mode) — Ctrl/Cmd+Shift+F. SHORTCUT DECISION,
392
+ // recorded: the benchmarks are Unity's Shift+Space (maximize view under
393
+ // cursor) and VS Code zen's Ctrl+K Z chord — but this registry is
394
+ // single-fire and chord-less, and Space already participates in the
395
+ // overlay's space-pan HOLD gesture (`WorldSelectionOverlay`), so both
396
+ // benchmarks' literal keys would collide. mod+shift+F ("Focus") is free
397
+ // in this registry and unclaimed by Chromium on an app page.
398
+ {
399
+ key: 'f',
400
+ mod: true,
401
+ shift: true,
402
+ scope: 'global',
403
+ action: () => toggleWorkspaceFocus(),
404
+ },
353
405
 
354
406
  // --- Viewport-scoped (only when viewport/canvas is active) ---
355
407
  {