@vgai/editor 0.2.0 → 0.4.0-canary.20260715.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (430) hide show
  1. package/README.md +24 -0
  2. package/dist/assets/axe-C7YBtOuM.js +30 -0
  3. package/dist/assets/browserAll-DDtGGE48.js +1 -0
  4. package/dist/assets/create-runtime-DbTlBlKG.js +1 -0
  5. package/dist/assets/{game-BI111o5f.js → game-BE0r7DMI.js} +3 -3
  6. package/dist/assets/game-BdTHR2_X.js +1 -0
  7. package/dist/assets/{game-pt_1lQLv.js → game-C3iQGSqo.js} +1 -1
  8. package/dist/assets/game-CcHfYxjP.js +1 -0
  9. package/dist/assets/game-Cqzj_lpD.js +1 -0
  10. package/dist/assets/game-DSZdeCHu.js +1 -0
  11. package/dist/assets/game-Dch9sAPc.js +1 -0
  12. package/dist/assets/{game-xsOho_wg.js → game-SAFn90pA.js} +3 -3
  13. package/dist/assets/game-loop-DMIgSMV-.js +1 -0
  14. package/dist/assets/{game-source-CvidN7AB.js → game-source-Dk83w26t.js} +1 -1
  15. package/dist/assets/{index-Bp5cecD6.js → index-4idIsHHJ.js} +2 -2
  16. package/dist/assets/{index-DL7RcQ0n.js → index-C-LhOTBN.js} +1 -1
  17. package/dist/assets/{index-Cs8xwv3e.js → index-CDkxceqE.js} +1 -1
  18. package/dist/assets/index-CQEfi217.js +15412 -0
  19. package/dist/assets/index-Dvi-V0NE.css +1 -0
  20. package/dist/assets/ingest-siblings-s0P5I1Ub.js +1 -0
  21. package/dist/assets/mount-manifest-DXMOlF79.js +1 -0
  22. package/dist/assets/react-18-C9eHn8x1.js +1 -0
  23. package/dist/assets/webworkerAll-Fn0e-ouF.js +1 -0
  24. package/dist/assets/world-documents-GM0a9Kv7.js +1 -0
  25. package/dist/index.html +15 -13
  26. package/dist/ingest/racing-game/vgai.game.json +5 -4
  27. package/dist/ingest/simcity/vgai.game.json +5 -4
  28. package/dist/ingest/tanks/vgai.game.json +5 -4
  29. package/dist/project-scripts.bundle.js +3917 -0
  30. package/dist/scenes/untitled.vscn.json +2 -0
  31. package/dist-server/packaged.mjs +7697 -3435
  32. package/package.json +31 -4
  33. package/scripts/probe-reporter.ts +349 -0
  34. package/scripts/run-probe.ts +2260 -0
  35. package/server/asset-catalog-audit.ts +268 -0
  36. package/server/asset-catalog-v2.ts +146 -0
  37. package/server/asset-library-routes.ts +276 -58
  38. package/server/canonical-path.ts +1 -1
  39. package/server/dev.ts +148 -44
  40. package/server/editor-server.ts +888 -61
  41. package/server/editor-sse.ts +115 -4
  42. package/server/harness-chat-service.ts +796 -0
  43. package/server/local-asset-catalog.ts +157 -22
  44. package/server/packaged.ts +51 -21
  45. package/server/process-shutdown.ts +136 -0
  46. package/server/prod.ts +9 -6
  47. package/server/project-hmr-files.ts +41 -0
  48. package/server/project-operations.ts +343 -0
  49. package/server/project-optimize-deps-entries.ts +4 -4
  50. package/server/project-output-writer.ts +156 -0
  51. package/server/project-validation.ts +140 -0
  52. package/server/project-view.ts +8 -50
  53. package/server/server-utils.ts +75 -10
  54. package/server/session-registry.ts +12 -0
  55. package/src/EditorContext.tsx +107 -3
  56. package/src/action-registry.ts +115 -17
  57. package/src/adapter-resolver.ts +213 -478
  58. package/src/asset-events.ts +64 -1
  59. package/src/asset-preview.ts +906 -0
  60. package/src/asset-selection.ts +121 -0
  61. package/src/asset-workflow/asset-capabilities.ts +259 -0
  62. package/src/asset-workflow/asset-editor-errors.ts +46 -0
  63. package/src/asset-workflow/asset-import-pipeline.ts +176 -0
  64. package/src/asset-workflow/asset-library-query.ts +107 -0
  65. package/src/asset-workflow/asset-types.ts +192 -0
  66. package/src/asset-workflow/asset-workflow-quality.ts +65 -0
  67. package/src/asset-workflow/import-contract.ts +113 -0
  68. package/src/asset-workflow/model-conversion.ts +126 -0
  69. package/src/asset-workflow/model-inspection.ts +185 -0
  70. package/src/asset-workflow/project-asset-commands.ts +23 -0
  71. package/src/asset-workflow/project-asset-health.ts +153 -0
  72. package/src/asset-workflow/project-asset-operations.ts +119 -0
  73. package/src/asset-workflow/thumbnail-system.ts +172 -0
  74. package/src/authoring/active-systems.ts +15 -0
  75. package/src/authoring/boundary-authoring-adapter.ts +16 -5
  76. package/src/authoring/composite-authoring-adapter.ts +305 -124
  77. package/src/authoring/design-time-layers.ts +300 -117
  78. package/src/authoring/edit-mode-authoring.ts +278 -293
  79. package/src/authoring/embed-only-adapter.ts +4 -2
  80. package/src/authoring/first-party-hierarchy-menu.ts +7 -2
  81. package/src/authoring/first-party-inspector/AddSectionMenu.tsx +5 -12
  82. package/src/authoring/first-party-inspector/EnvironmentSection.tsx +53 -126
  83. package/src/authoring/first-party-inspector/HeaderSection.tsx +54 -65
  84. package/src/authoring/first-party-inspector/is-first-party-selection.ts +30 -11
  85. package/src/authoring/first-party-inspector/register.tsx +13 -2
  86. package/src/authoring/ingest-authoring-adapter.ts +142 -45
  87. package/src/authoring/mount-failure-report.ts +5 -5
  88. package/src/authoring/provenance.ts +41 -0
  89. package/src/authoring/react-dom-authoring-adapter.ts +92 -92
  90. package/src/authoring/react-inspector-section.tsx +489 -51
  91. package/src/authoring/react-world-authoring-adapter.ts +541 -306
  92. package/src/authoring/story-overlay.ts +1 -1
  93. package/src/authoring/story-types.ts +11 -0
  94. package/src/authoring/vgai-scene-authoring-adapter.ts +54 -25
  95. package/src/authoring/viewport-tool-context.ts +78 -0
  96. package/src/authoring/world-canvas-viewport-state.ts +35 -0
  97. package/src/authoring/world-hidden-viewport.ts +186 -0
  98. package/src/authoring/world-pan-state.ts +33 -17
  99. package/src/authoring/world-session-state.ts +1 -1
  100. package/src/authoring/world2d-authoring-adapter.ts +109 -52
  101. package/src/availability-tick.ts +56 -0
  102. package/src/browser-play-entry.ts +5 -5
  103. package/src/browser-project-scripts.ts +1 -0
  104. package/src/build-identity.ts +15 -0
  105. package/src/command-listener.ts +893 -19
  106. package/src/components/AlignToolbar.tsx +74 -63
  107. package/src/components/AppRoot.tsx +193 -26
  108. package/src/components/ApplicationMenus.tsx +272 -0
  109. package/src/components/AssetBrowser.tsx +1450 -293
  110. package/src/components/AssetEditorShell.tsx +141 -0
  111. package/src/components/AssetImportDetails.tsx +218 -0
  112. package/src/components/AssetLibraryPanel.tsx +14 -0
  113. package/src/components/CameraInfo.tsx +11 -20
  114. package/src/components/CenterDocuments.tsx +585 -0
  115. package/src/components/CommandPalette.tsx +75 -30
  116. package/src/components/ConsolePanel.css +55 -0
  117. package/src/components/ConsolePanel.tsx +57 -112
  118. package/src/components/DebugConsolePanel.tsx +461 -0
  119. package/src/components/DebuggerPanel.tsx +165 -0
  120. package/src/components/DefaultEditorLayout.tsx +167 -231
  121. package/src/components/GameHierarchy.tsx +873 -290
  122. package/src/components/GamePerformanceOverlay.tsx +46 -0
  123. package/src/components/HarnessChatPanel.tsx +2352 -0
  124. package/src/components/HistoryPanel.tsx +226 -0
  125. package/src/components/Inspector.tsx +153 -99
  126. package/src/components/InspectorToolSection.tsx +6 -4
  127. package/src/components/MountFailureBanner.tsx +31 -48
  128. package/src/components/NetworkSection.tsx +25 -14
  129. package/src/components/OnlineAssetBrowser.tsx +794 -343
  130. package/src/components/OverlayReportBanner.tsx +38 -64
  131. package/src/components/PerformancePanel.tsx +206 -0
  132. package/src/components/PlayBar.tsx +93 -263
  133. package/src/components/PrefabSaveDialog.tsx +55 -127
  134. package/src/components/ProjectHeader.css +60 -0
  135. package/src/components/ProjectHeader.tsx +170 -105
  136. package/src/components/ProjectScreen.tsx +246 -184
  137. package/src/components/ReactCanvasControls.tsx +185 -0
  138. package/src/components/ResolutionPicker.tsx +85 -0
  139. package/src/components/RootActivateDialog.tsx +39 -68
  140. package/src/components/SaveDialog.tsx +55 -127
  141. package/src/components/SaveStatus.tsx +11 -29
  142. package/src/components/StartupLoadingScreen.tsx +96 -0
  143. package/src/components/StateWatchPanel.tsx +302 -0
  144. package/src/components/StatsOverlay.tsx +12 -5
  145. package/src/components/StatusBar.tsx +64 -0
  146. package/src/components/ThemeManagerDialog.css +89 -0
  147. package/src/components/ThemeManagerDialog.tsx +371 -0
  148. package/src/components/ToolHost.tsx +26 -15
  149. package/src/components/Toolbar.tsx +117 -214
  150. package/src/components/VgaiVoxelLogo.tsx +89 -0
  151. package/src/components/ViewportOverlay.tsx +97 -172
  152. package/src/components/ViewportPanel.tsx +130 -31
  153. package/src/components/WorkspaceDock.tsx +891 -0
  154. package/src/components/WorldSelectionOverlay.tsx +51 -63
  155. package/src/components/WorldTextEditor.tsx +9 -5
  156. package/src/components/asset-documents.tsx +390 -0
  157. package/src/components/asset-editor-persistence.ts +44 -0
  158. package/src/components/asset-selection-section.tsx +338 -0
  159. package/src/components/asset-viewers/AudioViewer.tsx +73 -21
  160. package/src/components/asset-viewers/GenericJsonViewer.tsx +26 -11
  161. package/src/components/asset-viewers/ImageViewer.tsx +43 -11
  162. package/src/components/asset-viewers/InputMapViewer.tsx +512 -134
  163. package/src/components/asset-viewers/MaterialAssetEditor.tsx +540 -0
  164. package/src/components/asset-viewers/ModelViewer.tsx +805 -121
  165. package/src/components/asset-viewers/OnlineAssetDetail.tsx +177 -60
  166. package/src/components/asset-viewers/SourceAssetViewer.tsx +121 -0
  167. package/src/components/asset-workflow.css +506 -0
  168. package/src/components/build-documents.tsx +696 -0
  169. package/src/components/core-utilities.tsx +75 -0
  170. package/src/components/data-documents.tsx +364 -0
  171. package/src/components/{DataPanel.tsx → data-editor.tsx} +138 -288
  172. package/src/components/debugger-panel-state.ts +57 -0
  173. package/src/components/inspector-widgets/AlignmentGrid.tsx +8 -14
  174. package/src/components/inspector-widgets/BorderEditor.tsx +41 -33
  175. package/src/components/inspector-widgets/ColorPicker.tsx +39 -39
  176. package/src/components/inspector-widgets/FontPicker.tsx +13 -21
  177. package/src/components/inspector-widgets/GradientEditor.tsx +11 -19
  178. package/src/components/inspector-widgets/ScrubbableInput.tsx +6 -3
  179. package/src/components/inspector-widgets/ShadowEditor.tsx +20 -33
  180. package/src/components/inspector-widgets/shared.tsx +90 -49
  181. package/src/components/inspectors/AnimationSection.tsx +39 -40
  182. package/src/components/inspectors/AudioSection.tsx +28 -39
  183. package/src/components/inspectors/BoneAttachmentSection.tsx +19 -24
  184. package/src/components/inspectors/CameraSection.tsx +14 -23
  185. package/src/components/inspectors/ComponentsSection.tsx +39 -43
  186. package/src/components/inspectors/JointsSection.tsx +34 -43
  187. package/src/components/inspectors/LightSection.tsx +90 -35
  188. package/src/components/inspectors/MaterialSection.tsx +137 -174
  189. package/src/components/inspectors/MeshSection.tsx +9 -17
  190. package/src/components/inspectors/NavigationSection.tsx +8 -15
  191. package/src/components/inspectors/ParticleSection.tsx +91 -76
  192. package/src/components/inspectors/PhysicsSection.tsx +42 -46
  193. package/src/components/inspectors/PostProcessingSection.tsx +28 -36
  194. package/src/components/inspectors/RenderingSection.tsx +12 -20
  195. package/src/components/inspectors/ShadowSection.tsx +7 -8
  196. package/src/components/inspectors/SplineSection.tsx +31 -42
  197. package/src/components/inspectors/TransformSection.tsx +14 -22
  198. package/src/components/patterns/Dialog.tsx +95 -0
  199. package/src/components/patterns/Fields.tsx +44 -0
  200. package/src/components/patterns/List.tsx +25 -0
  201. package/src/components/patterns/StateSurface.tsx +40 -0
  202. package/src/components/patterns/Surfaces.tsx +115 -0
  203. package/src/components/patterns/Tabs.tsx +80 -0
  204. package/src/components/patterns/Toolbar.tsx +51 -0
  205. package/src/components/patterns/Tree.tsx +72 -0
  206. package/src/components/primitives/Button.tsx +46 -0
  207. package/src/components/primitives/ColorInput.tsx +11 -47
  208. package/src/components/primitives/EditorIcon.tsx +99 -0
  209. package/src/components/primitives/FormControls.tsx +71 -0
  210. package/src/components/primitives/JsonInput.tsx +15 -2
  211. package/src/components/primitives/Layout.tsx +100 -0
  212. package/src/components/primitives/Menu.tsx +105 -0
  213. package/src/components/primitives/NumberInput.tsx +8 -35
  214. package/src/components/primitives/Panel.tsx +49 -44
  215. package/src/components/primitives/SectionHeader.tsx +10 -28
  216. package/src/components/primitives/Text.tsx +46 -0
  217. package/src/components/primitives/Tooltip.tsx +20 -12
  218. package/src/components/primitives/Vec3Input.tsx +3 -0
  219. package/src/components/primitives/banner-tones.ts +33 -0
  220. package/src/components/primitives/editor-icons.ts +102 -0
  221. package/src/components/primitives/panel-header-styles.ts +30 -0
  222. package/src/components/project-operation-documents.tsx +226 -0
  223. package/src/components/status-contributions.tsx +175 -0
  224. package/src/components/story-documents-register.ts +15 -0
  225. package/src/components/story-documents.tsx +1185 -0
  226. package/src/components/tool-documents.tsx +110 -0
  227. package/src/components/workspace-dock.css +293 -0
  228. package/src/components/workspace-history.ts +33 -0
  229. package/src/components/world-documents.tsx +145 -0
  230. package/src/components/xstate-documents.tsx +209 -0
  231. package/src/composite-screenshot.ts +248 -0
  232. package/src/design-system/index.ts +70 -0
  233. package/src/design-system-stories/Foundation.stories.tsx +183 -0
  234. package/src/design-system-stories/Patterns.stories.tsx +251 -0
  235. package/src/design-system-stories/Workspace.stories.tsx +538 -0
  236. package/src/doctor/report.ts +57 -13
  237. package/src/editor-api.ts +295 -31
  238. package/src/editor-compatibility.ts +200 -0
  239. package/src/editor-console.ts +35 -17
  240. package/src/editor-hotkeys.ts +85 -33
  241. package/src/editor-store.ts +538 -233
  242. package/src/editor-viewport.ts +160 -34
  243. package/src/entity-factory.ts +14 -3
  244. package/src/gizmo-registry.ts +21 -5
  245. package/src/harness-chat-editor-context.ts +37 -0
  246. package/src/harness-chat-indicator.ts +68 -0
  247. package/src/harness-chat-layout.ts +53 -0
  248. package/src/harness-chat-lifecycle.ts +170 -0
  249. package/src/harness-chat-reconnect.ts +85 -0
  250. package/src/harness-chat-types.ts +409 -0
  251. package/src/hierarchy-drop.ts +50 -0
  252. package/src/hierarchy-expansion-state.ts +100 -0
  253. package/src/hierarchy-menu-registry.ts +1 -1
  254. package/src/hierarchy-projection.ts +76 -0
  255. package/src/history/editor-session.ts +21 -0
  256. package/src/history/history-commands.ts +147 -0
  257. package/src/history/history-service.ts +904 -0
  258. package/src/history/json-history-resource.ts +165 -0
  259. package/src/history/persistence-coordinator.ts +35 -0
  260. package/src/history/project-file-history.ts +266 -0
  261. package/src/history/project-root-history-backends.ts +53 -0
  262. package/src/history/resource-registry.ts +209 -0
  263. package/src/history/snapshot-store.ts +108 -0
  264. package/src/history/source-history-backend.ts +374 -0
  265. package/src/history/types.ts +100 -0
  266. package/src/hmr-registration-group.ts +67 -0
  267. package/src/hmr-stable-react-context.ts +23 -0
  268. package/src/hosted-example.ts +12 -2
  269. package/src/hotkeys.ts +89 -18
  270. package/src/ingest/discovery-react.ts +9 -10
  271. package/src/ingest/discovery.ts +4 -4
  272. package/src/ingest/discovery2d.ts +5 -5
  273. package/src/ingest/games/bloom-composer/vgai.game.json +3 -3
  274. package/src/ingest/games/embed-bundle/vgai.game.json +3 -3
  275. package/src/ingest/games/games-fps/vgai.game.json +3 -3
  276. package/src/ingest/games/iframe-reachable/vgai.game.json +3 -3
  277. package/src/ingest/games/interactive-cubes/vgai.game.json +3 -3
  278. package/src/ingest/games/mismatched-three/vgai.game.json +3 -3
  279. package/src/ingest/games/own-three-bundled/vgai.game.json +3 -3
  280. package/src/ingest/games/pointerlock-maze/vgai.game.json +7 -4
  281. package/src/ingest/games-2d/bubbo-bubbo/vgai.game.json +3 -3
  282. package/src/ingest/games-2d/bunnymark/vgai.game.json +3 -3
  283. package/src/ingest/games-2d/flappy/vgai.game.json +3 -3
  284. package/src/ingest/games-2d/flappy-pixi/vgai.game.json +3 -3
  285. package/src/ingest/games-2d/puzzling-potions/vgai.game.json +3 -3
  286. package/src/ingest/games-2d/tilemap-camera/vgai.game.json +3 -3
  287. package/src/ingest/games-react/react-rpg/vgai.game.json +3 -3
  288. package/src/ingest/types.ts +1 -1
  289. package/src/ingest-mode.ts +47 -52
  290. package/src/ingest-siblings.ts +23 -33
  291. package/src/initial-scene.ts +1 -2
  292. package/src/main.tsx +16 -8
  293. package/src/manifest-project.ts +10 -12
  294. package/src/model-thumbnail.ts +261 -26
  295. package/src/module-mode.ts +44 -50
  296. package/src/play-log-events.ts +26 -0
  297. package/src/play-mode.ts +495 -401
  298. package/src/play-scene-adoption.ts +23 -0
  299. package/src/playground/main.ts +68 -24
  300. package/src/playwright-shim.ts +473 -0
  301. package/src/project-manager.ts +90 -10
  302. package/src/project-operations.ts +112 -0
  303. package/src/project-story-discovery.ts +25 -0
  304. package/src/project-tool-discovery.ts +43 -0
  305. package/src/scene-serializer.ts +0 -6
  306. package/src/scene-sync.ts +7 -2
  307. package/src/script-loader.ts +3 -3
  308. package/src/skeleton-helper.ts +57 -0
  309. package/src/storage/seed.ts +68 -8
  310. package/src/stories/StoryPreviewMount.tsx +265 -0
  311. package/src/stories/action-stories.fixture.tsx +44 -0
  312. package/src/stories/button-stories.fixture.tsx +50 -0
  313. package/src/stories/compose-project-stories.ts +182 -0
  314. package/src/stories/loader-stories.fixture.tsx +53 -0
  315. package/src/stories/story-discovery.ts +130 -0
  316. package/src/stories/story-registry.ts +146 -0
  317. package/src/theme-css.ts +1049 -0
  318. package/src/theme-library.ts +238 -0
  319. package/src/theme-preference.ts +130 -0
  320. package/src/theme.ts +527 -0
  321. package/src/tool-loader.ts +80 -24
  322. package/src/ui-source/inspect.ts +27 -4
  323. package/src/ui-source/source-write-backend.ts +83 -22
  324. package/src/widgets/index.ts +9 -18
  325. package/src/workspace-aux-commands.ts +11 -0
  326. package/src/workspace-dock-controller.ts +64 -0
  327. package/src/workspace-document-ids.ts +5 -0
  328. package/src/workspace-document-registry.ts +367 -0
  329. package/src/workspace-state-persistence.ts +455 -0
  330. package/src/workspace-status-registry.ts +110 -0
  331. package/src/workspace-utility-commands.ts +49 -0
  332. package/src/workspace-utility-registry.ts +161 -0
  333. package/src/world-document-routing.ts +16 -0
  334. package/src/xstate-inspect/XStateMachineInspector.tsx +544 -0
  335. package/src/xstate-inspect/character-animation-machine.fixture.ts +74 -0
  336. package/src/xstate-inspect/use-live-actor-state.ts +39 -0
  337. package/src/xstate-inspect/xstate-graph.ts +265 -0
  338. package/src/xstate-inspect/xstate-layout.ts +76 -0
  339. package/src/z-index.ts +26 -0
  340. package/template/.claude/skills/editor/SKILL.md +129 -90
  341. package/template/AGENTS.md +1110 -0
  342. package/template/CLAUDE.md +1 -512
  343. package/template/IDIOMS.md +50 -0
  344. package/template/check-idioms.ts +706 -0
  345. package/template/manifest-entry-modules-plugin.ts +53 -0
  346. package/template/package.json +13 -4
  347. package/template/public/scenes/default.scn2d.json +6 -0
  348. package/template/public/scenes/default.vscn.json +7 -1
  349. package/template/public/scenes/untitled.vscn.json +10 -0
  350. package/template/scripts/playtest.ts +40 -0
  351. package/template/server/loopback.ts +75 -0
  352. package/template/server/rooms/arena-room.ts +69 -1
  353. package/template/server/rooms/game-room.ts +68 -1
  354. package/template/src/data/README.md +9 -4
  355. package/template/src/data/data-ref.ts +35 -0
  356. package/template/src/data/tuning.schema.ts +1 -1
  357. package/template/src/main.ts +41 -62
  358. package/template/src/manifest-entry-modules.d.ts +3 -0
  359. package/template/src/operations/README.md +88 -0
  360. package/template/src/runtime/pixi-adapter.ts +24 -0
  361. package/template/src/scripts/components/data-spinner.ts +43 -2
  362. package/template/src/scripts/components/spin-lap-math.ts +27 -0
  363. package/template/src/tools/README.md +5 -3
  364. package/template/src/tools/example.tool.tsx +13 -7
  365. package/template/src/ui/Button.stories.tsx +66 -0
  366. package/template/src/ui/RebindPanel.tsx +2 -6
  367. package/template/src/ui/game.tsx +17 -0
  368. package/template/tests/acceptance/example.spec.ts +64 -0
  369. package/template/tests/logic/example.test.ts +31 -0
  370. package/template/tests/logic/room.test.ts +100 -0
  371. package/template/tests/tsconfig.json +30 -0
  372. package/template/validate-manifest.ts +5 -5
  373. package/template/validate-scenes.ts +50 -18
  374. package/template/vgai.game.json +20 -13
  375. package/template/vite.config.ts +77 -16
  376. package/vite-plugin-ui-oid.ts +261 -17
  377. package/dist/assets/CCDIKSolver-Dz-ysxZF.js +0 -1
  378. package/dist/assets/SelectionBox-BXsv_6aH.js +0 -1
  379. package/dist/assets/browser-project-scripts-DOru4L1x.js +0 -2
  380. package/dist/assets/browserAll-CEkWYlFk.js +0 -1
  381. package/dist/assets/create-runtime-DYIWr3va.js +0 -1
  382. package/dist/assets/data-asset-Bb9sIM7i.js +0 -5
  383. package/dist/assets/game-8SDZPPgH.js +0 -1
  384. package/dist/assets/game-CevorxyV.js +0 -1
  385. package/dist/assets/game-Di7XlywD.js +0 -1
  386. package/dist/assets/game-DjnCaw8R.js +0 -1
  387. package/dist/assets/game-Q9A0aXSV.js +0 -1
  388. package/dist/assets/index-CPVV6pjw.js +0 -1
  389. package/dist/assets/index-CpOnYyeD.js +0 -213
  390. package/dist/assets/index-Dr8H_6Rl.js +0 -1
  391. package/dist/assets/index-_bCaipUk.js +0 -13650
  392. package/dist/assets/ingest-siblings-Dz8eEqrV.js +0 -1
  393. package/dist/assets/mount-manifest-Bhk0ohsl.js +0 -1
  394. package/dist/assets/scene-query-BivAHhJu.js +0 -1
  395. package/dist/assets/webworkerAll-BLrH0F6F.js +0 -1
  396. package/dist/assets/xstate-animation-binding-1NGLmw6y.js +0 -1
  397. package/dist/assets/xstate.esm-BgUD33nl.js +0 -3
  398. package/src/authoring/scene-ui-layer.ts +0 -485
  399. package/src/authoring/ui-authoring-adapter.ts +0 -325
  400. package/src/authoring/ui-hierarchy-menu.ts +0 -40
  401. package/src/authoring/ui-inspector-sections.tsx +0 -156
  402. package/src/authoring/undo-timeline.ts +0 -145
  403. package/src/components/BottomPanel.tsx +0 -326
  404. package/src/components/BuildPanel.tsx +0 -455
  405. package/src/components/FolderTree.tsx +0 -179
  406. package/src/components/RightPanel.tsx +0 -166
  407. package/src/components/WorldContextMenu.tsx +0 -257
  408. package/src/components/asset-viewers/AssetViewer.tsx +0 -38
  409. package/src/ingest/games-react/react-rpg/src/ui/game-state.tsx +0 -129
  410. package/src/scene-ui-mode/active-scene-ui.ts +0 -58
  411. package/src/scene-ui-mode/scene-ui-palette-panel.tsx +0 -152
  412. package/src/scene-ui-mode/scene-ui-timeline-tab.tsx +0 -29
  413. package/src/scene-ui-mode/ui-prefab-dialog-host.tsx +0 -74
  414. package/src/scene-ui-mode/ui-prefab-hierarchy-menu.ts +0 -49
  415. package/src/scene-ui-mode/ui-prefab-io.ts +0 -76
  416. package/src/ui-editor/inspector.tsx +0 -563
  417. package/src/ui-editor/node-ops.ts +0 -266
  418. package/src/ui-editor/overlay.tsx +0 -380
  419. package/src/ui-editor/palette.tsx +0 -114
  420. package/src/ui-editor/react-store.ts +0 -78
  421. package/src/ui-editor/timeline-panel.tsx +0 -443
  422. package/src/ui-editor/ui-edit-store.ts +0 -552
  423. package/src/ui-editor/ui-prefab.ts +0 -95
  424. package/template/project.json +0 -9
  425. package/template/src/scripts/main.ts +0 -94
  426. package/template/src/ui/DefaultHud.tsx +0 -40
  427. package/template/src/ui/game-state.tsx +0 -37
  428. package/template/src/ui/mount-default-hud.tsx +0 -19
  429. package/template/src/ui/mount-ui.ts +0 -15
  430. package/vite-plugin-react-world-provider.ts +0 -81
