@volter/editor-core 0.5.57

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 (719) hide show
  1. package/BUNDLED_NOTICES +1527 -0
  2. package/LICENSE +686 -0
  3. package/LICENSE-APACHE +202 -0
  4. package/NOTICE +18 -0
  5. package/README.md +24 -0
  6. package/dist/build/chunk-JS4D4XZ3.js +175 -0
  7. package/dist/build/chunk-JS4D4XZ3.js.map +7 -0
  8. package/dist/build/vite-plugin-product-contributions.js +100 -0
  9. package/dist/build/vite-plugin-product-contributions.js.map +7 -0
  10. package/dist/build/vite-plugin-shared-react.js +25 -0
  11. package/dist/build/vite-plugin-shared-react.js.map +7 -0
  12. package/dist/build/vite-plugin-shared-three.js +86 -0
  13. package/dist/build/vite-plugin-shared-three.js.map +7 -0
  14. package/dist/server/chunk-KMJC7AGO.js +98 -0
  15. package/dist/server/chunk-KMJC7AGO.js.map +7 -0
  16. package/dist/server/chunk-PSILUMGS.js +46 -0
  17. package/dist/server/chunk-PSILUMGS.js.map +7 -0
  18. package/dist/server/frame-proxy.js +255 -0
  19. package/dist/server/frame-proxy.js.map +7 -0
  20. package/dist/server/open-browser.js +53 -0
  21. package/dist/server/open-browser.js.map +7 -0
  22. package/dist/server/process-shutdown.js +127 -0
  23. package/dist/server/process-shutdown.js.map +7 -0
  24. package/dist/server/session-registry.js +141 -0
  25. package/dist/server/session-registry.js.map +7 -0
  26. package/dist/server/spawn-opener.js +11 -0
  27. package/dist/server/spawn-opener.js.map +7 -0
  28. package/dist/server/worktree-identity.js +11 -0
  29. package/dist/server/worktree-identity.js.map +7 -0
  30. package/dist-server/packaged.mjs +88816 -0
  31. package/package.json +118 -0
  32. package/scripts/build-plugins.mjs +14 -0
  33. package/scripts/build-server.mjs +26 -0
  34. package/scripts/build-session.mjs +9 -0
  35. package/server/account-credentials.ts +60 -0
  36. package/server/account-service.ts +1434 -0
  37. package/server/adapter-region-includes.ts +47 -0
  38. package/server/asset-catalog-v2.ts +175 -0
  39. package/server/asset-history-snapshots.ts +196 -0
  40. package/server/asset-ledger-store.ts +195 -0
  41. package/server/asset-library-routes.ts +1595 -0
  42. package/server/blender-wasm-artifact.ts +430 -0
  43. package/server/boot-timings.ts +106 -0
  44. package/server/canonical-path.ts +50 -0
  45. package/server/checkout-workspace-preflight.ts +349 -0
  46. package/server/cloud-asset-catalog.ts +158 -0
  47. package/server/coding-inference-launch.ts +237 -0
  48. package/server/collaboration-account-client.ts +202 -0
  49. package/server/collaboration-attribution.ts +122 -0
  50. package/server/collaboration-session.ts +934 -0
  51. package/server/comfyui-bridge.ts +248 -0
  52. package/server/console-ledger.ts +499 -0
  53. package/server/creation-site-transform.ts +304 -0
  54. package/server/creation-site-write.ts +648 -0
  55. package/server/data-file-serialize.ts +158 -0
  56. package/server/editor-brand-html.ts +72 -0
  57. package/server/editor-control-socket.ts +366 -0
  58. package/server/editor-server-options.ts +190 -0
  59. package/server/editor-server.ts +1483 -0
  60. package/server/editor-sse.ts +352 -0
  61. package/server/engine-provenance.ts +169 -0
  62. package/server/engine-source-restart.ts +117 -0
  63. package/server/frame-bridge.ts +115 -0
  64. package/server/frame-proxy.ts +490 -0
  65. package/server/frame-workbench.ts +259 -0
  66. package/server/frontend-handoff.ts +229 -0
  67. package/server/game-globals-shadow.ts +113 -0
  68. package/server/gameplay-session-retention.ts +149 -0
  69. package/server/gameplay-sessions.ts +123 -0
  70. package/server/generation-jobs.ts +201 -0
  71. package/server/generation-reconciler.ts +137 -0
  72. package/server/generative-execution-context.ts +59 -0
  73. package/server/git-workflow.ts +612 -0
  74. package/server/harness-chat-caller.ts +36 -0
  75. package/server/harness-chat-service.ts +1681 -0
  76. package/server/idle-shutdown.ts +170 -0
  77. package/server/js-profiling-policy.ts +52 -0
  78. package/server/launcher-settings.ts +84 -0
  79. package/server/local-asset-catalog.ts +410 -0
  80. package/server/managed-account-defaults.ts +22 -0
  81. package/server/mock-control-plane.ts +540 -0
  82. package/server/model-import-conversion.ts +345 -0
  83. package/server/native-credential-store.ts +162 -0
  84. package/server/open-browser.ts +118 -0
  85. package/server/packaged.ts +1192 -0
  86. package/server/play-stall.ts +126 -0
  87. package/server/process-shutdown.ts +218 -0
  88. package/server/product-presets.ts +55 -0
  89. package/server/project-build-artifact.ts +95 -0
  90. package/server/project-components.ts +100 -0
  91. package/server/project-dependency-invalidation.ts +114 -0
  92. package/server/project-file-scan.ts +235 -0
  93. package/server/project-hmr-files.ts +215 -0
  94. package/server/project-install-roots.ts +210 -0
  95. package/server/project-kinds.ts +71 -0
  96. package/server/project-mcp-servers.ts +82 -0
  97. package/server/project-module-freshness.ts +109 -0
  98. package/server/project-module-instance.ts +375 -0
  99. package/server/project-optimize-deps-entries.ts +827 -0
  100. package/server/project-output-writer.ts +679 -0
  101. package/server/project-package-origin.ts +63 -0
  102. package/server/project-root-surface.ts +831 -0
  103. package/server/project-scratch-path.ts +47 -0
  104. package/server/project-script-hmr.ts +619 -0
  105. package/server/project-serving-plugins.ts +236 -0
  106. package/server/project-tools.ts +653 -0
  107. package/server/project-validation.ts +250 -0
  108. package/server/project-verbs.ts +127 -0
  109. package/server/project-view.ts +52 -0
  110. package/server/project-watch.ts +1134 -0
  111. package/server/project-work-coordinator.ts +288 -0
  112. package/server/provider-credentials.ts +331 -0
  113. package/server/recent-projects-store.ts +98 -0
  114. package/server/redact-secrets.ts +71 -0
  115. package/server/repository-presence.ts +267 -0
  116. package/server/routes/account.ts +357 -0
  117. package/server/routes/agents.ts +60 -0
  118. package/server/routes/assets.ts +154 -0
  119. package/server/routes/build.ts +13 -0
  120. package/server/routes/collaboration.ts +595 -0
  121. package/server/routes/configurations.ts +419 -0
  122. package/server/routes/context.ts +264 -0
  123. package/server/routes/control-plane.ts +1811 -0
  124. package/server/routes/logs.ts +272 -0
  125. package/server/routes/project-identity.ts +302 -0
  126. package/server/routes/project-open.ts +429 -0
  127. package/server/routes/project-source.ts +686 -0
  128. package/server/routes/project-state.ts +383 -0
  129. package/server/routes/relay.ts +1029 -0
  130. package/server/routes/route-helpers.ts +29 -0
  131. package/server/routes/served-modules.ts +138 -0
  132. package/server/routes/session-tabs.ts +196 -0
  133. package/server/routes/settings.ts +121 -0
  134. package/server/routes/share-control.ts +486 -0
  135. package/server/routes/themes.ts +116 -0
  136. package/server/routes/tools.ts +230 -0
  137. package/server/routes/worktrees.ts +595 -0
  138. package/server/scoped-game-css.ts +461 -0
  139. package/server/server-utils.ts +1194 -0
  140. package/server/session-product.ts +112 -0
  141. package/server/session-registry.ts +230 -0
  142. package/server/share-claims.ts +138 -0
  143. package/server/share-host.ts +526 -0
  144. package/server/share-session-gateway.ts +1362 -0
  145. package/server/share-tunnel.ts +123 -0
  146. package/server/spawn-opener.ts +74 -0
  147. package/server/support/play/log-format.ts +76 -0
  148. package/server/support/play/session-record.ts +199 -0
  149. package/server/support/project/build-discipline.ts +718 -0
  150. package/server/support/project/inspection-node.ts +119 -0
  151. package/server/support/project/log-naming.ts +54 -0
  152. package/server/support/project/provenance.ts +290 -0
  153. package/server/support/project/run-name.ts +18 -0
  154. package/server/support/project/session-journal.ts +830 -0
  155. package/server/support/project/shared.ts +327 -0
  156. package/server/tab-bootstrap.ts +62 -0
  157. package/server/tab-heartbeat.ts +477 -0
  158. package/server/tab-lifecycle.ts +550 -0
  159. package/server/tab-presence.ts +1508 -0
  160. package/server/team-agent-mirror.ts +95 -0
  161. package/server/twin-auth.ts +138 -0
  162. package/server/vendored-lock-recorder.ts +968 -0
  163. package/server/worktree-identity.ts +121 -0
  164. package/server/worktree-management.ts +398 -0
  165. package/server/worktree-retention.d.mts +13 -0
  166. package/server/worktree-retention.mjs +205 -0
  167. package/src/EditorContext.tsx +169 -0
  168. package/src/account.ts +333 -0
  169. package/src/action-registry.ts +532 -0
  170. package/src/active-product.ts +74 -0
  171. package/src/active-project.ts +155 -0
  172. package/src/adapter-editor-config.ts +25 -0
  173. package/src/adapter-observation.ts +49 -0
  174. package/src/animation/stage-transport.ts +379 -0
  175. package/src/animation/three-clips-subject.ts +172 -0
  176. package/src/api/asset-library-wire.ts +45 -0
  177. package/src/api/assets.ts +365 -0
  178. package/src/api/base.ts +10 -0
  179. package/src/api/build.ts +99 -0
  180. package/src/api/git-wire.ts +56 -0
  181. package/src/api/logs.ts +92 -0
  182. package/src/api/project-identity.ts +74 -0
  183. package/src/api/project-open.ts +355 -0
  184. package/src/api/project-source.ts +162 -0
  185. package/src/api/project-state.ts +107 -0
  186. package/src/api/relay.ts +268 -0
  187. package/src/api/settings.ts +36 -0
  188. package/src/api/themes.ts +45 -0
  189. package/src/api/worktrees.ts +257 -0
  190. package/src/asset-compare-core.ts +171 -0
  191. package/src/asset-compare.ts +294 -0
  192. package/src/asset-editor-context.tsx +100 -0
  193. package/src/asset-events.ts +97 -0
  194. package/src/asset-inspector-actions.ts +87 -0
  195. package/src/asset-preview-framing.ts +357 -0
  196. package/src/asset-preview.ts +2802 -0
  197. package/src/asset-selection-viewer-registry.ts +113 -0
  198. package/src/asset-selection.ts +133 -0
  199. package/src/asset-workflow/asset-capabilities.ts +344 -0
  200. package/src/asset-workflow/asset-import-jobs.ts +106 -0
  201. package/src/asset-workflow/asset-ledger-backend.ts +126 -0
  202. package/src/asset-workflow/asset-ledger.ts +156 -0
  203. package/src/asset-workflow/asset-materialization-report.ts +140 -0
  204. package/src/asset-workflow/asset-pack-manifest.ts +320 -0
  205. package/src/asset-workflow/asset-types.ts +142 -0
  206. package/src/asset-workflow/asset-workflow-quality.ts +61 -0
  207. package/src/asset-workflow/audio-preview-player.ts +193 -0
  208. package/src/asset-workflow/audio-waveform.ts +22 -0
  209. package/src/asset-workflow/cloud-asset-client.ts +263 -0
  210. package/src/asset-workflow/folder-preview.ts +345 -0
  211. package/src/asset-workflow/hosted-asset-materialization.ts +236 -0
  212. package/src/asset-workflow/image-view-scale.ts +32 -0
  213. package/src/asset-workflow/import-contract.ts +124 -0
  214. package/src/asset-workflow/ledger-write-lock.ts +244 -0
  215. package/src/asset-workflow/model-inspection.ts +818 -0
  216. package/src/asset-workflow/pixi-spritesheet.ts +197 -0
  217. package/src/asset-workflow/preview-resource-lifetime.ts +44 -0
  218. package/src/asset-workflow/project-asset-commands.ts +23 -0
  219. package/src/asset-workflow/project-asset-health.ts +139 -0
  220. package/src/asset-workflow/project-asset-operations.ts +154 -0
  221. package/src/asset-workflow/project-asset-roots.ts +68 -0
  222. package/src/asset-workflow/project-content.ts +288 -0
  223. package/src/asset-workflow/project-source-index.ts +550 -0
  224. package/src/asset-workflow/thumbnail-system.ts +256 -0
  225. package/src/authoring/active-adapter.ts +199 -0
  226. package/src/authoring/active-systems.ts +422 -0
  227. package/src/authoring/adapter-key.ts +18 -0
  228. package/src/authoring/authoring-asset-url.ts +27 -0
  229. package/src/authoring/bootstrap-state.ts +49 -0
  230. package/src/authoring/boundary-authoring-adapter.ts +184 -0
  231. package/src/authoring/breakpoint-state.ts +43 -0
  232. package/src/authoring/canvas-scene-guides.ts +76 -0
  233. package/src/authoring/component-instance-root.ts +171 -0
  234. package/src/authoring/composite-authoring-adapter.ts +2110 -0
  235. package/src/authoring/consumer-actions.ts +520 -0
  236. package/src/authoring/css-numeric-style.ts +97 -0
  237. package/src/authoring/design-time-layers.ts +849 -0
  238. package/src/authoring/design-time-mount-registry.ts +235 -0
  239. package/src/authoring/design-time-settle.ts +343 -0
  240. package/src/authoring/edit-mode-authoring.ts +619 -0
  241. package/src/authoring/eyedropper-session.ts +60 -0
  242. package/src/authoring/instance-source-menu-register.ts +13 -0
  243. package/src/authoring/instance-source-menu.ts +135 -0
  244. package/src/authoring/layered-pick.ts +183 -0
  245. package/src/authoring/live-gesture-lock.ts +50 -0
  246. package/src/authoring/live-object-transform.ts +62 -0
  247. package/src/authoring/mount-failure-report.ts +154 -0
  248. package/src/authoring/mounted-root-subjects.ts +144 -0
  249. package/src/authoring/no-authoring-adapter.ts +55 -0
  250. package/src/authoring/null-inspection-subjects.tsx +75 -0
  251. package/src/authoring/object3d-document-persistence.ts +106 -0
  252. package/src/authoring/object3d-document-session-registry.ts +120 -0
  253. package/src/authoring/object3d-document-session.ts +1326 -0
  254. package/src/authoring/object3d-gesture-controller.ts +113 -0
  255. package/src/authoring/panel-authoring.ts +121 -0
  256. package/src/authoring/prefab-instance-inspector-section.tsx +237 -0
  257. package/src/authoring/prefab-instance-section-model.ts +55 -0
  258. package/src/authoring/project-authoring-session.ts +105 -0
  259. package/src/authoring/provenance.ts +99 -0
  260. package/src/authoring/quarks-particle-systems.ts +19 -0
  261. package/src/authoring/react-canvas-navigation.ts +255 -0
  262. package/src/authoring/react-design-canvas-style.ts +20 -0
  263. package/src/authoring/react-story-board.ts +937 -0
  264. package/src/authoring/selection-scope.ts +195 -0
  265. package/src/authoring/shell-document-ops.ts +169 -0
  266. package/src/authoring/shell-object3d-document-write-policy.ts +108 -0
  267. package/src/authoring/shell-viewport-policy.ts +48 -0
  268. package/src/authoring/source-object3d-authoring-adapter.ts +526 -0
  269. package/src/authoring/stories-scope.ts +35 -0
  270. package/src/authoring/story-board-chrome-fit.ts +107 -0
  271. package/src/authoring/story-board-presentation.ts +111 -0
  272. package/src/authoring/three-projection-core.ts +226 -0
  273. package/src/authoring/viewport-pick-context.ts +40 -0
  274. package/src/authoring/viewport-raycast.ts +240 -0
  275. package/src/authoring/viewport-tool-context.ts +73 -0
  276. package/src/authoring/world-canvas-viewport-state.ts +35 -0
  277. package/src/authoring/world-hidden-viewport.ts +152 -0
  278. package/src/authoring/world-pan-state.ts +198 -0
  279. package/src/authoring/world-session-state.ts +101 -0
  280. package/src/authoring/write-pipe.ts +173 -0
  281. package/src/availability-tick.ts +66 -0
  282. package/src/bitmap-label.ts +120 -0
  283. package/src/blender-tab-metrics.ts +161 -0
  284. package/src/board-open-actions.ts +20 -0
  285. package/src/boot-routing.ts +391 -0
  286. package/src/build-identity.ts +15 -0
  287. package/src/bytes-codec.ts +62 -0
  288. package/src/camera-authoring.ts +175 -0
  289. package/src/cancellation-reason.ts +58 -0
  290. package/src/canvas-preview-frames.ts +482 -0
  291. package/src/capture-camera-pose.ts +77 -0
  292. package/src/chrome-registry.ts +159 -0
  293. package/src/chrome-slot-registry.ts +91 -0
  294. package/src/collaboration-client.ts +264 -0
  295. package/src/collaboration-presence.ts +41 -0
  296. package/src/command-dispatch.ts +19 -0
  297. package/src/command-listener.ts +2743 -0
  298. package/src/command-registry.ts +70 -0
  299. package/src/component-board-registry.ts +205 -0
  300. package/src/component-states-registry.ts +200 -0
  301. package/src/components/AgentPresentationNotice.tsx +75 -0
  302. package/src/components/AlignToolbar.tsx +204 -0
  303. package/src/components/AppRoot.tsx +394 -0
  304. package/src/components/ApplicationMenus.tsx +415 -0
  305. package/src/components/AssetBrowser.tsx +2843 -0
  306. package/src/components/AssetEditorShell.tsx +216 -0
  307. package/src/components/AssetInspectorToolSection.tsx +124 -0
  308. package/src/components/BoardRulers.tsx +354 -0
  309. package/src/components/CameraInfo.tsx +81 -0
  310. package/src/components/CanvasSceneViewport.tsx +556 -0
  311. package/src/components/CapabilityCoverageSection.tsx +185 -0
  312. package/src/components/CenterDocuments.tsx +22 -0
  313. package/src/components/ChromeSlot.tsx +20 -0
  314. package/src/components/CodeView.tsx +470 -0
  315. package/src/components/CollaborationHeaderControl.css +74 -0
  316. package/src/components/CompactInspectorCard.tsx +190 -0
  317. package/src/components/CompactInspectorShell.tsx +39 -0
  318. package/src/components/ConsolePanel.css +55 -0
  319. package/src/components/ConsolePanel.tsx +270 -0
  320. package/src/components/DefaultEditorLayout.tsx +106 -0
  321. package/src/components/DocumentHeaderStrip.tsx +96 -0
  322. package/src/components/DocumentShelfRail.tsx +45 -0
  323. package/src/components/DocumentThumbnail.tsx +345 -0
  324. package/src/components/EditorLeaseGuard.tsx +372 -0
  325. package/src/components/ErrorBanner.tsx +123 -0
  326. package/src/components/FolderPreviewTile.tsx +159 -0
  327. package/src/components/GameHierarchy.tsx +3842 -0
  328. package/src/components/GameplaySessionTimeline.tsx +295 -0
  329. package/src/components/InspectionProjection.tsx +968 -0
  330. package/src/components/Inspector.tsx +233 -0
  331. package/src/components/InspectorCanvasPreview.tsx +35 -0
  332. package/src/components/InspectorFieldsSection.tsx +290 -0
  333. package/src/components/InspectorObjectPreview.tsx +57 -0
  334. package/src/components/InspectorStoriesSection.tsx +92 -0
  335. package/src/components/InspectorToolSection.tsx +96 -0
  336. package/src/components/InspectorTransformSection.tsx +245 -0
  337. package/src/components/LightExplorerPanel.tsx +433 -0
  338. package/src/components/MediaProperties.tsx +145 -0
  339. package/src/components/NonThreeAuthoringBootstrap.tsx +19 -0
  340. package/src/components/Object3DDocumentToolbar.css +100 -0
  341. package/src/components/Object3DDocumentToolbar.tsx +454 -0
  342. package/src/components/Object3DDocumentViewport.tsx +58 -0
  343. package/src/components/ProjectHeader.css +617 -0
  344. package/src/components/ProjectHeader.tsx +328 -0
  345. package/src/components/ProjectLayout.tsx +249 -0
  346. package/src/components/ReactCanvasControls.tsx +284 -0
  347. package/src/components/RootSelectionOverlay.tsx +3162 -0
  348. package/src/components/RootTextEditor.tsx +79 -0
  349. package/src/components/SaveStatus.tsx +70 -0
  350. package/src/components/StageHost.tsx +1954 -0
  351. package/src/components/StageOverlays.tsx +21 -0
  352. package/src/components/StartupErrorScreen.tsx +76 -0
  353. package/src/components/StartupLoadingScreen.tsx +65 -0
  354. package/src/components/StatsOverlay.tsx +78 -0
  355. package/src/components/SurfaceStateOverlay.tsx +24 -0
  356. package/src/components/ToolContributionSurfaces.tsx +65 -0
  357. package/src/components/ToolHost.tsx +370 -0
  358. package/src/components/ToolObject3DPreview.tsx +39 -0
  359. package/src/components/Toolbar.tsx +595 -0
  360. package/src/components/TransientHint.tsx +44 -0
  361. package/src/components/TransportStrip.tsx +174 -0
  362. package/src/components/VersionControlSection.tsx +470 -0
  363. package/src/components/VgaiLogo.css +83 -0
  364. package/src/components/VgaiLogo.tsx +35 -0
  365. package/src/components/ViewportControlsHint.tsx +60 -0
  366. package/src/components/ViewportFurniture.tsx +401 -0
  367. package/src/components/ViewportOverlay.tsx +145 -0
  368. package/src/components/ViewportOverlaysMenu.tsx +153 -0
  369. package/src/components/ViewportShadingMenu.tsx +300 -0
  370. package/src/components/ViewportViewMenu.tsx +101 -0
  371. package/src/components/WorkspaceDocumentSurface.tsx +204 -0
  372. package/src/components/WorkspaceUtilitySurface.tsx +22 -0
  373. package/src/components/WorktreeSwitcher.css +239 -0
  374. package/src/components/WorktreeSwitcher.tsx +890 -0
  375. package/src/components/account-documents.tsx +1162 -0
  376. package/src/components/asset-documents.tsx +812 -0
  377. package/src/components/asset-editor-persistence.ts +216 -0
  378. package/src/components/asset-selection-section.tsx +535 -0
  379. package/src/components/asset-thumbnails.tsx +312 -0
  380. package/src/components/asset-viewers/AudioViewer.tsx +201 -0
  381. package/src/components/asset-viewers/EntityModelDocument.tsx +122 -0
  382. package/src/components/asset-viewers/EnvironmentAssetDocument.tsx +440 -0
  383. package/src/components/asset-viewers/GenericJsonViewer.tsx +102 -0
  384. package/src/components/asset-viewers/ImageViewer.tsx +300 -0
  385. package/src/components/asset-viewers/JsonAssetDocument.tsx +93 -0
  386. package/src/components/asset-viewers/LiveModuleDocument.tsx +417 -0
  387. package/src/components/asset-viewers/LutAssetDocument.tsx +444 -0
  388. package/src/components/asset-viewers/ModelAssetDocument.tsx +105 -0
  389. package/src/components/asset-viewers/Object3DPreview.tsx +359 -0
  390. package/src/components/asset-viewers/OnlineAssetDetail.tsx +421 -0
  391. package/src/components/asset-viewers/PasteboardModuleDocument.tsx +67 -0
  392. package/src/components/asset-viewers/QuarksAssetDocument.tsx +526 -0
  393. package/src/components/asset-viewers/ShaderAssetDocument.tsx +743 -0
  394. package/src/components/asset-viewers/SourceAssetViewer.tsx +281 -0
  395. package/src/components/asset-viewers/SpritesheetSpriteView.tsx +102 -0
  396. package/src/components/asset-viewers/VideoViewer.tsx +101 -0
  397. package/src/components/asset-viewers/shader-source.ts +144 -0
  398. package/src/components/asset-workflow.css +731 -0
  399. package/src/components/board-guides.ts +150 -0
  400. package/src/components/compact-inspector.css +539 -0
  401. package/src/components/core-utilities.tsx +90 -0
  402. package/src/components/editor-notifications.css +40 -0
  403. package/src/components/engine-workspace.css +274 -0
  404. package/src/components/inspector-preview-section.tsx +238 -0
  405. package/src/components/inspector-property-grouping.ts +64 -0
  406. package/src/components/inspector-revert-label.ts +20 -0
  407. package/src/components/inspector-selection.ts +42 -0
  408. package/src/components/inspector-stories-gating.ts +171 -0
  409. package/src/components/inspector-transform-subject.ts +11 -0
  410. package/src/components/inspector-transform.ts +75 -0
  411. package/src/components/kind-documents.tsx +500 -0
  412. package/src/components/palette-action-publisher.tsx +140 -0
  413. package/src/components/primitives/DraftColorInput.tsx +74 -0
  414. package/src/components/product-shell.css +1829 -0
  415. package/src/components/project-tool-documents.tsx +410 -0
  416. package/src/components/scene-documents.tsx +223 -0
  417. package/src/components/stage-keyboard.tsx +37 -0
  418. package/src/components/stage-overlay-set.tsx +107 -0
  419. package/src/components/stage-presence-markers.ts +478 -0
  420. package/src/components/standard-viewport-dressing.ts +417 -0
  421. package/src/components/status-contributions.tsx +403 -0
  422. package/src/components/tool-documents.tsx +309 -0
  423. package/src/components/tool-schema-form.tsx +262 -0
  424. package/src/components/use-after-paint.ts +41 -0
  425. package/src/components/use-project-image-assets.ts +86 -0
  426. package/src/components/viewport-header-controls.css +90 -0
  427. package/src/components/viewport-surface-status.tsx +55 -0
  428. package/src/components/workspace-history.ts +32 -0
  429. package/src/components/workspace-static-panel-registry.tsx +152 -0
  430. package/src/components/workspace-surfaces.css +621 -0
  431. package/src/components/world-documents.tsx +586 -0
  432. package/src/components/world-overlay-gestures.ts +1694 -0
  433. package/src/composite-screenshot.ts +1641 -0
  434. package/src/console-sync.ts +131 -0
  435. package/src/constraint-helper.ts +338 -0
  436. package/src/content-entry-source-registry.ts +184 -0
  437. package/src/coverage/authoring-seam-evidence.ts +300 -0
  438. package/src/coverage/canvas-reveal.ts +192 -0
  439. package/src/coverage/design-time-surfaces.ts +101 -0
  440. package/src/coverage/live-seam-evidence.ts +11 -0
  441. package/src/coverage/ontology-invariants.ts +466 -0
  442. package/src/coverage/session-vitals.ts +501 -0
  443. package/src/coverage/system-seam-evidence.ts +72 -0
  444. package/src/crash-null-boundary.ts +36 -0
  445. package/src/creation-site-edit.ts +1479 -0
  446. package/src/creation-site-registry.ts +160 -0
  447. package/src/delegate-harness-registry.ts +143 -0
  448. package/src/document-context-registry.ts +177 -0
  449. package/src/document-open-registry.ts +200 -0
  450. package/src/document-preview-source.ts +20 -0
  451. package/src/document-renderer-session.ts +138 -0
  452. package/src/editor-api.ts +46 -0
  453. package/src/editor-chrome-capture.ts +139 -0
  454. package/src/editor-commands.ts +164 -0
  455. package/src/editor-console.ts +563 -0
  456. package/src/editor-current-view.ts +82 -0
  457. package/src/editor-document-probe.ts +881 -0
  458. package/src/editor-git-client.ts +115 -0
  459. package/src/editor-host-door.ts +462 -0
  460. package/src/editor-hotkeys.ts +842 -0
  461. package/src/editor-lease-view.ts +39 -0
  462. package/src/editor-lease.ts +415 -0
  463. package/src/editor-mode.ts +19 -0
  464. package/src/editor-notifications.ts +140 -0
  465. package/src/editor-presence.ts +563 -0
  466. package/src/editor-presentation-activity.ts +50 -0
  467. package/src/editor-presentation-notice.ts +42 -0
  468. package/src/editor-runtime.tsx +145 -0
  469. package/src/editor-server-response.ts +86 -0
  470. package/src/editor-session-attribution.ts +75 -0
  471. package/src/editor-session-mode.ts +54 -0
  472. package/src/editor-shell-store.ts +1304 -0
  473. package/src/editor-state-facets.ts +74 -0
  474. package/src/editor-styles.css +33 -0
  475. package/src/editor-view-presentation.ts +810 -0
  476. package/src/editor-viewport.ts +5302 -0
  477. package/src/entity-lod.ts +31 -0
  478. package/src/entity-object.ts +91 -0
  479. package/src/files/file-provider.ts +62 -0
  480. package/src/files/project-files.ts +264 -0
  481. package/src/finders/index.ts +136 -0
  482. package/src/finders/scenes-from-entrypoint-selection.ts +387 -0
  483. package/src/frame/bridge.tsx +1408 -0
  484. package/src/frame/product.ts +77 -0
  485. package/src/gameplay-dom-recording.ts +319 -0
  486. package/src/gameplay-export-state.ts +14 -0
  487. package/src/gameplay-replay.ts +417 -0
  488. package/src/gameplay-session-time.ts +9 -0
  489. package/src/gameplay-sessions.ts +204 -0
  490. package/src/harness-chat-types.ts +253 -0
  491. package/src/hierarchy-component-marks.ts +298 -0
  492. package/src/hierarchy-drop.ts +91 -0
  493. package/src/hierarchy-expansion-state.ts +80 -0
  494. package/src/hierarchy-header-slot.ts +52 -0
  495. package/src/hierarchy-internals.ts +197 -0
  496. package/src/hierarchy-kind-icon.ts +217 -0
  497. package/src/hierarchy-mark-reader.ts +73 -0
  498. package/src/hierarchy-menu-registry.ts +67 -0
  499. package/src/hierarchy-node-rows.ts +307 -0
  500. package/src/hierarchy-panel-view.ts +280 -0
  501. package/src/hierarchy-projection.ts +76 -0
  502. package/src/hierarchy-row-cache.ts +243 -0
  503. package/src/hierarchy-row-model.ts +308 -0
  504. package/src/hierarchy-rows.ts +11 -0
  505. package/src/hierarchy-walk.ts +86 -0
  506. package/src/history/editor-session.ts +25 -0
  507. package/src/history/history-commands.ts +147 -0
  508. package/src/history/history-delegate.ts +163 -0
  509. package/src/history/history-limit-notices.ts +43 -0
  510. package/src/history/history-service.ts +1173 -0
  511. package/src/history/persistence-coordinator.ts +35 -0
  512. package/src/history/project-file-history.ts +386 -0
  513. package/src/history/project-root-history-backends.ts +139 -0
  514. package/src/history/resource-registry.ts +209 -0
  515. package/src/history/snapshot-store.ts +103 -0
  516. package/src/history/source-history-backend.ts +546 -0
  517. package/src/history/types.ts +124 -0
  518. package/src/hmr-registration-group.ts +67 -0
  519. package/src/hmr-stable-react-context.ts +23 -0
  520. package/src/hotkeys.ts +188 -0
  521. package/src/inference-diagnostics.ts +69 -0
  522. package/src/initial-project.ts +80 -0
  523. package/src/inspection/active-subject.ts +578 -0
  524. package/src/inspection/active-surface.ts +142 -0
  525. package/src/inspection/compose.ts +1064 -0
  526. package/src/inspection/display.ts +170 -0
  527. package/src/inspection/document-subject.ts +109 -0
  528. package/src/inspection/game-subject.ts +85 -0
  529. package/src/inspection/model.ts +542 -0
  530. package/src/inspection/null-subject.ts +115 -0
  531. package/src/inspection/serialize.ts +357 -0
  532. package/src/inspection/use-active-inspection.ts +180 -0
  533. package/src/inspector-presentation.ts +201 -0
  534. package/src/inspector-section-registry.ts +221 -0
  535. package/src/instance-source-actions.ts +163 -0
  536. package/src/instanced-presentation.ts +164 -0
  537. package/src/js-heap.ts +71 -0
  538. package/src/key-actions.ts +91 -0
  539. package/src/keymap-presets.ts +401 -0
  540. package/src/layout-policy.ts +31 -0
  541. package/src/learn-links.ts +73 -0
  542. package/src/light-explorer-model.ts +134 -0
  543. package/src/live-canvas-frame.ts +55 -0
  544. package/src/live-document.ts +279 -0
  545. package/src/live-module-source.ts +230 -0
  546. package/src/live-session-registry.ts +220 -0
  547. package/src/live-transition.ts +633 -0
  548. package/src/manifest-project.ts +107 -0
  549. package/src/model-thumbnail.ts +523 -0
  550. package/src/native-selection-style.ts +202 -0
  551. package/src/object3d-document-write-policy.ts +137 -0
  552. package/src/packaged-runtime.ts +108 -0
  553. package/src/palettes/maya.palette.json +57 -0
  554. package/src/palettes/substance.palette.json +57 -0
  555. package/src/pasteboard-module.ts +81 -0
  556. package/src/performance-profiler.ts +367 -0
  557. package/src/performance-sources.ts +69 -0
  558. package/src/play-boot-phase.ts +145 -0
  559. package/src/presentation-surface.ts +248 -0
  560. package/src/project-adapter.ts +1143 -0
  561. package/src/project-asset-refresh.ts +26 -0
  562. package/src/project-declaration-refresh.ts +31 -0
  563. package/src/project-local-state.ts +118 -0
  564. package/src/project-manager.ts +243 -0
  565. package/src/project-module-changes.ts +163 -0
  566. package/src/project-module-split.ts +266 -0
  567. package/src/project-provenance.ts +115 -0
  568. package/src/project-ready.ts +42 -0
  569. package/src/project-session-reset.ts +67 -0
  570. package/src/project-shape.ts +68 -0
  571. package/src/project-tool-discovery.ts +66 -0
  572. package/src/project-tools.ts +107 -0
  573. package/src/project-work-types.ts +149 -0
  574. package/src/projection/three.ts +898 -0
  575. package/src/projection/types.ts +44 -0
  576. package/src/readiness.ts +113 -0
  577. package/src/reflection-probe-helper.ts +142 -0
  578. package/src/reported-play-state.ts +90 -0
  579. package/src/resolve-relative-specifier.ts +33 -0
  580. package/src/scene-document-plan.ts +315 -0
  581. package/src/scene-framing.ts +315 -0
  582. package/src/scene-live-open.ts +210 -0
  583. package/src/scene-view-fog.ts +89 -0
  584. package/src/scoped-game-css.ts +152 -0
  585. package/src/session-orphan-record.ts +193 -0
  586. package/src/session-tombstone.ts +126 -0
  587. package/src/settings/settings-provider.ts +82 -0
  588. package/src/settings-store.ts +345 -0
  589. package/src/shared-view-restore.ts +42 -0
  590. package/src/shell-store-door.ts +45 -0
  591. package/src/source-conflict.ts +122 -0
  592. package/src/spatial-handle-visuals.ts +332 -0
  593. package/src/stage-context.ts +341 -0
  594. package/src/stage-store-registry.ts +63 -0
  595. package/src/stale-chunk-recovery.ts +34 -0
  596. package/src/state-report-deferral.ts +73 -0
  597. package/src/storage/host-files-storage.ts +97 -0
  598. package/src/storage/http-storage.ts +174 -0
  599. package/src/storage/index.ts +75 -0
  600. package/src/storage/mem-storage.ts +149 -0
  601. package/src/storage/path-lock.ts +44 -0
  602. package/src/storage/paths.ts +26 -0
  603. package/src/storage/types.ts +116 -0
  604. package/src/stories/StoryComponentThumbnail.tsx +184 -0
  605. package/src/stories/StoryPreviewMount.tsx +306 -0
  606. package/src/stories/component-content-source.tsx +106 -0
  607. package/src/stories/component-states-source.ts +78 -0
  608. package/src/stories/compose-project-stories.ts +255 -0
  609. package/src/stories/pixi-story-model.ts +30 -0
  610. package/src/stories/prefabs-finder.ts +54 -0
  611. package/src/stories/prefabs-from-stories.ts +182 -0
  612. package/src/stories/project-story-discovery.ts +78 -0
  613. package/src/stories/project-story-regions.ts +24 -0
  614. package/src/stories/story-actions.ts +54 -0
  615. package/src/stories/story-capture-command.ts +124 -0
  616. package/src/stories/story-capture.ts +584 -0
  617. package/src/stories/story-declared-medium.ts +126 -0
  618. package/src/stories/story-discovery.ts +176 -0
  619. package/src/stories/story-document-openers.ts +36 -0
  620. package/src/stories/story-dom-runtime.ts +78 -0
  621. package/src/stories/story-grouping.ts +111 -0
  622. package/src/stories/story-lane.ts +88 -0
  623. package/src/stories/story-mount-turn.ts +27 -0
  624. package/src/stories/story-opener.ts +260 -0
  625. package/src/stories/story-pixi-preview.ts +408 -0
  626. package/src/stories/story-presentation.ts +215 -0
  627. package/src/stories/story-registry.ts +517 -0
  628. package/src/stories/story-three-preview.ts +807 -0
  629. package/src/stories/three-story-model.ts +96 -0
  630. package/src/story-three-preview-runtime.ts +56 -0
  631. package/src/surface-keyboard.ts +112 -0
  632. package/src/surface-state.ts +124 -0
  633. package/src/tab-bootstrap.js +628 -0
  634. package/src/tab-census.ts +198 -0
  635. package/src/tab-lifecycle-client.ts +196 -0
  636. package/src/theme-library.ts +844 -0
  637. package/src/theme-preference.ts +378 -0
  638. package/src/theme.css +3437 -0
  639. package/src/three-viewport/bone-selection-highlight.ts +119 -0
  640. package/src/three-viewport/camera-fit.ts +41 -0
  641. package/src/three-viewport/interactive-renderer.ts +132 -0
  642. package/src/three-viewport/selection-brackets.ts +310 -0
  643. package/src/three-viewport/selection-outline.ts +183 -0
  644. package/src/three-viewport/skeleton-helper.ts +61 -0
  645. package/src/three-viewport/source-color.ts +167 -0
  646. package/src/three-viewport/studio-environment.ts +96 -0
  647. package/src/three-viewport-presentation.ts +23 -0
  648. package/src/tool-contribution-play.ts +74 -0
  649. package/src/tool-loader.ts +1798 -0
  650. package/src/transform-mode-request.ts +57 -0
  651. package/src/transient-hint.ts +78 -0
  652. package/src/trigger-volume-helper.ts +116 -0
  653. package/src/ui-source/adapter-region-includes.ts +241 -0
  654. package/src/ui-source/ensure-import.ts +132 -0
  655. package/src/ui-source/file-region-resolver.ts +302 -0
  656. package/src/ui-source/inspect.ts +775 -0
  657. package/src/ui-source/oid-transform.ts +1845 -0
  658. package/src/ui-source/plan-csf-story.ts +196 -0
  659. package/src/ui-source/plan-extract-component.ts +421 -0
  660. package/src/ui-source/plan-fork-component.ts +621 -0
  661. package/src/ui-source/plan-named-style.ts +95 -0
  662. package/src/ui-source/plan-source-edit.ts +353 -0
  663. package/src/ui-source/r3f-contract-resolver.ts +327 -0
  664. package/src/ui-source/r3f-diagnostic-index.ts +165 -0
  665. package/src/ui-source/r3f-environment-binding.ts +133 -0
  666. package/src/ui-source/r3f-joint-binding.ts +251 -0
  667. package/src/ui-source/r3f-lod-binding.ts +91 -0
  668. package/src/ui-source/r3f-particle-binding.ts +235 -0
  669. package/src/ui-source/r3f-physics-binding.ts +483 -0
  670. package/src/ui-source/r3f-project-contracts.ts +444 -0
  671. package/src/ui-source/relative-import-specifier.ts +34 -0
  672. package/src/ui-source/reparent-guard.ts +544 -0
  673. package/src/ui-source/source-edit-request.ts +97 -0
  674. package/src/ui-source/source-write-backend.ts +618 -0
  675. package/src/ui-source/syntactic-prop-specs.ts +296 -0
  676. package/src/ui-source/tier-source-write-backend.ts +279 -0
  677. package/src/ui-source/ts-ast.ts +171 -0
  678. package/src/ui-source/utility-class-support.ts +169 -0
  679. package/src/ui-source/write-component-default.ts +133 -0
  680. package/src/ui-source/writer.ts +1989 -0
  681. package/src/viewport-activation-timings.ts +840 -0
  682. package/src/viewport-authoring-policy.ts +186 -0
  683. package/src/viewport-controls-hint.ts +57 -0
  684. package/src/viewport-door.ts +237 -0
  685. package/src/viewport-shading-boundary.ts +12 -0
  686. package/src/vite-error-surface.ts +141 -0
  687. package/src/wait-until.ts +37 -0
  688. package/src/workspace-areas.ts +156 -0
  689. package/src/workspace-aux-commands.ts +11 -0
  690. package/src/workspace-available-documents.ts +127 -0
  691. package/src/workspace-core-utilities.ts +31 -0
  692. package/src/workspace-document-ids.ts +59 -0
  693. package/src/workspace-document-registry.ts +612 -0
  694. package/src/workspace-document-restore.ts +145 -0
  695. package/src/workspace-host-commands.ts +141 -0
  696. package/src/workspace-persistence-gate.ts +40 -0
  697. package/src/workspace-play-utilities.ts +44 -0
  698. package/src/workspace-presets.ts +425 -0
  699. package/src/workspace-regions.ts +294 -0
  700. package/src/workspace-state-persistence.ts +536 -0
  701. package/src/workspace-static-panels.ts +73 -0
  702. package/src/workspace-status-registry.ts +121 -0
  703. package/src/workspace-style.ts +239 -0
  704. package/src/workspace-utility-commands.ts +74 -0
  705. package/src/workspace-utility-registry.ts +263 -0
  706. package/src/workspace-viewport-rect.ts +97 -0
  707. package/src/world-adoption.ts +115 -0
  708. package/src/world-document-routing.ts +104 -0
  709. package/vite-plugin-creation-site-write.ts +184 -0
  710. package/vite-plugin-creation-site.ts +80 -0
  711. package/vite-plugin-game-static.ts +303 -0
  712. package/vite-plugin-module-doorways.ts +336 -0
  713. package/vite-plugin-product-contributions.ts +197 -0
  714. package/vite-plugin-project-game-static.ts +125 -0
  715. package/vite-plugin-project-jsx-js.ts +65 -0
  716. package/vite-plugin-project-root-absolute-assets.ts +359 -0
  717. package/vite-plugin-shared-react.ts +420 -0
  718. package/vite-plugin-shared-three.ts +203 -0
  719. package/vite-plugin-ui-oid.ts +2106 -0
