@volter/sdk 0.0.0-stage → 0.5.204

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 (523) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +20 -0
  3. package/README.md +38 -3
  4. package/package.json +510 -4
  5. package/src/account.ts +210 -0
  6. package/src/chrome.ts +88 -0
  7. package/src/client.ts +1646 -0
  8. package/src/commands.ts +66 -0
  9. package/src/contributions.ts +619 -0
  10. package/src/css-numeric-style.ts +97 -0
  11. package/src/document-probe.ts +282 -0
  12. package/src/editor-view.ts +225 -0
  13. package/src/extension.ts +40 -0
  14. package/src/generations.ts +178 -0
  15. package/src/host.ts +1157 -0
  16. package/src/http-transport.browser.ts +14 -0
  17. package/src/http-transport.node.ts +19 -0
  18. package/src/index.ts +131 -0
  19. package/src/kit/CapabilityCoverageSection.tsx +185 -0
  20. package/src/kit/account-client.ts +333 -0
  21. package/src/kit/action-registry.ts +317 -0
  22. package/src/kit/active-product.ts +76 -0
  23. package/src/kit/active-project.ts +155 -0
  24. package/src/kit/adapter-editor-config.ts +25 -0
  25. package/src/kit/adapter-module.ts +7 -0
  26. package/src/kit/adapter-observation.ts +49 -0
  27. package/src/kit/animation/animation-clock.ts +479 -0
  28. package/src/kit/animation/stage-transport.ts +385 -0
  29. package/src/kit/api/assets.ts +365 -0
  30. package/src/kit/api/project-open.ts +355 -0
  31. package/src/kit/api/project-source.ts +180 -0
  32. package/src/kit/api/project-state.ts +110 -0
  33. package/src/kit/api/relay.ts +270 -0
  34. package/src/kit/api/themes.ts +45 -0
  35. package/src/kit/api-asset-library-wire.ts +45 -0
  36. package/src/kit/api-base.ts +10 -0
  37. package/src/kit/api-build.ts +99 -0
  38. package/src/kit/api-git-wire.ts +56 -0
  39. package/src/kit/api-logs.ts +92 -0
  40. package/src/kit/api-project-identity.ts +74 -0
  41. package/src/kit/api-settings.ts +36 -0
  42. package/src/kit/api-worktrees.ts +205 -0
  43. package/src/kit/asset-capabilities.ts +344 -0
  44. package/src/kit/asset-compare-core.ts +171 -0
  45. package/src/kit/asset-editor-context.tsx +101 -0
  46. package/src/kit/asset-events.ts +96 -0
  47. package/src/kit/asset-inspector-actions.ts +87 -0
  48. package/src/kit/asset-selection-viewer-registry.ts +113 -0
  49. package/src/kit/asset-selection.ts +146 -0
  50. package/src/kit/asset-thumbnails.ts +25 -0
  51. package/src/kit/asset-viewers.ts +115 -0
  52. package/src/kit/asset-workflow/asset-import-jobs.ts +106 -0
  53. package/src/kit/asset-workflow/asset-ledger-backend.ts +126 -0
  54. package/src/kit/asset-workflow/asset-ledger.ts +156 -0
  55. package/src/kit/asset-workflow/asset-materialization-report.ts +140 -0
  56. package/src/kit/asset-workflow/asset-pack-manifest.ts +320 -0
  57. package/src/kit/asset-workflow/asset-types.ts +142 -0
  58. package/src/kit/asset-workflow/audio-preview-player.ts +193 -0
  59. package/src/kit/asset-workflow/audio-waveform.ts +22 -0
  60. package/src/kit/asset-workflow/cloud-asset-client.ts +263 -0
  61. package/src/kit/asset-workflow/hosted-asset-materialization.ts +236 -0
  62. package/src/kit/asset-workflow/image-view-scale.ts +31 -0
  63. package/src/kit/asset-workflow/import-contract.ts +124 -0
  64. package/src/kit/asset-workflow/ledger-write-lock.ts +244 -0
  65. package/src/kit/asset-workflow/pixi-spritesheet.ts +197 -0
  66. package/src/kit/asset-workflow/preview-resource-lifetime.ts +44 -0
  67. package/src/kit/asset-workflow/project-asset-commands.ts +20 -0
  68. package/src/kit/asset-workflow/project-content.ts +288 -0
  69. package/src/kit/asset-workflow/project-source-index.ts +545 -0
  70. package/src/kit/asset-workflow/thumbnail-system.ts +256 -0
  71. package/src/kit/authoring/active-adapter.ts +200 -0
  72. package/src/kit/authoring/active-systems.ts +422 -0
  73. package/src/kit/authoring/adapter-key.ts +18 -0
  74. package/src/kit/authoring/authoring-asset-url.ts +27 -0
  75. package/src/kit/authoring/bootstrap-state.ts +49 -0
  76. package/src/kit/authoring/boundary-authoring-adapter.ts +189 -0
  77. package/src/kit/authoring/canvas-scene-guides.ts +84 -0
  78. package/src/kit/authoring/composite-authoring-adapter.ts +2109 -0
  79. package/src/kit/authoring/consumer-actions.ts +531 -0
  80. package/src/kit/authoring/design-time-layers.ts +852 -0
  81. package/src/kit/authoring/design-time-mount-registry.ts +244 -0
  82. package/src/kit/authoring/edit-mode-authoring.ts +637 -0
  83. package/src/kit/authoring/empty-project-authoring.ts +22 -0
  84. package/src/kit/authoring/instance-source-menu.ts +135 -0
  85. package/src/kit/authoring/layered-pick.ts +185 -0
  86. package/src/kit/authoring/mounted-root-subjects.ts +146 -0
  87. package/src/kit/authoring/no-authoring-adapter.ts +59 -0
  88. package/src/kit/authoring/object3d-document-persistence.ts +122 -0
  89. package/src/kit/authoring/panel-authoring.ts +121 -0
  90. package/src/kit/authoring/project-authoring-session.ts +105 -0
  91. package/src/kit/authoring/provenance.ts +99 -0
  92. package/src/kit/authoring/react-canvas-navigation.ts +259 -0
  93. package/src/kit/authoring/react-design-canvas-style.ts +20 -0
  94. package/src/kit/authoring/react-story-board.ts +917 -0
  95. package/src/kit/authoring/selection-scope.ts +195 -0
  96. package/src/kit/authoring/shell-document-ops.ts +169 -0
  97. package/src/kit/authoring/story-board-chrome-fit.ts +107 -0
  98. package/src/kit/authoring/story-board-presentation.ts +111 -0
  99. package/src/kit/authoring/three-root.ts +67 -0
  100. package/src/kit/authoring/viewport-tool-context.ts +73 -0
  101. package/src/kit/authoring/viewport-tool-owner.ts +38 -0
  102. package/src/kit/authoring/world-session-state.ts +101 -0
  103. package/src/kit/authoring-seam-evidence.ts +300 -0
  104. package/src/kit/availability-tick.ts +66 -0
  105. package/src/kit/bitmap-label.ts +120 -0
  106. package/src/kit/boot-routing.ts +392 -0
  107. package/src/kit/breakpoint-state.ts +43 -0
  108. package/src/kit/build-identity.ts +16 -0
  109. package/src/kit/bytes-codec.ts +62 -0
  110. package/src/kit/cancellation-reason.ts +58 -0
  111. package/src/kit/canvas-frames.ts +88 -0
  112. package/src/kit/capture-camera-pose.ts +77 -0
  113. package/src/kit/capture-size.ts +88 -0
  114. package/src/kit/chrome-registry.ts +159 -0
  115. package/src/kit/chrome-slot-registry.ts +91 -0
  116. package/src/kit/collaboration-client.ts +264 -0
  117. package/src/kit/collaboration-presence.ts +41 -0
  118. package/src/kit/command-dispatch.ts +19 -0
  119. package/src/kit/command-listener.ts +2182 -0
  120. package/src/kit/command-registry.ts +71 -0
  121. package/src/kit/component-board-registry.ts +205 -0
  122. package/src/kit/component-states-registry.ts +199 -0
  123. package/src/kit/components/AlignToolbar.tsx +204 -0
  124. package/src/kit/components/ApplicationMenus.tsx +372 -0
  125. package/src/kit/components/AssetEditorShell.tsx +216 -0
  126. package/src/kit/components/AssetInspectorToolSection.tsx +124 -0
  127. package/src/kit/components/BoardRulers.tsx +354 -0
  128. package/src/kit/components/CanvasAddNodeDialogs.tsx +529 -0
  129. package/src/kit/components/CanvasSceneViewport.tsx +1195 -0
  130. package/src/kit/components/ChromeSlot.tsx +20 -0
  131. package/src/kit/components/CodeView.tsx +470 -0
  132. package/src/kit/components/CompactInspectorShell.tsx +39 -0
  133. package/src/kit/components/ConsolePanel.tsx +273 -0
  134. package/src/kit/components/GameplaySessionTimeline.tsx +295 -0
  135. package/src/kit/components/InspectionProjection.tsx +932 -0
  136. package/src/kit/components/Inspector.tsx +270 -0
  137. package/src/kit/components/InspectorCanvasPreview.tsx +35 -0
  138. package/src/kit/components/InspectorFieldsSection.tsx +290 -0
  139. package/src/kit/components/InspectorStoriesSection.tsx +92 -0
  140. package/src/kit/components/InspectorToolSection.tsx +96 -0
  141. package/src/kit/components/InspectorTransformSection.tsx +245 -0
  142. package/src/kit/components/LightExplorerPanel.tsx +433 -0
  143. package/src/kit/components/MediaProperties.tsx +145 -0
  144. package/src/kit/components/ProjectHeader.tsx +328 -0
  145. package/src/kit/components/ReactCanvasControls.tsx +358 -0
  146. package/src/kit/components/RootSelectionOverlay.tsx +3688 -0
  147. package/src/kit/components/RootTextEditor.tsx +79 -0
  148. package/src/kit/components/SaveStatus.tsx +70 -0
  149. package/src/kit/components/SurfaceCrashBoundary.tsx +105 -0
  150. package/src/kit/components/SurfaceStateOverlay.tsx +24 -0
  151. package/src/kit/components/ToolContributionSurfaces.tsx +49 -0
  152. package/src/kit/components/ToolHost.tsx +380 -0
  153. package/src/kit/components/Toolbar.tsx +811 -0
  154. package/src/kit/components/TransientHint.tsx +44 -0
  155. package/src/kit/components/VersionControlSection.tsx +470 -0
  156. package/src/kit/components/ViewportOverlaysMenu.tsx +177 -0
  157. package/src/kit/components/VolterLogo.tsx +18 -0
  158. package/src/kit/components/WorktreeSwitcher.tsx +712 -0
  159. package/src/kit/components/account-documents.tsx +1162 -0
  160. package/src/kit/components/asset-documents.tsx +794 -0
  161. package/src/kit/components/asset-editor-persistence.ts +216 -0
  162. package/src/kit/components/asset-selection-section.tsx +545 -0
  163. package/src/kit/components/asset-thumbnails.tsx +307 -0
  164. package/src/kit/components/asset-viewers/AudioViewer.tsx +201 -0
  165. package/src/kit/components/asset-viewers/GenericJsonViewer.tsx +102 -0
  166. package/src/kit/components/asset-viewers/ImageViewer.tsx +300 -0
  167. package/src/kit/components/asset-viewers/JsonAssetDocument.tsx +98 -0
  168. package/src/kit/components/asset-viewers/OnlineAssetDetail.tsx +426 -0
  169. package/src/kit/components/asset-viewers/SourceAssetViewer.tsx +356 -0
  170. package/src/kit/components/asset-viewers/SpritesheetSpriteView.tsx +102 -0
  171. package/src/kit/components/asset-viewers/VideoViewer.tsx +101 -0
  172. package/src/kit/components/asset-viewers/shader-source.ts +144 -0
  173. package/src/kit/components/board-guides.ts +150 -0
  174. package/src/kit/components/canvas-scene-hotkeys.ts +37 -0
  175. package/src/kit/components/canvas-temporary-pivot.ts +34 -0
  176. package/src/kit/components/core-utilities.tsx +94 -0
  177. package/src/kit/components/inspector-preview-section.tsx +223 -0
  178. package/src/kit/components/inspector-revert-label.ts +20 -0
  179. package/src/kit/components/inspector-selection.ts +42 -0
  180. package/src/kit/components/inspector-stories-gating.ts +171 -0
  181. package/src/kit/components/inspector-transform-subject.ts +11 -0
  182. package/src/kit/components/inspector-transform.ts +88 -0
  183. package/src/kit/components/kind-documents.tsx +544 -0
  184. package/src/kit/components/primitives/DraftColorInput.tsx +74 -0
  185. package/src/kit/components/project-tool-documents.tsx +402 -0
  186. package/src/kit/components/scene-documents.tsx +221 -0
  187. package/src/kit/components/status-contributions.tsx +407 -0
  188. package/src/kit/components/tool-documents.tsx +302 -0
  189. package/src/kit/components/tool-schema-form.tsx +262 -0
  190. package/src/kit/components/use-after-paint.ts +41 -0
  191. package/src/kit/components/use-project-image-assets.ts +86 -0
  192. package/src/kit/components/workspace-history.ts +32 -0
  193. package/src/kit/components/world-documents.tsx +570 -0
  194. package/src/kit/components/world-overlay-gestures.ts +1939 -0
  195. package/src/kit/composite-screenshot.ts +2238 -0
  196. package/src/kit/content-entry-source-registry.ts +184 -0
  197. package/src/kit/contribution-surfaces.ts +48 -0
  198. package/src/kit/coverage/canvas-reveal.ts +192 -0
  199. package/src/kit/coverage/design-time-surfaces.ts +101 -0
  200. package/src/kit/coverage/ontology-invariants.ts +466 -0
  201. package/src/kit/coverage/session-vitals.ts +503 -0
  202. package/src/kit/crash-null-boundary.ts +36 -0
  203. package/src/kit/creation-site-edit.ts +1491 -0
  204. package/src/kit/creation-site-registry.ts +160 -0
  205. package/src/kit/delegate-harness-registry.ts +134 -0
  206. package/src/kit/document-areas.ts +70 -0
  207. package/src/kit/document-context-registry.ts +193 -0
  208. package/src/kit/document-open-registry.ts +200 -0
  209. package/src/kit/document-play-extension.ts +221 -0
  210. package/src/kit/document-preview-source.ts +20 -0
  211. package/src/kit/document-renderer-session.ts +138 -0
  212. package/src/kit/document-stage-sessions.ts +26 -0
  213. package/src/kit/document-viewports.ts +120 -0
  214. package/src/kit/editor-api.ts +46 -0
  215. package/src/kit/editor-chrome-capture.ts +136 -0
  216. package/src/kit/editor-commands.ts +176 -0
  217. package/src/kit/editor-console.ts +580 -0
  218. package/src/kit/editor-current-view.ts +56 -0
  219. package/src/kit/editor-document-probe.ts +1168 -0
  220. package/src/kit/editor-git-client.ts +115 -0
  221. package/src/kit/editor-hotkeys.ts +728 -0
  222. package/src/kit/editor-lease-view.ts +39 -0
  223. package/src/kit/editor-lease.ts +415 -0
  224. package/src/kit/editor-mode.ts +19 -0
  225. package/src/kit/editor-notifications.ts +140 -0
  226. package/src/kit/editor-presence.ts +563 -0
  227. package/src/kit/editor-presentation-activity.ts +58 -0
  228. package/src/kit/editor-presentation-notice.ts +42 -0
  229. package/src/kit/editor-runtime.tsx +147 -0
  230. package/src/kit/editor-server-response.ts +86 -0
  231. package/src/kit/editor-session-attribution.ts +85 -0
  232. package/src/kit/editor-session-mode.ts +54 -0
  233. package/src/kit/editor-state-facets.ts +74 -0
  234. package/src/kit/editor-view-presentation.ts +777 -0
  235. package/src/kit/environment-images.ts +58 -0
  236. package/src/kit/eyedropper-session.ts +60 -0
  237. package/src/kit/files/file-provider.ts +62 -0
  238. package/src/kit/files/project-files.ts +270 -0
  239. package/src/kit/finders/index.ts +137 -0
  240. package/src/kit/finders/scenes-from-entrypoint-selection.ts +387 -0
  241. package/src/kit/frame/frame-parts.ts +30 -0
  242. package/src/kit/framed-document-capture.ts +34 -0
  243. package/src/kit/game-globals-prelude.ts +143 -0
  244. package/src/kit/game-surface-defaults.ts +33 -0
  245. package/src/kit/gameplay-dom-recording.ts +318 -0
  246. package/src/kit/gameplay-export-state.ts +14 -0
  247. package/src/kit/gameplay-replay.ts +417 -0
  248. package/src/kit/gameplay-session-time.ts +9 -0
  249. package/src/kit/gameplay-sessions.ts +204 -0
  250. package/src/kit/hierarchy-component-marks.ts +298 -0
  251. package/src/kit/hierarchy-internals.ts +197 -0
  252. package/src/kit/hierarchy-kind-icon.ts +217 -0
  253. package/src/kit/hierarchy-menu-registry.ts +67 -0
  254. package/src/kit/hierarchy-node-rows.ts +307 -0
  255. package/src/kit/hierarchy-panel-view.ts +280 -0
  256. package/src/kit/hierarchy-projection.ts +76 -0
  257. package/src/kit/hierarchy-row-media.ts +45 -0
  258. package/src/kit/hierarchy-row-model.ts +308 -0
  259. package/src/kit/hierarchy-rows.ts +11 -0
  260. package/src/kit/hierarchy-walk.ts +86 -0
  261. package/src/kit/history/editor-session.ts +25 -0
  262. package/src/kit/history/history-commands.ts +147 -0
  263. package/src/kit/history/history-delegate.ts +187 -0
  264. package/src/kit/history/history-limit-notices.ts +43 -0
  265. package/src/kit/history/history-service.ts +1189 -0
  266. package/src/kit/history/persistence-coordinator.ts +35 -0
  267. package/src/kit/history/project-file-history.ts +386 -0
  268. package/src/kit/history/project-root-history-backends.ts +139 -0
  269. package/src/kit/history/resource-registry.ts +209 -0
  270. package/src/kit/history/snapshot-store.ts +103 -0
  271. package/src/kit/history/source-history-backend.ts +546 -0
  272. package/src/kit/history-types.ts +124 -0
  273. package/src/kit/hmr-registration-group.ts +67 -0
  274. package/src/kit/hmr-stable-react-context.ts +23 -0
  275. package/src/kit/hotkeys.ts +190 -0
  276. package/src/kit/inference-diagnostics.ts +69 -0
  277. package/src/kit/initial-project.ts +80 -0
  278. package/src/kit/inspection/active-subject.ts +571 -0
  279. package/src/kit/inspection/active-surface.ts +142 -0
  280. package/src/kit/inspection/compose-subject.ts +1055 -0
  281. package/src/kit/inspection/compose.ts +7 -0
  282. package/src/kit/inspection/display.ts +171 -0
  283. package/src/kit/inspection/document-subject.ts +109 -0
  284. package/src/kit/inspection/game-subject.ts +85 -0
  285. package/src/kit/inspection/null-subject.ts +119 -0
  286. package/src/kit/inspection/serialize.ts +357 -0
  287. package/src/kit/inspection/use-active-inspection.ts +180 -0
  288. package/src/kit/inspection-model.ts +542 -0
  289. package/src/kit/inspection-node-media.ts +58 -0
  290. package/src/kit/inspector-presentation.ts +203 -0
  291. package/src/kit/inspector-property-grouping.ts +64 -0
  292. package/src/kit/inspector-section-registry.ts +221 -0
  293. package/src/kit/instance-source-actions.ts +163 -0
  294. package/src/kit/js-heap.ts +71 -0
  295. package/src/kit/key-actions.ts +91 -0
  296. package/src/kit/keymap-presets.ts +428 -0
  297. package/src/kit/layout-policy.ts +31 -0
  298. package/src/kit/light-explorer-model.ts +134 -0
  299. package/src/kit/live-canvas-frame.ts +55 -0
  300. package/src/kit/live-document.ts +296 -0
  301. package/src/kit/live-gesture-lock.ts +50 -0
  302. package/src/kit/live-seam-evidence.ts +11 -0
  303. package/src/kit/live-session-registry.ts +220 -0
  304. package/src/kit/live-transition.ts +391 -0
  305. package/src/kit/manifest-project.ts +107 -0
  306. package/src/kit/module-fetch-diagnosis.ts +192 -0
  307. package/src/kit/mount-failure-report.ts +154 -0
  308. package/src/kit/native-selection-style.ts +497 -0
  309. package/src/kit/object3d-document-write-policy.ts +137 -0
  310. package/src/kit/packaged-runtime.ts +108 -0
  311. package/src/kit/palettes/maya.palette.json +57 -0
  312. package/src/kit/palettes/substance.palette.json +57 -0
  313. package/src/kit/performance-profiler.ts +367 -0
  314. package/src/kit/performance-sources.ts +69 -0
  315. package/src/kit/photograph-notice.ts +141 -0
  316. package/src/kit/play-boot-phase.ts +166 -0
  317. package/src/kit/play-camera-flight.ts +35 -0
  318. package/src/kit/png-encode.worker.ts +26 -0
  319. package/src/kit/presentation-surface.ts +248 -0
  320. package/src/kit/product-command.ts +90 -0
  321. package/src/kit/project-adapter.ts +1140 -0
  322. package/src/kit/project-asset-refresh.ts +23 -0
  323. package/src/kit/project-asset-roots.ts +68 -0
  324. package/src/kit/project-local-state.ts +151 -0
  325. package/src/kit/project-manager.ts +243 -0
  326. package/src/kit/project-module-changes.ts +201 -0
  327. package/src/kit/project-module-split.ts +270 -0
  328. package/src/kit/project-play-layers.ts +25 -0
  329. package/src/kit/project-provenance.ts +115 -0
  330. package/src/kit/project-ready.ts +42 -0
  331. package/src/kit/project-shape.ts +68 -0
  332. package/src/kit/project-tools.ts +107 -0
  333. package/src/kit/projection-types.ts +44 -0
  334. package/src/kit/readiness.ts +113 -0
  335. package/src/kit/renderer-resource-counts.ts +27 -0
  336. package/src/kit/reported-play-state.ts +90 -0
  337. package/src/kit/resolve-contributed-command.ts +14 -0
  338. package/src/kit/resolve-relative-specifier.ts +33 -0
  339. package/src/kit/retained-document-states.ts +91 -0
  340. package/src/kit/scene-document-plan.ts +320 -0
  341. package/src/kit/scene-live-open.ts +210 -0
  342. package/src/kit/scoped-game-css.ts +152 -0
  343. package/src/kit/served-url.ts +5 -0
  344. package/src/kit/session-close.ts +17 -0
  345. package/src/kit/session-tombstone.ts +127 -0
  346. package/src/kit/settings/settings-provider.ts +82 -0
  347. package/src/kit/settings-store.ts +348 -0
  348. package/src/kit/shell-document-state.ts +27 -0
  349. package/src/kit/shell-store-door.ts +45 -0
  350. package/src/kit/shell-store.ts +722 -0
  351. package/src/kit/source-conflict.ts +122 -0
  352. package/src/kit/stage-context.ts +377 -0
  353. package/src/kit/stage-invalidation.ts +25 -0
  354. package/src/kit/stage-store-registry.ts +69 -0
  355. package/src/kit/startup-failure.ts +80 -0
  356. package/src/kit/state-report-deferral.ts +73 -0
  357. package/src/kit/storage/host-files-storage.ts +97 -0
  358. package/src/kit/storage/http-storage.ts +174 -0
  359. package/src/kit/storage/index.ts +75 -0
  360. package/src/kit/storage/mem-storage.ts +158 -0
  361. package/src/kit/storage/path-lock.ts +44 -0
  362. package/src/kit/storage/paths.ts +26 -0
  363. package/src/kit/storage-types.ts +127 -0
  364. package/src/kit/stories/StoryPreviewMount.tsx +306 -0
  365. package/src/kit/stories/compose-project-stories.ts +255 -0
  366. package/src/kit/stories/prefabs-finder.ts +54 -0
  367. package/src/kit/stories/prefabs-from-stories.ts +182 -0
  368. package/src/kit/stories/project-story-regions.ts +24 -0
  369. package/src/kit/stories/story-capture.ts +579 -0
  370. package/src/kit/stories/story-declared-medium.ts +126 -0
  371. package/src/kit/stories/story-discovery.ts +176 -0
  372. package/src/kit/stories/story-dom-runtime.ts +78 -0
  373. package/src/kit/stories/story-grouping.ts +111 -0
  374. package/src/kit/stories/story-mount-turn.ts +27 -0
  375. package/src/kit/stories/story-presentation.ts +215 -0
  376. package/src/kit/stories/story-preview-component.ts +7 -0
  377. package/src/kit/stories/story-registry.ts +530 -0
  378. package/src/kit/stories-scope.ts +35 -0
  379. package/src/kit/story-document-openers.ts +36 -0
  380. package/src/kit/story-thumbnails.ts +47 -0
  381. package/src/kit/surface-keyboard.ts +101 -0
  382. package/src/kit/surface-state.ts +135 -0
  383. package/src/kit/system-seam-evidence.ts +72 -0
  384. package/src/kit/tab-census.ts +202 -0
  385. package/src/kit/tab-lifecycle-client.ts +227 -0
  386. package/src/kit/theme-library.ts +897 -0
  387. package/src/kit/theme-preference.ts +429 -0
  388. package/src/kit/three-viewport-presentation.ts +23 -0
  389. package/src/kit/tool-contribution-play.ts +74 -0
  390. package/src/kit/tool-loader.ts +1918 -0
  391. package/src/kit/transform-mode-request.ts +66 -0
  392. package/src/kit/transient-hint.ts +78 -0
  393. package/src/kit/transport-strip.tsx +174 -0
  394. package/src/kit/ui-source/adapter-region-includes.ts +238 -0
  395. package/src/kit/ui-source/file-region-resolver.ts +302 -0
  396. package/src/kit/ui-source/inspect.ts +775 -0
  397. package/src/kit/ui-source/source-write-backend.ts +605 -0
  398. package/src/kit/ui-source/tier-source-write-backend.ts +279 -0
  399. package/src/kit/user-local-state.ts +105 -0
  400. package/src/kit/viewport-activation-timings.ts +840 -0
  401. package/src/kit/viewport-editor-controls.ts +22 -0
  402. package/src/kit/viewport-presentation.ts +668 -0
  403. package/src/kit/viewport-surface-status.tsx +55 -0
  404. package/src/kit/wait-until.ts +37 -0
  405. package/src/kit/worker-call-metrics.ts +166 -0
  406. package/src/kit/workspace-areas.ts +191 -0
  407. package/src/kit/workspace-aux-commands.ts +11 -0
  408. package/src/kit/workspace-available-documents.ts +142 -0
  409. package/src/kit/workspace-core-utilities.ts +31 -0
  410. package/src/kit/workspace-document-ids.ts +59 -0
  411. package/src/kit/workspace-document-registry.ts +624 -0
  412. package/src/kit/workspace-document-restore.ts +146 -0
  413. package/src/kit/workspace-host-commands.ts +141 -0
  414. package/src/kit/workspace-persistence-gate.ts +40 -0
  415. package/src/kit/workspace-play-utilities.ts +44 -0
  416. package/src/kit/workspace-presets.ts +446 -0
  417. package/src/kit/workspace-regions.ts +276 -0
  418. package/src/kit/workspace-static-panels.ts +73 -0
  419. package/src/kit/workspace-status-registry.ts +121 -0
  420. package/src/kit/workspace-storage.ts +35 -0
  421. package/src/kit/workspace-style.ts +226 -0
  422. package/src/kit/workspace-utility-commands.ts +74 -0
  423. package/src/kit/workspace-utility-registry.ts +263 -0
  424. package/src/kit/world-adoption-event.ts +23 -0
  425. package/src/kit/world-adoption.ts +115 -0
  426. package/src/kit/world-canvas-viewport-state.ts +35 -0
  427. package/src/kit/world-document-routing.ts +104 -0
  428. package/src/kit/world-pan-state.ts +198 -0
  429. package/src/kit/write-pipe.ts +173 -0
  430. package/src/layout-arrangements.ts +5 -0
  431. package/src/layouts.tsx +108 -0
  432. package/src/looks.ts +16 -0
  433. package/src/project/output-roots.ts +73 -0
  434. package/src/project/tab-census.ts +155 -0
  435. package/src/project-tool-catalog.ts +104 -0
  436. package/src/selection.tsx +107 -0
  437. package/src/services.ts +18 -0
  438. package/src/session/build-report.ts +22 -0
  439. package/src/session/collaboration-types.ts +262 -0
  440. package/src/session/command-table.ts +327 -0
  441. package/src/session/discovery.ts +100 -0
  442. package/src/session/editor-brand.ts +48 -0
  443. package/src/session/editor-compatibility.ts +329 -0
  444. package/src/session/editor-control-lifecycle.ts +68 -0
  445. package/src/session/editor-control-protocol.ts +5 -0
  446. package/src/session/entrypoint-selection-readers.ts +66 -0
  447. package/src/session/entrypoint-selection-source.ts +120 -0
  448. package/src/session/game-css-scope.ts +30 -0
  449. package/src/session/hosted-attachment.ts +225 -0
  450. package/src/session/limited-view.ts +82 -0
  451. package/src/session/product-create.ts +24 -0
  452. package/src/session/product-locator.ts +478 -0
  453. package/src/session/project-module-url.ts +242 -0
  454. package/src/session/project-serving.ts +164 -0
  455. package/src/session/project-upgrade.ts +669 -0
  456. package/src/session/registry-format.ts +210 -0
  457. package/src/session/relative-path-guard.ts +56 -0
  458. package/src/session/scoped-game-css.ts +461 -0
  459. package/src/session/source-glob.ts +15 -0
  460. package/src/session/tool-contribution-convention.ts +123 -0
  461. package/src/session/workbench-locator.ts +712 -0
  462. package/src/session.ts +41 -0
  463. package/src/share.ts +160 -0
  464. package/src/source-analysis.ts +28 -0
  465. package/src/source-authoring.ts +439 -0
  466. package/src/tools/errors.ts +91 -0
  467. package/src/tools/provider-execution.ts +70 -0
  468. package/src/tools/registry.ts +341 -0
  469. package/src/tools/types.ts +159 -0
  470. package/src/transport.ts +100 -0
  471. package/src/types.ts +1693 -0
  472. package/src/views.ts +164 -0
  473. package/src/widgets/design-system.ts +93 -0
  474. package/src/widgets/editor-appearance.ts +151 -0
  475. package/src/widgets/editor-material.ts +83 -0
  476. package/src/widgets/icon-set-registry.ts +105 -0
  477. package/src/widgets/index.ts +71 -0
  478. package/src/widgets/inspector-widgets/AlignmentGrid.tsx +182 -0
  479. package/src/widgets/inspector-widgets/AssetSlotPicker.tsx +123 -0
  480. package/src/widgets/inspector-widgets/BorderEditor.tsx +309 -0
  481. package/src/widgets/inspector-widgets/ColorPicker.tsx +549 -0
  482. package/src/widgets/inspector-widgets/CurveEditor.tsx +359 -0
  483. package/src/widgets/inspector-widgets/FilterEditor.tsx +108 -0
  484. package/src/widgets/inspector-widgets/FontPicker.tsx +191 -0
  485. package/src/widgets/inspector-widgets/GradientEditor.tsx +623 -0
  486. package/src/widgets/inspector-widgets/ScrubbableInput.tsx +180 -0
  487. package/src/widgets/inspector-widgets/ShadowEditor.tsx +319 -0
  488. package/src/widgets/inspector-widgets/color-utils.ts +201 -0
  489. package/src/widgets/inspector-widgets/curve-utils.ts +212 -0
  490. package/src/widgets/inspector-widgets/index.ts +25 -0
  491. package/src/widgets/inspector-widgets/shared.tsx +140 -0
  492. package/src/widgets/interactive-edit-scope.ts +33 -0
  493. package/src/widgets/patterns/Dialog.tsx +140 -0
  494. package/src/widgets/patterns/Fields.tsx +44 -0
  495. package/src/widgets/patterns/List.tsx +25 -0
  496. package/src/widgets/patterns/StateSurface.tsx +40 -0
  497. package/src/widgets/patterns/Surfaces.tsx +122 -0
  498. package/src/widgets/patterns/Tabs.tsx +80 -0
  499. package/src/widgets/patterns/Toolbar.tsx +72 -0
  500. package/src/widgets/patterns/Tree.tsx +72 -0
  501. package/src/widgets/primitives/AnchoredMenu.tsx +260 -0
  502. package/src/widgets/primitives/Button.tsx +62 -0
  503. package/src/widgets/primitives/ColorInput.tsx +78 -0
  504. package/src/widgets/primitives/DraftTextInput.tsx +63 -0
  505. package/src/widgets/primitives/EditorIcon.tsx +157 -0
  506. package/src/widgets/primitives/FormControls.tsx +88 -0
  507. package/src/widgets/primitives/HoverPreview.tsx +96 -0
  508. package/src/widgets/primitives/JsonInput.tsx +113 -0
  509. package/src/widgets/primitives/Layout.tsx +100 -0
  510. package/src/widgets/primitives/Menu.tsx +161 -0
  511. package/src/widgets/primitives/NumberInput.tsx +169 -0
  512. package/src/widgets/primitives/Panel.tsx +80 -0
  513. package/src/widgets/primitives/SectionHeader.tsx +77 -0
  514. package/src/widgets/primitives/Text.tsx +54 -0
  515. package/src/widgets/primitives/ThemeRootPortal.tsx +52 -0
  516. package/src/widgets/primitives/Tooltip.tsx +204 -0
  517. package/src/widgets/primitives/Vec3Input.tsx +70 -0
  518. package/src/widgets/primitives/banner-tones.ts +32 -0
  519. package/src/widgets/primitives/clamp-to-viewport.ts +44 -0
  520. package/src/widgets/primitives/editor-icons.ts +254 -0
  521. package/src/widgets/primitives/panel-header-styles.ts +42 -0
  522. package/src/widgets/theme.ts +2841 -0
  523. package/src/widgets/z-index.ts +25 -0