@@ -1,6 +1,12 @@
1
+ import { Checkbox, FileInput, Select, TextInput, themeVars } from '../design-system';
1
2
  /**
2
- * DATA dock tab (W2, docs/DATA-TOOLS-DESIGN.md §2.4) — lists every
3
- * `src/data/*.data.json` of the open project and edits it in place.
3
+ * Data-asset EDITING machinery (docs/DATA-TOOLS-DESIGN.md §2.4, re-homed by
4
+ * the workspace-shell program W3 — docs/EDITOR-WORKSPACE-SHELL-TODO.md §9/W3,
5
+ * inventory row B5). Formerly `DataPanel.tsx`, the permanent bottom DATA tab;
6
+ * that tab is gone — each data asset now opens as a NAMED center form/table
7
+ * document (`data-documents.tsx`, kind `'data'`, title = the file's own name
8
+ * per §8, e.g. `tuning.data.json`). This module keeps the editing internals
9
+ * both eras share, unchanged:
4
10
  *
5
11
  * Architecture (spec §2.1): widgets are generated from the EMITTED
6
12
  * `*.schema.json` (JSON Schema, the interchange artifact) via
@@ -11,38 +17,31 @@
11
17
  * - **table** (`z.record`) → a grid: one row per key in the data file, one
12
18
  * column per row-schema field, every cell a widget.
13
19
  *
14
- * Writes (D1, §2.5): every widget commit POSTs the whole updated file to
15
- * `/__editor/data-file` immediately — no local buffering, no save button;
16
- * undo is git. The `"$schema"` key is held out of editing everywhere and
17
- * re-serialized first so git diffs stay minimal.
20
+ * Writes (D1, §2.5): every widget commit hands the whole updated file to the
21
+ * caller's `writeFile` immediately — no local buffering, no save button. The
22
+ * write PATH itself (key-order fold → serialize → POST `/__editor/data-file`
23
+ * or history write) lives with the document host (`data-documents.tsx`) and
24
+ * is byte-identical to the old panel's; DATA-TOOLS-DESIGN's transaction rules
25
+ * stay authoritative. The `"$schema"` key is held out of editing everywhere
26
+ * and re-serialized first so git diffs stay minimal.
18
27
  *
19
28
  * Table rows can be added/removed (W6b) — see `TableEditor` below, which also
20
29
  * carries CSV export/import (W6c, `data-csv.ts`) — a spreadsheet-friendly
21
- * bulk-edit path for the same table. The empty state (`EmptyState`, W6d)
30
+ * bulk-edit path for the same table. The empty state (`DataEmptyState`, W6d)
22
31
  * teaches the create-a-data-asset recipe with a "Copy starter files" button;
23
- * no file-creating scaffold button this wave (deferred — needs a
24
- * purpose-scoped write verb, a security-surface decision). Still pending:
25
- * adding a whole new FIELD to a schema (a `.schema.ts` code change, not an
26
- * editor concern).
32
+ * it now renders inside the `Data Assets` center document when the project
33
+ * has no data assets yet. Still pending: adding a whole new FIELD to a
34
+ * schema (a `.schema.ts` code change, not an editor concern).
27
35
  *
28
36
  * Cross-asset refs (§2.2): a field declared with `dataRef(target)`
29
37
  * (`@engine/data/data-ref`) renders as a `stem#key` PICKER instead of free
30
- * text — `RefOptionsContext` reduces this panel's already-loaded `files`
31
- * state into `stem -> key[]` once per change and threads it to `Widget`'s
32
- * `'ref'` case (deep in `FieldList`/`TableEditor`) without prop-drilling.
38
+ * text — the host provides `RefOptionsContext` (loaded files reduced to
39
+ * `stem -> key[]`) and it threads to `Widget`'s `'ref'` case (deep in
40
+ * `FieldList`/`TableEditor`) without prop-drilling.
33
41
  */