@@ -0,0 +1,619 @@
1
+ /**
2
+ * Edit-mode authoring — project open loads `vgai.project.json` and
3
+ * installs a {@link CompositeAuthoringAdapter} over EVERY declared world, so a
4
+ * project's composition is disclosed in edit mode. Unlike play mode,
5
+ * roots are NOT running here: a world whose SURFACE has a registered live
6
+ * adapter factory (`active-adapter.ts`'s `setBaseAuthoringFactory`, filled by
7
+ * that surface's integration) gets a live projection over whatever is mounted
8
+ * into the store; every other declared world gets a read-only
9
+ * {@link BoundaryAuthoringAdapter} describing it from the manifest, upgraded
10
+ * to a live adapter only once its design-time layer actually mounts.
11
+ *
12
+ * THIS MODULE NAMES NO SURFACE. It used to pick the project's `three` root by
13
+ * name and build that one adapter itself; the surface key is what replaced
14
+ * that, so a second integration is a registration rather than a branch here.
15
+ *
16
+ * A project with one world and a project with
17
+ * many roots use the SAME game/world authoring tree. Cardinality may affect
18
+ * presentation density, never hierarchy semantics, routing, or persistence.
19
+ * Manifest-less projects still synthesize the conventional `main` world, so
20
+ * every project reaches this one path.
21
+ */
22
+
23
+ import { declaredRoots } from '@volter/editor-project/adapter/manifest-interpreter';
24
+ import { editorConsole } from '../editor-console';
25
+ import { assertEditorServerAnswered } from '../editor-server-response';
26
+ import { sourceMutationAttribution } from '../editor-session-attribution';
27
+ import type { EditorShellStore } from '../editor-shell-store';
28
+ import { hierarchyProjectionFromProjectConfig } from '../hierarchy-projection';
29
+ import { getProjectFileHistory, type ProjectFileHistory } from '../history/project-file-history';
30
+ import { getManifestHistoryBackend } from '../history/project-root-history-backends';
31
+ import { fetchRawGameManifest } from '../manifest-project';
32
+ import { getCurrentProject } from '../project-manager';
33
+ import { handleProjectMutationFailure } from '../source-conflict';
34
+ import {
35
+ activeOverrideIsEditMode,
36
+ baseAuthoringFactory,
37
+ getAuthoringOverride,
38
+ hasAuthoringOverride,
39
+ markEditModeOverride,
40
+ setActiveAuthoring,
41
+ } from './active-adapter';
42
+ import { beginAuthoringBootstrap } from './bootstrap-state';
43
+ import { BoundaryAuthoringAdapter, type BoundaryRootInfo } from './boundary-authoring-adapter';
44
+ import {
45
+ CompositeAuthoringAdapter,
46
+ type CompositeChild,
47
+ type RootManifestProvider,
48
+ } from './composite-authoring-adapter';
49
+
50
+ /**
51
+ * The mounted Scene document's acknowledged edit-mode reinstall owner.
52
+ *
53
+ * A rebuild request can land while Play's dock transition has no Scene
54
+ * document mounted. A one-shot `window` event loses that request forever: Stop
55
+ * restores the already-suspended composite, whose R3F child now points at no
56
+ * scene, and the Hierarchy stays empty even though the Edit viewport still
57
+ * draws. Keeping the request HERE until an owner binds makes the handoff a
58
+ * completion path rather than timing choreography.
59
+ */
60
+ /**
61
+ * The `surface` of the ONE placeholder root installed when `vgai.project.json`
62
+ * cannot be parsed. `world-documents.tsx` reads it to keep the Scene document
63
+ * (and with it the edit-mode rebuild OWNER) mounted through that state, so a
64
+ * manifest that becomes valid again can remount without a reload.
65
+ */
66
+ export const INVALID_MANIFEST_SURFACE = '(invalid manifest)';
67
+
68
+ type EditModeRebuildOwner = () => void | Promise<void>;
69
+
70
+ let editModeRebuildRequested = false;
71
+ let editModeRebuildScheduled = false;
72
+ let editModeRebuildRunning = false;
73
+ let editModeRebuildOwner: EditModeRebuildOwner | null = null;
74
+
75
+ function drainEditModeRebuild(): void {
76
+ if (
77
+ editModeRebuildScheduled ||
78
+ editModeRebuildRunning ||
79
+ !editModeRebuildRequested ||
80
+ !editModeRebuildOwner
81
+ )
82
+ return;
83
+ editModeRebuildScheduled = true;
84
+ const owner = editModeRebuildOwner;
85
+ queueMicrotask(() => {
86
+ editModeRebuildScheduled = false;
87
+ if (editModeRebuildOwner !== owner) {
88
+ drainEditModeRebuild();
89
+ return;
90
+ }
91
+ // Coalesce requests received before the install starts. Only a request
92
+ // arriving during the actual install earns another pass.
93
+ editModeRebuildRequested = false;
94
+ editModeRebuildRunning = true;
95
+ void Promise.resolve()
96
+ .then(owner)
97
+ .catch((error: unknown) => {
98
+ editorConsole.error(
99
+ `Edit-mode rebuild failed: ${error instanceof Error ? error.message : String(error)}`,
100
+ 'authoring',
101
+ );
102
+ })
103
+ .finally(() => {
104
+ editModeRebuildRunning = false;
105
+ drainEditModeRebuild();
106
+ });
107
+ });
108
+ }
109
+
110
+ /** Bind the project session that reinstalls edit composition and its attached stages. */
111
+ export function bindEditModeRebuildOwner(owner: EditModeRebuildOwner): () => void {
112
+ editModeRebuildOwner = owner;
113
+ drainEditModeRebuild();
114
+ return () => {
115
+ if (editModeRebuildOwner === owner) editModeRebuildOwner = null;
116
+ };
117
+ }
118
+
119
+ /** Request one acknowledged reinstall after the current transition settles. */
120
+ export function queueEditModeRebuild(): void {
121
+ editModeRebuildRequested = true;
122
+ drainEditModeRebuild();
123
+ }
124
+
125
+ /**
126
+ * The display-relevant slice of a manifest world entry this module needs —
127
+ * deliberately LOOSE (a bare `string` `surface`, not the engine's validated
128
+ * `AdapterRoot['surface']` union) so a world that fails schema validation
129
+ * (an unknown surface) can still be represented and surfaced as an error node
130
+ * (#18). Built by the LENIENT parse below (`parseEditModeManifest`), reachable
131
+ * from the production project-open path — NOT gated on strict Zod, which would
132
+ * reject the whole file for one bad world and make every declared world vanish
133
+ * (defect 2).
134
+ */
135
+ export interface EditModeRootSpec {
136
+ readonly id: string;
137
+ readonly surface: string;
138
+ readonly adapter?: string | undefined;
139
+ readonly scene?: string | undefined;
140
+ readonly entry?: string | undefined;
141
+ readonly zOrder?: number | undefined;
142
+ readonly pausable?: boolean | undefined;
143
+ /**
144
+ * `world` — the component this root's world IS, in the game's own source.
145
+ * When present it is what EDIT mounts (a design-time document,
146
+ * `r3f-design-session.ts`); `entry` stays what PLAY mounts.
147
+ */
148
+ readonly world?: { readonly entry: string; readonly export?: string | undefined } | undefined;
149
+ }
150
+
151
+ export interface EditModeManifest {
152
+ readonly roots: readonly EditModeRootSpec[];
153
+ }
154
+
155
+ const KNOWN_WORLD_KINDS = new Set(['three', 'canvas', 'dom']);
156
+
157
+ function asString(v: unknown): string | undefined {
158
+ return typeof v === 'string' ? v : undefined;
159
+ }
160
+
161
+ /**
162
+ * The raw root-level `world` fact, read as defensively as everything else in
163
+ * this module's lenient parse: anything but an object carrying a string
164
+ * `entry` is simply absent, which puts the root back on its `entry` for both
165
+ * modes rather than failing the whole manifest.
166
+ *
167
+ * It is read off the ROOT, not off any adapter: the split it names — "`entry`
168
+ * mounts the running game, this names the thing an author edits" — belongs to
169
+ * a vendored ingest and a translated first-party port alike.
170
+ */
171
+ function readDesignWorld(root: Record<string, unknown>): EditModeRootSpec['world'] {
172
+ const world = root['world'];
173
+ if (!world || typeof world !== 'object') return undefined;
174
+ const entry = asString((world as Record<string, unknown>)['entry']);
175
+ if (!entry) return undefined;
176
+ return { entry, export: asString((world as Record<string, unknown>)['export']) };
177
+ }
178
+
179
+ /** Display string for a raw `adapter` field — informational only (the Boundary
180
+ * inspector's read-only `adapter` property). Read defensively: the raw JSON
181
+ * may be a string ('default'), a `{ module }`/`{ ingest }` object, or absent. */
182
+ function displayAdapter(adapter: unknown): string | undefined {
183
+ if (adapter === undefined || adapter === null) return undefined;
184
+ if (typeof adapter === 'string') return adapter;
185
+ if (typeof adapter === 'object') {
186
+ const obj = adapter as Record<string, unknown>;
187
+ if (typeof obj['module'] === 'string') return `module:${obj['module']}`;
188
+ const ingest = obj['ingest'];
189
+ if (ingest && typeof ingest === 'object') return 'ingest';
190
+ }
191
+ return undefined;
192
+ }
193
+
194
+ /**
195
+ * LENIENT parse (defect 2): read a raw `vgai.project.json` object's `roots[]`
196
+ * defensively into `EditModeRootSpec[]`, so a single bad world (unknown
197
+ * `surface`, missing `scene`+`entry`) becomes an error node (#18) while its VALID
198
+ * siblings still open — never the strict-Zod all-or-nothing of
199
+ * `loadGameManifest`. Returns `null` when there is no usable `roots` array at
200
+ * all (a present-but-unusable manifest, distinct from an ABSENT one) so the
201
+ * caller can fall back to the synthesized single-world floor. A world missing
202
+ * an `id` gets a positional placeholder so it still surfaces rather than
203
+ * vanishing. `surface` is carried through verbatim (even a bogus string) —
204
+ * `resolveRootFailureReason` decides resolvability downstream.
205
+ */
206
+ export function parseEditModeManifest(raw: unknown): EditModeManifest | null {
207
+ if (!raw || typeof raw !== 'object') return null;
208
+ const worldsRaw = (raw as Record<string, unknown>)['roots'];
209
+ if (worldsRaw === undefined) return null;
210
+ // Zero roots is a real shape (ARCHITECTURE-CORE §Roots): nothing mounts,
211
+ // and the editor derives its chrome from what IS declared.
212
+ if (!Array.isArray(worldsRaw)) return null;
213
+ const roots: EditModeRootSpec[] = worldsRaw.map((entry, i) => {
214
+ const w = (entry && typeof entry === 'object' ? entry : {}) as Record<string, unknown>;
215
+ const zOrderRaw = w['zOrder'];
216
+ const pausableRaw = w['pausable'];
217
+ return {
218
+ id: asString(w['id']) ?? `(world ${i})`,
219
+ // Missing/non-string surface is itself unresolvable — carry a sentinel so
220
+ // resolveRootFailureReason names it, rather than crashing on undefined.
221
+ surface:
222
+ (typeof w['adapter'] === 'string' ? asString(w['adapter']) : undefined) ??
223
+ asString(
224
+ w['adapter'] && typeof w['adapter'] === 'object'
225
+ ? (w['adapter'] as Record<string, unknown>)['surface']
226
+ : undefined,
227
+ ) ??
228
+ '(missing adapter surface)',
229
+ adapter: displayAdapter(w['adapter']),
230
+ scene: asString(w['scene']),
231
+ entry: asString(w['entry']),
232
+ zOrder: typeof zOrderRaw === 'number' ? zOrderRaw : undefined,
233
+ pausable: typeof pausableRaw === 'boolean' ? pausableRaw : undefined,
234
+ dev: w['dev'] === true,
235
+ world: readDesignWorld(w),
236
+ };
237
+ });
238
+ return { roots };
239
+ }
240
+
241
+ /**
242
+ * Structural resolvability (#18) — NOT a filesystem check: "missing entry/scene
243
+ * file" here means the world declares NEITHER field (mirrors the manifest
244
+ * schema's own `checkAdapterSceneEntryRules`, `manifest/load.ts`). A live "does
245
+ * the file actually exist on disk" probe is B1 territory (the design-time mount
246
+ * attempt itself degrades to this same error-node floor when a layer throws) —
247
+ * out of scope here, where only the Three world is fetched by this surface.
248
+ */
249
+ export function resolveRootFailureReason(world: EditModeRootSpec): string | null {
250
+ if (!KNOWN_WORLD_KINDS.has(world.surface)) {
251
+ return `Unknown world surface "${world.surface}" — expected one of: three, canvas, react.`;
252
+ }
253
+ if (!world.scene && !world.entry) {
254
+ return `World "${world.id}" declares neither \`scene\` nor \`entry\` — nothing to mount.`;
255
+ }
256
+ return null;
257
+ }
258
+
259
+ // ---------------------------------------------------------------------------
260
+ // A4 (D8) — ManifestAuthoring: read-modify-write root composition properties
261
+ // ---------------------------------------------------------------------------
262
+
263
+ /** A raw `vgai.project.json` world entry, read/written defensively — same
264
+ * looseness as {@link EditModeRootSpec}, but this is the RAW (unknown)
265
+ * object, never Zod-parsed, so unrelated fields survive a round trip. */
266
+ type RawAdapterRoot = Record<string, unknown>;
267
+
268
+ function findRawRoot(raw: Record<string, unknown>, worldId: string): RawAdapterRoot | undefined {
269
+ const roots = raw['roots'];
270
+ if (!Array.isArray(roots)) return undefined;
271
+ return roots.find(
272
+ (w): w is RawAdapterRoot =>
273
+ !!w && typeof w === 'object' && (w as RawAdapterRoot)['id'] === worldId,
274
+ );
275
+ }
276
+
277
+ /** Materialize D19's inferred world only when a user edits one of its
278
+ * manifest-backed properties. Until then the raw file remains minimal. */
279
+ function ensureRawRoot(raw: Record<string, unknown>, worldId: string): RawAdapterRoot | undefined {
280
+ return findRawRoot(raw, worldId);
281
+ }
282
+
283
+ /**
284
+ * ManifestAuthoring (A4, D8) — authored roots' manifest-backed
285
+ * {@link RootManifestProvider}: holds the RAW parsed `vgai.project.json`
286
+ * object (read-modify-write — NEVER round-tripped through the strict Zod
287
+ * schema, so fields this module doesn't know about survive untouched) and
288
+ * writes it back via `POST /__editor/manifest` (the one manifest-write verb,
289
+ * `editor-server.ts`).
290
+ *
291
+ * Two write modes:
292
+ * - a REAL manifest (`synthesized: false`) writes through on every edit —
293
+ * the acceptance's "round-trips vgai.project.json on disk" needs no separate
294
+ * save step.
295
+ * - a SYNTHESIZED manifest (`synthesized: true`, no `vgai.project.json` on disk
296
+ * yet) BUFFERS edits in memory only; nothing is written until the
297
+ * explicit `materialize()` call (the generic inspector's "Create
298
+ * vgai.project.json" action). D19 makes this branch reachable for a
299
+ * manifest-less conventional project because its inferred root is always
300
+ * present.
301
+ *
302
+ * File-watcher landmine: `chokidar` only watches `public/` (`editor-server.ts`),
303
+ * so a manifest write at the PROJECT ROOT emits no SSE — `notifyIngestEdit()`
304
+ * after every successful write is what keeps the hierarchy panel's badges
305
+ * live instead of stale until reopen.
306
+ */
307
+ export class ManifestAuthoring implements RootManifestProvider {
308
+ private readonly raw: Record<string, unknown>;
309
+ private synthesizedValue: boolean;
310
+ private readonly store: EditorShellStore;
311
+ private readonly fileHistory: ProjectFileHistory | null;
312
+ private readonly unsubscribeHistory: (() => void) | null;
313
+
314
+ constructor(raw: Record<string, unknown>, synthesized: boolean, store: EditorShellStore) {
315
+ this.raw = raw;
316
+ this.synthesizedValue = synthesized;
317
+ this.store = store;
318
+ const history = store.projectHistory;
319
+ this.fileHistory = history
320
+ ? getProjectFileHistory(history, getManifestHistoryBackend(), 'project-manifest')
321
+ : null;
322
+ this.unsubscribeHistory = this.fileHistory
323
+ ? this.fileHistory.subscribeAll((path) => {
324
+ if (path !== 'vgai.project.json') return;
325
+ void getManifestHistoryBackend()
326
+ .readBytes(path)
327
+ .then((bytes) => JSON.parse(new TextDecoder().decode(bytes)) as Record<string, unknown>)
328
+ .then((next) => {
329
+ for (const key of Object.keys(this.raw)) delete this.raw[key];
330
+ Object.assign(this.raw, next);
331
+ this.store.notifyIngestEdit();
332
+ })
333
+ .catch(() => {});
334
+ })
335
+ : null;
336
+ }
337
+
338
+ getGameName(): string {
339
+ const name = this.raw['name'];
340
+ return typeof name === 'string' ? name : '';
341
+ }
342
+
343
+ get synthesized(): boolean {
344
+ return this.synthesizedValue;
345
+ }
346
+
347
+ setGameName(name: string): void {
348
+ this.raw['name'] = name;
349
+ this.persist('Rename Game');
350
+ }
351
+
352
+ getRootContentSource(worldId: string): string | undefined {
353
+ const world = findRawRoot(this.raw, worldId);
354
+ if (!world) return undefined;
355
+ const scene = world['scene'];
356
+ if (typeof scene === 'string') return `Scene · ${scene}`;
357
+ const entry = world['entry'];
358
+ if (typeof entry === 'string') return `Entry · ${entry}`;
359
+ return 'Adapter-owned runtime content';
360
+ }
361
+
362
+ getRootZOrder(worldId: string): number {
363
+ const z = findRawRoot(this.raw, worldId)?.['zOrder'];
364
+ return typeof z === 'number' ? z : 0;
365
+ }
366
+
367
+ setRootZOrder(worldId: string, value: number): void {
368
+ const world = ensureRawRoot(this.raw, worldId);
369
+ if (!world) return;
370
+ world['zOrder'] = value;
371
+ this.persist('Change World Order');
372
+ }
373
+
374
+ getRootPausable(worldId: string): boolean {
375
+ const p = findRawRoot(this.raw, worldId)?.['pausable'];
376
+ return typeof p === 'boolean' ? p : true;
377
+ }
378
+
379
+ setRootPausable(worldId: string, value: boolean): void {
380
+ const world = ensureRawRoot(this.raw, worldId);
381
+ if (!world) return;
382
+ world['pausable'] = value;
383
+ this.persist('Change World Pausing');
384
+ }
385
+
386
+ /** The "Create vgai.project.json" action (generic inspector, while
387
+ * `synthesized`) — materializes the buffered edits to disk. Also safe to
388
+ * call on a non-synthesized instance (equivalent to an explicit re-save). */
389
+ async materialize(): Promise<boolean> {
390
+ const written = await this.write('Create Game Manifest');
391
+ if (written) this.synthesizedValue = false;
392
+ return written;
393
+ }
394
+
395
+ dispose(): void {
396
+ this.unsubscribeHistory?.();
397
+ }
398
+
399
+ private persist(label: string): void {
400
+ if (this.synthesized) return; // buffered only — wait for materialize()
401
+ void this.write(label);
402
+ }
403
+
404
+ private async write(label: string): Promise<boolean> {
405
+ const content = JSON.stringify(this.raw, null, 2);
406
+ try {
407
+ if (this.fileHistory) {
408
+ await this.fileHistory.write('vgai.project.json', content, {
409
+ label,
410
+ kind: 'manifest',
411
+ contentType: 'application/json',
412
+ });
413
+ this.store.notifyIngestEdit();
414
+ return true;
415
+ }
416
+ // `vgai.project.json` is PROJECT-ROOT-relative, which is why it is
417
+ // written through the session's own manifest route rather than the
418
+ // asset storage backend (that one is rooted at `public/`).
419
+ const write = async () => {
420
+ const res = await fetch('/__editor/manifest', {
421
+ method: 'POST',
422
+ headers: { 'Content-Type': 'application/json' },
423
+ body: JSON.stringify({
424
+ path: 'vgai.project.json',
425
+ content,
426
+ ...sourceMutationAttribution(),
427
+ }),
428
+ });
429
+ // `!res.ok` alone read a page fallback as a written manifest.
430
+ assertEditorServerAnswered(res, 'Write vgai.project.json failed');
431
+ if (!res.ok) {
432
+ await handleProjectMutationFailure(res, {
433
+ label: 'Write vgai.project.json',
434
+ attempted: { 'vgai.project.json': content },
435
+ reapply: write,
436
+ });
437
+ }
438
+ };
439
+ await write();
440
+ // No SSE for a project-root write (file-watcher only covers `public/`)
441
+ // — notify directly so the hierarchy panel's badges refresh in place.
442
+ this.store.notifyIngestEdit();
443
+ return true;
444
+ } catch (err) {
445
+ if (this.fileHistory) {
446
+ void getManifestHistoryBackend()
447
+ .readBytes('vgai.project.json')
448
+ .then((bytes) => JSON.parse(new TextDecoder().decode(bytes)) as Record<string, unknown>)
449
+ .then((next) => {
450
+ for (const key of Object.keys(this.raw)) delete this.raw[key];
451
+ Object.assign(this.raw, next);
452
+ this.store.notifyIngestEdit();
453
+ })
454
+ .catch(() => {});
455
+ }
456
+ editorConsole.error(`Failed to write vgai.project.json: ${err}`, 'project');
457
+ return false;
458
+ }
459
+ }
460
+ }
461
+
462
+ let _manifestAuthoring: ManifestAuthoring | null = null;
463
+
464
+ /**
465
+ * Build the composite over every declared world and install it as the active
466
+ * authoring override for every non-empty composition
467
+ * (D19). Always returns the built composite so callers can inspect it.
468
+ *
469
+ * The project's sole three content root gets the live Three adapter. The
470
+ * manifest rejects a second content root of the same medium, so this function
471
+ * accepts no focus parameter and never arbitrates between competing Three
472
+ * documents.
473
+ *
474
+ * `rawManifestInfo` (A4, D8, optional) — the RAW parsed `vgai.project.json` +
475
+ * whether it was synthesized (never written to disk); when given and the
476
+ * composite has a world, a `ManifestAuthoring` is built over it
477
+ * and passed to `CompositeAuthoringAdapter` as its root-property manifest
478
+ * surface. When omitted, composition properties are read-only.
479
+ */
480
+ export function installEditModeAuthoring(
481
+ store: EditorShellStore,
482
+ manifest: EditModeManifest,
483
+ rawManifestInfo?: { raw: Record<string, unknown>; synthesized: boolean },
484
+ ): CompositeAuthoringAdapter {
485
+ const children: CompositeChild[] = declaredRoots(manifest).map((world) => {
486
+ // D12 (B4) — install-time zOrder for every child, not just the Boundary's
487
+ // own inspector-displayed value: `childAdapters()`'s pick/paint-order
488
+ // consumers (the layered pick walk, the hierarchy zOrder badge) need it
489
+ // off ANY child, including a live world.
490
+ const zOrder = world.zOrder ?? 0;
491
+ // A SURFACE whose integration registered a live adapter gets it; every
492
+ // other declared world gets the manifest-only Boundary disclosure, to be
493
+ // upgraded when its design-time layer actually mounts. This installer
494
+ // names no surface: `active-adapter.ts`'s factory seam is keyed by the
495
+ // world's own `surface`, and the schema allows at most one root per
496
+ // medium, so there is nothing to choose between. An integration that
497
+ // registers AFTER this ran asks for `queueEditModeRebuild()`, the same
498
+ // door a source change uses.
499
+ const live = baseAuthoringFactory(world.surface);
500
+ if (live) {
501
+ return {
502
+ worldId: world.id,
503
+ kind: world.surface,
504
+ adapter: live(store, world.id),
505
+ zOrder,
506
+ };
507
+ }
508
+ const reason = resolveRootFailureReason(world);
509
+ const info: BoundaryRootInfo = {
510
+ id: world.id,
511
+ kind: world.surface,
512
+ adapter: world.adapter,
513
+ entryOrScenePath: world.scene ?? world.entry,
514
+ zOrder,
515
+ pausable: world.pausable ?? true,
516
+ };
517
+ return {
518
+ worldId: world.id,
519
+ kind: world.surface,
520
+ adapter: new BoundaryAuthoringAdapter(store, info, reason ?? undefined),
521
+ zOrder,
522
+ };
523
+ });
524
+
525
+ // D19 — every composition, including one root, uses the same adapter projection.
526
+ // A synthesized manifest uses the same tree; its manifest-backed
527
+ // edits remain buffered until an explicit project change materializes it.
528
+ const manifestAuthoring =
529
+ rawManifestInfo && children.length >= 1
530
+ ? new ManifestAuthoring(rawManifestInfo.raw, rawManifestInfo.synthesized, store)
531
+ : undefined;
532
+ _manifestAuthoring = manifestAuthoring ?? null;
533
+ const projection = hierarchyProjectionFromProjectConfig(getCurrentProject()?.config);
534
+ const composite = new CompositeAuthoringAdapter(children, manifestAuthoring, projection);
535
+
536
+ if (children.length >= 1) {
537
+ // Symmetry with `exitEditModeAuthoring`, which already refuses to clear an
538
+ // override it does not own ("never clobbers a DIFFERENT session, e.g.
539
+ // ingest/play, that took over afterward"). Installing owed the same
540
+ // courtesy and did not give it: a FOREIGN session — an ingested game — was
541
+ // silently overwritten here, which handed the shared Hierarchy/Inspector
542
+ // panels back to the project mid-session. The user saw the project's roots
543
+ // where the ingested game's tree belonged, and, for an opaque bundle, a
544
+ // neighbouring world's fields where the editor owed them the honest
545
+ // no-authoring ceiling. Teardown-aware but install-blind is not a safe
546
+ // asymmetry for a single-slot override.
547
+ if (hasAuthoringOverride() && !activeOverrideIsEditMode()) {
548
+ editorConsole.warn(
549
+ 'Edit-mode authoring not installed: a foreign session (ingest/play) owns the authoring override.',
550
+ 'authoring',
551
+ );
552
+ return composite;
553
+ }
554
+ // Brand BEFORE installing so the store's save guard sees it the instant
555
+ // the override is live (defect 1: the focused first-party child must be
556
+ // able to Ctrl+S/autosave through the store, unlike a foreign override).
557
+ markEditModeOverride(composite);
558
+ setActiveAuthoring(composite);
559
+ store.notifyIngestEdit();
560
+ }
561
+
562
+ return composite;
563
+ }
564
+
565
+ /** Teardown symmetric to `installEditModeAuthoring` — clears the override
566
+ * ONLY if it is still exactly the composite this module last installed
567
+ * (never clobbers a DIFFERENT session, e.g. ingest/play, that took over
568
+ * afterward). */
569
+ export function exitEditModeAuthoring(installed?: CompositeAuthoringAdapter): void {
570
+ if (installed && getAuthoringOverride() === installed) {
571
+ setActiveAuthoring(null);
572
+ }
573
+ _manifestAuthoring?.dispose();
574
+ _manifestAuthoring = null;
575
+ }
576
+
577
+ /**
578
+ * Project-open wiring: fetch the RAW `vgai.project.json` and install the edit-mode
579
+ * composite via the LENIENT parse (defect 2) — a manifest with one bad world
580
+ * still opens its valid roots, surfacing the bad one as an error node (#18).
581
+ * ONLY a genuinely ABSENT manifest (the route 404s → `fetchRawGameManifest`
582
+ * returns `null`), or one so malformed it has no usable `roots` array,
583
+ * synthesizes a single `{ id: 'main', surface: 'three', scene: <resolved> }`
584
+ * game IN MEMORY (never written to disk), where `<resolved>` mirrors
585
+ * `loadInitialScene`'s OWN resolution order. This is the only call site that
586
+ * should call `installEditModeAuthoring` at ordinary project open. The shell-owned
587
+ * `project-authoring-session.ts` installs it independently of open viewport tabs.
588
+ */
589
+ export async function installEditModeAuthoringForProject(
590
+ store: EditorShellStore,
591
+ ): Promise<CompositeAuthoringAdapter> {
592
+ const finishBootstrap = beginAuthoringBootstrap(store);
593
+ let manifest: EditModeManifest;
594
+ // The RAW object backing `ManifestAuthoring` (read-modify-write, never
595
+ // round-tripped through Zod). An omitted roots field is a real manifest
596
+ // using D19's convention, not a synthesized/unsaved manifest.
597
+ let rawManifestInfo: { raw: Record<string, unknown>; synthesized: boolean } | undefined;
598
+ try {
599
+ const raw = await fetchRawGameManifest();
600
+ const parsed = raw !== null && parseEditModeManifest(raw);
601
+ if (parsed) {
602
+ manifest = parsed;
603
+ rawManifestInfo = { raw: raw as Record<string, unknown>, synthesized: false };
604
+ } else {
605
+ throw new Error('manifest has no `roots` array (zero roots is fine; a missing field is not)');
606
+ }
607
+ } catch (err) {
608
+ const detail = err instanceof Error ? err.message : String(err);
609
+ editorConsole.error(`Failed to load vgai.project.json: ${detail}`, 'project');
610
+ manifest = {
611
+ roots: [{ id: 'manifest', surface: INVALID_MANIFEST_SURFACE, adapter: detail }],
612
+ };
613
+ }
614
+ try {
615
+ return installEditModeAuthoring(store, manifest, rawManifestInfo);
616
+ } finally {
617
+ finishBootstrap();
618
+ }
619
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Eyedropper session (D3.d) — a module-level subscribable singleton bridging the
3
+ * C1 `ColorPicker` (mounted inside the Inspector panel) and the canvas
4
+ * (`RootSelectionOverlay`), the two SIBLING React trees a "click the eyedropper
5
+ * button, then click somewhere on the canvas" gesture must cross when the native
6
+ * `EyeDropper` API is unavailable (the FALLBACK path this whole module exists
7
+ * for — see `ColorPicker.tsx`'s `handleEyedropper` and the `ColorSampleProvider`
8
+ * contract doc comment for why the native path needs none of this: it samples
9
+ * real rendered pixels itself).
10
+ *
11
+ * Mirrors `world-session-state.ts`'s "bare module singleton" shape, but keeps
12
+ * its OWN subscriber list (rather than piggybacking on `EditorShellStore.
13
+ * notifyIngestEdit`) since this is transient cross-panel UI state, not an
14
+ * authored/session toggle any editor-store snapshot needs to carry.
15
+ *
16
+ * Only ONE fallback pick can be in flight at a time — beginning a new one
17
+ * silently supersedes whatever was pending (mirrors the ColorPicker's own
18
+ * "one popover at a time" assumption; nothing today opens two eyedroppers at
19
+ * once).
20
+ */
21
+
22
+ export type EyedropperApply = (color: string | null) => void;
23
+
24
+ let activeApply: EyedropperApply | null = null;
25
+ const listeners = new Set<() => void>();
26
+
27
+ function notify(): void {
28
+ for (const l of listeners) l();
29
+ }
30
+
31
+ /** Begin a fallback eyedropper session — `apply` is the widget's own
32
+ * sampled-color callback, called exactly once when the session resolves
33
+ * (`null` color means "cancelled", e.g. Escape — never a fabricated color). */
34
+ export function beginEyedropperSession(apply: EyedropperApply): void {
35
+ activeApply = apply;
36
+ notify();
37
+ }
38
+
39
+ /** True while a fallback session is awaiting a canvas click/Escape. */
40
+ export function isEyedropperSessionActive(): boolean {
41
+ return activeApply !== null;
42
+ }
43
+
44
+ /** Resolve the active session with a sampled color (or `null` to cancel),
45
+ * then close it. A no-op if no session is active. */
46
+ export function resolveEyedropperSession(color: string | null): void {
47
+ const apply = activeApply;
48
+ if (!apply) return;
49
+ activeApply = null;
50
+ notify();
51
+ apply(color);
52
+ }
53
+
54
+ /** Subscribe to session begin/end transitions — `RootSelectionOverlay` binds
55
+ * this via `useSyncExternalStore` so it re-renders (shows/hides the cursor
56
+ * swatch) the instant a session starts or ends. */
57
+ export function subscribeEyedropperSession(listener: () => void): () => void {
58
+ listeners.add(listener);
59
+ return () => listeners.delete(listener);
60
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * H3 side-effect registration module (imported by `main.tsx` alongside the
3
+ * other contribution-seam imports): installs the instance row's
4
+ * `Go to Callsite` / `Open Component Source` hierarchy items at editor boot.
5
+ *
6
+ * Kept separate from `instance-source-menu.ts` itself so unit tests can
7
+ * import that module (and the double-click helper it also exports) without
8
+ * mutating the shared hierarchy-menu registry as a side effect of the import.
9
+ */
10
+
11
+ import { ensureInstanceSourceMenuRegistered } from './instance-source-menu';
12
+
13
+ ensureInstanceSourceMenuRegistered();