@volter/sdk 0.0.0-stage → 0.5.203

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 +1166 -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 +317 -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 +403 -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,270 @@
1
+ /**
2
+ * PD-3's runtime backstop: DETECT a cross-root module split and report it
3
+ * LOUDLY, so the next one can never be silent the way the measured one was
4
+ * ("HUD rendered defaults forever while `game.state()` moved; no error, no
5
+ * warning").
6
+ *
7
+ * `project-module-url.ts` removes the deterministic CAUSE (one mount epoch
8
+ * shared by every root's entry url). This module is the tripwire for whatever
9
+ * that guarantee does not cover — a future root resolver that hand-builds a
10
+ * url, a `/@fs//doubled-slash` form reappearing, a symlink-uncanonical root,
11
+ * or a source edit landing between two roots' transforms inside one mount.
12
+ *
13
+ * HOW IT MEASURES, and why this observable and not another
14
+ * --------------------------------------------------------
15
+ * Browser ES-module identity is per-URL and a module is EVALUATED exactly
16
+ * once per url, so "two live instances of one file" is exactly "two distinct
17
+ * urls for one file were fetched as modules". Resource Timing already records
18
+ * every one of those fetches with a timestamp, which makes the whole check a
19
+ * pure function over `performance.getEntriesByType('resource')` — no
20
+ * instrumentation injected into project code, no per-module cost, and
21
+ * trivially unit-testable against a synthetic entry list.
22
+ *
23
+ * The window matters, and is what keeps this SOUND rather than noisy:
24
+ *
25
+ * - Counting over the whole session would fire on every healthy remount —
26
+ * an edited module legitimately gets a new `?t=` url each mount, and the
27
+ * superseded instance's fetch stays in the timeline forever.
28
+ * - Counting only fetches made DURING one mount cannot false-positive: a
29
+ * single mount has no legitimate reason to evaluate one file twice. A file
30
+ * reused from the browser's module registry is not re-fetched, so it never
31
+ * inflates the count.
32
+ *
33
+ * The cost of that soundness is the honest gap recorded here: the ONE case
34
+ * this cannot see is a root that reuses a cached module while a sibling
35
+ * evaluates a fresh one (the original PD-3 shape) — the cached side performs
36
+ * no fetch at all. That case is closed by construction upstream, in
37
+ * `project-module-url.ts`; this module is deliberately the second line, not
38
+ * the first.
39
+ */
40
+
41
+ /** The Resource Timing fields this module reads — declared structurally so a
42
+ * test can hand over a plain array and so nothing here depends on the DOM
43
+ * lib's `PerformanceResourceTiming`. */
44
+ export interface ResourceTimingLike {
45
+ readonly name: string;
46
+ readonly startTime: number;
47
+ }
48
+
49
+ /** One file that was evaluated more than once inside a single mount. */
50
+ export interface ProjectModuleSplit {
51
+ /** The file's path (query stripped) — the `/@fs/…` pathname as fetched, so
52
+ * it names the module the way every other editor/dev-server message does. */
53
+ readonly path: string;
54
+ /** Every distinct url the file was fetched under during the window, in
55
+ * fetch order. Always length >= 2. */
56
+ readonly urls: readonly string[];
57
+ }
58
+
59
+ /** Module-graph extensions vite serves for a NON-module purpose — the same
60
+ * file legitimately produces a different module for each of these, so two
61
+ * urls differing only by one of them is not a split. */
62
+ const NON_MODULE_QUERY_KEYS = new Set(['raw', 'url', 'worker', 'sharedworker', 'inline', 'init']);
63
+
64
+ import { PROJECT_MOUNT_QUERY } from '@volter/sdk/session/project-module-url';
65
+
66
+ const MODULE_EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'];
67
+ const STORY_MODULE_PATTERN = /\.stories\.[cm]?[jt]sx?$/i;
68
+
69
+ function pathAndQuery(name: string): { path: string; query: string } | null {
70
+ // Resource Timing `name` is an absolute url. Parsing against a fixed base
71
+ // keeps this pure (no `window.location` read) and works for both forms.
72
+ let parsed: URL;
73
+ try {
74
+ parsed = new URL(name, 'http://volter.invalid');
75
+ } catch {
76
+ return null;
77
+ }
78
+ return { path: parsed.pathname, query: parsed.search };
79
+ }
80
+
81
+ function isNonModuleQuery(query: string): boolean {
82
+ const params = new URLSearchParams(query);
83
+ for (const key of params.keys()) {
84
+ if (NON_MODULE_QUERY_KEYS.has(key)) return true;
85
+ }
86
+ return false;
87
+ }
88
+
89
+ /**
90
+ * The pure half: given the Resource Timing entries of one mount window and
91
+ * the project's absolute root, return every project file fetched under more
92
+ * than one url.
93
+ *
94
+ * `projectRoot` is matched against the `/@fs/`-mounted pathname, which is how
95
+ * every project module the editor imports is served in dev. A project served
96
+ * some other way simply yields no candidates — an empty result, never a
97
+ * fabricated one.
98
+ */
99
+ /** The one candidate test: is this fetch a MODULE of the project under test?
100
+ * Split out so the grouping loop stays one thing. */
101
+ function projectModuleFetch(
102
+ entry: ResourceTimingLike,
103
+ root: string,
104
+ since: number,
105
+ ): { group: string; path: string; url: string } | null {
106
+ if (entry.startTime < since) return null;
107
+ const parts = pathAndQuery(entry.name);
108
+ if (!parts) return null;
109
+ const { path, query } = parts;
110
+ if (!path.includes(root)) return null;
111
+ if (!MODULE_EXTENSIONS.some((ext) => path.endsWith(ext))) return null;
112
+ // Portable CSF is a design-time document, not part of a mounted root's
113
+ // runtime module graph. Story discovery deliberately gives every refresh a
114
+ // fresh `?t=` URL (`stories/story-discovery.ts`), and a board refresh may
115
+ // overlap this Play mount window. Counting that intentional reload as a
116
+ // cross-root split makes a healthy multi-root game report an error even
117
+ // though every root entry still shares the one `volter-mount` epoch.
118
+ if (STORY_MODULE_PATTERN.test(path)) return null;
119
+ // The project's adapter is the same shape: a binding table the editor reads
120
+ // WITHOUT booting the game (`project-adapter.ts`'s `importAdapterModule`), fresh
121
+ // `?t=` on every read, and imported by no root.
122
+ if (path.endsWith('/volter.adapter.ts')) return null;
123
+ if (isNonModuleQuery(query)) return null;
124
+ // The mount id is not a variant of a module — it names WHICH INSTANCE's copy
125
+ // this is, and per-instance module graphs are the isolation working (see
126
+ // ARCHITECTURE-CORE §Multiplayer authoring). Two instances fetch every
127
+ // project module under different urls BY DESIGN, so comparing across them
128
+ // would report the entire project as split the moment a second one mounts —
129
+ // every module, every time, on the loudest diagnostic in the play path.
130
+ // Group per instance instead: the question this watch asks ("did the roots
131
+ // of one mount fail to share a module?") is a per-instance question. With
132
+ // one instance — every mount today — there is one group and nothing changes.
133
+ const params = new URLSearchParams(query);
134
+ const mount = params.get(PROJECT_MOUNT_QUERY) ?? '';
135
+ params.delete(PROJECT_MOUNT_QUERY);
136
+ const rest = params.toString();
137
+ return {
138
+ group: `${mount}\u0000${path}`,
139
+ path,
140
+ url: `${path}${rest ? `?${rest}` : ''}`,
141
+ };
142
+ }
143
+
144
+ export function findProjectModuleSplits(
145
+ resources: readonly ResourceTimingLike[],
146
+ opts: { readonly projectRoot: string; readonly since: number },
147
+ ): ProjectModuleSplit[] {
148
+ const root = opts.projectRoot.endsWith('/') ? opts.projectRoot.slice(0, -1) : opts.projectRoot;
149
+ if (root.length === 0) return [];
150
+ const byGroup = new Map<string, { path: string; urls: string[] }>();
151
+
152
+ for (const entry of resources) {
153
+ const fetched = projectModuleFetch(entry, root, opts.since);
154
+ if (!fetched) continue;
155
+ const seen = byGroup.get(fetched.group);
156
+ if (seen === undefined) byGroup.set(fetched.group, { path: fetched.path, urls: [fetched.url] });
157
+ else if (!seen.urls.includes(fetched.url)) seen.urls.push(fetched.url);
158
+ }
159
+
160
+ const splits: ProjectModuleSplit[] = [];
161
+ for (const { path, urls } of byGroup.values()) {
162
+ if (urls.length > 1) splits.push({ path, urls });
163
+ }
164
+ return splits;
165
+ }
166
+
167
+ /**
168
+ * The message a split is reported with. Pure (and exported) so the wording is
169
+ * a testable contract rather than an inline string: a silent split is the
170
+ * entire defect, so the report has to NAME the module and show the two urls
171
+ * that prove it.
172
+ */
173
+ export function formatProjectModuleSplitMessage(split: ProjectModuleSplit): string {
174
+ return (
175
+ `Cross-root module split: ${split.path} was loaded ${split.urls.length} times in one mount, ` +
176
+ 'so each root holds its OWN copy of its module-level state (a `let` written by one root is ' +
177
+ 'invisible to the other). Urls: ' +
178
+ split.urls.join(' | ')
179
+ );
180
+ }
181
+
182
+ // ---------------------------------------------------------------------------
183
+ // The stateful half — one mount window, and the reports it produced
184
+ // ---------------------------------------------------------------------------
185
+
186
+ interface PerformanceLike {
187
+ now(): number;
188
+ getEntriesByType(type: string): ResourceTimingLike[];
189
+ }
190
+
191
+ function performanceHost(): PerformanceLike | null {
192
+ const candidate = (globalThis as { performance?: unknown }).performance;
193
+ if (!candidate || typeof candidate !== 'object') return null;
194
+ const perf = candidate as Partial<PerformanceLike>;
195
+ if (typeof perf.now !== 'function' || typeof perf.getEntriesByType !== 'function') return null;
196
+ return perf as PerformanceLike;
197
+ }
198
+
199
+ // Capture this diagnostic window independently of the browser's bounded
200
+ // Resource Timing history. Module lookup is owned by the game realm.
201
+ let resourceObserver: PerformanceObserver | null = null;
202
+ let windowResources: ResourceTimingLike[] = [];
203
+
204
+ let windowStart: number | null = null;
205
+ let reports: ProjectModuleSplit[] = [];
206
+
207
+ /** Open the mount window. Called immediately before a composition's roots are
208
+ * resolved/imported; clears the previous mount's reports so the diagnostic
209
+ * can always go back to healthy (the PD-1 lesson — a report that cannot
210
+ * clear itself is worse than none). */
211
+ export function beginProjectModuleSplitWatch(): void {
212
+ reports = [];
213
+ resourceObserver?.disconnect();
214
+ resourceObserver = null;
215
+ windowResources = [];
216
+ const perf = performanceHost();
217
+ if (!perf) {
218
+ windowStart = null;
219
+ return;
220
+ }
221
+ windowStart = perf.now();
222
+ if (typeof PerformanceObserver !== 'undefined') {
223
+ resourceObserver = new PerformanceObserver((list) => {
224
+ windowResources.push(...list.getEntries());
225
+ });
226
+ resourceObserver.observe({ type: 'resource' });
227
+ }
228
+ }
229
+
230
+ /**
231
+ * Close the mount window and record what it found. Called after every root
232
+ * has mounted (not merely resolved) so a root that imports its entry lazily
233
+ * inside `mount()` is inside the window too. Returns the reports so the
234
+ * caller can log them; a no-op window (no `performance`, or no `begin`) is an
235
+ * empty result, never a guess.
236
+ */
237
+ export function endProjectModuleSplitWatch(projectRoot: string): readonly ProjectModuleSplit[] {
238
+ const perf = performanceHost();
239
+ if (!perf || windowStart === null) {
240
+ windowStart = null;
241
+ return reports;
242
+ }
243
+ const entries = resourceObserver
244
+ ? [...windowResources, ...resourceObserver.takeRecords()]
245
+ : perf.getEntriesByType('resource');
246
+ resourceObserver?.disconnect();
247
+ resourceObserver = null;
248
+ windowResources = [];
249
+ reports = findProjectModuleSplits(entries, {
250
+ projectRoot,
251
+ since: windowStart,
252
+ });
253
+ windowStart = null;
254
+ return reports;
255
+ }
256
+
257
+ /** What the last closed mount window found — `[]` on a healthy mount. Read by
258
+ * `command-listener.ts`'s `collectState` so the editor's `status` command carries it. */
259
+ export function getProjectModuleSplitReports(): readonly ProjectModuleSplit[] {
260
+ return reports;
261
+ }
262
+
263
+ /** Drop every recorded split — what a torn-down play session calls. */
264
+ export function clearProjectModuleSplitReports(): void {
265
+ resourceObserver?.disconnect();
266
+ resourceObserver = null;
267
+ windowResources = [];
268
+ reports = [];
269
+ windowStart = null;
270
+ }
@@ -0,0 +1,25 @@
1
+ /** A UI tool offers project roots to any playing stage. The caller lends a
2
+ * container and one mount epoch shared with its world/script; Stop disposes it.
3
+ * Neither the game context nor a product needs an overlay field. */
4
+ import type { ProjectMountEpoch } from '../session/project-module-url';
5
+ export interface MountedProjectPlayLayers {
6
+ /** Entries whose dependency graph belongs to these layers. */
7
+ readonly entries: readonly string[];
8
+ dispose(): void;
9
+ }
10
+ export type ProjectPlayLayers = (options: {
11
+ readonly projectRoot: string;
12
+ readonly epoch: ProjectMountEpoch;
13
+ readonly container: HTMLElement;
14
+ /** Report all declared entries before importing or mounting them, so a failed
15
+ * first mount can be retried when an entry or its dependency is saved. */
16
+ readonly onEntries: (entries: readonly string[]) => void;
17
+ }) => Promise<MountedProjectPlayLayers>;
18
+ const key = Symbol.for('volter.project-play-layers');
19
+ const page = globalThis as typeof globalThis & { [key]?: ProjectPlayLayers };
20
+ export function projectPlayLayers(): ProjectPlayLayers | null { return page[key] ?? null; }
21
+ export function registerProjectPlayLayers(provider: ProjectPlayLayers): () => void {
22
+ if (page[key]) throw new Error('A UI tool already offers project Play layers.');
23
+ page[key] = provider;
24
+ return () => { if (page[key] === provider) delete page[key]; };
25
+ }
@@ -0,0 +1,115 @@
1
+ const PROVENANCE_PATH = '.volter/provenance.json';
2
+
3
+ export interface ProjectOutputProvenance {
4
+ readonly operationId: string;
5
+ readonly createdAt: string;
6
+ readonly operationName: string;
7
+ readonly operationSource?: string;
8
+ readonly input?: unknown;
9
+ readonly output: {
10
+ readonly path: string;
11
+ readonly bytes: number;
12
+ readonly sha256: string;
13
+ readonly mediaType?: string;
14
+ readonly role?: string;
15
+ };
16
+ }
17
+
18
+ /** The project-root-relative FILE behind a served asset path — the served path
19
+ * with `public/` put back, which is where a writer's bytes have to land. */
20
+ export function projectOutputPath(assetPath: string): string {
21
+ const clean = assetPath.split(/[?#]/, 1)[0]!.replace(/^\/+/, '');
22
+ return clean.startsWith('public/') ? clean : `public/${clean}`;
23
+ }
24
+
25
+ async function readProjectProvenance(): Promise<unknown> {
26
+ // NOT read through `editor-server-response.ts`: this route's GET half serves
27
+ // raw file bytes as `text/plain` (routes/project-source.ts), and that reader
28
+ // asserts `application/json` — it would reject the success case.
29
+ const response = await fetch(
30
+ `/__editor/volter-file?${new URLSearchParams({ path: PROVENANCE_PATH })}`,
31
+ );
32
+ if (!response.ok) return null;
33
+ return JSON.parse(await response.text());
34
+ }
35
+
36
+ function record(value: unknown): Record<string, unknown> | null {
37
+ return value && typeof value === 'object' && !Array.isArray(value)
38
+ ? (value as Record<string, unknown>)
39
+ : null;
40
+ }
41
+
42
+ function parsedOutput(
43
+ value: unknown,
44
+ expectedPath: string,
45
+ ): ProjectOutputProvenance['output'] | null {
46
+ const output = record(value);
47
+ if (
48
+ output?.['path'] !== expectedPath ||
49
+ typeof output['bytes'] !== 'number' ||
50
+ typeof output['sha256'] !== 'string'
51
+ )
52
+ return null;
53
+ const mediaType = output['mediaType'];
54
+ const role = output['role'];
55
+ return {
56
+ path: expectedPath,
57
+ bytes: output['bytes'],
58
+ sha256: output['sha256'],
59
+ ...(typeof mediaType === 'string' ? { mediaType } : {}),
60
+ ...(typeof role === 'string' ? { role } : {}),
61
+ };
62
+ }
63
+
64
+ function operationMatches(
65
+ operationId: string,
66
+ value: unknown,
67
+ expectedPath: string,
68
+ ): ProjectOutputProvenance[] {
69
+ const operation = record(value);
70
+ const identity = record(operation?.['operation']);
71
+ const outputs = operation?.['outputs'];
72
+ const createdAt = operation?.['createdAt'];
73
+ const operationName = identity?.['name'];
74
+ if (
75
+ !operation ||
76
+ !identity ||
77
+ typeof createdAt !== 'string' ||
78
+ typeof operationName !== 'string' ||
79
+ !Array.isArray(outputs)
80
+ )
81
+ return [];
82
+ const operationSource = identity['source'];
83
+ return outputs.flatMap((value) => {
84
+ const output = parsedOutput(value, expectedPath);
85
+ if (!output) return [];
86
+ return [
87
+ {
88
+ operationId,
89
+ createdAt,
90
+ operationName,
91
+ ...(typeof operationSource === 'string' ? { operationSource } : {}),
92
+ ...(operation['input'] !== undefined ? { input: operation['input'] } : {}),
93
+ output,
94
+ },
95
+ ];
96
+ });
97
+ }
98
+
99
+ /** Resolve the newest central provenance operation that produced this asset path. */
100
+ export async function provenanceForProjectAsset(
101
+ assetPath: string,
102
+ ): Promise<ProjectOutputProvenance | null> {
103
+ const document = record(await readProjectProvenance());
104
+ const operations = record(document?.['operations']);
105
+ if (!operations) return null;
106
+ const expectedPath = projectOutputPath(assetPath);
107
+ const matches = Object.entries(operations).flatMap(([operationId, operation]) =>
108
+ operationMatches(operationId, operation, expectedPath),
109
+ );
110
+ return matches.sort((left, right) => right.createdAt.localeCompare(left.createdAt))[0] ?? null;
111
+ }
112
+
113
+ export function __projectOutputPathForTest(assetPath: string): string {
114
+ return projectOutputPath(assetPath);
115
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * THE PROJECT-READY HOOK — the host's side of `host.project.onReady`: the
3
+ * moment both bootstraps (`the world root's stage`'s boot chain, after the scene
4
+ * loads and the composite installs; `NonThreeAuthoringBootstrap`'s, after
5
+ * its composite installs) reach when a lane may auto-launch what the
6
+ * manifest declares. Listeners run in registration order, each awaited, so
7
+ * a later one may read what an earlier one mounted.
8
+ *
9
+ * LATCHED, per project, for the same reason `hosted-example.ts`'s auto-play
10
+ * decision is: this hook's registrants are PACKAGE SERVICES, and a
11
+ * contribution pass is asynchronous — it can finish on either side of the
12
+ * boot chain. Unlatched, a service that registered one tick late simply
13
+ * never ran, and the lane it starts (the ingest auto-launch) silently
14
+ * did nothing for the whole session; measured 2026-09-17 on a staged
15
+ * vendored game, which mounted nothing at all. The latch is keyed to the
16
+ * project that reached ready, so opening a second project does not fire its
17
+ * services against the first project's boot.
18
+ */
19
+ import { getCurrentProject } from '@volter/sdk/kit/project-manager';
20
+
21
+ const listeners = new Set<() => void | Promise<void>>();
22
+
23
+ /** The `rootPath` of the project whose boot chain last reached ready. */
24
+ let readyFor: string | null = null;
25
+
26
+ function currentProjectKey(): string | null {
27
+ return getCurrentProject()?.rootPath ?? null;
28
+ }
29
+
30
+ export function onProjectReady(fn: () => void | Promise<void>): () => void {
31
+ listeners.add(fn);
32
+ const key = currentProjectKey();
33
+ if (key !== null && readyFor === key) void fn();
34
+ return () => {
35
+ listeners.delete(fn);
36
+ };
37
+ }
38
+
39
+ export async function runProjectReady(): Promise<void> {
40
+ readyFor = currentProjectKey();
41
+ for (const fn of [...listeners]) await fn();
42
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * What the active project DECLARES, as the chrome reads it (ARCHITECTURE-CORE
3
+ * §Roots: "a project's shape is derived from what it declares, never
4
+ * assumed"). Nothing here names a kind of project; the questions are the
5
+ * ones chrome actually has — does anything mount? — answered from the
6
+ * manifest's own `roots`.
7
+ */
8
+
9
+ import { useSyncExternalStore } from 'react';
10
+ import { getCurrentProject, onProjectChange } from '@volter/sdk/kit/active-project';
11
+
12
+ /** True when the active project declares at least one root — something the
13
+ * host mounts, plays and instances. A project config from before
14
+ * `rootCount` existed answers true, which is what every project was. */
15
+ export function projectMounts(): boolean {
16
+ const count = getCurrentProject()?.config.rootCount;
17
+ return count === undefined ? true : count > 0;
18
+ }
19
+
20
+ /** {@link projectMounts} as a React subscription. */
21
+ export function useProjectMounts(): boolean {
22
+ return useSyncExternalStore(onProjectChange, projectMounts, projectMounts);
23
+ }
24
+
25
+ const shapeListeners = new Set<() => void>();
26
+
27
+ /** The adapter host resolved (or re-resolved) the document table: what the
28
+ * project declares may have changed without the project itself changing. */
29
+ export function notifyProjectShapeChanged(): void {
30
+ for (const fn of shapeListeners) fn();
31
+ }
32
+
33
+ /** Fires on {@link notifyProjectShapeChanged} and on a project change. */
34
+ export function subscribeProjectShape(fn: () => void): () => void {
35
+ shapeListeners.add(fn);
36
+ const stopProject = onProjectChange(fn);
37
+ return () => {
38
+ shapeListeners.delete(fn);
39
+ stopProject();
40
+ };
41
+ }
42
+
43
+ /** The document kinds the active project's resolved table holds, supplied by
44
+ * the adapter host (`project-adapter.ts` registers it) so this module —
45
+ * which a bounded host's closure carries — imports no adapter machinery. `null`
46
+ * until an adapter has resolved. */
47
+ let documentKindsSupplier: (() => readonly string[] | null) | null = null;
48
+ export function registerDocumentKindsSupplier(supplier: () => readonly string[] | null): void {
49
+ documentKindsSupplier = supplier;
50
+ }
51
+
52
+ /** True when the active project's resolved document table holds an entry
53
+ * of `kind` — what a workspace built around one kind of document requires
54
+ * (Model, Sculpt and Texture require a `model`). Before the adapter has
55
+ * resolved, the answer is true, so a workspace never vanishes mid-boot. */
56
+ export function projectDeclaresDocumentKind(kind: string): boolean {
57
+ const kinds = documentKindsSupplier?.() ?? null;
58
+ if (kinds === null) return true;
59
+ return kinds.includes(kind);
60
+ }
61
+
62
+ /** The same answer as a LIST, for a message that has to name the vocabulary
63
+ * rather than test one value against it (`present-view`'s refusal on an
64
+ * unknown document kind). `null` before the adapter has resolved — a refusal
65
+ * that cannot read the table says less, never something invented. */
66
+ export function projectDocumentKinds(): readonly string[] | null {
67
+ return documentKindsSupplier?.() ?? null;
68
+ }
@@ -0,0 +1,107 @@
1
+ import type { ProjectToolCatalog } from '@volter/sdk/project-tool-catalog';
2
+ import { connectToolFileEvents } from './asset-events';
3
+ import { editorServerJson } from '@volter/sdk/kit/editor-server-response';
4
+ import { onProjectChange } from './project-manager';
5
+
6
+ export type {
7
+ ProjectToolCatalog,
8
+ ProjectToolCatalogEntry,
9
+ ProjectToolContribution,
10
+ ToolContributionPoint,
11
+ } from '@volter/sdk/project-tool-catalog';
12
+
13
+ export type ProjectToolOutcome =
14
+ | {
15
+ ok: true;
16
+ data: unknown;
17
+ generation?: import('@volter/sdk/generations').GenerationJob;
18
+ generationWarning?: string;
19
+ }
20
+ | { ok: false; error: { code: string; message: string; data?: unknown; issues?: unknown[] } };
21
+
22
+ const EMPTY_CATALOG: ProjectToolCatalog = { tools: [], contributions: [], loadErrors: [] };
23
+ let catalog = EMPTY_CATALOG;
24
+ let version = 0;
25
+ const listeners = new Set<() => void>();
26
+
27
+ function publish(next: ProjectToolCatalog): void {
28
+ catalog = next;
29
+ version++;
30
+ for (const listener of listeners) listener();
31
+ }
32
+
33
+ export function getProjectTools(): ProjectToolCatalog {
34
+ return catalog;
35
+ }
36
+
37
+ export function projectToolsVersion(): number {
38
+ return version;
39
+ }
40
+
41
+ export function subscribeProjectTools(listener: () => void): () => void {
42
+ listeners.add(listener);
43
+ return () => listeners.delete(listener);
44
+ }
45
+
46
+ export async function refreshProjectTools(): Promise<ProjectToolCatalog> {
47
+ try {
48
+ const response = await fetch('/__editor/project-tools');
49
+ const next = await editorServerJson<ProjectToolCatalog>(response, 'Catalog request failed');
50
+ publish(next);
51
+ return next;
52
+ } catch (error) {
53
+ const next = {
54
+ tools: [],
55
+ contributions: [],
56
+ loadErrors: [
57
+ {
58
+ sourcePath: 'package.json#volter.tools',
59
+ message: error instanceof Error ? error.message : String(error),
60
+ },
61
+ ],
62
+ };
63
+ publish(next);
64
+ return next;
65
+ }
66
+ }
67
+
68
+ export async function runProjectTool(
69
+ name: string,
70
+ input: unknown,
71
+ options: { confirm?: boolean } = {},
72
+ ): Promise<ProjectToolOutcome> {
73
+ const response = await fetch('/__editor/project-tools/run', {
74
+ method: 'POST',
75
+ headers: { 'Content-Type': 'application/json' },
76
+ body: JSON.stringify({ name, input, confirm: options.confirm === true }),
77
+ });
78
+ // Named BEFORE parsing. A host with no editor server answers this POST with
79
+ // its page fallback, and `res.json()` on HTML throws `Unexpected token '<'` —
80
+ // an error that names neither the tool nor the reason, surfacing to the user
81
+ // as a broken tool rather than a host that never ran one.
82
+ const outcome = await editorServerJson<ProjectToolOutcome>(
83
+ response,
84
+ `Running the project tool ${JSON.stringify(name)} failed`,
85
+ );
86
+ if (!outcome || typeof outcome !== 'object' || typeof outcome.ok !== 'boolean') {
87
+ throw new Error(`Tool request returned an invalid response (${response.status}).`);
88
+ }
89
+ return outcome;
90
+ }
91
+
92
+ /** Editor-init lifecycle for the Node-side registered tool catalog. */
93
+ export function startProjectToolCatalog(): () => void {
94
+ void refreshProjectTools();
95
+ const stopProjectWatch = onProjectChange(() => void refreshProjectTools());
96
+ const stopFileWatch = connectToolFileEvents(() => void refreshProjectTools());
97
+ return () => {
98
+ stopProjectWatch();
99
+ stopFileWatch();
100
+ };
101
+ }
102
+
103
+ export function __resetProjectToolsForTest(): void {
104
+ catalog = EMPTY_CATALOG;
105
+ version = 0;
106
+ listeners.clear();
107
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * The PROJECTION family's surface-neutral shapes (ARCHITECTURE-CORE §The editor
3
+ * protocol).
4
+ *
5
+ * A projection answers "what nodes are in this world, what are their stable
6
+ * ids, and how do they nest" over the RUNTIME objects a mounted world is made
7
+ * of — the live `Object3D`/`Container`/DOM element, never an AST node. A walk
8
+ * always answers: an empty projection over a mounted world is a defect, never a
9
+ * fact.
10
+ *
11
+ * Only the shapes live here. The projectors themselves are per surface
12
+ * (`./three.ts`, `./pixi.ts`, `./dom.ts`), because what an
13
+ * object IS, how identity is minted and what an editor-owned object looks like
14
+ * are all surface facts.
15
+ */
16
+
17
+ /**
18
+ * One projected authoring node.
19
+ *
20
+ * `parentId` is the nearest ADMITTED ancestor — not the runtime parent — so a
21
+ * projection that folds a library's internals into their owner reports the
22
+ * owner. `null` means this node is a root of the projection.
23
+ */
24
+ export interface ProjectedNode<TObject> {
25
+ readonly object: TObject;
26
+ readonly id: string;
27
+ readonly parentId: string | null;
28
+ readonly childIds: string[];
29
+ }
30
+
31
+ /**
32
+ * One walk's product: every node by id, the roots in walk order, and whatever
33
+ * the surface counts about itself.
34
+ *
35
+ * `nodes` is keyed by the id the rest of the editor addresses the node by, so
36
+ * the id the gizmo binds to, the id the hierarchy row shows and the id
37
+ * `EditorShellStore.objectMap` indexes can never disagree — they are all this
38
+ * one map.
39
+ */
40
+ export interface Projection<TObject, TStats> {
41
+ readonly nodes: Map<string, ProjectedNode<TObject>>;
42
+ readonly rootIds: string[];
43
+ readonly stats: TStats;
44
+ }