@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,308 @@
1
+ /**
2
+ * Pure row-model math for the hierarchy panel.
3
+ *
4
+ * Four questions a row needs answered, all extracted here so they are unit
5
+ * testable without a DOM, an adapter session, or a live source tree:
6
+ *
7
+ * 1. **Is this row a component instance, and what is its type?** The
8
+ * adapter already computes `EditorNode.typeLabel`; the row just needs to
9
+ * know when to print it. Detached `#n` pockets deliberately carry no
10
+ * `typeLabel` — a pocket must not impersonate the `<Enemy>` that
11
+ * rendered it — so "has a typeLabel AND is a component row" is the whole
12
+ * rule and no special-casing of pockets is needed here.
13
+ * 2. **Is every transform channel refused, and with what sentence?**
14
+ * The adapter's `reason` is the ONE canonical text (doctrine rule 2): the
15
+ * hierarchy tooltip, the inspector field, and the gizmo-denial hint all
16
+ * show this exact string, never a paraphrase. So this module NEVER writes
17
+ * a reason of its own — it only forwards the adapter's.
18
+ * 3. **Does this row have authorability warnings, and what do they say?**
19
+ * Same rule as H2, one step stronger: the diagnostic message is written by
20
+ * the analyzer that found the problem and is shown VERBATIM. This module
21
+ * picks no wording, adds no severity of its own and truncates nothing — it
22
+ * counts and newline-joins.
23
+ * 4. **What may this row DO?** One predicate ({@link rowAffordances}) that
24
+ * every gate in the panel consults, instead of five copies of
25
+ * `!isStructural && !isInternal` drifting apart.
26
+ *
27
+ * Cost note: `R3fSourceAuthoringAdapter.editability` re-analyzes JSX
28
+ * attributes from cached source text on every call (string scan + parse). It
29
+ * is NOT free per render, which is why {@link transformLockSummary}
30
+ * short-circuits on the first WRITABLE channel (the overwhelmingly common
31
+ * case costs exactly one probe, not three) and why {@link TransformLockCache}
32
+ * exists at all.
33
+ */
34
+
35
+ import type { EditorNode, TransformChannel, TransformEditability } from '@volter/project/adapter';
36
+
37
+ /** The three channels a lock glyph summarizes, in probe order. */
38
+ const CHANNELS: readonly TransformChannel[] = ['position', 'rotation', 'scale'];
39
+
40
+ // ------------------------------------------------------------------ H1
41
+
42
+ export interface RowIdentity {
43
+ /** The row's own name — unchanged, and still the ONLY thing search matches. */
44
+ readonly label: string;
45
+ /** The component type to print as a dim suffix, or null for a plain row. */
46
+ readonly typeSuffix: string | null;
47
+ }
48
+
49
+ /**
50
+ * H1 — `EnemyBravo ·Enemy`. A row earns the type suffix (and the instance
51
+ * accent tint that travels with it) only when it BOTH represents a component
52
+ * instance (`role: 'component'`) and the adapter told us its type.
53
+ */
54
+ export function rowIdentity(node: Pick<EditorNode, 'label' | 'role' | 'typeLabel'>): RowIdentity {
55
+ const isInstance = node.role === 'component' && !!node.typeLabel;
56
+ return { label: node.label, typeSuffix: isInstance ? node.typeLabel! : null };
57
+ }
58
+
59
+ // ------------------------------------------------------------------ H2
60
+
61
+ export interface TransformLockSummary {
62
+ /** True only when position, rotation AND scale are all refused. */
63
+ readonly locked: boolean;
64
+ /** The position channel's verbatim adapter reason (never rewritten here). */
65
+ readonly reason?: string;
66
+ }
67
+
68
+ /** Shared immutable "nothing to say" result — avoids per-row allocation. */
69
+ export const UNLOCKED: TransformLockSummary = { locked: false };
70
+
71
+ /** One channel probe. `undefined` means the adapter declares no editability
72
+ * opinion at all, which every consumer in this editor reads as writable
73
+ * (`editability?.(…)?.writable ?? true`). */
74
+ export type EditabilityProbe = (channel: TransformChannel) => TransformEditability | undefined;
75
+
76
+ /**
77
+ * H2 — collapse the three channels into one row-level verdict. Short-circuits
78
+ * on the first writable channel, so an ordinary movable row pays for ONE
79
+ * `editability` call.
80
+ *
81
+ * The surfaced reason is the POSITION channel's, matching the design record:
82
+ * per-channel detail stays inspector-only, and the row shows one sentence.
83
+ */
84
+ export function transformLockSummary(probe: EditabilityProbe): TransformLockSummary {
85
+ let positionReason: string | undefined;
86
+ for (const channel of CHANNELS) {
87
+ const verdict = probe(channel);
88
+ if (!verdict || verdict.writable) return UNLOCKED;
89
+ if (channel === 'position') positionReason = verdict.reason;
90
+ }
91
+ return positionReason === undefined ? { locked: true } : { locked: true, reason: positionReason };
92
+ }
93
+
94
+ /** The minimal adapter surface {@link TransformLockCache} needs — structurally
95
+ * satisfied by `AuthoringAdapter` without importing it. */
96
+ export interface EditabilitySource {
97
+ readonly transforms?:
98
+ | {
99
+ readonly editability?:
100
+ | ((id: string, channel: TransformChannel) => TransformEditability)
101
+ | undefined;
102
+ }
103
+ | undefined;
104
+ }
105
+
106
+ /**
107
+ * Memoized {@link transformLockSummary} per row id.
108
+ *
109
+ * INVALIDATION KEY: `(source identity, version)`. `version` is supplied by the
110
+ * caller and must be a monotonically increasing counter that advances whenever
111
+ * anything the adapter's `editability` reads could have changed. `GameHierarchy`
112
+ * passes `store.getSnapshot() + adapterVersion` — the shell store's `_version`
113
+ * (bumped by `_notify()`, which EVERY source-write path funnels through via
114
+ * `notifyIngestEdit()`) plus its own adapter-subscription counter. Both are
115
+ * monotone, so their sum is monotone, and a stale entry therefore cannot
116
+ * survive a source edit: the edit bumps `_version` before the re-render that
117
+ * would read the cache.
118
+ *
119
+ * The cache also clears on ADAPTER SWITCH (the `source !== this.source`
120
+ * check), so ids minted by one adapter can never answer for another's.
121
+ */
122
+ export class TransformLockCache {
123
+ private entries = new Map<string, TransformLockSummary>();
124
+ private source: EditabilitySource | null = null;
125
+ private version = Number.NaN;
126
+ /** Test-visible: how many times the adapter was actually probed. */
127
+ private computed = 0;
128
+
129
+ get computeCount(): number {
130
+ return this.computed;
131
+ }
132
+
133
+ summaryFor(source: EditabilitySource, version: number, id: string): TransformLockSummary {
134
+ if (this.source !== source || this.version !== version) {
135
+ this.entries.clear();
136
+ this.source = source;
137
+ this.version = version;
138
+ }
139
+ const cached = this.entries.get(id);
140
+ if (cached) return cached;
141
+ this.computed++;
142
+ const editability = source.transforms?.editability;
143
+ const summary = editability
144
+ ? transformLockSummary((channel) => editability(id, channel))
145
+ : UNLOCKED;
146
+ this.entries.set(id, summary);
147
+ return summary;
148
+ }
149
+ }
150
+
151
+ // ------------------------------------------------------------------ H6
152
+
153
+ /** What a row is allowed to do. Every field is a REFUSAL gate, never a
154
+ * capability claim: `true` means "this row model does not stand in the way",
155
+ * and the adapter's own provider/value probes still decide whether the
156
+ * affordance renders at all (a `document` row has no `name` path, so it never
157
+ * renames regardless of what this says). */
158
+ export interface RowAffordances {
159
+ /** Reparent-by-drag. */
160
+ readonly draggable: boolean;
161
+ /** Inline rename (double-click) and the Rename menu item. */
162
+ readonly renamable: boolean;
163
+ /** ANY write: create/duplicate/delete/group, the visibility eye, the lock
164
+ * toggle, the entity-asset save. One flag, because H6's rule is not
165
+ * per-operation — a revealed internal has no writable surface at all. */
166
+ readonly writable: boolean;
167
+ /** Whether the row's label participates in hierarchy search. */
168
+ readonly searchable: boolean;
169
+ }
170
+
171
+ const ORDINARY_ROW: RowAffordances = {
172
+ draggable: true,
173
+ renamable: true,
174
+ writable: true,
175
+ searchable: true,
176
+ };
177
+ const STRUCTURAL_ROW: RowAffordances = {
178
+ draggable: false,
179
+ renamable: false,
180
+ writable: true,
181
+ searchable: true,
182
+ };
183
+ /**
184
+ * H6 — a revealed internal. Non-writable BY CONSTRUCTION, not by policy: it is
185
+ * a rendered part of a component's output with no authored source identity, so
186
+ * there is nothing for a rename/reparent/delete to write to. Selection stays
187
+ * open (the id resolves, the inspector shows what it honestly can, and H2's
188
+ * lock-with-reason sentence explains the refusal); search is closed, because a
189
+ * `mixamorig:Spine` match across four enemies buries every real row.
190
+ */
191
+ const INTERNAL_ROW: RowAffordances = {
192
+ draggable: false,
193
+ renamable: false,
194
+ writable: false,
195
+ searchable: false,
196
+ };
197
+
198
+ /**
199
+ * The ONE gate for "may this row be written to / dragged / found by search".
200
+ *
201
+ * `structural` keeps its pre-H6 meaning exactly (world groups, organization
202
+ * rows, root-group members, and the `STRUCTURAL_ROLES` set): non-draggable,
203
+ * with its write items gated by the adapter probes the panel already runs.
204
+ * `internal` is the new, stronger state and it wins over everything.
205
+ */
206
+ export function rowAffordances(row: {
207
+ readonly structural: boolean;
208
+ readonly internal: boolean;
209
+ }): RowAffordances {
210
+ if (row.internal) return INTERNAL_ROW;
211
+ return row.structural ? STRUCTURAL_ROW : ORDINARY_ROW;
212
+ }
213
+
214
+ // ------------------------------------------------------------------ H5
215
+
216
+ /**
217
+ * The two fields a row badge needs from one diagnostic. Structurally satisfied
218
+ * by `R3fAuthoringDiagnostic` — declared narrowly here so the hierarchy never
219
+ * imports an R3F/ui-source type (the same contract-only rule H2's
220
+ * {@link EditabilitySource} and H3's `InstanceSourceLocator` follow).
221
+ */
222
+ export interface RowDiagnostic {
223
+ readonly code: string;
224
+ readonly message: string;
225
+ }
226
+
227
+ export interface RowWarningBadge {
228
+ /** How many diagnostics this row carries — always ≥ 1 when a badge exists. */
229
+ readonly count: number;
230
+ /** Every message, VERBATIM and newline-joined, in the order the adapter
231
+ * returned them. The badge's tooltip is this string and nothing else. */
232
+ readonly tooltip: string;
233
+ /** The codes, for the badge's `data-` attribute (a test can name the exact
234
+ * finding without matching on prose that is allowed to be reworded). */
235
+ readonly codes: readonly string[];
236
+ }
237
+
238
+ /**
239
+ * H5 — collapse a row's diagnostics into its badge, or `null` for the
240
+ * overwhelmingly common "nothing to warn about" row.
241
+ *
242
+ * The verbatim rule is the point: doctrine rule 2 says the analyzer's sentence
243
+ * is the ONE canonical text, so multiple findings are STACKED (newline-joined),
244
+ * never summarized into "3 problems" and never truncated. A row with two
245
+ * warnings shows both sentences.
246
+ */
247
+ export function rowWarningBadge(
248
+ diagnostics: readonly RowDiagnostic[] | undefined | null,
249
+ ): RowWarningBadge | null {
250
+ if (!diagnostics || diagnostics.length === 0) return null;
251
+ return {
252
+ count: diagnostics.length,
253
+ tooltip: diagnostics.map((diagnostic) => diagnostic.message).join('\n'),
254
+ codes: diagnostics.map((diagnostic) => diagnostic.code),
255
+ };
256
+ }
257
+
258
+ /** The minimal adapter surface {@link RowWarningCache} needs — structurally
259
+ * satisfied by `CompositeAuthoringAdapter`/`R3fSourceAuthoringAdapter` without
260
+ * importing either, and honestly absent on every adapter that runs no source
261
+ * analyzer (which then shows no badges, rather than fabricated ones). */
262
+ export interface RowDiagnosticsSource {
263
+ readonly diagnosticsFor?: ((id: string) => readonly RowDiagnostic[] | undefined) | undefined;
264
+ }
265
+
266
+ /**
267
+ * Memoized {@link rowWarningBadge} per row id, with the SAME invalidation
268
+ * contract as {@link TransformLockCache} — `(source identity, version)`, where
269
+ * `GameHierarchy` passes the same `store.getSnapshot() + adapterVersion` key to
270
+ * both.
271
+ *
272
+ * That key is exactly right for H5 and not by coincidence: diagnostics arrive
273
+ * on the OID index, and the R3F adapter's `refreshSourceState()` calls
274
+ * `store.notifyIngestEdit()` the moment a new index lands — which bumps the
275
+ * store `_version` that is half this key. So a fresh index invalidates these
276
+ * badges by construction, on the same tick, through the path every source-write
277
+ * and HMR remount already funnels through.
278
+ *
279
+ * Worth caching even though the adapter's own lookup is two map reads: on a
280
+ * composite it is a `route(id)` ownership walk, and the badge object plus its
281
+ * joined tooltip string would otherwise be reallocated for every row on every
282
+ * render.
283
+ */
284
+ export class RowWarningCache {
285
+ private entries = new Map<string, RowWarningBadge | null>();
286
+ private source: RowDiagnosticsSource | null = null;
287
+ private version = Number.NaN;
288
+ /** Test-visible: how many times the adapter was actually probed. */
289
+ private computed = 0;
290
+
291
+ get computeCount(): number {
292
+ return this.computed;
293
+ }
294
+
295
+ badgeFor(source: RowDiagnosticsSource, version: number, id: string): RowWarningBadge | null {
296
+ if (this.source !== source || this.version !== version) {
297
+ this.entries.clear();
298
+ this.source = source;
299
+ this.version = version;
300
+ }
301
+ const cached = this.entries.get(id);
302
+ if (cached !== undefined) return cached;
303
+ this.computed++;
304
+ const badge = source.diagnosticsFor ? rowWarningBadge(source.diagnosticsFor(id)) : null;
305
+ this.entries.set(id, badge);
306
+ return badge;
307
+ }
308
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Hierarchy child-cap constants.
3
+ *
4
+ * The hierarchy panel flattens the ADAPTER's `EditorNode` tree through
5
+ * `hierarchy-node-rows.ts`. This module holds only the two row-cap
6
+ * constants, shared with that flattener so every consumer caps identically.
7
+ */
8
+
9
+ /** Max children shown per parent before a "… N more" row (when capping is on). */
10
+ export const CHILD_CAP = 20;
11
+ export const MORE_ID_PREFIX = '__more__:';
@@ -0,0 +1,86 @@
1
+ /**
2
+ * ONE breadth-first walk of an authoring hierarchy, and the reason it is not
3
+ * written inline four more times.
4
+ *
5
+ * WHAT THIS REPLACES, AND WHY IT IS A BUG AND NOT A STYLE PREFERENCE. Four
6
+ * modules carried the same hand-rolled BFS — `activeHierarchyRows`,
7
+ * `authoringDocumentSourcePath`, the Content panel's `hierarchyNodes`, the
8
+ * composite adapter's `childAssetEntries`, the Light Explorer's `lightNodes` —
9
+ * and every one of them drained its queue with `Array.prototype.shift()`.
10
+ * `shift` is not O(1) on a large array: V8 moves the remaining elements down,
11
+ * so a queue that grows to thousands makes the walk QUADRATIC in node count.
12
+ *
13
+ * Measured with the page's own `Profiler` on the scale harness's 20 000-node
14
+ * canvas world (2026-08-20), profiling the 1.4s window around one relayed
15
+ * `select`: **1471 of 1606 samples were inside `activeHierarchyRows`** — one
16
+ * deferred `collectState` refresh spending 1.4 seconds walking a tree whose
17
+ * every other reader answers in single-digit milliseconds. The study's
18
+ * superlinear growth ratios (canvas ×22-×55, three ×12-×42 from N=1000 to
19
+ * N=5000, where linear is ×5) are what a quadratic walk read through a
20
+ * linear-looking API produces.
21
+ *
22
+ * The cursor below is the whole fix. Nothing about the traversal ORDER,
23
+ * de-duplication, or the set of nodes visited changes — a caller gets exactly
24
+ * the sequence its own loop produced, and the dedup guard (first occurrence
25
+ * wins, a cycle terminates) is the one every copy already had.
26
+ */
27
+
28
+ import type { EditorNode, HierarchyProvider } from '@volter/project/adapter';
29
+
30
+ /** The two members every walker here needs; deliberately not the whole provider. */
31
+ export type WalkableHierarchy = Pick<HierarchyProvider, 'roots' | 'node'>;
32
+
33
+ export interface HierarchyWalkOptions {
34
+ /**
35
+ * Extra children to enqueue behind `id`'s own — the Light Explorer's revealed
36
+ * internals, which are reachable through the adapter but not through
37
+ * `childIds`. Already-visited ids are dropped by the same guard as any other
38
+ * child, so an internal that is also a projected child is visited once.
39
+ */
40
+ readonly extraChildren?: (id: string) => Iterable<EditorNode> | undefined;
41
+ }
42
+
43
+ /**
44
+ * Visit every reachable node breadth-first, each id exactly once.
45
+ *
46
+ * Return `false` from `visit` to STOP the walk — the early-exit searches
47
+ * (`authoringDocumentSourcePath`) are why this takes a callback rather than
48
+ * only returning an array: a search that answers on the first row must not pay
49
+ * for a full walk of a 20 000-node tree first.
50
+ */
51
+ export function forEachHierarchyNode(
52
+ hierarchy: WalkableHierarchy,
53
+ visit: (node: EditorNode) => boolean | void,
54
+ options: HierarchyWalkOptions = {},
55
+ ): void {
56
+ const queue: EditorNode[] = [...hierarchy.roots()];
57
+ const seen = new Set<string>();
58
+ // A CURSOR, never `shift()`. See this file's header for the measurement.
59
+ for (let cursor = 0; cursor < queue.length; cursor += 1) {
60
+ const node = queue[cursor]!;
61
+ if (seen.has(node.id)) continue;
62
+ seen.add(node.id);
63
+ if (visit(node) === false) return;
64
+ for (const childId of node.childIds) {
65
+ const child = hierarchy.node(childId);
66
+ if (child) queue.push(child);
67
+ }
68
+ for (const extra of options.extraChildren?.(node.id) ?? []) queue.push(extra);
69
+ }
70
+ }
71
+
72
+ /** Every reachable node, breadth-first, de-duplicated by id. */
73
+ export function hierarchyNodesBreadthFirst(
74
+ hierarchy: WalkableHierarchy,
75
+ options: HierarchyWalkOptions = {},
76
+ ): EditorNode[] {
77
+ const nodes: EditorNode[] = [];
78
+ forEachHierarchyNode(
79
+ hierarchy,
80
+ (node) => {
81
+ nodes.push(node);
82
+ },
83
+ options,
84
+ );
85
+ return nodes;
86
+ }
@@ -0,0 +1,25 @@
1
+ import { HistoryCommands } from './history-commands';
2
+ import { connectHistoryLimitNotices } from './history-limit-notices';
3
+ import { HistoryService, type HistoryServiceOptions } from '@volter/sdk/kit/history/history-service';
4
+
5
+ /** Owns project-lifetime editor services; disposed when EditorProvider unmounts. */
6
+ export class EditorSession {
7
+ readonly history: HistoryService;
8
+ readonly historyCommands: HistoryCommands;
9
+ private readonly releaseLimitNotices: () => void;
10
+
11
+ constructor(
12
+ readonly projectIdentity: string,
13
+ historyOptions: HistoryServiceOptions = {},
14
+ ) {
15
+ this.history = new HistoryService(historyOptions);
16
+ this.historyCommands = new HistoryCommands(this.history);
17
+ this.releaseLimitNotices = connectHistoryLimitNotices(this.history);
18
+ }
19
+
20
+ dispose(): void {
21
+ this.releaseLimitNotices();
22
+ this.historyCommands.dispose();
23
+ this.history.dispose();
24
+ }
25
+ }
@@ -0,0 +1,147 @@
1
+ import type { HistoryService } from '@volter/sdk/kit/history/history-service';
2
+
3
+ export interface HistoryCommandSnapshot {
4
+ readonly version: number;
5
+ readonly busy: boolean;
6
+ readonly canUndo: boolean;
7
+ readonly canRedo: boolean;
8
+ readonly undoLabel: string | null;
9
+ readonly redoLabel: string | null;
10
+ }
11
+
12
+ /** Shell command surface for the one project HistoryService timeline. */
13
+ export class HistoryCommands {
14
+ private tail: Promise<void> = Promise.resolve();
15
+ private readonly listeners = new Set<() => void>();
16
+ private pending = 0;
17
+ private version = 0;
18
+ private disposed = false;
19
+ private readonly idleWaiters = new Set<{
20
+ unsubscribe: () => void;
21
+ reject: (error: Error) => void;
22
+ }>();
23
+ private readonly unsubscribeHistory: () => void;
24
+ private snapshot: HistoryCommandSnapshot;
25
+
26
+ constructor(private readonly history: HistoryService) {
27
+ this.snapshot = this.buildSnapshot();
28
+ this.unsubscribeHistory = history.subscribe(this.notify);
29
+ }
30
+
31
+ subscribe = (listener: () => void): (() => void) => {
32
+ if (this.disposed) return () => undefined;
33
+ this.listeners.add(listener);
34
+ return () => this.listeners.delete(listener);
35
+ };
36
+
37
+ getSnapshot = (): HistoryCommandSnapshot => this.snapshot;
38
+
39
+ undo(): Promise<boolean> {
40
+ return this.enqueue(async () => {
41
+ await this.waitForServiceIdle();
42
+ this.assertNotDisposed();
43
+ return this.history.undo();
44
+ });
45
+ }
46
+
47
+ redo(): Promise<boolean> {
48
+ return this.enqueue(async () => {
49
+ await this.waitForServiceIdle();
50
+ this.assertNotDisposed();
51
+ return this.history.redo();
52
+ });
53
+ }
54
+
55
+ jumpTo(cursor: number): Promise<boolean> {
56
+ return this.enqueue(async () => {
57
+ await this.waitForServiceIdle();
58
+ this.assertNotDisposed();
59
+ return this.history.jumpTo(cursor);
60
+ });
61
+ }
62
+
63
+ get canUndo(): boolean {
64
+ return this.snapshot.canUndo;
65
+ }
66
+
67
+ get canRedo(): boolean {
68
+ return this.snapshot.canRedo;
69
+ }
70
+
71
+ dispose(): void {
72
+ if (this.disposed) return;
73
+ this.disposed = true;
74
+ this.unsubscribeHistory();
75
+ const error = new Error('History commands are disposed.');
76
+ for (const waiter of this.idleWaiters) {
77
+ waiter.unsubscribe();
78
+ waiter.reject(error);
79
+ }
80
+ this.idleWaiters.clear();
81
+ this.listeners.clear();
82
+ this.notify();
83
+ }
84
+
85
+ private enqueue(operation: () => Promise<boolean>): Promise<boolean> {
86
+ if (this.disposed) return Promise.reject(new Error('History commands are disposed.'));
87
+ this.pending++;
88
+ this.notify();
89
+ const run = () => {
90
+ if (this.disposed) throw new Error('History commands are disposed.');
91
+ return operation();
92
+ };
93
+ const result = this.tail.then(run, run);
94
+ this.tail = result.then(
95
+ () => undefined,
96
+ () => undefined,
97
+ );
98
+ return result.finally(() => {
99
+ this.pending--;
100
+ this.notify();
101
+ });
102
+ }
103
+
104
+ private assertNotDisposed(): void {
105
+ if (this.disposed) throw new Error('History commands are disposed.');
106
+ }
107
+
108
+ private waitForServiceIdle(): Promise<void> {
109
+ if (this.disposed) return Promise.reject(new Error('History commands are disposed.'));
110
+ if (!this.history.getSnapshot().busy) return Promise.resolve();
111
+ return new Promise((resolve, reject) => {
112
+ const waiter: {
113
+ unsubscribe: () => void;
114
+ reject: (error: Error) => void;
115
+ } = { unsubscribe: () => undefined, reject };
116
+ const finish = () => {
117
+ waiter.unsubscribe();
118
+ this.idleWaiters.delete(waiter);
119
+ };
120
+ waiter.unsubscribe = this.history.subscribe(() => {
121
+ if (this.history.getSnapshot().busy) return;
122
+ finish();
123
+ resolve();
124
+ });
125
+ this.idleWaiters.add(waiter);
126
+ });
127
+ }
128
+
129
+ private notify = (): void => {
130
+ this.version++;
131
+ this.snapshot = this.buildSnapshot();
132
+ for (const listener of this.listeners) listener();
133
+ };
134
+
135
+ private buildSnapshot(): HistoryCommandSnapshot {
136
+ const current = this.history.getSnapshot();
137
+ const busy = this.pending > 0 || current.busy;
138
+ return {
139
+ version: this.version,
140
+ busy,
141
+ canUndo: !this.disposed && !busy && current.canUndo,
142
+ canRedo: !this.disposed && !busy && current.canRedo,
143
+ undoLabel: current.undoLabel,
144
+ redoLabel: current.redoLabel,
145
+ };
146
+ }
147
+ }