@@ -0,0 +1,544 @@
1
+ /**
2
+ * KIND DOCUMENTS — an adapter-table document (a model, a page; ARCHITECTURE-CORE
3
+ * §The project model, "Documents, not scenes") opened in the editor
4
+ * registered for its kind (owner ruling, 2026-09-05: the tab IS the thing —
5
+ * `cage`, kind Model — and the editor is chosen by the document's kind; code
6
+ * is never a fallback, it opens only when code is opened).
7
+ *
8
+ * A `workspace.document` contribution declares `export const documentKind =
9
+ * 'model'` (`tool-loader.ts`, `documentContributionForKind`). Opening a table
10
+ * entry of that kind opens ONE document per entry — id `document:<entry id>`,
11
+ * title = the entry's label — whose content, header and shelf are the
12
+ * contribution's own components mounted through the same `ToolHost` a tool
13
+ * document uses, with the entry handed over as `props.document`
14
+ * (`ToolDocumentEntry`). Persisted and restored by the entry's id
15
+ * (`workspace-state-persistence.ts`); presented in view links as
16
+ * `{ kind: 'document', id }`. A kind with no registered editor opens nothing
17
+ * here and the caller falls back to the entry's source, by its own choice.
18
+ */
19
+
20
+ import type { ToolDocumentEntry } from '@volter/sdk/contributions';
21
+ import { themeVars } from '@volter/sdk/widgets';
22
+ import type { DocumentEntry } from '@volter/project/adapter/adapter-module';
23
+ import { type ComponentType, useSyncExternalStore } from 'react';
24
+ import { setSelectedAsset } from '@volter/sdk/kit/asset-selection';
25
+ import { assetCapabilities } from '@volter/sdk/kit/asset-capabilities';
26
+ import {
27
+ awaitAnnouncedObject3DDocumentSession,
28
+ waitForContributedDocumentMount,
29
+ } from '@volter/sdk/kit/document-context-registry';
30
+ import { registerDocumentOpener } from '@volter/sdk/kit/document-open-registry';
31
+ import type { AssetKind } from '@volter/sdk/kit/asset-selection';
32
+ import {
33
+ projectAdapterFacet,
34
+ type ResolvedDocumentTable,
35
+ subscribeProjectAdapter,
36
+ } from '@volter/sdk/kit/project-adapter';
37
+ import {
38
+ documentContributionForKind,
39
+ getGlobalToolContributions,
40
+ subscribeToolContributions,
41
+ } from '@volter/sdk/kit/tool-loader';
42
+ import { waitUntil } from '@volter/sdk/kit/wait-until';
43
+ import { getCurrentProject } from '@volter/sdk/kit/active-project';
44
+ import {
45
+ type OpenWorkspaceDocumentOptions,
46
+ openWorkspaceDocument,
47
+ openWorkspaceDocuments,
48
+ type WorkspaceDocumentContentProps,
49
+ } from '@volter/sdk/kit/workspace-document-registry';
50
+ import { registerWorkspaceDocumentRestorer } from '@volter/sdk/kit/workspace-document-restore';
51
+ import { openAssetDocument } from '@volter/sdk/kit/components/asset-documents';
52
+ import { ToolHost } from '@volter/sdk/kit/components/ToolHost';
53
+
54
+ const PREFIX = 'document:';
55
+
56
+ /** Stable identity for one table entry's document. */
57
+ export function kindDocumentId(entryId: string): string {
58
+ return `${PREFIX}${entryId}`;
59
+ }
60
+
61
+ /** The table entry id a kind document id names, or `null` for another kind of id. */
62
+ export function kindDocumentEntryId(documentId: string): string | null {
63
+ return documentId.startsWith(PREFIX) ? documentId.slice(PREFIX.length) : null;
64
+ }
65
+
66
+ /** The entries of every open kind document, by document id — what content,
67
+ * header and shelf mounts read, and what persistence records. */
68
+ const entries = new Map<
69
+ string,
70
+ { readonly entry: DocumentEntry; readonly props: ToolDocumentEntry }
71
+ >();
72
+
73
+ export function kindDocumentEntry(documentId: string): DocumentEntry | undefined {
74
+ return entries.get(documentId)?.entry;
75
+ }
76
+
77
+ function asToolDocumentEntry(entry: DocumentEntry): ToolDocumentEntry {
78
+ return {
79
+ id: entry.id,
80
+ kind: entry.kind,
81
+ label: entry.label,
82
+ ...(entry.source
83
+ ? {
84
+ source: {
85
+ path: entry.source.path,
86
+ ...(entry.source.export ? { export: entry.source.export } : {}),
87
+ },
88
+ }
89
+ : {}),
90
+ };
91
+ }
92
+
93
+ /**
94
+ * What a table entry of a kind NOTHING edits opens as: the asset its source
95
+ * already is. A module, or anything the asset routes do not know, opens as
96
+ * source; a kind the routes DO know (a model, an image, a video) opens in its
97
+ * own viewer. Before this, every unedited kind opened as source.
98
+ */
99
+ export function uneditedKindAssetKind(entry: DocumentEntry): AssetKind {
100
+ const path = entry.source?.path;
101
+ if (!path) return 'source';
102
+ const kind = assetCapabilities(path).kind;
103
+ return kind === 'model' ||
104
+ kind === 'image' ||
105
+ kind === 'video' ||
106
+ kind === 'audio' ||
107
+ kind === 'json'
108
+ ? kind
109
+ : 'source';
110
+ }
111
+
112
+ /** Is there an editor registered for documents of `kind`? */
113
+ export function hasKindEditor(kind: string): boolean {
114
+ return documentContributionForKind(kind) !== undefined;
115
+ }
116
+
117
+ /**
118
+ * Open (or activate) the document for one table entry in the editor
119
+ * registered for its kind. `false` (opens nothing) when no contribution
120
+ * declares that kind — the caller decides what an unedited kind opens as.
121
+ */
122
+ export function openKindDocument(
123
+ entry: DocumentEntry,
124
+ options: OpenWorkspaceDocumentOptions = {},
125
+ ): boolean {
126
+ const contribution = documentContributionForKind(entry.kind);
127
+ if (!contribution) return false;
128
+ const id = kindDocumentId(entry.id);
129
+ entries.set(id, { entry, props: asToolDocumentEntry(entry) });
130
+ openWorkspaceDocument(
131
+ {
132
+ id,
133
+ // The tab is the THING: the entry's own label, never the editor's name.
134
+ title: entry.label,
135
+ kind: 'document',
136
+ workspaceRole: 'authored-subject',
137
+ provenance: {
138
+ ...(entry.source ? { sourcePath: entry.source.path } : {}),
139
+ origin: contribution.file,
140
+ },
141
+ Content: KindDocumentContent,
142
+ ...(contribution.Toolbar ? { Toolbar: KindDocumentToolbar } : {}),
143
+ ...(contribution.Shelf ? { Shelf: KindDocumentShelf } : {}),
144
+ presentation: () => ({ kind: 'document', id: entry.id }),
145
+ persist: () => ({ entryId: entry.id }),
146
+ onDispose: (documentId) => {
147
+ entries.delete(documentId);
148
+ },
149
+ },
150
+ options,
151
+ );
152
+ return true;
153
+ }
154
+
155
+ /**
156
+ * THE `document` ADDRESS (`document-open-registry.ts`) — the other half of the
157
+ * `presentation()` above. An entry's id is the whole address; which editor
158
+ * opens it, and what that document's id turns out to be, are this module's
159
+ * rules and the presenter no longer holds either. Registered at module load,
160
+ * the shape `packages/editor-game/src/three/story-documents/three-story-documents.tsx:239`
161
+ * uses.
162
+ *
163
+ * SETTLING is the two waits an explicit address needs, and they are separate
164
+ * because they fail differently. The TABLE resolves more than once — a
165
+ * contributed finder (the mesh capability's models finder) registers after the
166
+ * first resolution and brings its entries — so a missing entry is not yet an
167
+ * answer; and a kind's EDITOR arrives with the contribution pass, which on a
168
+ * cold reload is well past the default window. Each refuses in its own words:
169
+ * a table that lists no such document is a different defect from a kind
170
+ * nothing can edit, and only this module can tell them apart.
171
+ */
172
+ registerDocumentOpener<{ readonly id: string }>({
173
+ id: 'document',
174
+ owner: 'kind-documents',
175
+ open: (_store, request) => {
176
+ const entry = tableEntry(request.id);
177
+ if (!entry || !hasKindEditor(entry.kind)) return null;
178
+ return openKindDocument(entry) ? kindDocumentId(entry.id) : null;
179
+ },
180
+ settle: async (request) => {
181
+ const REGISTRATION_WINDOW_MS = 20_000;
182
+ await waitUntil(() => tableEntry(request.id) !== undefined, REGISTRATION_WINDOW_MS);
183
+ const entry = tableEntry(request.id);
184
+ if (!entry) throw new Error(`The project's document table lists no document: ${request.id}`);
185
+ if (await waitUntil(() => hasKindEditor(entry.kind), REGISTRATION_WINDOW_MS)) return;
186
+ throw new Error(
187
+ `No editor is registered for documents of kind '${entry.kind}' (${request.id})`,
188
+ );
189
+ },
190
+ /**
191
+ * THE KIND'S OWN READINESS — a contributed document is ready to be driven
192
+ * once its React root has committed and, if that root mounted a stage, once
193
+ * the stage has registered its Object3D session. The presenter used to hold
194
+ * this rule for this address by name (`editor-view-presentation.ts`'s
195
+ * `kind === 'tool' || 'asset'`); it belongs here, where the contribution the
196
+ * host mounted is what answers.
197
+ */
198
+ ready: async (documentId) => {
199
+ await waitForContributedDocumentMount(documentId);
200
+ await awaitAnnouncedObject3DDocumentSession(documentId);
201
+ },
202
+ });
203
+
204
+ function tableEntry(id: string): DocumentEntry | undefined {
205
+ return projectAdapterFacet()?.scenes.entries.find((candidate) => candidate.id === id);
206
+ }
207
+
208
+ /**
209
+ * `openKindDocument` once the kind's editor is registered — now, or when the
210
+ * contribution pass that brings it completes. A restored layout and a
211
+ * shared view both name a document before the project's contributions have
212
+ * loaded (measured 2026-09-05: the entry arrived, the editor had not, and
213
+ * the document opened nothing). Gives up when the project changes under it.
214
+ */
215
+ export function openKindDocumentWhenReady(
216
+ entry: DocumentEntry,
217
+ options: OpenWorkspaceDocumentOptions = {},
218
+ ): void {
219
+ if (openKindDocument(entry, options)) return;
220
+ const stop = subscribeToolContributions(() => {
221
+ if (openKindDocument(entry, options)) stop();
222
+ });
223
+ }
224
+
225
+ /** Open the kind document `documentId` names once its entry and editor exist,
226
+ * without taking focus — a tab the workbench restored asking for its content.
227
+ * False when the id is not a kind document's. */
228
+ export function reopenKindDocument(documentId: string): boolean {
229
+ const entryId = kindDocumentEntryId(documentId);
230
+ if (entryId === null) return false;
231
+ // Not `whenDocumentEntry`: a restored tab asks before the page has a project,
232
+ // and that helper reads the project's arrival as a switch and gives up.
233
+ const attempt = (): boolean => {
234
+ const entry = projectAdapterFacet()?.scenes.entries.find((candidate) => candidate.id === entryId);
235
+ if (!entry) return false;
236
+ openKindDocumentWhenReady(entry, { activate: false });
237
+ return true;
238
+ };
239
+ if (!attempt()) {
240
+ const stop = subscribeProjectAdapter(() => {
241
+ if (attempt()) stop();
242
+ });
243
+ }
244
+ return true;
245
+ }
246
+
247
+ /** Every open kind document takes its slots afresh when contributions
248
+ * change (a module re-evaluated on save may have gained or lost its
249
+ * `Toolbar`); `openWorkspaceDocument` on an open id refreshes the descriptor. */
250
+ export function installKindDocumentRefresh(): () => void {
251
+ return subscribeToolContributions(() => {
252
+ const open = new Set(openWorkspaceDocuments().map((d) => d.descriptor.id));
253
+ for (const [id, { entry }] of entries) {
254
+ if (!open.has(id)) continue;
255
+ if (documentContributionForKind(entry.kind))
256
+ openKindDocument(entry, { activate: false });
257
+ }
258
+ });
259
+ }
260
+
261
+ // --- Restore, and what this kind does when a project opens ----------------
262
+
263
+ /**
264
+ * Run `fn` with the table entry `entryId` names once the adapter's table
265
+ * lists it — now, or on the adapter change that brings it. A table resolves
266
+ * MORE THAN ONCE: a contributed finder (the mesh capability's models finder)
267
+ * registers after the first resolution and the table is resolved again with
268
+ * its entries, so "not pending" is not "complete" (measured 2026-09-05: a
269
+ * model document restored on the first resolution found no entry). Stops
270
+ * waiting when the project changes under it.
271
+ */
272
+ function whenDocumentEntry(entryId: string, fn: (entry: DocumentEntry) => void): void {
273
+ const project = getCurrentProject();
274
+ const attempt = (): boolean => {
275
+ if (getCurrentProject() !== project) return true;
276
+ const facet = projectAdapterFacet();
277
+ if (!facet) return false;
278
+ const entry = facet.scenes.entries.find((candidate) => candidate.id === entryId);
279
+ if (!entry) return false;
280
+ fn(entry);
281
+ return true;
282
+ };
283
+ if (attempt()) return;
284
+ const stop = subscribeProjectAdapter(() => {
285
+ if (attempt()) stop();
286
+ });
287
+ }
288
+
289
+ /** The table entry a fresh checkout opens on: the declared default when it
290
+ * is a document with a source (and not a scene, which is pinned elsewhere),
291
+ * else the NEWEST such entry — the table lists finder sources newest first,
292
+ * so with several models and nothing declared the one most recently written
293
+ * is the one on screen (Photoshop reopens the last document; a models
294
+ * project with two models and no record used to open on nothing at all). */
295
+ function defaultTableEntry(table: ResolvedDocumentTable): DocumentEntry | null {
296
+ // An entry opens by its source file or by its kind's own editor: a models project with no
297
+ // `.blend` lists only the standing `blender:runtime` entry, which has no file and is still
298
+ // the thing to open.
299
+ const candidates = table.entries.filter(
300
+ (entry) =>
301
+ entry.kind !== 'scene' &&
302
+ entry.kind !== 'prefab' &&
303
+ (entry.source !== undefined || documentContributionForKind(entry.kind) !== undefined),
304
+ );
305
+ const declared = candidates.find((entry) => entry.id === table.default);
306
+ if (declared) return declared;
307
+ return candidates[0] ?? null;
308
+ }
309
+
310
+ /** Discovery can fill an empty workspace, but it must not replace a document
311
+ * the person already has open. Adding or generating a file advertises it in
312
+ * Content; activating it remains an explicit document-open operation. */
313
+ let stopFollowingTableDocuments: (() => void) | null = null;
314
+ /** The follow rule's baseline, persisted as this kind's own session state. */
315
+ let seenTableIds: Set<string> | null = null;
316
+ /** Keep the discovery baseline across reloads so a new entry can fill an
317
+ * otherwise empty workspace once, without reopening existing entries. */
318
+ function followNewTableDocuments(seen?: readonly string[]): void {
319
+ stopFollowingTableDocuments?.();
320
+ let known: Set<string> | null = seen ? new Set(seen) : null;
321
+ const observe = (): void => {
322
+ const facet = projectAdapterFacet();
323
+ if (!facet || facet.documentsPending) return;
324
+ const ids = new Set(facet.scenes.entries.map((entry) => entry.id));
325
+ if (known === null) {
326
+ known = ids;
327
+ seenTableIds = ids;
328
+ return;
329
+ }
330
+ const entry = [...facet.scenes.entries]
331
+ .reverse()
332
+ .find(
333
+ (candidate) =>
334
+ !known?.has(candidate.id) &&
335
+ candidate.kind !== 'scene' &&
336
+ candidate.kind !== 'prefab' &&
337
+ candidate.source &&
338
+ hasKindEditor(candidate.kind),
339
+ );
340
+ // Advance before opening: document activation can publish the table again.
341
+ known = ids;
342
+ seenTableIds = ids;
343
+ if (openWorkspaceDocuments().some((document) => !document.descriptor.area)) return;
344
+ if (entry?.source && openKindDocument(entry, { activate: true, preview: true })) {
345
+ setSelectedAsset({
346
+ path: `/${entry.source.path}`,
347
+ name: entry.label,
348
+ kind: 'source',
349
+ capabilities: assetCapabilities(entry.source.path),
350
+ origin: 'project',
351
+ health: 'healthy',
352
+ selectionCount: 1,
353
+ });
354
+ }
355
+ };
356
+ observe();
357
+ stopFollowingTableDocuments = subscribeProjectAdapter(observe);
358
+ }
359
+
360
+ /**
361
+ * A RECORD WHOSE FILES ARE ALL GONE opens the project's default, not nothing: a models project
362
+ * whose only `.blend` was deleted between sessions would otherwise sit on an empty workspace
363
+ * (on Cyclotron, the cover's 90 s refusal). Decided once, for the whole record, and only
364
+ * on a table that loaded cleanly for this project — a failed or partial load lists nothing and
365
+ * proves nothing gone.
366
+ */
367
+ function openDefaultWhenRestoresAreGone(entryIds: readonly string[]): void {
368
+ const project = getCurrentProject();
369
+ const attempt = (): boolean => {
370
+ if (getCurrentProject() !== project) return true;
371
+ const facet = projectAdapterFacet();
372
+ if (!facet || facet.documentsPending || facet.error !== null) return false;
373
+ if (facet.scenes.entries.some((entry) => entryIds.includes(entry.id))) return true;
374
+ openDefaultTableDocument();
375
+ return true;
376
+ };
377
+ if (attempt()) return;
378
+ const stop = subscribeProjectAdapter(() => {
379
+ if (attempt()) stop();
380
+ });
381
+ }
382
+
383
+ function openDefaultTableDocument(): void {
384
+ const project = getCurrentProject();
385
+ const attempt = (): boolean => {
386
+ if (getCurrentProject() !== project) return true;
387
+ const facet = projectAdapterFacet();
388
+ if (!facet || facet.documentsPending) return false;
389
+ // "SOMETHING IS ALREADY OPEN" MEANS A DOCUMENT A PERSON IS IN — never an
390
+ // AREA document. A workspace's own `areas` (the Model workspace's Timeline)
391
+ // open with the layout, before the adapter's table has settled, and they
392
+ // are never activatable (`workspace-document-registry.ts` gates activation
393
+ // on `!descriptor.area`). Counting one as "the session already has a
394
+ // document" is what left a fresh `--template models` scaffold under the
395
+ // Code-OSS frame with "No document open yet (0 registered)" and the cube
396
+ // never opened — measured 2026-09-20, walk 3 beat 2: the table held
397
+ // `model:src/models/cube.blend` while `open` held only the timeline.
398
+ if (openWorkspaceDocuments().some((document) => !document.descriptor.area)) return true;
399
+ const entry = defaultTableEntry(facet.scenes);
400
+ // A non-scene entry nothing can open YET (its kind's editor registers after the first
401
+ // table) is waited for: the table resolves again when the contributions land.
402
+ if (!entry) return !facet.scenes.entries.some((one) => one.kind !== 'scene' && one.kind !== 'prefab');
403
+ if (!entry.source) {
404
+ // No file: only its kind's editor opens it.
405
+ openKindDocument(entry);
406
+ return true;
407
+ }
408
+ {
409
+ const path = `/${entry.source.path}`;
410
+ // The kind's own editor when one is registered (a model opens as a
411
+ // model); the source only for a kind nothing edits.
412
+ if (!openKindDocument(entry)) {
413
+ openAssetDocument(path, uneditedKindAssetKind(entry));
414
+ }
415
+ // Opened AND selected, the way a Content click leaves it: the kind's
416
+ // own asset inspector (a model's Edit mesh door) is the first thing
417
+ // the Inspector shows.
418
+ setSelectedAsset({
419
+ path,
420
+ name: entry.label,
421
+ kind: 'source',
422
+ capabilities: assetCapabilities(entry.source.path),
423
+ origin: 'project',
424
+ health: 'healthy',
425
+ selectionCount: 1,
426
+ });
427
+ }
428
+ return true;
429
+ };
430
+ if (attempt()) return;
431
+ const stop = subscribeProjectAdapter(() => {
432
+ if (attempt()) stop();
433
+ });
434
+ }
435
+
436
+ registerWorkspaceDocumentRestorer({
437
+ kind: 'document',
438
+ owner: 'kind-documents',
439
+ // The table resolves asynchronously; an entry that is gone (or a kind whose
440
+ // editor is gone) reopens nothing, like a deleted tool. It also resolves
441
+ // AFTER the restore loop has ended and the stored active id has been asked
442
+ // for, so a kind document that was the active tab must activate ITSELF as
443
+ // it reopens — or the page lands on whichever sibling resolved first (a
444
+ // session reloaded onto the starter cube while its mushroom was the tab in
445
+ // use, 2026-09-06).
446
+ restore: ({ state, active }) => {
447
+ const record = state as { entryId?: unknown } | null | undefined;
448
+ const entryId = typeof record?.entryId === 'string' ? record.entryId : null;
449
+ if (!entryId) return false;
450
+ whenDocumentEntry(entryId, (entry) => {
451
+ openKindDocumentWhenReady(entry, { activate: active });
452
+ });
453
+ return true;
454
+ },
455
+ persistKindState: () => (seenTableIds ? { seen: [...seenTableIds] } : undefined),
456
+ beginRestore: ({ state, hasDocumentsToRestore, documentsToRestore }) => {
457
+ const record = state as { seen?: unknown } | null | undefined;
458
+ const seen = Array.isArray(record?.seen)
459
+ ? record.seen.filter((id): id is string => typeof id === 'string')
460
+ : undefined;
461
+ // A SESSION WITH NOTHING TO RESTORE opens on the project's own DEFAULT
462
+ // document — what the adapter table declares (or its one non-scene
463
+ // entry): a models project opens its model, a website its page. Scenes
464
+ // have their pinned door (`CenterDocuments`) and are not this one's
465
+ // business.
466
+ //
467
+ // This used to read `!hasRecord`, and "a project that recorded 'nothing
468
+ // open' keeps nothing open" stood beside it as if it were a decision. It
469
+ // was a hole: closing the last document writes `open: []`, and every boot
470
+ // after that restored nothing and opened nothing (walk 5 beat 0 —
471
+ // measured on a `cyclotron create` scaffold, where the product's cover
472
+ // then sat out its 90 s budget and blamed Blender for a model nobody had
473
+ // asked it to open).
474
+ if (!hasDocumentsToRestore) openDefaultTableDocument();
475
+ else {
476
+ // Only when the whole record is this kind's: another kind's document may be coming back.
477
+ const entryIds = documentsToRestore.map((doc) =>
478
+ doc.kind === 'document' ? (doc.state as { entryId?: unknown } | null)?.entryId : undefined,
479
+ );
480
+ if (entryIds.every((id): id is string => typeof id === 'string')) {
481
+ openDefaultWhenRestoresAreGone(entryIds);
482
+ }
483
+ }
484
+ followNewTableDocuments(seen);
485
+ },
486
+ });
487
+
488
+ function useContribution(documentId: string) {
489
+ useSyncExternalStore(subscribeToolContributions, getGlobalToolContributions);
490
+ const entry = entries.get(documentId)?.props;
491
+ return { entry, contribution: entry ? documentContributionForKind(entry.kind) : undefined };
492
+ }
493
+
494
+ export function KindDocumentToolbar({ documentId, active }: WorkspaceDocumentContentProps) {
495
+ const { entry, contribution } = useContribution(documentId);
496
+ if (!entry || !contribution?.Toolbar) return null;
497
+ return (
498
+ <ToolHost
499
+ key={`${contribution.id}:${contribution.version}:toolbar:${documentId}`}
500
+ contribution={contribution}
501
+ Component={contribution.Toolbar as unknown as ComponentType<Record<string, unknown>>}
502
+ documentId={documentId}
503
+ active={active}
504
+ document={entry}
505
+ />
506
+ );
507
+ }
508
+
509
+ export function KindDocumentShelf({ documentId, active }: WorkspaceDocumentContentProps) {
510
+ const { entry, contribution } = useContribution(documentId);
511
+ if (!entry || !contribution?.Shelf) return null;
512
+ return (
513
+ <ToolHost
514
+ key={`${contribution.id}:${contribution.version}:shelf:${documentId}`}
515
+ contribution={contribution}
516
+ Component={contribution.Shelf as unknown as ComponentType<Record<string, unknown>>}
517
+ documentId={documentId}
518
+ active={active}
519
+ document={entry}
520
+ />
521
+ );
522
+ }
523
+
524
+ export function KindDocumentContent({ documentId, active }: WorkspaceDocumentContentProps) {
525
+ const { entry, contribution } = useContribution(documentId);
526
+ if (!entry || !contribution) {
527
+ return (
528
+ <div
529
+ style={{ padding: 12, fontSize: 12, color: themeVars.content.muted, pointerEvents: 'auto' }}
530
+ >
531
+ No editor is registered for this document's kind — close this document.
532
+ </div>
533
+ );
534
+ }
535
+ return (
536
+ <ToolHost
537
+ key={`${contribution.id}:${contribution.version}:${documentId}`}
538
+ contribution={contribution}
539
+ documentId={documentId}
540
+ active={active}
541
+ document={entry}
542
+ />
543
+ );
544
+ }
@@ -0,0 +1,74 @@
1
+ /**
2
+ * A colour swatch whose picking is LOCAL until the pick is COMMITTED — the
3
+ * discipline {@link DraftTextInput} applies to every Inspector row whose
4
+ * `onChange` is a SOURCE WRITE, for the one control that could not use it.
5
+ *
6
+ * WHY. A native `<input type="color">` fires `input` continuously while the
7
+ * user drags inside the picker, and React's `onChange` maps to that event. The
8
+ * Inspector's colour row wrote SOURCE per event, so one colour pick queued a
9
+ * burst of writes and remounts: the field re-rendered from the old source
10
+ * value under the picker, the last write carried the pre-edit colour, and the
11
+ * refusal that followed marked the path dynamic — which greys the swatch until
12
+ * the next remount. Two human passes reported it the same way ("the colour
13
+ * changes just once, then I can't select colour again"; "change the colour to
14
+ * red — that did not work").
15
+ *
16
+ * The native `change` event is the pick's own commit (fired when the picker
17
+ * closes, and immediately for a programmatic set), so it is what writes. While
18
+ * the picker is open the swatch shows the draft; when it is not being edited
19
+ * the swatch tracks the live value, so an external change still shows.
20
+ */
21
+
22
+ import { ColorSwatchInput } from '@volter/sdk/widgets';
23
+ import { type InputHTMLAttributes, useEffect, useRef, useState } from 'react';
24
+
25
+ export interface DraftColorInputProps
26
+ extends Omit<InputHTMLAttributes<HTMLInputElement>, 'value' | 'onChange'> {
27
+ /** The live value, shown whenever the swatch is not being picked. */
28
+ readonly value: string;
29
+ /** Fires ONCE per committed pick, with the final colour. Not called when
30
+ * the colour is unchanged. */
31
+ readonly onCommit: (next: string) => void;
32
+ /** Fires on EVERY value the picker streams while it is open, so the viewport
33
+ * follows the pointer. Live-only: the commit above is what persists. */
34
+ readonly onPreview?: (next: string) => void;
35
+ }
36
+
37
+ export function DraftColorInput({ value, onCommit, onPreview, ...rest }: DraftColorInputProps) {
38
+ const [draft, setDraft] = useState<string | null>(null);
39
+ const element = useRef<HTMLInputElement | null>(null);
40
+ // The value this pick STARTED from. A live preview makes `value` follow the
41
+ // draft (the object really is that colour now), so comparing the commit
42
+ // against `value` would find nothing changed and never persist — the commit
43
+ // must be measured against where the pick began.
44
+ const startValue = useRef<string | null>(null);
45
+ // The commit event is NATIVE `change`; React's onChange is the `input`
46
+ // stream, so this listener cannot be expressed as a prop.
47
+ const latest = useRef({ draft, onCommit });
48
+ latest.current = { draft, onCommit };
49
+ useEffect(() => {
50
+ const node = element.current;
51
+ if (!node) return;
52
+ const commit = (): void => {
53
+ const { draft: picked, onCommit: commitTo } = latest.current;
54
+ const next = picked ?? node.value;
55
+ if (next && next !== startValue.current) commitTo(next);
56
+ startValue.current = null;
57
+ setDraft(null);
58
+ };
59
+ node.addEventListener('change', commit);
60
+ return () => node.removeEventListener('change', commit);
61
+ }, []);
62
+ return (
63
+ <ColorSwatchInput
64
+ {...rest}
65
+ ref={element}
66
+ value={draft ?? value}
67
+ onChange={(event) => {
68
+ if (startValue.current === null) startValue.current = value;
69
+ setDraft(event.target.value);
70
+ onPreview?.(event.target.value);
71
+ }}
72
+ />
73
+ );
74
+ }