@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
@@ -9,6 +9,18 @@ import { BatchedRenderer } from 'three.quarks';
9
9
  import { getActiveAuthoring } from './authoring/active-adapter';
10
10
  import { pickTopmost } from './authoring/layered-pick';
11
11
  import { setViewportPickContext } from './authoring/viewport-pick-context';
12
+ import {
13
+ isViewportToolContextVisible,
14
+ resolveViewportToolContext,
15
+ } from './authoring/viewport-tool-context';
16
+ import {
17
+ applyWorldHiddenVisibility,
18
+ isThreejsSurfaceVisible,
19
+ resolveFocusedViewportWorldId,
20
+ suppressWorldEnvironment,
21
+ } from './authoring/world-hidden-viewport';
22
+ import { isWorldHidden } from './authoring/world-session-state';
23
+ import { themeVars, zIndex } from './design-system';
12
24
  import { downloadOnlineAsset, getDownloadedAssetPath, getOnlineAssetFiles } from './editor-api';
13
25
  import { EDITOR_LAYER } from './editor-layers';
14
26
  import type { EditorStore } from './editor-store';
@@ -37,6 +49,23 @@ const VC_DIRS: THREE.Vector3[] = [
37
49
  /* 5 -Z */ new THREE.Vector3(0, 0, -1),
38
50
  ];
39
51
 
