@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,775 @@
1
+ /**
2
+ * Live-DOM inspection helpers (Cap 1 of the React visual-edit parity port). These are
3
+ * `../../../visual-edit/preload.ts`'s inspection FUNCTIONS ported as DIRECT-CALL helpers.
4
+ *
5
+ * The no-iframe adaptation (see the parity spec): visual-edit injects `preload.ts` into
6
+ * an iframe and inspects the target app across a `postMessage` bridge. vgai mounts React
7
+ * roots as DOM layers in the SAME document and `ReactRootAuthoringAdapter` already holds
8
+ * the live root — so these run against the live element directly, no iframe/bridge.
9
+ *
10
+ * Headless-testable: none of these reach for a DOM global unconditionally. Fiber reads
11
+ * work on any object carrying a `__reactFiber$…` key (a plain fixture satisfies it).
12
+ * `getComputedStyles` takes a resolver (defaulting to `window.getComputedStyle` in a real
13
+ * browser, or the element's inline `.style` under vitest's `node` env — no jsdom).
14
+ * `getMatchedCssRules` takes its stylesheet list (defaulting to `document.styleSheets`).
15
+ *
16
+ * C4 (spec §9) fiber-access contract: `__reactFiber$…`/`__reactInternalInstance$…` are
17
+ * React's OWN internal instance keys — never a documented, versioned public API (the
18
+ * exact prefix has changed across React major versions, and nothing guarantees it won't
19
+ * again). `findFiber` therefore treats a missing/renamed key as an ORDINARY, expected
20
+ * outcome, not an error: it returns `null` rather than throwing, and every caller
21
+ * (`getReactComponentName`, `getCallSiteOid`, `readFiberProps`, `getComponentProps`) is
22
+ * `null`-safe from there. The one caller-visible fallback this enables is
23
+ * `getEffectiveOid`: call-site OID (from the fiber) when available, else the element's
24
+ * own `data-oid` DOM attribute — i.e. inspection degrades to DOM-only (oid/selection
25
+ * still work; component-name/props enrichment silently disappears) instead of failing.
26
+ * Covered by `ui-source-inspect.test.ts`'s "no fiber" case (a plain DOM-shaped fixture
27
+ * with no `__reactFiber$…` key at all, simulating both "fiber absent" and "key renamed").
28
+ */
29
+
30
+ import { warnGuessedFromText } from '../inference-diagnostics';
31
+
32
+ const OID_ATTR = 'data-oid';
33
+
34
+ /** The ~70 most-edited CSS properties visual-edit's `getComputedStyles` captures (:73). */
35
+ export const COMPUTED_STYLE_PROPS: readonly string[] = [
36
+ 'width',
37
+ 'height',
38
+ 'minWidth',
39
+ 'minHeight',
40
+ 'maxWidth',
41
+ 'maxHeight',
42
+ 'margin',
43
+ 'marginTop',
44
+ 'marginRight',
45
+ 'marginBottom',
46
+ 'marginLeft',
47
+ 'padding',
48
+ 'paddingTop',
49
+ 'paddingRight',
50
+ 'paddingBottom',
51
+ 'paddingLeft',
52
+ 'display',
53
+ 'flexDirection',
54
+ 'flexWrap',
55
+ 'justifyContent',
56
+ 'alignItems',
57
+ 'gap',
58
+ 'flexGrow',
59
+ 'flexShrink',
60
+ 'flexBasis',
61
+ 'alignSelf',
62
+ 'position',
63
+ 'top',
64
+ 'right',
65
+ 'bottom',
66
+ 'left',
67
+ 'backgroundColor',
68
+ 'backgroundImage',
69
+ 'color',
70
+ 'fontSize',
71
+ 'fontWeight',
72
+ 'fontFamily',
73
+ 'borderRadius',
74
+ 'borderTopLeftRadius',
75
+ 'borderTopRightRadius',
76
+ 'borderBottomLeftRadius',
77
+ 'borderBottomRightRadius',
78
+ 'border',
79
+ 'borderWidth',
80
+ 'borderColor',
81
+ 'borderStyle',
82
+ 'borderTopWidth',
83
+ 'borderRightWidth',
84
+ 'borderBottomWidth',
85
+ 'borderLeftWidth',
86
+ 'borderTopStyle',
87
+ 'borderRightStyle',
88
+ 'borderBottomStyle',
89
+ 'borderLeftStyle',
90
+ 'borderTopColor',
91
+ 'borderRightColor',
92
+ 'borderBottomColor',
93
+ 'borderLeftColor',
94
+ 'opacity',
95
+ 'overflow',
96
+ 'zIndex',
97
+ 'transform',
98
+ 'mixBlendMode',
99
+ 'filter',
100
+ 'backdropFilter',
101
+ 'textShadow',
102
+ 'boxShadow',
103
+ 'textAlign',
104
+ 'lineHeight',
105
+ 'letterSpacing',
106
+ 'textTransform',
107
+ 'textDecoration',
108
+ 'whiteSpace',
109
+ 'wordWrap',
110
+ 'cursor',
111
+ ];
112
+
113
+ /** camelCase CSS prop -> kebab-case (`fontSize` -> `font-size`). */
114
+ export function camelToKebab(prop: string): string {
115
+ return prop.replace(/([A-Z])/g, '-$1').toLowerCase();
116
+ }
117
+
118
+ /** kebab-case CSS prop -> camelCase (`font-size` -> `fontSize`). */
119
+ export function kebabToCamel(prop: string): string {
120
+ return prop.replace(/-([a-z])/g, (_, c: string) => c.toUpperCase());
121
+ }
122
+
123
+ /** The minimal shape a resolved computed-style value source needs. A real
124
+ * `CSSStyleDeclaration` satisfies this structurally. */
125
+ export interface ComputedStyleLike {
126
+ getPropertyValue(prop: string): string;
127
+ }
128
+
129
+ /** Resolves an element to a `getPropertyValue`-capable style source (kebab keys). */
130
+ export type ComputedStyleResolver = (el: unknown) => ComputedStyleLike;
131
+
132
+ /** Read one inline style property off an element's `.style` of either shape (a real
133
+ * `CSSStyleDeclaration` or a plain-object test fixture) — the same read
134
+ * `react-world-authoring-adapter.ts` uses. */
135
+ function inlineStyleProp(style: unknown, prop: string): unknown {
136
+ return style ? (style as Record<string, unknown>)[prop] : undefined;
137
+ }
138
+
139
+ /**
140
+ * The default resolver: real `window.getComputedStyle` in a browser (so CLASS-styled
141
+ * and CSS-file-styled properties resolve, fixing the "class-styled props show blank"
142
+ * bug), or — under vitest's `node` env (no `window`) — a shim reading the element's
143
+ * inline `.style` object, so headless fixtures keep working unchanged.
144
+ */
145
+ export const browserOrInlineResolver: ComputedStyleResolver = (el) => {
146
+ const w = (globalThis as { window?: { getComputedStyle?: (e: unknown) => ComputedStyleLike } })
147
+ .window;
148
+ if (w?.getComputedStyle) return w.getComputedStyle(el);
149
+ const style = (el as { style?: unknown }).style;
150
+ return { getPropertyValue: (k: string) => String(inlineStyleProp(style, kebabToCamel(k)) ?? '') };
151
+ };
152
+
153
+ /**
154
+ * Capture the commonly-edited computed styles of an element as a camelCase-keyed record
155
+ * (visual-edit `getComputedStyles` :73). The resolver is injectable for headless tests;
156
+ * the default resolves against the live browser DOM (or inline style under `node`).
157
+ */
158
+ export function getComputedStyles(
159
+ el: unknown,
160
+ resolve: ComputedStyleResolver = browserOrInlineResolver,
161
+ ): Record<string, string> {
162
+ const cs = resolve(el);
163
+ const result: Record<string, string> = {};
164
+ for (const p of COMPUTED_STYLE_PROPS) result[p] = cs.getPropertyValue(camelToKebab(p));
165
+ return result;
166
+ }
167
+
168
+ /** Read a single computed style property (camelCase), via the same resolver. */
169
+ export function getComputedStyleValue(
170
+ el: unknown,
171
+ prop: string,
172
+ resolve: ComputedStyleResolver = browserOrInlineResolver,
173
+ ): string {
174
+ return resolve(el).getPropertyValue(camelToKebab(prop));
175
+ }
176
+
177
+ // --- React fiber inspection (visual-edit preload.ts :110/:134/:158) ---
178
+
179
+ /** A minimal fiber node shape — enough for the reads below (`preload.ts` uses `any`). */
180
+ interface FiberLike {
181
+ return?: FiberLike | null;
182
+ type?: unknown;
183
+ memoizedProps?: Record<string, unknown> | null;
184
+ }
185
+
186
+ /** Find the React fiber attached to a DOM element (React 18+ `__reactFiber$…`, older
187
+ * `__reactInternalInstance$…`). Works on any object carrying such a key — a plain
188
+ * fixture with `{ __reactFiber$x: {...} }` satisfies it headlessly. */
189
+ export function findFiber(el: unknown): FiberLike | null {
190
+ if (!el || typeof el !== 'object') return null;
191
+ const key = Object.keys(el as object).find(
192
+ (k) => k.startsWith('__reactFiber$') || k.startsWith('__reactInternalInstance$'),
193
+ );
194
+ if (!key) return null;
195
+ return ((el as Record<string, unknown>)[key] as FiberLike) ?? null;
196
+ }
197
+
198
+ /** The parent fiber IF this element is the ROOT element of a function component
199
+ * (`fiber.return` points straight at the component fiber). Else null. */
200
+ function componentParentFiber(el: unknown): FiberLike | null {
201
+ const fiber = findFiber(el);
202
+ if (!fiber?.return) return null;
203
+ const parent = fiber.return;
204
+ return parent.type && typeof parent.type === 'function' ? parent : null;
205
+ }
206
+
207
+ /** Nearest component name for an element that is a component's root element
208
+ * (visual-edit `getReactComponentName` :110). */
209
+ export function getReactComponentName(el: unknown): string | null {
210
+ const parent = componentParentFiber(el);
211
+ if (!parent) return null;
212
+ const type = parent.type as { displayName?: string; name?: string };
213
+ return type.displayName || type.name || null;
214
+ }
215
+
216
+ /** The call-site `data-oid` prop passed to a component root (`<StatCard data-oid="x"/>`)
217
+ * read off the component fiber's props (visual-edit `getCallSiteOid` :134). */
218
+ export function getCallSiteOid(el: unknown): string | null {
219
+ const parent = componentParentFiber(el);
220
+ if (!parent) return null;
221
+ const v = parent.memoizedProps?.[OID_ATTR];
222
+ return typeof v === 'string' ? v : null;
223
+ }
224
+
225
+ /** Call-site OID for component roots, else the element's own `data-oid`
226
+ * (visual-edit `getEffectiveOid` :148). */
227
+ export function getEffectiveOid(el: { getAttribute?(name: string): string | null }): string | null {
228
+ return getCallSiteOid(el) ?? el.getAttribute?.(OID_ATTR) ?? null;
229
+ }
230
+
231
+ /** Primitive (string/number/boolean) props of a component root, stringified
232
+ * (visual-edit `readFiberProps` :158). Skips children/key/ref/data-oid/style/className
233
+ * and any non-primitive value. Returns null when there are none. */
234
+ export function readFiberProps(el: unknown): Record<string, string> | null {
235
+ const parent = componentParentFiber(el);
236
+ if (!parent) return null;
237
+ const props = parent.memoizedProps;
238
+ if (!props || typeof props !== 'object') return null;
239
+
240
+ const SKIP = new Set(['children', 'key', 'ref', OID_ATTR, 'style', 'className']);
241
+ const result: Record<string, string> = {};
242
+ for (const [key, value] of Object.entries(props)) {
243
+ if (SKIP.has(key)) continue;
244
+ if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
245
+ result[key] = String(value);
246
+ }
247
+ }
248
+ return Object.keys(result).length > 0 ? result : null;
249
+ }
250
+
251
+ /** The component's call-site OID + its editable primitive props, or null if the element
252
+ * is not a component root with props (visual-edit `getComponentProps` :463). Cap 4 feeds
253
+ * the Props inspector section from this. */
254
+ export function getComponentProps(
255
+ el: { getAttribute?(name: string): string | null } & unknown,
256
+ ): { callSiteOid: string; props: Record<string, string> } | null {
257
+ const callSiteOid = getCallSiteOid(el);
258
+ if (!callSiteOid) return null;
259
+ const props = readFiberProps(el);
260
+ if (!props) return null;
261
+ return { callSiteOid, props };
262
+ }
263
+
264
+ // --- Matched CSS rules (visual-edit preload.ts getMatchedCssRules :473) ---
265
+
266
+ export interface MatchedCssRule {
267
+ selectorText: string;
268
+ properties: Record<string, string>;
269
+ /** The source file the owning `<style>`/`<link>` traces to (via `data-vite-dev-id`). */
270
+ sourceFile: string;
271
+ }
272
+
273
+ /** The minimal element shape needed to trace matched rules — `matches(selector)`. */
274
+ export interface MatchableElement {
275
+ matches(selector: string): boolean;
276
+ }
277
+
278
+ /** A structural stand-in for a `CSSStyleRule` (headless-testable). */
279
+ export interface StyleRuleLike {
280
+ selectorText: string;
281
+ style: { length: number; getPropertyValue(prop: string): string; [index: number]: string };
282
+ }
283
+
284
+ /** A structural stand-in for a `CSSStyleSheet` + its owner node. */
285
+ export interface StyleSheetLike {
286
+ ownerNode?: { id?: string; getAttribute?(name: string): string | null } | null;
287
+ cssRules: ArrayLike<unknown>;
288
+ }
289
+
290
+ /** The id of visual-edit's own preview `<style>` tag — skipped when tracing rules. */
291
+ const PREVIEW_STYLE_TAG_ID = '__visual-edit-preview-styles';
292
+
293
+ /** Is this rule a style rule (vs `@media`/`@keyframes`)? Uses `CSSStyleRule` when the DOM
294
+ * provides it, else a structural check so headless fixtures work. */
295
+ function isStyleRule(rule: unknown): rule is StyleRuleLike {
296
+ const CSR = (globalThis as { CSSStyleRule?: unknown }).CSSStyleRule;
297
+ if (typeof CSR === 'function') return rule instanceof (CSR as new () => unknown);
298
+ const r = rule as Partial<StyleRuleLike>;
299
+ return !!r && typeof r.selectorText === 'string' && !!r.style;
300
+ }
301
+
302
+ /** Read every declared property off a style rule's declaration block. */
303
+ function readRuleProperties(rule: StyleRuleLike): Record<string, string> {
304
+ const properties: Record<string, string> = {};
305
+ for (let i = 0; i < rule.style.length; i++) {
306
+ const prop = rule.style[i] as string;
307
+ properties[prop] = rule.style.getPropertyValue(prop);
308
+ }
309
+ return properties;
310
+ }
311
+
312
+ /**
313
+ * Trace the CSS rules from first-party stylesheets that MATCH an element, keyed back to
314
+ * their source file via the owner node's `data-vite-dev-id` (visual-edit
315
+ * `getMatchedCssRules` :473). Only rules from a stylesheet with a `data-vite-dev-id`
316
+ * (i.e. a real source file Vite is serving) are returned — Cap 2 edits those files.
317
+ * Sheets default to `document.styleSheets`; injectable for headless tests.
318
+ */
319
+ /**
320
+ * Walk every STYLE rule of every first-party stylesheet (one with a
321
+ * `data-vite-dev-id` — a real source file Vite is serving), DESCENDING grouping
322
+ * rules. Descent is the load-bearing half: the dev server wraps a project
323
+ * stylesheet's whole body in `@scope ([data-vgai-game-styles]) { … }`
324
+ * (server/scoped-game-css.ts), so in the served CSSOM every project rule is a
325
+ * grouping-rule CHILD — a top-level-only walk sees none of them, which is
326
+ * exactly why the Cap-2 cascade route never fired for scoped game CSS. A
327
+ * `@media` group is only entered when its condition currently HOLDS
328
+ * (`matchMedia`): a rule inside a non-matching breakpoint is not in cascade
329
+ * and must not be offered as an edit target.
330
+ */
331
+ function visitFirstPartyStyleRules(
332
+ sheets: Iterable<StyleSheetLike>,
333
+ visit: (rule: StyleRuleLike, sourceFile: string) => void,
334
+ ): void {
335
+ const mm = (globalThis as { matchMedia?: (q: string) => { matches: boolean } }).matchMedia;
336
+ const walk = (rules: ArrayLike<unknown>, sourceFile: string): void => {
337
+ for (const rule of Array.from(rules)) {
338
+ if (isStyleRule(rule)) {
339
+ visit(rule, sourceFile);
340
+ continue;
341
+ }
342
+ const group = rule as {
343
+ cssRules?: ArrayLike<unknown>;
344
+ media?: { mediaText?: string };
345
+ containerQuery?: unknown;
346
+ cssText?: string;
347
+ };
348
+ if (!group.cssRules) continue;
349
+ const mediaText = group.media?.mediaText;
350
+ if (typeof mediaText === 'string' && mm && !mm(mediaText).matches) continue;
351
+ // A @container group is a BREAKPOINT scope (the serve-time responsive
352
+ // preview rewrites width @media into these). Whether it applies depends
353
+ // on each frame's own size — unanswerable from this element-independent
354
+ // walk — and offering its rules as silent cascade targets would route a
355
+ // BASE edit into a breakpoint. Breakpoint writes take the explicit
356
+ // media-scoped door instead.
357
+ if (
358
+ typeof group.containerQuery === 'string' ||
359
+ group.cssText?.trimStart().startsWith('@container')
360
+ )
361
+ continue;
362
+ walk(group.cssRules, sourceFile);
363
+ }
364
+ };
365
+ for (const sheet of sheets) {
366
+ const owner = sheet.ownerNode;
367
+ if (owner?.id === PREVIEW_STYLE_TAG_ID) continue;
368
+ const sourceFile = owner?.getAttribute?.('data-vite-dev-id') ?? null;
369
+ if (!sourceFile) continue;
370
+ try {
371
+ walk(sheet.cssRules, sourceFile);
372
+ } catch {
373
+ // Cross-origin stylesheet — its `cssRules` throws; skip it (same as visual-edit).
374
+ }
375
+ }
376
+ }
377
+
378
+ /** Where a named style (a single-class rule `.name`) is declared, if any
379
+ * first-party stylesheet declares one — the fact that decides APPLY (the
380
+ * class exists, add the token) vs CREATE (write a new rule). Later sheets
381
+ * win, matching cascade order. */
382
+ export function findClassRuleSource(
383
+ className: string,
384
+ sheets: Iterable<StyleSheetLike> = (
385
+ globalThis as { document?: { styleSheets?: Iterable<StyleSheetLike> } }
386
+ ).document?.styleSheets ?? [],
387
+ ): { sourceFile: string } | null {
388
+ let found: { sourceFile: string } | null = null;
389
+ visitFirstPartyStyleRules(sheets, (rule, sourceFile) => {
390
+ if (rule.selectorText.trim() === `.${className}`) found = { sourceFile };
391
+ });
392
+ return found;
393
+ }
394
+
395
+ /** The distinct first-party stylesheet source files currently serving CSS, in
396
+ * document order — the candidate homes for a NEW named-style rule when no
397
+ * matched rule already names one. */
398
+ export function firstPartyStylesheetFiles(
399
+ sheets: Iterable<StyleSheetLike> = (
400
+ globalThis as { document?: { styleSheets?: Iterable<StyleSheetLike> } }
401
+ ).document?.styleSheets ?? [],
402
+ ): string[] {
403
+ const files: string[] = [];
404
+ for (const sheet of sheets) {
405
+ const owner = sheet.ownerNode;
406
+ if (owner?.id === PREVIEW_STYLE_TAG_ID) continue;
407
+ const sourceFile = owner?.getAttribute?.('data-vite-dev-id') ?? null;
408
+ if (!sourceFile) continue;
409
+ const clean = sourceFile.split('?')[0] ?? sourceFile;
410
+ if (clean.endsWith('.css') && !files.includes(sourceFile)) files.push(sourceFile);
411
+ }
412
+ return files;
413
+ }
414
+
415
+ export function getMatchedCssRules(
416
+ el: MatchableElement,
417
+ sheets: Iterable<StyleSheetLike> = (
418
+ globalThis as { document?: { styleSheets?: Iterable<StyleSheetLike> } }
419
+ ).document?.styleSheets ?? [],
420
+ ): MatchedCssRule[] {
421
+ const matched: MatchedCssRule[] = [];
422
+ visitFirstPartyStyleRules(sheets, (rule, sourceFile) => {
423
+ if (el.matches(rule.selectorText)) {
424
+ matched.push({
425
+ selectorText: rule.selectorText,
426
+ properties: readRuleProperties(rule),
427
+ sourceFile,
428
+ });
429
+ }
430
+ });
431
+ return matched;
432
+ }
433
+
434
+ // --- Design tokens (visual-edit preload.ts getDesignTokens :506) — Cap 7 ---
435
+
436
+ export interface DesignToken {
437
+ name: string;
438
+ value: string;
439
+ category: 'color' | 'spacing' | 'other';
440
+ /**
441
+ * WHERE the token is declared, when a project stylesheet rule declares it —
442
+ * the write address `writeCss(file, selector, --name, value)` targets, which
443
+ * is what upgrades the token's inspector row from read-only to editable. A
444
+ * token with no declaration trace (set inline on `:root` by script — e.g. a
445
+ * theme data module mirroring itself, or an inherited host style) stays
446
+ * read-only, and its EDIT door is the declaring source itself.
447
+ */
448
+ declaredIn?: { sourceFile: string; selector: string };
449
+ }
450
+
451
+ /**
452
+ * Trace `:root`-scope custom-property DECLARATIONS to their stylesheet
453
+ * source (`data-vite-dev-id`, the same trace {@link getMatchedCssRules}
454
+ * uses). Later declarations win, matching the cascade for equal-specificity
455
+ * `:root` rules. Rules under `[data-theme]`/media scopes are deliberately
456
+ * NOT the base declaration — modes override the base; the base row is what
457
+ * a token edit writes.
458
+ */
459
+ export function traceTokenDeclarations(
460
+ sheets: Iterable<StyleSheetLike> = (
461
+ globalThis as { document?: { styleSheets?: Iterable<StyleSheetLike> } }
462
+ ).document?.styleSheets ?? [],
463
+ ): Map<string, { sourceFile: string; selector: string }> {
464
+ const out = new Map<string, { sourceFile: string; selector: string }>();
465
+ const visit = (rule: unknown, sourceFile: string, inScope: boolean): void => {
466
+ if (isStyleRule(rule)) {
467
+ const selector = rule.selectorText;
468
+ // The dev server rewrites a project stylesheet's `:root { … }` into
469
+ // `@scope ([data-vgai-game-styles]) { :scope { … } }` (measured), so a
470
+ // scope-wrapped `:scope` IS a `:root` declaration — and the recorded
471
+ // write address is the SOURCE's `:root`, because the css writer edits
472
+ // source text, not the served rewrite.
473
+ const scopeBase = inScope && /(^|,)\s*:scope\s*($|,)/.test(selector);
474
+ const rootBase =
475
+ /(^|,)\s*(:root|html)\s*($|,)/.test(selector) && !selector.includes('[data-theme');
476
+ if (!scopeBase && !rootBase) return;
477
+ for (let i = 0; i < rule.style.length; i++) {
478
+ const prop = rule.style[i]!;
479
+ if (!prop.startsWith('--')) continue;
480
+ out.set(prop, { sourceFile, selector: scopeBase ? ':root' : selector });
481
+ }
482
+ return;
483
+ }
484
+ const group = rule as { cssRules?: ArrayLike<unknown>; cssText?: string };
485
+ if (!group.cssRules) return;
486
+ const scoped = inScope || Boolean(group.cssText?.trimStart().startsWith('@scope'));
487
+ for (const child of Array.from(group.cssRules)) visit(child, sourceFile, scoped);
488
+ };
489
+ for (const sheet of sheets) {
490
+ const owner = sheet.ownerNode;
491
+ if (owner?.id === PREVIEW_STYLE_TAG_ID) continue;
492
+ const sourceFile = owner?.getAttribute?.('data-vite-dev-id') ?? null;
493
+ if (!sourceFile) continue;
494
+ try {
495
+ for (const rule of Array.from(sheet.cssRules)) visit(rule, sourceFile, false);
496
+ } catch {
497
+ // Cross-origin stylesheet — its `cssRules` throws; skip it.
498
+ }
499
+ }
500
+ return out;
501
+ }
502
+
503
+ /**
504
+ * Enumerate the `:root` CSS custom properties (design tokens) resolved on the document
505
+ * root, classified color/spacing/other (visual-edit `getDesignTokens` :506). Captures
506
+ * Tailwind v4 `@theme`/`oklch` vars; skips Tailwind internal `--tw-*`, Font
507
+ * Awesome internals, and the editor chrome's reserved `--vgai-*` namespace.
508
+ * The latter is infrastructure inherited from the editor host, never authored
509
+ * game data. The computed declaration is injectable for headless tests
510
+ * (defaults to the live `:root`).
511
+ */
512
+ export function getDesignTokens(
513
+ computed: (ComputedStyleLike & ArrayLike<string>) | undefined = readRootComputed(),
514
+ ): DesignToken[] {
515
+ if (!computed) return [];
516
+ const tokens: DesignToken[] = [];
517
+ const seen = new Set<string>();
518
+ for (let i = 0; i < computed.length; i++) {
519
+ const name = computed[i] as string;
520
+ if (
521
+ !name.startsWith('--') ||
522
+ name.startsWith('--tw-') ||
523
+ name.startsWith('--fa-') ||
524
+ name.startsWith('--vgai-') ||
525
+ // Code-OSS theme tokens inherit into game roots but belong to the host.
526
+ name.startsWith('--vscode-') ||
527
+ name === '--chat-input-control-height' ||
528
+ // The `--dv-*` chrome variables inherit from the editor shell into
529
+ // every game-CSS scope root, so a board's token read sees them
530
+ // (measured: 15 heuristic warnings per board open). Editor chrome, not
531
+ // game data — same exclusion as `--vgai-*`.
532
+ name.startsWith('--dv-') ||
533
+ seen.has(name)
534
+ )
535
+ continue;
536
+ seen.add(name);
537
+ const value = computed.getPropertyValue(name).trim();
538
+ if (!value) continue;
539
+ tokens.push({ name, value, category: classifyToken(name, value) });
540
+ }
541
+ const declarations = traceTokenDeclarations();
542
+ // The indexed loop above only lists custom properties the SUPPLIED style
543
+ // declares directly — an element inside a game-CSS scope RESOLVES its
544
+ // inherited tokens (`getPropertyValue`) but does not ITERATE them
545
+ // (measured). The declaration trace supplies the missing names, so scoped
546
+ // game tokens enumerate wherever the caller's element can resolve them.
547
+ for (const name of declarations.keys()) {
548
+ if (seen.has(name) || name.startsWith('--tw-') || name.startsWith('--fa-')) continue;
549
+ if (
550
+ name.startsWith('--vgai-') ||
551
+ name.startsWith('--dv-') ||
552
+ name.startsWith('--vscode-') ||
553
+ name === '--chat-input-control-height'
554
+ )
555
+ continue;
556
+ seen.add(name);
557
+ const value = computed.getPropertyValue(name).trim();
558
+ if (!value) continue;
559
+ tokens.push({ name, value, category: classifyToken(name, value) });
560
+ }
561
+ // Best-effort declaration trace — a token with no traced rule simply has no
562
+ // `declaredIn`, which the inspector renders as read-only (see the field).
563
+ for (const token of tokens) {
564
+ const declared = declarations.get(token.name);
565
+ if (declared) token.declaredIn = declared;
566
+ }
567
+ return tokens;
568
+ }
569
+
570
+ const COLOR_VALUE_RE = /^(#[0-9a-f]{3,8}|rgba?\(|hsla?\(|oklch\()/i;
571
+ const SPACING_NAME_RE = /spacing|gap|margin|padding|radius|size|width|height/i;
572
+
573
+ const COLOR_NAME_RE = /color/i;
574
+
575
+ /**
576
+ * Classify a design token by its name + value (visual-edit `getDesignTokens`
577
+ * :524), in two rungs.
578
+ *
579
+ * The VALUE is ground truth: `oklch(…)`/`#rrggbb` IS a color, whatever the
580
+ * token is called. Only when the value settles nothing does the NAME decide —
581
+ * and that rung is a guess about someone else's naming convention
582
+ * (`--brand-colorway` is not a color; `--icon-size: 2` is not spacing if it is
583
+ * a count). The guess still stands, because a swatch for `--accent: red` is
584
+ * better than a text box; it is just no longer silent
585
+ * (ARCHITECTURE-CORE §The editor protocol, "Zero inference").
586
+ *
587
+ * `other` is not a guess — it is the honest "nothing said", and reports nothing.
588
+ */
589
+ function classifyToken(name: string, value: string): DesignToken['category'] {
590
+ if (COLOR_VALUE_RE.test(value)) return 'color';
591
+ if (COLOR_NAME_RE.test(name)) {
592
+ warnGuessedFromText(':root', name, 'color');
593
+ return 'color';
594
+ }
595
+ if (SPACING_NAME_RE.test(name) && /^\d/.test(value)) {
596
+ warnGuessedFromText(':root', name, 'spacing');
597
+ return 'spacing';
598
+ }
599
+ return 'other';
600
+ }
601
+
602
+ // --- Cap 8: UX-polish helpers (visual-edit preload.ts getElementsInRect :635 /
603
+ // getSnapTargets :592 / getEmptyContainers :563 / getColorAtPoint :667 /
604
+ // getAvailableFonts :677). Ported as pure/injectable direct-call helpers. ---
605
+
606
+ export interface Rect {
607
+ x: number;
608
+ y: number;
609
+ width: number;
610
+ height: number;
611
+ }
612
+
613
+ /** Axis-aligned rectangle intersection test (edges from x/y/width/height). */
614
+ export function rectsIntersect(a: Rect, b: Rect): boolean {
615
+ if (a.x + a.width < b.x || a.x > b.x + b.width) return false;
616
+ if (a.y + a.height < b.y || a.y > b.y + b.height) return false;
617
+ return true;
618
+ }
619
+
620
+ /** A marquee candidate: an OID-tagged element's rect + the oids of its OID-tagged
621
+ * descendants (for the deepest-element filter). */
622
+ export interface MarqueeCandidate {
623
+ oid: string;
624
+ rect: Rect;
625
+ descendantOids: string[];
626
+ }
627
+
628
+ /**
629
+ * Marquee-select: the OID elements intersecting `rect`, filtered to the DEEPEST matches —
630
+ * an element is dropped if any of its OID descendants also matched (visual-edit
631
+ * `getElementsInRect` :635). Zero-area candidates are ignored. Pure; the browser wrapper
632
+ * builds candidates from `document.querySelectorAll('[data-oid]')`.
633
+ */
634
+ export function getElementsInRect(
635
+ rect: Rect,
636
+ candidates: readonly MarqueeCandidate[],
637
+ ): { oid: string; rect: Rect }[] {
638
+ const hit = candidates.filter(
639
+ (c) => (c.rect.width > 0 || c.rect.height > 0) && rectsIntersect(c.rect, rect),
640
+ );
641
+ const hitOids = new Set(hit.map((c) => c.oid));
642
+ return hit
643
+ .filter((c) => !c.descendantOids.some((d) => d !== c.oid && hitOids.has(d)))
644
+ .map((c) => ({ oid: c.oid, rect: c.rect }));
645
+ }
646
+
647
+ /** Per-side padding of a container (px). */
648
+ export interface Padding {
649
+ top: number;
650
+ right: number;
651
+ bottom: number;
652
+ left: number;
653
+ }
654
+
655
+ /**
656
+ * Snap targets for dragging a child: the parent's PADDING box + its other children's rects
657
+ * (visual-edit `getSnapTargets` :592). Pure geometry.
658
+ */
659
+ export function computeSnapTargets(
660
+ parentRect: Rect,
661
+ padding: Padding,
662
+ siblingRects: readonly Rect[],
663
+ ): { paddingBox: Rect; siblingRects: Rect[] } {
664
+ return {
665
+ paddingBox: {
666
+ x: parentRect.x + padding.left,
667
+ y: parentRect.y + padding.top,
668
+ width: parentRect.width - padding.left - padding.right,
669
+ height: parentRect.height - padding.top - padding.bottom,
670
+ },
671
+ siblingRects: siblingRects.filter((r) => r.width > 0 && r.height > 0),
672
+ };
673
+ }
674
+
675
+ /** An empty-container candidate (an OID element with no visible children/text). */
676
+ export interface EmptyCandidate {
677
+ oid: string;
678
+ rect: Rect;
679
+ displayName: string;
680
+ hasVisibleChildren: boolean;
681
+ hasText: boolean;
682
+ }
683
+
684
+ /**
685
+ * Empty-container hint targets: OID elements with no visible children, no text, and a
686
+ * collapsed dimension (< 8px) — shown as a placeholder so an empty flex/grid container is
687
+ * still selectable (visual-edit `getEmptyContainers` :563). The placeholder rect is grown
688
+ * to a minimum tappable size AROUND the measured box. Keeping the measured center fixed is
689
+ * load-bearing: a zero-width/height flex item denotes a line/point, and growing only toward
690
+ * the bottom-right makes the grey dashed hint appear displaced from that authored position.
691
+ */
692
+ export function findEmptyContainers(
693
+ candidates: readonly EmptyCandidate[],
694
+ ): { oid: string; rect: Rect; displayName: string }[] {
695
+ const out: { oid: string; rect: Rect; displayName: string }[] = [];
696
+ for (const c of candidates) {
697
+ if (c.hasVisibleChildren || c.hasText) continue;
698
+ if (c.rect.width >= 8 && c.rect.height >= 8) continue;
699
+ const width = Math.max(c.rect.width, 40);
700
+ const height = Math.max(c.rect.height, 24);
701
+ out.push({
702
+ oid: c.oid,
703
+ displayName: c.displayName,
704
+ rect: {
705
+ x: c.rect.x - (width - c.rect.width) / 2,
706
+ y: c.rect.y - (height - c.rect.height) / 2,
707
+ width,
708
+ height,
709
+ },
710
+ });
711
+ }
712
+ return out;
713
+ }
714
+
715
+ const TRANSPARENT_BG = new Set(['', 'transparent', 'rgba(0, 0, 0, 0)']);
716
+
717
+ /** Is a computed background color effectively transparent? */
718
+ export function isTransparentBackground(bg: string): boolean {
719
+ return TRANSPARENT_BG.has(bg);
720
+ }
721
+
722
+ /**
723
+ * Eyedropper: the effective background color at a point — the first non-transparent
724
+ * background walking from the hit element up its ancestor chain, else `#fff` (visual-edit
725
+ * `getColorAtPoint` :667 / `getEffectiveBackground` :63). `bgChain` is hit-element-first.
726
+ */
727
+ export function effectiveColorFromChain(bgChain: readonly string[]): string {
728
+ for (const bg of bgChain) if (!isTransparentBackground(bg)) return bg;
729
+ return '#fff';
730
+ }
731
+
732
+ const WEB_SAFE_FONTS = [
733
+ 'Arial',
734
+ 'Helvetica',
735
+ 'Times New Roman',
736
+ 'Georgia',
737
+ 'Verdana',
738
+ 'Courier New',
739
+ 'Impact',
740
+ 'Trebuchet MS',
741
+ 'Palatino Linotype',
742
+ 'Lucida Console',
743
+ 'monospace',
744
+ 'sans-serif',
745
+ 'serif',
746
+ ];
747
+
748
+ /** The available font families: the loaded fonts (quotes stripped) merged with the
749
+ * web-safe fallbacks, de-duped and sorted (visual-edit `getAvailableFonts` :677). */
750
+ export function mergeFonts(loaded: readonly string[] = []): string[] {
751
+ const fonts = new Set<string>();
752
+ for (const f of loaded) fonts.add(f.replace(/^["']|["']$/g, ''));
753
+ for (const f of WEB_SAFE_FONTS) fonts.add(f);
754
+ return [...fonts].sort((a, b) => a.localeCompare(b));
755
+ }
756
+
757
+ /** Browser wrapper: enumerate `document.fonts` families merged with the web-safe list.
758
+ * Returns just the web-safe list under a headless (no `document.fonts`) environment. */
759
+ export function getAvailableFonts(): string[] {
760
+ const g = globalThis as { document?: { fonts?: Iterable<{ family: string }> } };
761
+ const loaded: string[] = [];
762
+ const docFonts = g.document?.fonts;
763
+ if (docFonts) for (const f of docFonts) loaded.push(f.family);
764
+ return mergeFonts(loaded);
765
+ }
766
+
767
+ function readRootComputed(): (ComputedStyleLike & ArrayLike<string>) | undefined {
768
+ const g = globalThis as {
769
+ window?: { getComputedStyle?: (e: unknown) => ComputedStyleLike & ArrayLike<string> };
770
+ document?: { documentElement?: unknown };
771
+ };
772
+ const root = g.document?.documentElement;
773
+ if (!root || !g.window?.getComputedStyle) return undefined;
774
+ return g.window.getComputedStyle(root);
775
+ }