34
42
 
35
- import {
36
- createContext,
37
- Fragment,
38
- useCallback,
39
- useContext,
40
- useEffect,
41
- useMemo,
42
- useRef,
43
- useState,
44
- } from 'react';
45
- import { connectDataFileEvents } from '../asset-events';
43
+ import { createContext, Fragment, useContext, useEffect, useRef, useState } from 'react';
44
+ import { Button, ColorInput, IconButton, NumberInput, Tooltip } from '../design-system';
46
45
  import { csvToTable, tableToCsv } from './data-csv';
47
46
  import {
48
47
  type DataAssetShape,
@@ -50,19 +49,16 @@ import {
50
49
  defaultValueForDescriptor,
51
50
  describeDataSchema,
52
51
  } from './inspectors/json-schema-fields';
53
- import { ColorInput } from './primitives/ColorInput';
54
- import { NumberInput } from './primitives/NumberInput';
55
- import { Tooltip } from './primitives/Tooltip';
56
52
 
57
53
  /** One file as served by GET /__editor/data-files (raw text, client parses). */
58
- interface ServerDataFile {
54
+ export interface ServerDataFile {
59
55
  path: string;
60
56
  content: string;
61
57
  schema: string | null;
62
58
  }
63
59
 
64
60
  /** One file after client-side parsing + schema classification. */
65
- interface LoadedDataFile {
61
+ export interface LoadedDataFile {
66
62
  /** Project-relative path, e.g. `src/data/tuning.data.json`. */
67
63
  path: string;
68
64
  /** Parsed data object (`"$schema"` entry included), or null on parse error. */
@@ -87,33 +83,38 @@ interface LoadedDataFile {
87
83
 
88
84
  /**
89
85
  * Every loaded file's own top-level keys, by asset stem — the `'ref'` widget
90
- * kind's picker options. `DataPanel` already fetches and parses every data
91
- * file's raw text (`GET /__editor/data-files`); this just reduces that same
92
- * state into `stem -> key[]` once per `files` change and threads it to
93
- * `Widget` (deep inside `FieldList`/`TableEditor`) via context instead of a
94
- * prop through every intermediate component — the SAME shape a `dataRef`
95
- * field's `refTarget` addresses (`json-schema-fields.ts`).
86
+ * kind's picker options. The document host (`data-documents.tsx`) already
87
+ * fetches and parses every data file's raw text (`GET /__editor/data-files`);
88
+ * this just reduces that same state into `stem -> key[]` once per files
89
+ * change and threads it to `Widget` (deep inside `FieldList`/`TableEditor`)
90
+ * via context instead of a prop through every intermediate component — the
91
+ * SAME shape a `dataRef` field's `refTarget` addresses
92
+ * (`json-schema-fields.ts`).
96
93
  */
97
- const RefOptionsContext = createContext<ReadonlyMap<string, string[]>>(new Map());
98
-
99
- const inputStyle: React.CSSProperties = {
100
- width: '100%',
101
- background: '#1e1e1e',
102
- color: '#c5c8ce',
103
- border: '1px solid #333',
104
- borderRadius: 2,
105
- padding: '2px 4px',
106
- fontSize: 12,
107
- boxSizing: 'border-box',
108
- };
94
+ export const RefOptionsContext = createContext<ReadonlyMap<string, string[]>>(new Map());
109
95
 
110
96
  const labelStyle: React.CSSProperties = {
111
97
  fontSize: 11,
112
- color: '#8c8c8c',
98
+ color: themeVars.content.muted,
113
99
  width: 140,
114
100
  flexShrink: 0,
115
101
  };
116
102
 
103
+ /**
104
+ * B-10: the table header row previously reused the plain label span with no
105
+ * visual separation from data rows — now a real header band (surface
106
+ * background + hairline bottom border), the Unity/Godot table convention.
107
+ */
108
+ const tableHeadCellStyle: React.CSSProperties = {
109
+ ...labelStyle,
110
+ width: 'auto',
111
+ fontWeight: 600,
112
+ alignSelf: 'stretch',
113
+ background: themeVars.surface.chrome,
114
+ borderBottom: `1px solid ${themeVars.boundary.default}`,
115
+ padding: '3px 4px',
116
+ };
117
+
117
118
  /** Scan a (valid-JSON) string literal starting at the opening quote; returns the index just past the closing quote. */
118
119
  function skipJsonString(text: string, i: number): number {
119
120
  let j = i + 1;
@@ -196,7 +197,7 @@ function extractTopLevelKeyOrder(text: string): string[] {
196
197
  return keys;
197
198
  }
198
199
 
199
- function parseServerFile(f: ServerDataFile): LoadedDataFile {
200
+ export function parseServerFile(f: ServerDataFile): LoadedDataFile {
200
201
  let data: Record<string, unknown> | null = null;
201
202
  let error: string | undefined;
202
203
  try {
@@ -240,7 +241,10 @@ function parseServerFile(f: ServerDataFile): LoadedDataFile {
240
241
  * SESSION of edits, not just the first one: each commit's output order
241
242
  * becomes the next commit's `prevOrder`.
242
243
  */
243
- function nextKeyOrder(prevOrder: string[] | undefined, obj: Record<string, unknown>): string[] {
244
+ export function nextKeyOrder(
245
+ prevOrder: string[] | undefined,
246
+ obj: Record<string, unknown>,
247
+ ): string[] {
244
248
  const existing = prevOrder ?? Object.keys(obj);
245
249
  const kept = [...new Set(existing)].filter((k) => k in obj);
246
250
  const added = Object.keys(obj).filter((k) => !existing.includes(k));
@@ -260,7 +264,7 @@ function nextKeyOrder(prevOrder: string[] | undefined, obj: Record<string, unkno
260
264
  * the very first value edit. Emitting the object manually, key by key, in
261
265
  * the exact order the caller hands us, sidesteps that reindexing entirely.
262
266
  */
263
- function serializeDataFile(obj: Record<string, unknown>, keyOrder?: string[]): string {
267
+ export function serializeDataFile(obj: Record<string, unknown>, keyOrder?: string[]): string {
264
268
  const hasSchema = '$schema' in obj;
265
269
  const rest = (keyOrder ?? Object.keys(obj)).filter((k) => k !== '$schema' && k in obj);
266
270
  const order = hasSchema ? ['$schema', ...rest] : rest;
@@ -282,7 +286,7 @@ function serializeDataFile(obj: Record<string, unknown>, keyOrder?: string[]): s
282
286
  * than throwing — the write always succeeds, matching the panel's other
283
287
  * commit paths (`setCell` has the same defensive fallback).
284
288
  */
285
- function setDeep(
289
+ export function setDeep(
286
290
  obj: Record<string, unknown>,
287
291
  path: string[],
288
292
  value: unknown,
@@ -298,139 +302,6 @@ function setDeep(
298
302
  return { ...obj, [head]: setDeep(childObj, rest, value) };
299
303
  }
300
304
 
301
- export function DataPanel({ active }: { active: boolean }) {
302
- const [files, setFiles] = useState<LoadedDataFile[]>([]);
303
- const [selectedPath, setSelectedPath] = useState<string | null>(null);
304
-
305
- const refresh = useCallback(async () => {
306
- try {
307
- const res = await fetch('/__editor/data-files');
308
- if (!res.ok) return;
309
- const { files: raw } = (await res.json()) as { files: ServerDataFile[] };
310
- setFiles(raw.map(parseServerFile));
311
- } catch {
312
- /* server unreachable — keep whatever we last had */
313
- }
314
- }, []);
315
-
316
- // Re-scan whenever the tab is shown (D3: discovery IS the folder scan —
317
- // never a cached manifest, so activating the tab always reflects disk).
318
- useEffect(() => {
319
- if (active) void refresh();
320
- }, [active, refresh]);
321
-
322
- // W6a: a NEW `src/data/*.data.json`/`*.schema.json` (or a deleted one)
323
- // appears/disappears in the master list without switching tabs — the
324
- // server's `src/`-scoped watcher broadcasts add/unlink only (a `change`
325
- // event is deliberately excluded: it would echo this panel's own
326
- // `/__editor/data-file` POST writes back into a refetch, clobbering
327
- // in-flight drafts). `refresh` is the same rescan the tab-activation
328
- // effect above already runs.
329
- useEffect(() => connectDataFileEvents(() => void refresh()), [refresh]);
330
-
331
- const selected = files.find((f) => f.path === selectedPath) ?? files[0] ?? null;
332
-
333
- // `'ref'` widget picker options (§2.2's designer payoff): every loaded
334
- // file's own top-level keys, keyed by asset stem — recomputed only when
335
- // `files` actually changes (a fresh fetch, or a local commit updating one
336
- // file's `data` in place).
337
- const refOptionsByStem = useMemo(() => {
338
- const map = new Map<string, string[]>();
339
- for (const f of files) {
340
- if (!f.data) continue;
341
- const stem = f.path.replace(/^src\/data\//, '').replace(/\.data\.json$/, '');
342
- map.set(
343
- stem,
344
- Object.keys(f.data).filter((k) => k !== '$schema'),
345
- );
346
- }
347
- return map;
348
- }, [files]);
349
-
350
- /**
351
- * D1 (spec §2.5): commit → write the file IMMEDIATELY, no buffering. The
352
- * local copy is updated in the same tick so widgets stay live; disk is the
353
- * document. D5 resolution: this deliberately BYPASSES the play-mode overlay
354
- * (scene-entity-only) — a running game receives the change through the
355
- * shipped `.data.json` HMR path instead (see the `/__editor/data-file`
356
- * route's doc comment in editor-server.ts).
357
- *
358
- * Takes the whole `LoadedDataFile` (not just its path, #6) so it can read
359
- * that file's CURRENT `keyOrder` straight from the caller's own prop/state
360
- * closure — no stale-closure risk from reaching into the panel's `files`
361
- * state inside this `useCallback([])`. `nextKeyOrder` folds the commit's
362
- * keys into that order once, and the result becomes this file's `keyOrder`
363
- * going forward, so a whole session of edits keeps the file's original
364
- * on-disk key order (integer-like keys included) stable throughout.
365
- */
366
- const writeFile = useCallback((file: LoadedDataFile, nextData: Record<string, unknown>) => {
367
- const order = nextKeyOrder(file.keyOrder, nextData);
368
- const content = serializeDataFile(nextData, order);
369
- setFiles((prev) =>
370
- prev.map((f) => (f.path === file.path ? { ...f, data: nextData, keyOrder: order } : f)),
371
- );
372
- void fetch('/__editor/data-file', {
373
- method: 'POST',
374
- headers: { 'Content-Type': 'application/json' },
375
- body: JSON.stringify({ path: file.path, content }),
376
- });
377
- }, []);
378
-
379
- if (files.length === 0) {
380
- return <EmptyState />;
381
- }
382
-
383
- return (
384
- <RefOptionsContext.Provider value={refOptionsByStem}>
385
- <div style={{ display: 'flex', flex: 1, minHeight: 0 }}>
386
- {/* File list (master) */}
387
- <div
388
- style={{
389
- width: 200,
390
- flexShrink: 0,
391
- borderRight: '1px solid #333',
392
- overflowY: 'auto',
393
- padding: '4px 0',
394
- }}
395
- >
396
- {files.map((f) => {
397
- const isSelected = f.path === selected?.path;
398
- const name = f.path.replace(/^src\/data\//, '').replace(/\.data\.json$/, '');
399
- return (
400
- <button
401
- key={f.path}
402
- type="button"
403
- data-testid={`data-file-${name}`}
404
- onClick={() => setSelectedPath(f.path)}
405
- title={f.path}
406
- style={{
407
- display: 'block',
408
- width: '100%',
409
- textAlign: 'left',
410
- background: isSelected ? '#2c2c2c' : 'transparent',
411
- color: isSelected ? '#c5c8ce' : '#8c8c8c',
412
- border: 'none',
413
- borderLeft: isSelected ? '2px solid #579EFF' : '2px solid transparent',
414
- padding: '4px 10px',
415
- cursor: 'pointer',
416
- fontSize: 12,
417
- }}
418
- >
419
- {name}
420
- </button>
421
- );
422
- })}
423
- </div>
424
-
425
- {/* Editor (detail) */}
426
- <div style={{ flex: 1, minWidth: 0, overflow: 'auto', padding: 10 }}>
427
- {selected && <DataFileEditor file={selected} writeFile={writeFile} />}
428
- </div>
429
- </div>
430
- </RefOptionsContext.Provider>
431
- );
432
- }
433
-
434
305
  /**
435
306
  * A minimal, paste-ready `.schema.ts` + `.data.json` pair (W6d) — mirrors the
436
307
  * shape of the shipped `tuning.*` trio (template/src/data/README.md), just
@@ -459,14 +330,16 @@ export type Example = z.infer<typeof ExampleSchema>;
459
330
  `;
460
331
 
461
332
  /**
462
- * DATA tab empty state (W6d, docs/DATA-TOOLS-DESIGN.md §3.5): the project has
463
- * no `src/data/*.data.json` yet. Teaches the concrete recipe rather than just
464
- * naming the shape, plus a one-click "Copy starter files" so the first asset
465
- * doesn't require memorizing the trio from scratch. Once the files exist +
466
- * `npm run emit-schemas` has run, the new asset appears here automatically —
467
- * no reload, W6a's src-watcher SSE channel picks it up.
333
+ * Data-assets empty state (W6d, docs/DATA-TOOLS-DESIGN.md §3.5): the project
334
+ * has no `src/data/*.data.json` yet. Teaches the concrete recipe rather than
335
+ * just naming the shape, plus a one-click "Copy starter files" so the first
336
+ * asset doesn't require memorizing the trio from scratch. Rendered by the
337
+ * `Data Assets` center document (`data-documents.tsx`) since W3 re-homed the
338
+ * bottom DATA tab. Once the files exist + `npm run emit-schemas` has run,
339
+ * the new asset appears automatically — no reload, W6a's src-watcher SSE
340
+ * channel picks it up.
468
341
  */
469
- function EmptyState() {
342
+ export function DataEmptyState() {
470
343
  const [copied, setCopied] = useState(false);
471
344
 
472
345
  const copyStarter = () => {
@@ -477,7 +350,7 @@ function EmptyState() {
477
350
  };
478
351
 
479
352
  return (
480
- <div style={{ padding: 12, fontSize: 12, color: '#8c8c8c', maxWidth: 480 }}>
353
+ <div style={{ padding: 12, fontSize: 12, color: themeVars.content.muted, maxWidth: 480 }}>
481
354
  <p style={{ margin: '0 0 8px' }}>
482
355
  No data assets yet — a data asset is a <code>src/data/*.data.json</code> file governed by a
483
356
  Zod schema (docs/DATA-TOOLS-DESIGN.md §2).
@@ -500,27 +373,14 @@ function EmptyState() {
500
373
  See the project's <code>src/data/README.md</code> for the full trio doctrine and the shipped{' '}
501
374
  <code>tuning.*</code> worked example.
502
375
  </p>
503
- <button
504
- type="button"
505
- data-testid="data-empty-copy-starter"
506
- onClick={copyStarter}
507
- style={{
508
- background: '#2c2c2c',
509
- color: '#c5c8ce',
510
- border: '1px solid #444',
511
- borderRadius: 2,
512
- padding: '4px 10px',
513
- fontSize: 12,
514
- cursor: 'pointer',
515
- }}
516
- >
376
+ <Button size="compact" data-testid="data-empty-copy-starter" onClick={copyStarter}>
517
377
  {copied ? 'Copied' : 'Copy starter files'}
518
- </button>
378
+ </Button>
519
379
  </div>
520
380
  );
521
381
  }
522
382
 
523
- function DataFileEditor({
383
+ export function DataFileEditor({
524
384
  file,
525
385
  writeFile,
526
386
  }: {
@@ -577,10 +437,16 @@ function DataFileEditor({
577
437
  );
578
438
  }
579
439
 
580
- function Message({ text, tone }: { text: string; tone: 'error' | 'warn' }) {
440
+ function Message({ text: message, tone }: { text: string; tone: 'error' | 'warn' }) {
581
441
  return (
582
- <div style={{ fontSize: 12, color: tone === 'error' ? '#FF6B6B' : '#FFD866', maxWidth: 560 }}>
583
- {text}
442
+ <div
443
+ style={{
444
+ fontSize: 12,
445
+ color: tone === 'error' ? themeVars.semantic.danger : themeVars.semantic.warning,
446
+ maxWidth: 560,
447
+ }}
448
+ >
449
+ {message}
584
450
  </div>
585
451
  );
586
452
  }
@@ -685,43 +551,24 @@ function TableEditor({
685
551
  return (
686
552
  <div>
687
553
  <div style={{ display: 'flex', gap: 6, marginBottom: 8 }}>
688
- <button
689
- type="button"
554
+ <Button
555
+ size="compact"
690
556
  data-testid="data-csv-export"
691
557
  onClick={exportCsv}
692
558
  title="Download this table as a CSV file"
693
- style={{
694
- background: '#2c2c2c',
695
- color: '#c5c8ce',
696
- border: '1px solid #444',
697
- borderRadius: 2,
698
- padding: '3px 10px',
699
- fontSize: 12,
700
- cursor: 'pointer',
701
- }}
702
559
  >
703
560
  Export CSV
704
- </button>
705
- <button
706
- type="button"
561
+ </Button>
562
+ <Button
563
+ size="compact"
707
564
  data-testid="data-csv-import"
708
565
  onClick={() => fileInputRef.current?.click()}
709
566
  title="Import replaces every row in this file (undo is git)."
710
- style={{
711
- background: '#2c2c2c',
712
- color: '#c5c8ce',
713
- border: '1px solid #444',
714
- borderRadius: 2,
715
- padding: '3px 10px',
716
- fontSize: 12,
717
- cursor: 'pointer',
718
- }}
719
567
  >
720
568
  Import CSV
721
- </button>
722
- <input
569
+ </Button>
570
+ <FileInput
723
571
  ref={fileInputRef}
724
- type="file"
725
572
  accept=".csv,text/csv"
726
573
  style={{ display: 'none' }}
727
574
  onChange={(e) => void importCsv(e.target.files)}
@@ -743,11 +590,11 @@ function TableEditor({
743
590
  width: 'max-content',
744
591
  }}
745
592
  >
746
- {/* Header row */}
747
- <span style={{ ...labelStyle, width: 'auto' }} />
593
+ {/* Header row (B-10: real header band, not a bare label span) */}
594
+ <span style={tableHeadCellStyle} />
748
595
  {rowFields.map((f) => {
749
596
  const head = (
750
- <span key={f.name} style={{ ...labelStyle, width: 'auto', fontWeight: 600 }}>
597
+ <span key={f.name} style={tableHeadCellStyle}>
751
598
  {f.name}
752
599
  </span>
753
600
  );
@@ -759,14 +606,21 @@ function TableEditor({
759
606
  head
760
607
  );
761
608
  })}
762
- <span />
609
+ <span style={tableHeadCellStyle} />
763
610
 
764
611
  {rowKeys.map((rowKey) => {
765
612
  const row = data[rowKey];
766
613
  const rowObj = row && typeof row === 'object' ? (row as Record<string, unknown>) : {};
767
614
  return (
768
615
  <Fragment key={rowKey}>
769
- <span style={{ ...labelStyle, width: 'auto', color: '#b0b0b0', fontWeight: 600 }}>
616
+ <span
617
+ style={{
618
+ ...labelStyle,
619
+ width: 'auto',
620
+ color: themeVars.content.primary,
621
+ fontWeight: 600,
622
+ }}
623
+ >
770
624
  {rowKey}
771
625
  </span>
772
626
  {rowFields.map((f) => (
@@ -778,30 +632,24 @@ function TableEditor({
778
632
  testId={`data-cell-${rowKey}-${f.name}`}
779
633
  />
780
634
  ))}
781
- <button
635
+ <IconButton
782
636
  type="button"
637
+ variant="danger"
638
+ size="compact"
639
+ aria-label={`Remove row ${rowKey}`}
783
640
  data-testid={`data-row-remove-${rowKey}`}
784
641
  title="Remove row (undo is git)"
785
642
  onClick={() => removeRow(rowKey)}
786
- style={{
787
- background: 'transparent',
788
- border: 'none',
789
- color: '#8c8c8c',
790
- cursor: 'pointer',
791
- fontSize: 13,
792
- lineHeight: 1,
793
- padding: '2px 4px',
794
- }}
795
643
  >
796
644
  ×
797
- </button>
645
+ </IconButton>
798
646
  </Fragment>
799
647
  );
800
648
  })}
801
649
  </div>
802
650
 
803
651
  <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginTop: 8 }}>
804
- <input
652
+ <TextInput
805
653
  data-testid="data-row-add-key"
806
654
  placeholder="new-row-key"
807
655
  value={newKey}
@@ -812,24 +660,12 @@ function TableEditor({
812
660
  onKeyDown={(e) => {
813
661
  if (e.key === 'Enter') addRow();
814
662
  }}
815
- style={{ ...inputStyle, width: 160 }}
663
+ className="vgai-input"
664
+ style={{ width: 160 }}
816
665
  />
817
- <button
818
- type="button"
819
- data-testid="data-row-add"
820
- onClick={addRow}
821
- style={{
822
- background: '#2c2c2c',
823
- color: '#c5c8ce',
824
- border: '1px solid #444',
825
- borderRadius: 2,
826
- padding: '3px 10px',
827
- fontSize: 12,
828
- cursor: 'pointer',
829
- }}
830
- >
666
+ <Button size="compact" data-testid="data-row-add" onClick={addRow}>
831
667
  Add row
832
- </button>
668
+ </Button>
833
669
  </div>
834
670
  {addError && (
835
671
  <div style={{ marginTop: 4 }}>
@@ -901,8 +737,8 @@ function FieldList({
901
737
  key={f.name}
902
738
  data-testid={testId}
903
739
  style={{
904
- border: '1px solid #333',
905
- borderRadius: 3,
740
+ border: `1px solid ${themeVars.boundary.default}`,
741
+ borderRadius: themeVars.shape.small,
906
742
  padding: '6px 8px',
907
743
  marginBottom: 6,
908
744
  marginLeft: Math.min(path.length, 3) * 10,
@@ -936,7 +772,9 @@ function FieldList({
936
772
 
937
773
  function GroupHeader({ name, description }: { name: string; description?: string | undefined }) {
938
774
  const label = (
939
- <div style={{ fontSize: 11, color: '#a0a0a0', fontWeight: 600, marginBottom: 4 }}>{name}</div>
775
+ <div style={{ fontSize: 11, color: themeVars.content.muted, fontWeight: 600, marginBottom: 4 }}>
776
+ {name}
777
+ </div>
940
778
  );
941
779
  return description ? (
942
780
  <Tooltip text={description} position="right">
@@ -975,8 +813,8 @@ function Widget({
975
813
  return <NumberCell field={field} value={value} onCommit={onCommit} testId={testId} />;
976
814
  case 'boolean':
977
815
  return (
978
- <input
979
- type="checkbox"
816
+ <Checkbox
817
+ className="vgai-checkbox"
980
818
  data-testid={testId}
981
819
  checked={Boolean(value)}
982
820
  onChange={(e) => onCommit(e.target.checked)}
@@ -990,18 +828,19 @@ function Widget({
990
828
  );
991
829
  case 'enum':
992
830
  return (
993
- <select
831
+ <Select
994
832
  data-testid={testId}
995
833
  value={value == null ? '' : String(value)}
996
834
  onChange={(e) => onCommit(e.target.value)}
997
- style={{ ...inputStyle, cursor: 'pointer' }}
835
+ className="vgai-select"
836
+ style={{ width: '100%' }}
998
837
  >
999
838
  {(field.options ?? []).map((opt) => (
1000
839
  <option key={opt} value={opt}>
1001
840
  {opt}
1002
841
  </option>
1003
842
  ))}
1004
- </select>
843
+ </Select>
1005
844
  );
1006
845
  case 'string':
1007
846
  return <StringCell value={value} onCommit={onCommit} testId={testId} />;
@@ -1026,11 +865,12 @@ function Widget({
1026
865
  const options = targetKeys.map((k) => `${targetStem}#${k}`);
1027
866
  const isDangling = current !== '' && !options.includes(current);
1028
867
  return (
1029
- <select
868
+ <Select
1030
869
  data-testid={testId}
1031
870
  value={current}
1032
871
  onChange={(e) => onCommit(e.target.value)}
1033
- style={{ ...inputStyle, cursor: 'pointer' }}
872
+ className="vgai-select"
873
+ style={{ width: '100%' }}
1034
874
  >
1035
875
  <option value="">—</option>
1036
876
  {options.map((opt) => (
@@ -1039,7 +879,7 @@ function Widget({
1039
879
  </option>
1040
880
  ))}
1041
881
  {isDangling && <option value={current}>{current} (dangling)</option>}
1042
- </select>
882
+ </Select>
1043
883
  );
1044
884
  }
1045
885
  default:
@@ -1147,7 +987,7 @@ function StringCell({
1147
987
  };
1148
988
 
1149
989
  return (
1150
- <input
990
+ <TextInput
1151
991
  data-testid={testId}
1152
992
  value={draft}
1153
993
  onChange={(e) => setDraft(e.target.value)}
@@ -1162,7 +1002,8 @@ function StringCell({
1162
1002
  (e.target as HTMLInputElement).blur();
1163
1003
  }
1164
1004
  }}
1165
- style={inputStyle}
1005
+ className="vgai-input"
1006
+ style={{ width: '100%' }}
1166
1007
  />
1167
1008
  );
1168
1009
  }
@@ -1230,7 +1071,7 @@ function JsonCell({
1230
1071
 
1231
1072
  return (
1232
1073
  <div>
1233
- <input
1074
+ <TextInput
1234
1075
  data-testid={testId}
1235
1076
  value={draft}
1236
1077
  onChange={(e) => {
@@ -1248,7 +1089,16 @@ function JsonCell({
1248
1089
  (e.target as HTMLInputElement).blur();
1249
1090
  }
1250
1091
  }}
1251
- style={invalid ? { ...inputStyle, borderColor: '#FF6B6B', color: '#FF6B6B' } : inputStyle}
1092
+ className="vgai-input"
1093
+ style={
1094
+ invalid
1095
+ ? {
1096
+ width: '100%',
1097
+ borderColor: themeVars.semantic.danger,
1098
+ color: themeVars.semantic.danger,
1099
+ }
1100
+ : { width: '100%' }
1101
+ }
1252
1102
  title={
1253
1103
  invalid
1254
1104
  ? 'Not valid JSON — nothing written. Fix the JSON or press Escape to revert.'
@@ -1258,7 +1108,7 @@ function JsonCell({
1258
1108
  {invalid && (
1259
1109
  <div
1260
1110
  data-testid={`${testId}-error`}
1261
- style={{ fontSize: 10, color: '#FF6B6B', marginTop: 2 }}
1111
+ style={{ fontSize: 10, color: themeVars.semantic.danger, marginTop: 2 }}
1262
1112
  >
1263
1113
  Not valid JSON — nothing written. Fix the JSON or press Escape to revert.
1264
1114
  </div>