52
+ /**
53
+ * Godot axis color RGB triples (X/Y/Z) — EDITOR-STYLE-AUDIT.md V-13:
54
+ * previously defined independently, from scratch, in BOTH
55
+ * `_initOrientationGizmo` (the view-cube) and `_patchGizmo` (the transform
56
+ * gizmo), each with its own identical "Godot axis colors" comment. Hoisted
57
+ * to one module-level constant so a future retouch of one can't silently
58
+ * drift from the other. Kept as plain `[r,g,b]` triples rather than shared
59
+ * `THREE.Color` instances — call sites construct their own `new
60
+ * THREE.Color(...)` from these, so nothing here can be mutated in place by
61
+ * one call site (materials, sprite canvases) and leak into the other.
62
+ */
63
+ const GODOT_AXIS_COLOR_RGB: readonly [number, number, number][] = [
64
+ [0.96, 0.2, 0.32], // X
65
+ [0.53, 0.84, 0.01], // Y
66
+ [0.16, 0.55, 0.96], // Z
67
+ ];
68
+
40
69
  export class EditorViewport {
41
70
  readonly camera: THREE.PerspectiveCamera;
42
71
  readonly orbitControls: OrbitControls;
@@ -58,6 +87,9 @@ export class EditorViewport {
58
87
  private _store: EditorStore;
59
88
  private _objectMap = new Map<string, THREE.Object3D>();
60
89
  private _canvas: HTMLCanvasElement;
90
+ /** Camera input belongs to the whole viewport surface, including authoring
91
+ * overlays rendered above the WebGL canvas. */
92
+ private _interactionElement: HTMLElement;
61
93
  private _pointerDownPos = new THREE.Vector2();
62
94
  private _skipNextSync = false;
63
95
 
@@ -83,6 +115,15 @@ export class EditorViewport {
83
115
  * during a transform drag, which notifies per frame but changes none of them). */
84
116
  private _lastGizmoObjectMap: Map<string, THREE.Object3D> | null = null;
85
117
  private _lastGizmoSig = '';
118
+ /** Previous world-hidden eye state — edge detection for environment suppress/restore. */
119
+ private _lastWorldHidden = false;
120
+ /**
121
+ * Spec 28 — recomputed from surface visibility AND selection ownership on every
122
+ * `syncFromStore`; read by the per-frame render hooks (`renderViewCube`,
123
+ * `renderCameraPreview`) and the view-cube click path, which run between
124
+ * notifies and must not re-walk the composite 60×/s.
125
+ */
126
+ private _threejsToolContextActive = false;
86
127
  private _vcRaycaster = new THREE.Raycaster();
87
128
 
88
129
  // -- Asset drop --
@@ -147,8 +188,14 @@ export class EditorViewport {
147
188
  private _flyEuler = new THREE.Euler(0, 0, 0, 'YXZ');
148
189
  private _rightMouseDown = false;
149
190
 
150
- constructor(canvas: HTMLCanvasElement, scene: THREE.Scene, store: EditorStore) {
191
+ constructor(
192
+ canvas: HTMLCanvasElement,
193
+ scene: THREE.Scene,
194
+ store: EditorStore,
195
+ interactionElement: HTMLElement = canvas,
196
+ ) {
151
197
  this._canvas = canvas;
198
+ this._interactionElement = interactionElement;
152
199
  this._scene = scene;
153
200
  this._store = store;
154
201
 
@@ -183,7 +230,7 @@ export class EditorViewport {
183
230
  scene.add(this.batchedRenderer);
184
231
 
185
232
  // OrbitControls – Unity-style: right-drag = orbit, middle-drag = pan, scroll = zoom
186
- this.orbitControls = new OrbitControls(this.camera, canvas);
233
+ this.orbitControls = new OrbitControls(this.camera, interactionElement);
187
234
  this.orbitControls.enableDamping = true;
188
235
  this.orbitControls.dampingFactor = 0.1;
189
236
  this.orbitControls.mouseButtons = {
@@ -361,10 +408,10 @@ export class EditorViewport {
361
408
  // -- Fly camera input (right-click + WASD) --
362
409
  window.addEventListener('keydown', this._onFlyKeyDown);
363
410
  window.addEventListener('keyup', this._onFlyKeyUp);
364
- canvas.addEventListener('pointerdown', this._onFlyPointerDown);
365
- canvas.addEventListener('pointerup', this._onFlyPointerUp);
366
- canvas.addEventListener('pointermove', this._onFlyPointerMove);
367
- canvas.addEventListener('wheel', this._onFlyWheel, { passive: false });
411
+ interactionElement.addEventListener('pointerdown', this._onFlyPointerDown);
412
+ interactionElement.addEventListener('pointerup', this._onFlyPointerUp);
413
+ interactionElement.addEventListener('pointermove', this._onFlyPointerMove);
414
+ interactionElement.addEventListener('wheel', this._onFlyWheel, { passive: false });
368
415
 
369
416
  // Alt+Left-drag = orbit (Unity-style), via capture phase so it fires before OrbitControls
370
417
  canvas.addEventListener(
@@ -527,8 +574,22 @@ export class EditorViewport {
527
574
  this.transformControls.setRotationSnap(snap ? THREE.MathUtils.degToRad(vals.rotate) : null);
528
575
  this.transformControls.setScaleSnap(snap ? vals.scale : null);
529
576
 
530
- // Grid visibility
531
- this.grid.visible = this._store.showGrid;
577
+ // Spec 28 step 2 — visibility says a Three.js surface is painted;
578
+ // selection ownership says it is the native world the user is editing.
579
+ // The grid, view cube, camera preview, and transform gizmo require BOTH.
580
+ // Empty/organizational/cross-world selections deliberately leave only
581
+ // shell chrome rather than advertising an arbitrary coordinate system.
582
+ const toolContext = resolveViewportToolContext(
583
+ getActiveAuthoring(this._store),
584
+ this._store.selectedEntityIds,
585
+ );
586
+ this._threejsToolContextActive =
587
+ isThreejsSurfaceVisible(this._store) &&
588
+ isViewportToolContextVisible(this._store, toolContext) &&
589
+ toolContext?.kind === 'threejs';
590
+
591
+ // Grid visibility — the user's toggle, AND'd with the surface actually showing
592
+ this.grid.visible = this._store.showGrid && this._threejsToolContextActive;
532
593
 
533
594
  // The two passes below (apply gizmos + per-type helper/icon visibility) are
534
595
  // idempotent and O(total scene nodes). Their only inputs are the objectMap
@@ -536,11 +597,49 @@ export class EditorViewport {
536
597
  // transform drag/scrub (which still fires syncFromStore every frame). Gate
537
598
  // them on a cheap signature so a drag doesn't re-walk the whole graph 60×/s.
538
599
  const vis = this._store.helperVisibility;
539
- const gizmoSig = `${this._objectMap.size}|${this._store.showHelpers}|${JSON.stringify(vis)}`;
600
+ // World-hidden eye (D9) folded into the SAME cheap signature/gate as the
601
+ // gizmo/helper passes below — see `world-hidden-viewport.ts`'s doc
602
+ // comment for why this must be recomputed from scratch on every rebuild
603
+ // (never a one-shot flip) and why folding it in here (rather than a
604
+ // separate always-on pass) is safe: the toggle itself
605
+ // (`GameHierarchy.tsx`'s `toggleWorldHidden` + `store.notifyIngestEdit()`)
606
+ // changes `hiddenWorldId`'s hidden state, which changes this signature,
607
+ // so it re-applies on the very next `syncFromStore()` call — exactly the
608
+ // same notify path that already re-triggers this whole method.
609
+ const hiddenWorldId = resolveFocusedViewportWorldId(this._store);
610
+ const hidden = hiddenWorldId !== null && isWorldHidden(hiddenWorldId);
611
+ // While hidden, re-apply on EVERY notify, not just signature changes: a
612
+ // SINGLE-entity rebuild (scene-sync `updateEntityPreview`) mutates the
613
+ // existing objectMap in place — same instance, same size, so the gate
614
+ // below never re-fires — while re-stamping the rebuilt object visible
615
+ // from its descriptor. Cost is one map walk per notify only while a
616
+ // world is actually hidden; the gated call below still handles the
617
+ // hide→show transition (restoring per-entity visibility).
618
+ if (hidden) applyWorldHiddenVisibility(this._objectMap, hiddenWorldId);
619
+ // Scene-LEVEL environment (background/skybox/fog/IBL/ambient — none of it
620
+ // in the objectMap) + the post-processing chain. Edge: both directions
621
+ // re-apply the authored environment from `_sceneMeta` truth and bump
622
+ // `composerVersion` (ViewportPanel's rebuild strips scene effects while
623
+ // hidden). While hidden: suppress on EVERY notify — same rationale as the
624
+ // per-notify `applyWorldHiddenVisibility` above, because an inspector
625
+ // environment edit mid-hide re-paints the authored values.
626
+ if (hidden !== this._lastWorldHidden) {
627
+ this._lastWorldHidden = hidden;
628
+ this._store.reapplyEnvironment();
629
+ }
630
+ if (hidden) suppressWorldEnvironment(this._scene);
631
+ const gizmoSig = `${this._objectMap.size}|${this._store.showHelpers}|${JSON.stringify(vis)}|${hiddenWorldId ?? ''}|${hidden}`;
540
632
  if (this._objectMap !== this._lastGizmoObjectMap || gizmoSig !== this._lastGizmoSig) {
541
633
  this._lastGizmoObjectMap = this._objectMap;
542
634
  this._lastGizmoSig = gizmoSig;
543
635
 
636
+ // Threejs roots have no DOM layer to `display:none` (unlike react/pixi
637
+ // — `design-time-layers.ts`'s `applySessionStyle`), so this is what
638
+ // actually makes a hidden threejs world's group-row eye hide its
639
+ // objects in THIS viewport. ABOVE the per-entity `visible` flag (ANDed
640
+ // in, never overwritten) — see `world-hidden-viewport.ts`.
641
+ applyWorldHiddenVisibility(this._objectMap, hiddenWorldId);
642
+
544
643
  // Ensure gizmos (icon billboards + wireframe helpers) exist on all objects.
545
644
  // Idempotent — needed for game scene objects created by the runtime without gizmos.
546
645
  for (const obj of this._objectMap.values()) {
@@ -557,6 +656,10 @@ export class EditorViewport {
557
656
  }
558
657
  if (!getUserData(child, 'editorHelper')) return;
559
658
  const type = getUserData(child, 'editorHelperType') as string | undefined;
659
+ if (type === 'skeletons') {
660
+ child.visible = vis.skeletons || Boolean(getUserData(child, 'skeletonEnabled'));
661
+ return;
662
+ }
560
663
  if (type && type in vis) {
561
664
  child.visible = vis[type as keyof typeof vis];
562
665
  } else {
@@ -570,8 +673,11 @@ export class EditorViewport {
570
673
  }
571
674
  }
572
675
 
573
- // Attach gizmo based on pivot mode
574
- const selectedId = this._store.selectedEntityId;
676
+ // Attach gizmo based on pivot mode. Spec 28: no gizmo without a visible
677
+ // threejs surface — this whole block re-derives per notify, so detaching
678
+ // here is self-healing (the un-hide notify re-attaches to the same
679
+ // selection with no extra bookkeeping).
680
+ const selectedId = this._threejsToolContextActive ? this._store.selectedEntityId : null;
575
681
  if (selectedId) {
576
682
  if (!this.transformControls.dragging) {
577
683
  if (this._store.pivotMode === 'median-point' && this._store.selectedEntityIds.size > 1) {
@@ -803,6 +909,7 @@ export class EditorViewport {
803
909
 
804
910
  /** Render the orientation gizmo overlaid in the top-right corner. */
805
911
  renderViewCube(renderer: THREE.WebGLRenderer): void {
912
+ if (!this._threejsToolContextActive) return; // spec 28 — no selected 3D context, no compass
806
913
  const w = renderer.domElement.clientWidth;
807
914
  const h = renderer.domElement.clientHeight;
808
915
  const size = this._vcSize;
@@ -833,6 +940,7 @@ export class EditorViewport {
833
940
 
834
941
  /** Render a small camera preview in the bottom-right corner if a camera entity is selected. */
835
942
  renderCameraPreview(renderer: THREE.WebGLRenderer): void {
943
+ if (!this._threejsToolContextActive) return; // spec 28 — no selected 3D context, no preview
836
944
  const selectedEntity = this._store.selectedEntity;
837
945
  if (!selectedEntity?.camera) return;
838
946
 
@@ -904,10 +1012,10 @@ export class EditorViewport {
904
1012
  setViewportPickContext(null);
905
1013
  window.removeEventListener('keydown', this._onFlyKeyDown);
906
1014
  window.removeEventListener('keyup', this._onFlyKeyUp);
907
- this._canvas.removeEventListener('pointerdown', this._onFlyPointerDown);
908
- this._canvas.removeEventListener('pointerup', this._onFlyPointerUp);
909
- this._canvas.removeEventListener('pointermove', this._onFlyPointerMove);
910
- this._canvas.removeEventListener('wheel', this._onFlyWheel);
1015
+ this._interactionElement.removeEventListener('pointerdown', this._onFlyPointerDown);
1016
+ this._interactionElement.removeEventListener('pointerup', this._onFlyPointerUp);
1017
+ this._interactionElement.removeEventListener('pointermove', this._onFlyPointerMove);
1018
+ this._interactionElement.removeEventListener('wheel', this._onFlyWheel);
911
1019
  this._canvas.removeEventListener('pointerdown', this._onPointerDown);
912
1020
  this._canvas.removeEventListener('pointermove', this._onPointerMove);
913
1021
  this._canvas.removeEventListener('pointerup', this._onPointerUp);
@@ -939,12 +1047,8 @@ export class EditorViewport {
939
1047
  light.position.set(1, 2, 3);
940
1048
  this._vcScene.add(light);
941
1049
 
942
- // Godot axis colors
943
- const colors = [
944
- new THREE.Color(0.96, 0.2, 0.32), // X
945
- new THREE.Color(0.53, 0.84, 0.01), // Y
946
- new THREE.Color(0.16, 0.55, 0.96), // Z
947
- ];
1050
+ // Godot axis colors (V-13 — see module-level `GODOT_AXIS_COLOR_RGB`)
1051
+ const colors = GODOT_AXIS_COLOR_RGB.map(([r, g, b]) => new THREE.Color(r, g, b));
948
1052
  const axes = [
949
1053
  new THREE.Vector3(1, 0, 0),
950
1054
  new THREE.Vector3(0, 1, 0),
@@ -1283,10 +1387,11 @@ export class EditorViewport {
1283
1387
 
1284
1388
  /** Recolor gizmo handles to Godot axis colors & shift plane geometry to meet at center. */
1285
1389
  private _patchGizmo(gizmoHelper: THREE.Object3D): void {
1286
- // Godot axis colors: Color(0.96,0.20,0.32), Color(0.53,0.84,0.01), Color(0.16,0.55,0.96)
1287
- const axisX = new THREE.Color(0.96, 0.2, 0.32);
1288
- const axisY = new THREE.Color(0.53, 0.84, 0.01);
1289
- const axisZ = new THREE.Color(0.16, 0.55, 0.96);
1390
+ // Godot axis colors (V-13 — see module-level `GODOT_AXIS_COLOR_RGB`)
1391
+ const [axisRgbX, axisRgbY, axisRgbZ] = GODOT_AXIS_COLOR_RGB;
1392
+ const axisX = new THREE.Color(...axisRgbX!);
1393
+ const axisY = new THREE.Color(...axisRgbY!);
1394
+ const axisZ = new THREE.Color(...axisRgbZ!);
1290
1395
 
1291
1396
  // Handle color: axis handles use axis color, plane handles use normal-axis color
1292
1397
  const colorMap: Record<string, THREE.Color> = {
@@ -1591,12 +1696,16 @@ export class EditorViewport {
1591
1696
 
1592
1697
  if (!this._marqueeDiv) {
1593
1698
  this._marqueeDiv = document.createElement('div');
1699
+ // V-12 — was the string `'999'` (a stray string literal in an
1700
+ // otherwise-numeric z-index scale); now the canonical `zIndex.sticky`
1701
+ // token (numeric `1000`, same absorbed tier as the old `999`/`1000`
1702
+ // pair per the audit's own z-index reconciliation).
1594
1703
  Object.assign(this._marqueeDiv.style, {
1595
1704
  position: 'fixed',
1596
- border: '1px solid #579EFF',
1597
- background: 'rgba(87, 158, 255, 0.15)',
1705
+ border: `1px solid ${themeVars.accent.default}`,
1706
+ background: themeVars.accent.muted,
1598
1707
  pointerEvents: 'none',
1599
- zIndex: '999',
1708
+ zIndex: zIndex.sticky,
1600
1709
  });
1601
1710
  document.body.appendChild(this._marqueeDiv);
1602
1711
  }
@@ -1653,6 +1762,16 @@ export class EditorViewport {
1653
1762
  for (const [id, obj] of this._objectMap) {
1654
1763
  // Skip locked entities in marquee selection
1655
1764
  if (this._store.isEntityLocked(id)) continue;
1765
+ // Skip invisible entities — mirrors `raycastPick`'s single-click
1766
+ // behavior for free (THREE.Raycaster's own `intersectObject` already
1767
+ // stops descending into an `obj.visible === false` subtree, so a
1768
+ // single click can never land on one). Marquee did its own screen-
1769
+ // space rect test with no such check, so a world hidden via the
1770
+ // group-row eye (`world-hidden-viewport.ts` — forces `obj.visible =
1771
+ // false` for the whole world while hidden) stayed marquee-selectable
1772
+ // even though it was invisible and unclickable. Also correctly skips
1773
+ // an entity hidden via its OWN eye, for the same reason.
1774
+ if (!obj.visible) continue;
1656
1775
  const screen = this._projectToScreen(obj);
1657
1776
  if (screen.x >= left && screen.x <= right && screen.y >= top && screen.y <= bottom) {
1658
1777
  hitIds.push(id);
@@ -1680,8 +1799,9 @@ export class EditorViewport {
1680
1799
  // Don't interfere with gizmo clicks
1681
1800
  if (this.transformControls.dragging) return;
1682
1801
 
1683
- // Check orientation gizmo click first
1684
- if (this._handleViewCubeClick(e)) return;
1802
+ // Check orientation gizmo click first (spec 28 — the cube isn't rendered
1803
+ // without a visible threejs surface, so it can't be clicked either)
1804
+ if (this._threejsToolContextActive && this._handleViewCubeClick(e)) return;
1685
1805
 
1686
1806
  // D12 (B4) — topmost-first layered pick: the composite's non-threejs
1687
1807
  // children (react/pixi design-time layers) are tried topmost-first before
@@ -1720,13 +1840,19 @@ export class EditorViewport {
1720
1840
  private _showDropOverlay(): void {
1721
1841
  if (this._dropOverlay) return;
1722
1842
  const overlay = document.createElement('div');
1843
+ // V-12 — the stray string `'5'` (below every named tier in the z-index
1844
+ // scale) becomes the numeric `zIndex.base`, the lowest defined tier,
1845
+ // preserving its relative order (still below the marquee's `zIndex.
1846
+ // sticky` and every dropdown/menu). The semantic accent tokens reconcile this
1847
+ // block's one-off `#579EFF`/`rgba(87,158,255,0.08)` onto the canonical
1848
+ // accent tint per the audit's own §3 absorption list.
1723
1849
  Object.assign(overlay.style, {
1724
1850
  position: 'fixed',
1725
1851
  inset: '0',
1726
1852
  pointerEvents: 'none',
1727
- border: '2px dashed #579EFF',
1728
- background: 'rgba(87, 158, 255, 0.08)',
1729
- zIndex: '5',
1853
+ border: `2px dashed ${themeVars.accent.default}`,
1854
+ background: themeVars.accent.muted,
1855
+ zIndex: zIndex.base,
1730
1856
  });
1731
1857
  document.body.appendChild(overlay);
1732
1858
  this._dropOverlay = overlay;
@@ -1787,7 +1913,7 @@ export class EditorViewport {
1787
1913
  const baseName = online.name.replace(/\.[^.]+$/, '');
1788
1914
 
1789
1915
  // Already downloaded? Create entity instantly, no placeholder needed.
1790
- const cachedPath = getDownloadedAssetPath(online.source, online.name);
1916
+ const cachedPath = getDownloadedAssetPath(online.source, online.id);
1791
1917
  if (cachedPath) {
1792
1918
  this._store.addEntity(null, {
1793
1919
  id: crypto.randomUUID(),
@@ -4,6 +4,7 @@ import { buildClipMap } from '@engine/animation/clip-map';
4
4
  // disposal-safe clone (own materials + `__sharedGeometry` tags) — the same
5
5
  // clone-safety contract the runtime relies on.
6
6
  import { loadGLTF, resolveGltfNode } from '@engine/scene/asset-loaders';
7
+ import { applyImportCorrection, getAssetMeta, loadRegistry } from '@engine/scene/asset-registry';
7
8
  import { DEFAULTS } from '@engine/scene/defaults';
8
9
  import { deleteUserData, getUserData, setUserData } from '@engine/scene/user-data';
9
10
  import '@engine/scene/geometries';
@@ -20,6 +21,7 @@ import '@engine/scene/materials';
20
21
  import { createParticleSystemFromData } from '@engine/scene/particles-factory';
21
22
  import type { SceneEntity } from '@engine/scene/scene-types';
22
23
  import * as THREE from 'three';
24
+ import { ensureSkeletonHelper } from './skeleton-helper';
23
25
 
24
26
  /**
25
27
  * Load a GLTF and return a disposal-safe clone + its animation clips for the
@@ -40,9 +42,10 @@ function setupAnimation(
40
42
  animations: THREE.AnimationClip[],
41
43
  autoplay?: string,
42
44
  loop?: boolean,
45
+ clipAliases?: Record<string, string>,
43
46
  ): void {
44
47
  if (animations.length === 0) return;
45
- const clipMap = buildClipMap(animations);
48
+ const clipMap = buildClipMap(animations, clipAliases);
46
49
 
47
50
  // Expose available clip names for the inspector dropdown
48
51
  setUserData(group, '_availableClips', [...clipMap.keys()]);
@@ -95,10 +98,16 @@ export function createEntityObject(entity: SceneEntity): THREE.Object3D {
95
98
  const group = new THREE.Group();
96
99
  const src = entity.mesh.src;
97
100
 
98
- const gltfPromise = loadGltfWithClips(src);
101
+ // Runtime scene loading awaits this same registry before constructing a
102
+ // model. Await it alongside the GLTF so editor preview and Play apply the
103
+ // exact same visual-only scale/facing correction.
104
+ const gltfPromise = Promise.all([loadGltfWithClips(src), loadRegistry()]).then(
105
+ ([gltf]) => gltf,
106
+ );
99
107
 
100
108
  const autoplay = entity.animation?.autoplay;
101
109
  const loop = entity.animation?.loop;
110
+ const clipAliases = entity.animation?.clipAliases;
102
111
 
103
112
  const nodeName = entity.mesh.node;
104
113
  const lod = entity.mesh.lod;
@@ -128,6 +137,7 @@ export function createEntityObject(entity: SceneEntity): THREE.Object3D {
128
137
  content.rotation.set(0, 0, 0);
129
138
  content.scale.set(1, 1, 1);
130
139
  }
140
+ applyImportCorrection(content, getAssetMeta(src)?.importCorrection);
131
141
  group.add(content);
132
142
  // The shared loadGLTF already gave the clone its own materials and tagged
133
143
  // every mesh `__sharedGeometry` (so editor disposal in scene-sync never
@@ -136,7 +146,8 @@ export function createEntityObject(entity: SceneEntity): THREE.Object3D {
136
146
  content.traverse((n) => {
137
147
  setUserData(n, '__sharedGeometry', true);
138
148
  });
139
- setupAnimation(group, clone, animations, autoplay, loop);
149
+ setupAnimation(group, clone, animations, autoplay, loop, clipAliases);
150
+ ensureSkeletonHelper(group);
140
151
  });
141
152
  obj = group;
142
153
  } else {
@@ -24,6 +24,7 @@ import type {
24
24
  import { getUserData, setUserData } from '@engine/scene/user-data';
25
25
  import * as THREE from 'three';
26
26
  import { EDITOR_LAYER } from './editor-layers';
27
+ import { ensureSkeletonHelper } from './skeleton-helper';
27
28
 
28
29
  // ---------------------------------------------------------------------------
29
30
  // Registry types
@@ -361,7 +362,7 @@ const audioGizmo: GizmoEntry = {
361
362
  * `dims` already has the entity's composed world scale (self × ancestors)
362
363
  * applied, so this function itself must NOT apply any further scale.
363
364
  */
364
- function createColliderHelper(
365
+ export function createColliderHelper(
365
366
  collider: SceneCollider,
366
367
  dims: ColliderWorldDimensions,
367
368
  ): THREE.Object3D | null {
@@ -424,7 +425,9 @@ function createColliderHelper(
424
425
  return null;
425
426
  }
426
427
 
427
- return group.children.length > 0 ? group : null;
428
+ if (group.children.length === 0) return null;
429
+ if (collider.offset) group.position.fromArray(collider.offset);
430
+ return group;
428
431
  }
429
432
 
430
433
  const colliderGizmo: GizmoEntry = {
@@ -566,11 +569,23 @@ const GIZMO_REGISTRY: GizmoEntry[] = [
566
569
  */
567
570
  export function applyEntityGizmos(obj: THREE.Object3D): void {
568
571
  const entity = getUserData(obj, 'entity') as SceneEntity | undefined;
569
- if (!entity) return;
572
+ if (!entity) {
573
+ ensureSkeletonHelper(obj);
574
+ return;
575
+ }
570
576
 
571
- // Idempotent: skip if gizmos already applied
572
- if (obj.children.some((c) => getUserData(c, 'editorHelper') || getUserData(c, 'editorIcon')))
577
+ // Skeletons are created independently from entity gizmos and must not make
578
+ // collider/light/etc. setup look complete.
579
+ const hasEntityGizmos = obj.children.some(
580
+ (child) =>
581
+ getUserData(child, 'editorIcon') ||
582
+ (getUserData(child, 'editorHelper') &&
583
+ getUserData(child, 'editorHelperType') !== 'skeletons'),
584
+ );
585
+ if (hasEntityGizmos) {
586
+ ensureSkeletonHelper(obj);
573
587
  return;
588
+ }
574
589
 
575
590
  let added = false;
576
591
  for (const entry of GIZMO_REGISTRY) {
@@ -605,4 +620,5 @@ export function applyEntityGizmos(obj: THREE.Object3D): void {
605
620
 
606
621
  // Force matrix computation so helpers render at the correct position immediately
607
622
  if (added) obj.updateMatrixWorld(true);
623
+ ensureSkeletonHelper(obj);
608
624
  }
@@ -0,0 +1,37 @@
1
+ /** Lightweight bridge from the editor shell into the coding-agent panel.
2
+ * Kept free of EditorContext's engine import graph so the panel remains
3
+ * independently testable and the Supercode-facing UI stays framework-thin. */
4
+ export interface HarnessChatEditorStore {
5
+ subscribe(listener: () => void): () => void;
6
+ getSnapshot(): number;
7
+ readonly selectedEntityId: string | null;
8
+ readonly selectedEntity: {
9
+ id?: string | undefined;
10
+ name?: string | undefined;
11
+ } | null;
12
+ readonly playState: 'stopped' | 'playing' | 'paused';
13
+ }
14
+
15
+ let current: HarnessChatEditorStore | null = null;
16
+ let version = 0;
17
+ const listeners = new Set<() => void>();
18
+
19
+ export function setHarnessChatEditorStore(store: HarnessChatEditorStore | null): void {
20
+ if (current === store) return;
21
+ current = store;
22
+ version++;
23
+ for (const listener of listeners) listener();
24
+ }
25
+
26
+ export function harnessChatEditorStore(): HarnessChatEditorStore | null {
27
+ return current;
28
+ }
29
+
30
+ export function subscribeHarnessChatEditorStore(listener: () => void): () => void {
31
+ listeners.add(listener);
32
+ return () => listeners.delete(listener);
33
+ }
34
+
35
+ export function harnessChatEditorStoreVersion(): number {
36
+ return version;
37
+ }
@@ -0,0 +1,68 @@
1
+ import type { HarnessChatSnapshot } from './harness-chat-types';
2
+
3
+ export interface HarnessChatIndicator {
4
+ /** This editor owns the selected runtime. This is deliberately a state,
5
+ * not a fabricated multi-agent count. */
6
+ controlled: boolean;
7
+ working: boolean;
8
+ needsInput: boolean;
9
+ following: boolean;
10
+ unavailable: boolean;
11
+ }
12
+
13
+ let current: HarnessChatIndicator = {
14
+ controlled: false,
15
+ working: false,
16
+ needsInput: false,
17
+ following: false,
18
+ unavailable: false,
19
+ };
20
+ let version = 0;
21
+ const listeners = new Set<() => void>();
22
+
23
+ export function updateHarnessChatIndicator(snapshot: HarnessChatSnapshot): void {
24
+ const next: HarnessChatIndicator = {
25
+ controlled: snapshot.connection.ownsRuntime,
26
+ working: snapshot.turn.state !== 'idle',
27
+ needsInput: snapshot.requests.some((request) => request.status === 'pending'),
28
+ following: snapshot.connection.follow !== 'inactive',
29
+ unavailable: snapshot.status === 'unavailable',
30
+ };
31
+ if (
32
+ next.controlled === current.controlled &&
33
+ next.working === current.working &&
34
+ next.needsInput === current.needsInput &&
35
+ next.following === current.following &&
36
+ next.unavailable === current.unavailable
37
+ ) {
38
+ return;
39
+ }
40
+ current = next;
41
+ version++;
42
+ for (const listener of listeners) listener();
43
+ }
44
+
45
+ export function harnessChatIndicator(): HarnessChatIndicator {
46
+ return current;
47
+ }
48
+
49
+ export function harnessChatIndicatorVersion(): number {
50
+ return version;
51
+ }
52
+
53
+ export function subscribeHarnessChatIndicator(listener: () => void): () => void {
54
+ listeners.add(listener);
55
+ return () => listeners.delete(listener);
56
+ }
57
+
58
+ export function __resetHarnessChatIndicatorForTest(): void {
59
+ current = {
60
+ controlled: false,
61
+ working: false,
62
+ needsInput: false,
63
+ following: false,
64
+ unavailable: false,
65
+ };
66
+ version++;
67
+ for (const listener of listeners) listener();
68
+ }
@@ -0,0 +1,53 @@
1
+ /** Presentation state for the permanent coding-agent surface.
2
+ *
3
+ * Chat is a Dockview panel, so Dockview owns its position and size. This tiny
4
+ * store owns only whether the optional panel is present. Supercode's server
5
+ * controller remains independent of either surface, so closing/moving the
6
+ * panel never detaches or hands off a controlled harness session.
7
+ */
8
+
9
+ export interface HarnessChatLayoutState {
10
+ readonly collapsed: boolean;
11
+ }
12
+
13
+ let state: HarnessChatLayoutState = { collapsed: false };
14
+ let version = 0;
15
+ const listeners = new Set<() => void>();
16
+
17
+ function publish(next: HarnessChatLayoutState): void {
18
+ if (next.collapsed === state.collapsed) return;
19
+ state = next;
20
+ version += 1;
21
+ for (const listener of listeners) listener();
22
+ }
23
+
24
+ export function subscribeHarnessChatLayout(listener: () => void): () => void {
25
+ listeners.add(listener);
26
+ return () => listeners.delete(listener);
27
+ }
28
+
29
+ export function harnessChatLayoutVersion(): number {
30
+ return version;
31
+ }
32
+
33
+ export function harnessChat(): HarnessChatLayoutState {
34
+ return state;
35
+ }
36
+
37
+ export function setHarnessChatCollapsed(collapsed: boolean): void {
38
+ publish({ ...state, collapsed });
39
+ }
40
+
41
+ export function toggleHarnessChatCollapsed(): void {
42
+ setHarnessChatCollapsed(!state.collapsed);
43
+ }
44
+
45
+ export function hydrateHarnessChatLayout(next: Partial<HarnessChatLayoutState>): void {
46
+ publish({ collapsed: next.collapsed ?? state.collapsed });
47
+ }
48
+
49
+ export function __resetHarnessChatLayoutForTest(): void {
50
+ state = { collapsed: false };
51
+ version = 0;
52
+ listeners.clear();
53
+ }