@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,336 @@
1
+ /**
2
+ * The editor's MODULE DOORWAYS: synthetic ES modules that statically re-export
3
+ * a fixed set of members, so the editor SHELL reaches a package through the
4
+ * OPENED PROJECT's Vite graph instead of through its own prebuilt bundle.
5
+ *
6
+ * One plugin, one declarative table per doorway. Everything below is the same
7
+ * two-line mechanism — `resolveId` maps `/__vgai-<name>` to a `\0`-prefixed
8
+ * virtual id, `load` answers with a literal string of `export … from '<bare
9
+ * specifier>'` lines — and the ONLY thing that ever differed between the five
10
+ * was the specifier table, so the tables are the module's data and the plugin
11
+ * machinery is written once.
12
+ *
13
+ * ## Why a doorway exists at all
14
+ *
15
+ * Under the PACKAGED runtime (`server/packaged.ts` — a `@vgai/editor` npm
16
+ * package with no monorepo checkout) the editor shell is a prebuilt production
17
+ * bundle with its own React, three, `@react-three/fiber`, `pixi.js`,
18
+ * `@pixi/react` and `@storybook/react` inlined, while the opened project's
19
+ * source is served by a SEPARATE, project-rooted Vite instance that resolves
20
+ * those same bare specifiers from the PROJECT's `node_modules`. A bare static
21
+ * `import` in shell code therefore holds a DIFFERENT module instance than the
22
+ * objects it is pointed at. A doorway is how the shell asks the project's graph
23
+ * for the same identity the project itself resolved: the synthetic body's
24
+ * specifiers go through that instance's own transform-time resolver and its own
25
+ * `optimizeDeps` prebundle cache, exactly the way a project entry module's own
26
+ * `import … from 'react'` does.
27
+ *
28
+ * `dev.ts` has no such split — one Vite
29
+ * instance, and the repo-root `vite.config.ts`'s `resolve.dedupe` already
30
+ * collapses `react`/`three`/`pixi.js`/`@pixi/react`/`@react-three/fiber` onto
31
+ * one instance — so this plugin is registered ONLY on the packaged runtime's
32
+ * project-rooted instance, plus the root `vitest.config.ts` (two doorways
33
+ * there, so the branch is exercisable headlessly).
34
+ *
35
+ * ## Why the doorways stay SEPARATE modules
36
+ *
37
+ * The plugin merges; the MODULES deliberately do not. Each doorway is fetched
38
+ * only when the lane that needs it actually mounts, so its packages are only
39
+ * ever demanded of a project that has them:
40
+ *
41
+ * - a DOM/canvas-only project must not resolve `@react-three/fiber` merely to
42
+ * mount an ordinary React root (which is why the r3f rows are not on the
43
+ * react-world doorway — keeping them there meant a valid 2D project could
44
+ * not boot the packaged editor without installing an unrelated renderer
45
+ * stack), nor a three-only project `@pixi/react`;
46
+ * - an INGEST root's whole premise is a game that brought its OWN stack, so
47
+ * the three-ingest doorway does not borrow `/__vgai-r3f-runtime` even though
48
+ * that module already publishes `projectThree` and reusing it would be one
49
+ * line: a vendored plain-three game has no Fiber installed, and demanding it
50
+ * would break the exact case the doorway closes;
51
+ * - `@storybook/react` is a devDependency a project may drop, so a project
52
+ * with no stories must never pay for it and a project missing it must lose
53
+ * only the story lane (with an error naming the missing package, surfaced by
54
+ * `src/story-dom-runtime.ts`), never react-world mounting.
55
+ *
56
+ * ## The measured defects, per doorway
57
+ *
58
+ * These are the failures each row set was bought with. None of them reproduce
59
+ * from a checkout — every one needs a real packaged build.
60
+ *
61
+ * ### `/__vgai-react-world-runtime` (`REACT_WORLD_DOORWAY`)
62
+ *
63
+ * Mounting a react world with `createRoot` from the editor's own bundle while
64
+ * the entry component's hooks ran against the project's `react` produced two
65
+ * React module instances: `useContext`/`useState` read and wrote different
66
+ * internal singletons, and `useContext` threw on a `null` dispatcher (confirmed
67
+ * live; see `server/packaged.ts`'s header, "React-world OID authoring parity",
68
+ * and `src/react-mount-runtime.ts`'s `resolveReactRootMountRuntime`).
69
+ *
70
+ * A real-browser run then caught a SECOND bug the wiring tests could not see:
71
+ * `flushSync` must come from bare `react-dom`, and this instance's
72
+ * `optimizeDeps` uses a project-entry-scoped crawl, so an injected bare
73
+ * specifier the crawl cannot see is served RAW — `react-dom`'s package entry
74
+ * re-exports its implementation through a `NODE_ENV`-conditional `require(...)`
75
+ * the raw-serve path cannot see through. Because a doorway is ONE ES module
76
+ * with several `export … from` statements, that single broken re-export sinks
77
+ * the whole dynamic import, breaking even Play mode's `ReactRootAdapter.mount()`
78
+ * which never touches `flushSync`:
79
+ *
80
+ * SyntaxError: The requested module '/node_modules/react-dom/index.js'
81
+ * does not provide an export named 'flushSync'
82
+ *
83
+ * — gone once bare `react-dom` was in `optimizeDeps.include`, in the same run.
84
+ * That is what `EDITOR_RUNTIME_MODULE_SPECIFIERS` (below, read by
85
+ * `server/project-optimize-deps-entries.ts`) exists to keep true.
86
+ *
87
+ * WHICH react the graph then points at is not this module's business and has
88
+ * changed: `packaged.ts` redirects every React specifier in this graph to the
89
+ * editor SHELL's own built React chunks (`vite-plugin-shared-react.ts`), so the
90
+ * page has exactly one React the way `dev.ts` always did. The contract is
91
+ * unchanged and still load-bearing — the mount call and the entry component's
92
+ * hooks must resolve `react` through the SAME graph, whatever that graph points
93
+ * at.
94
+ *
95
+ * ### `/__vgai-canvas-runtime` (`CANVAS_DOORWAY`)
96
+ *
97
+ * `src/authoring/canvas-design-mount.ts` and `src/binding-resolver.ts` are
98
+ * SHELL modules. A bare `await import('@vgai/game-runtime/canvas-react')` there built the
99
+ * adapter — and thus called `createRoot` and `extend` — with the SHELL's
100
+ * copies, then rendered the PROJECT's world component inside it. Measured on a
101
+ * packaged build against `examples/retro-shooter`:
102
+ *
103
+ * Invalid hook call … more than one copy of React in the same app (×12)
104
+ * TypeError: Cannot read properties of null (reading 'useSyncExternalStore')
105
+ * [design-time-layers] world "world" (canvas) failed to mount:
106
+ * canvas world "world": no first commit within 10s
107
+ *
108
+ * — the canvas world never design-mounted, and the Scene view was a Boundary
109
+ * node.
110
+ *
111
+ * `projectPixi` rides along because mounting is only half of what the editor
112
+ * does to a canvas world. Everything AFTERWARDS — the authoring adapter that
113
+ * duplicates a node, the drop that loads a texture, the capture trap an ingest
114
+ * root installs, the preview that photographs a selection — is SHELL code
115
+ * holding `pixi.js` VALUES, and those values came from a different module
116
+ * instance than the objects they point at. Four measured failures:
117
+ *
118
+ * - `object.constructor === Container` is FALSE for every project node, so
119
+ * `PixiAuthoringAdapter`'s duplicate gate refuses a plain project Container
120
+ * with the sentence it reserves for a game's own subclass;
121
+ * - `Assets.load` reads the SHELL's cache, so an image dropped on the world is
122
+ * fetched and decoded a second time into a texture the project's own loader
123
+ * has never heard of;
124
+ * - `installSceneCapture2D` traps the SHELL's `Application.prototype`, which an
125
+ * ingested game never calls — MEASURED on a packaged build of the
126
+ * `bunnymark` ingest fixture, the mount died with the engine's own words:
127
+ * "the game never rendered, or it bundles its own (un-shared) copy of
128
+ * pixi.js" (8s of visible time, then the whole root failed by name);
129
+ * - a selection preview clones a project subtree through a five-way
130
+ * `instanceof` chain of SHELL classes, which every branch misses, and renders
131
+ * the result on a SHELL `Application` against the project's GPU textures.
132
+ *
133
+ * So, stated once: A CANVAS SURFACE HOLDS ONE PIXI NAMESPACE, and it is the one
134
+ * the graph its objects came from resolved. The mount site chooses it
135
+ * (`resolveCanvasPixiForEditor`) and hands it to whatever it constructs;
136
+ * nothing downstream reaches for a static import. `CanvasHostContext` carries
137
+ * no renderer namespace (the mount calls `extend(PIXI)` with its OWN `pixi.js`
138
+ * import, which is the project's once this doorway resolves it), so the MOUNT
139
+ * needs nothing further.
140
+ *
141
+ * ### `/__vgai-three-ingest-runtime` (`THREE_INGEST_DOORWAY`)
142
+ *
143
+ * `src/authoring/ingest-root-adapter.ts` is SHELL code, and it installed the
144
+ * render accessor trap on the `three` it statically imported — while the
145
+ * ingested game's entry is served as `/@fs/<project>/…` by the project-rooted
146
+ * Vite and therefore resolves the PROJECT's `three`. The trap sat on a
147
+ * `WebGLRenderer.prototype` the game never constructs. The engine states the
148
+ * invariant in `adapter/ingest/scene-capture.ts`'s own header — "every trap
149
+ * must be installed on the SAME `three` module/addon instance the game uses" —
150
+ * and says exactly what a violation looks like. MEASURED on a packaged build
151
+ * (published `@vgai/editor@0.5.20`, real npm install) against a ~30-line
152
+ * unmodified three.js game declared as a `{ surface: 'three', ingest: {} }`
153
+ * root:
154
+ *
155
+ * WARNING: Multiple instances of Three.js being imported.
156
+ * Scene capture timed out after 15000ms of VISIBLE time (0ms
157
+ * browser-suspended …) — the game never rendered, or it bundles its own
158
+ * (un-shared) copy of three.
159
+ *
160
+ * — three.js's own duplicate-instance guard naming the cause, beside the mount
161
+ * failing by name 15 seconds later. The ADDONS ride along because they are the
162
+ * same identity question: `EffectComposer` and `CSS3DRenderer` are FILES inside
163
+ * the `three` package tree, so an unmodified game's `three/addons/…` import
164
+ * resolves to the copy beside its own `three`, and trapping the shell's would
165
+ * miss a composer-driven or CSS3D-driven game for precisely that reason.
166
+ *
167
+ * ### `/__vgai-story-runtime` (`STORY_DOORWAY`)
168
+ *
169
+ * A CSF module is dynamically imported through the project's Vite graph
170
+ * (`src/stories/story-discovery.ts`'s `/@fs/` import), so its components' hooks
171
+ * resolve against the PROJECT's own `react` — while `mountIsolatedStory`
172
+ * (`StoryPreviewMount.tsx`) rendered them with the editor SPA's statically
173
+ * bundled `react-dom`, and `compose-project-stories.ts` composed them with the
174
+ * editor's own bundled `@storybook/react`. Two React module instances: every
175
+ * story render died on "Invalid hook call" — confirmed live in a package-native
176
+ * project, where the Stories panel and the `vgai screenshot` story lane were
177
+ * both dead.
178
+ *
179
+ * ### `/__vgai-r3f-runtime` (`R3F_DOORWAY`)
180
+ *
181
+ * The three lane's original doorway, and the pattern the canvas and
182
+ * three-ingest ones were transcribed from: the R3F entry adjudicator, plus
183
+ * `projectThree` for the same reason `projectPixi` exists on the canvas
184
+ * doorway.
185
+ *
186
+ * ## Why the module BODY is exported (`doorwayModuleSource`)
187
+ *
188
+ * A synthesized module hangs off no file the `optimizeDeps` crawl can reach, so
189
+ * its specifiers were discovered only when a lane first mounted — mid-session —
190
+ * which re-optimizes and hard-reloads the controlling tab. Measured on a real
191
+ * canonical-Pixi project with a cold `node_modules/.vite`: the boot pass
192
+ * prebundled 19 deps; one request for the synthetic modules took it to 21,
193
+ * adding `three` and `@react-three/fiber` — two optimizer waves, two reloads.
194
+ * `server/project-optimize-deps-entries.ts` closes that by reading
195
+ * `EDITOR_RUNTIME_MODULE_SPECIFIERS` out of the SAME strings the browser is
196
+ * served, which is what stops the prebundle list from drifting from what the
197
+ * modules actually import.
198
+ */
199
+ import { STORY_RUNTIME_PATH } from '@volter/editor-sdk/host';
200
+ import type { Plugin } from 'vite';
201
+
202
+ /** One `from '<specifier>'` line of a doorway's synthetic module body. */
203
+ export interface ModuleDoorwayRow {
204
+ /** The bare (or aliased) specifier this row re-exports from. */
205
+ readonly from: string;
206
+ /**
207
+ * Named re-exports, verbatim and in order — `'createRoot as createR3FRoot'`
208
+ * is a single entry, because the rename IS the published name.
209
+ */
210
+ readonly names?: readonly string[];
211
+ /**
212
+ * Publish the specifier's whole namespace under this binding
213
+ * (`import * as projectThree from 'three'` + `export { projectThree }`).
214
+ * Namespace imports lead the module body and their re-export closes it, the
215
+ * way a hand-written module reads.
216
+ */
217
+ readonly namespace?: string;
218
+ }
219
+
220
+ /** A synthetic module the editor shell imports by URL to reach the project's graph. */
221
+ export interface ModuleDoorway {
222
+ /** The URL shell code imports (`/__vgai-r3f-runtime`). Part of the public API. */
223
+ readonly path: string;
224
+ readonly rows: readonly ModuleDoorwayRow[];
225
+ }
226
+
227
+ /**
228
+ * The dynamic-import-facing URL `src/binding-resolver.ts`'s
229
+ * `resolveReactRootMountRuntime` imports.
230
+ */
231
+ export const REACT_WORLD_RUNTIME_PATH = '/__vgai-react-world-runtime';
232
+ export const R3F_RUNTIME_PATH = '/__vgai-r3f-runtime';
233
+ export const CANVAS_RUNTIME_PATH = '/__vgai-canvas-runtime';
234
+ export const THREE_INGEST_RUNTIME_PATH = '/__vgai-three-ingest-runtime';
235
+ /** The dynamic-import-facing URL `stories/story-dom-runtime.ts` imports. Its
236
+ * one spelling is `@volter/editor-sdk/host`, because a reader reaches a host
237
+ * fact through the published door and never through this build tier; this
238
+ * plugin still owns WHAT is served at that address, below. */
239
+ export { STORY_RUNTIME_PATH };
240
+
241
+ export const R3F_DOORWAY: ModuleDoorway = {
242
+ path: R3F_RUNTIME_PATH,
243
+ rows: [
244
+ { from: 'three', namespace: 'projectThree' },
245
+ { from: 'react', names: ['createElement'] },
246
+ {
247
+ from: '@react-three/fiber',
248
+ names: ['createRoot as createR3FRoot', 'extend as extendThree'],
249
+ },
250
+ ],
251
+ };
252
+
253
+ export const THREE_INGEST_DOORWAY: ModuleDoorway = {
254
+ path: THREE_INGEST_RUNTIME_PATH,
255
+ rows: [
256
+ { from: 'three', namespace: 'projectThree' },
257
+ {
258
+ from: 'three/examples/jsm/postprocessing/EffectComposer.js',
259
+ names: ['EffectComposer'],
260
+ },
261
+ {
262
+ from: 'three/examples/jsm/renderers/CSS3DRenderer.js',
263
+ names: ['CSS3DRenderer'],
264
+ },
265
+ ],
266
+ };
267
+
268
+ export const STORY_DOORWAY: ModuleDoorway = {
269
+ path: STORY_RUNTIME_PATH,
270
+ rows: [
271
+ { from: '@storybook/react', names: ['composeStories', 'setProjectAnnotations'] },
272
+ { from: 'react-dom', names: ['flushSync'] },
273
+ { from: 'react-dom/client', names: ['createRoot'] },
274
+ ],
275
+ };
276
+
277
+ /**
278
+ * Every doorway the PACKAGED runtime serves, in registration order.
279
+ *
280
+ * `vitest.config.ts` deliberately registers a SUBSET (react-world + story), and
281
+ * `dev.ts` registers none — see the header for why a doorway is only ever
282
+ * served to a lane that asked for it.
283
+ */
284
+ export const PACKAGED_MODULE_DOORWAYS: readonly ModuleDoorway[] = [
285
+ R3F_DOORWAY,
286
+ THREE_INGEST_DOORWAY,
287
+ STORY_DOORWAY,
288
+ ];
289
+
290
+ /**
291
+ * The exact module text a doorway is served as — a literal string of STATIC
292
+ * `import`/`export … from` lines and nothing else, so every specifier goes
293
+ * through the serving instance's own resolver.
294
+ */
295
+ export function doorwayModuleSource(doorway: ModuleDoorway): string {
296
+ const lines: string[] = [];
297
+ for (const row of doorway.rows) {
298
+ if (row.namespace) lines.push(`import * as ${row.namespace} from '${row.from}';`);
299
+ }
300
+ for (const row of doorway.rows) {
301
+ if (!row.names || row.names.length === 0) continue;
302
+ lines.push(`export { ${row.names.join(', ')} } from '${row.from}';`);
303
+ }
304
+ for (const row of doorway.rows) {
305
+ if (row.namespace) lines.push(`export { ${row.namespace} };`);
306
+ }
307
+ return lines.join('\n');
308
+ }
309
+
310
+ /** A doorway's private virtual id — `\0`-prefixed so no other plugin claims it. */
311
+ function virtualIdOf(doorway: ModuleDoorway): string {
312
+ return `\0vgai${doorway.path.replace(/^\/__vgai/, '')}`;
313
+ }
314
+
315
+ /**
316
+ * The ONE plugin serving every doorway handed to it.
317
+ *
318
+ * Registered per host with the doorways that host is meant to answer for, which
319
+ * is the whole conditional cost model: a doorway not in this list is not a
320
+ * module the graph can reach, so its packages are never demanded.
321
+ */
322
+ export function moduleDoorwaysPlugin(doorways: readonly ModuleDoorway[]): Plugin {
323
+ const byPath = new Map(doorways.map((doorway) => [doorway.path, virtualIdOf(doorway)]));
324
+ const bodies = new Map(
325
+ doorways.map((doorway) => [virtualIdOf(doorway), doorwayModuleSource(doorway)]),
326
+ );
327
+ return {
328
+ name: 'vgai-module-doorways',
329
+ resolveId(id) {
330
+ return byPath.get(id);
331
+ },
332
+ load(id) {
333
+ return bodies.get(id);
334
+ },
335
+ };
336
+ }
@@ -0,0 +1,197 @@
1
+ /**
2
+ * `vgai:contributions/<package>` — a package's DECLARED contributions, read at
3
+ * build/serve time and served as a module of static `import()`s.
4
+ *
5
+ * A PRODUCT is code (ARCHITECTURE-CORE §The target shape, rule 8: "Compositions
6
+ * are code; the frame's and the loader's manifests are declarations and stay").
7
+ * `packages/game-editor/src/index.ts` and `packages/model-editor/src/index.ts`
8
+ * name the packages they mount, in TypeScript, and each name is spelled as an
9
+ * import of this virtual module:
10
+ *
11
+ * import blender from 'vgai:contributions/@vgai/blender';
12
+ *
13
+ * whose body this plugin synthesizes from that package's own
14
+ * `package.json#vgai.contributions`:
15
+ *
16
+ * export default [
17
+ * { entryPath: '@vgai/blender/contributions/blender.command.ts',
18
+ * load: () => import('@vgai/blender/contributions/blender.command') },
19
+ * …
20
+ * ];
21
+ *
22
+ * The declaration is the ONE source. Nothing is committed that a script
23
+ * generates, and a package that grows a contribution grows every product that
24
+ * names it with no second edit anywhere — which is the defect the generated
25
+ * table (`builds.generated.ts`, 529 committed lines derived from `builds/*.json`)
26
+ * existed to remove and then re-introduced from the other side: the table was
27
+ * committed, so it went stale, and a pre-commit check had to exist to notice.
28
+ *
29
+ * WHY A PLUGIN AND NOT `import.meta.glob`. A glob is a path pattern over THIS
30
+ * package's tree; what a product mounts is another package's own list, and a
31
+ * package's contributions live behind its export map, not at a path a consumer
32
+ * may guess. So the plugin reads the manifest the loader already reads
33
+ * (`server/project-tools.ts`'s `packageContributionModules` reads the same key
34
+ * for a PROJECT's declared packages) and emits the same `{ entryPath, load }`
35
+ * shape `tool-loader.ts` consumes. `vite-plugin-module-doorways.ts` is the
36
+ * precedent for the mechanism: `resolveId` maps a private id, `load` answers
37
+ * with a literal module body of static statements, and every specifier in it
38
+ * goes through the serving instance's own resolver.
39
+ *
40
+ * THE `entryPath` IS THE PACKAGE SPECIFIER, with its extension, because that is
41
+ * what the SESSION reports for the same module (`project-tools.ts` records a
42
+ * package's contribution by the manifest's own `./contributions/x.ts` spelling)
43
+ * and `tool-loader.ts` dedupes a package the product bundles against one the
44
+ * open project declares BY THAT STRING. The `load` import drops the extension
45
+ * for the same reason the old generator did: `@vgai/x/contributions/*` is an
46
+ * export-map wildcard, and the bundler resolves the extension.
47
+ *
48
+ * WHERE THE MANIFEST IS FOUND. From the IMPORTER — the product module doing the
49
+ * importing — through Node resolution of `<name>/package.json`, so the product
50
+ * reads the package its own install resolves. `resolveId` is the only hook with
51
+ * an importer, so it resolves the manifest and remembers it for `load`.
52
+ */
53
+
54
+ import { readFileSync } from 'node:fs';
55
+ import { createRequire } from 'node:module';
56
+ import { dirname, isAbsolute, join } from 'node:path';
57
+ import { pathToFileURL } from 'node:url';
58
+ import type { Plugin } from 'vite';
59
+
60
+ /** The specifier prefix a product writes. Part of the kit's public surface: a
61
+ * product package's source contains this string and nothing else about how a
62
+ * contribution is found. */
63
+ export const PRODUCT_CONTRIBUTIONS_PREFIX = 'vgai:contributions/';
64
+
65
+ /** One contribution a product bundles: the package specifier `tool-loader.ts`
66
+ * records as the module's `file`, and the lazy import the bundler follows. */
67
+ export interface BundledContribution {
68
+ readonly entryPath: string;
69
+ readonly load: () => Promise<unknown>;
70
+ }
71
+
72
+ /** The module text served for one package's declared contributions. Exported so
73
+ * the closure meter can read the same list this serves without re-deriving the
74
+ * rule (`scripts/validate-editor-closure.mjs`). */
75
+ export function productContributionsModuleSource(
76
+ packageName: string,
77
+ declared: readonly string[],
78
+ ): string {
79
+ const rows = declared.map((entry) => {
80
+ const relative = entry.replace(/^\.\//, '');
81
+ const specifier = `${packageName}/${relative}`;
82
+ const importable = specifier.replace(/\.(tsx|ts|jsx|js)$/, '');
83
+ return (
84
+ ` { entryPath: ${JSON.stringify(specifier)}, ` +
85
+ `load: () => import(${JSON.stringify(importable)}) },`
86
+ );
87
+ });
88
+ return [
89
+ `// ${packageName}'s package.json#vgai.contributions, read at build time by`,
90
+ '// packages/editor/vite-plugin-product-contributions.ts.',
91
+ 'export default [',
92
+ ...rows,
93
+ '];',
94
+ '',
95
+ ].join('\n');
96
+ }
97
+
98
+ /** A package's declared contribution modules, or a throw naming the package. */
99
+ export function readDeclaredContributions(manifestPath: string, packageName: string): string[] {
100
+ let manifest: { vgai?: { contributions?: unknown } };
101
+ try {
102
+ manifest = JSON.parse(readFileSync(manifestPath, 'utf8')) as typeof manifest;
103
+ } catch (error) {
104
+ throw new Error(
105
+ `${manifestPath} is not readable (${error instanceof Error ? error.message : String(error)}), ` +
106
+ `so ${packageName}'s contributions cannot be composed into this product.`,
107
+ );
108
+ }
109
+ const declared = manifest.vgai?.contributions;
110
+ if (declared === undefined)
111
+ throw new Error(
112
+ `${packageName} declares no package.json#vgai.contributions, so there is nothing for a ` +
113
+ 'product to mount from it. A package that contributes declares its modules there; a ' +
114
+ 'package that only exports code is imported by name instead.',
115
+ );
116
+ if (!Array.isArray(declared) || declared.some((entry) => typeof entry !== 'string'))
117
+ throw new Error(
118
+ `${packageName}'s package.json#vgai.contributions must be an array of ./-relative modules.`,
119
+ );
120
+ return declared as string[];
121
+ }
122
+
123
+ /**
124
+ * Resolve `<name>/package.json` from the importing module's own directory.
125
+ *
126
+ * `createRequire` walks `node_modules` upward exactly as the runtime does, so a
127
+ * product resolves the package version its own install carries — and in this
128
+ * workspace that is the checkout's symlink, which is the same file the estate
129
+ * scan reads.
130
+ */
131
+ function locateManifest(packageName: string, importer: string | undefined): string {
132
+ const from = importer && isAbsolute(importer) ? importer : join(process.cwd(), 'index.js');
133
+ const require = createRequire(pathToFileURL(from));
134
+ try {
135
+ return require.resolve(`${packageName}/package.json`);
136
+ } catch {
137
+ // An export map without a `./package.json` entry: fall back to the package
138
+ // directory Node resolves for the bare name's own files.
139
+ const resolvedFrom = createRequire(pathToFileURL(from));
140
+ const found = resolvedFrom.resolve(packageName);
141
+ let dir = dirname(found);
142
+ for (;;) {
143
+ const candidate = join(dir, 'package.json');
144
+ try {
145
+ if (JSON.parse(readFileSync(candidate, 'utf8')).name === packageName) return candidate;
146
+ } catch {
147
+ /* keep walking */
148
+ }
149
+ const parent = dirname(dir);
150
+ if (parent === dir)
151
+ throw new Error(
152
+ `${packageName} is not installed where ${from} can resolve it, so this product cannot ` +
153
+ 'mount its contributions. Declare it as a dependency of the product package.',
154
+ );
155
+ dir = parent;
156
+ }
157
+ }
158
+ }
159
+
160
+ /**
161
+ * The ONE plugin serving every `vgai:contributions/<package>` a product names.
162
+ *
163
+ * Registered on the repo-root `vite.config.ts` — which is both the product
164
+ * BUILD's config and the dev session's `configFile`
165
+ * (`packages/editor/server/dev.ts`), so one registration answers both hosts.
166
+ * The PACKAGED host's project-rooted instance never sees a product module (the
167
+ * product is a built chunk there), so it registers nothing.
168
+ */
169
+ export function productContributionsPlugin(): Plugin {
170
+ const manifests = new Map<string, string>();
171
+ return {
172
+ name: 'vgai-product-contributions',
173
+ resolveId(id, importer) {
174
+ if (!id.startsWith(PRODUCT_CONTRIBUTIONS_PREFIX)) return null;
175
+ const packageName = id.slice(PRODUCT_CONTRIBUTIONS_PREFIX.length);
176
+ if (packageName === '')
177
+ throw new Error(
178
+ `"${id}" names no package — the form is \`${PRODUCT_CONTRIBUTIONS_PREFIX}<package>\`.`,
179
+ );
180
+ const virtual = `\0${id}`;
181
+ manifests.set(virtual, locateManifest(packageName, importer));
182
+ return virtual;
183
+ },
184
+ load(id) {
185
+ const manifestPath = manifests.get(id);
186
+ if (manifestPath === undefined) return null;
187
+ const packageName = id.slice(`\0${PRODUCT_CONTRIBUTIONS_PREFIX}`.length);
188
+ // Watched, so a package that grows a contribution refreshes the product
189
+ // in a live session instead of waiting for a restart.
190
+ this.addWatchFile(manifestPath);
191
+ return productContributionsModuleSource(
192
+ packageName,
193
+ readDeclaredContributions(manifestPath, packageName),
194
+ );
195
+ },
196
+ };
197
+ }
@@ -0,0 +1,125 @@
1
+ /**
2
+ * vite-plugin-project-game-static — D-X2 (slice S1): the external-folder
3
+ * sibling of `vite-plugin-game-static.ts`. Serves the CURRENTLY OPEN
4
+ * project's own folder VERBATIM (no vite transform) at
5
+ * `/project-game-static/<path>` -> `<projectRoot>/<path>`, so a game's own
6
+ * data files reach it untransformed — an AssetPack `.json` spritesheet stays
7
+ * raw JSON instead of becoming an ESM module, the same R-X1 rationale
8
+ * `vite-plugin-game-static.ts`'s header records for the vendored route, just
9
+ * rooted at an arbitrary user folder.
10
+ *
11
+ * `getProjectRoot` is a THUNK, not a captured string: `open-project` can
12
+ * switch the current project live (`server/dev.ts`'s `onProjectOpened`
13
+ * callback), and this route must follow the CURRENT project root, not a
14
+ * boot-time snapshot — every request re-reads it. No project open (thunk
15
+ * returns `undefined`) -> `next()`, never a 5xx.
16
+ *
17
+ * `configureServer`-only: it exists to serve an OPENED project's files, which
18
+ * is a session's job and nothing else's.
19
+ */
20
+ import { readFile } from 'node:fs/promises';
21
+ import { extname, join, normalize, resolve, sep } from 'node:path';
22
+ import type { Plugin } from 'vite';
23
+ import { MIME } from './vite-plugin-game-static';
24
+
25
+ /**
26
+ * Resolve `rel` against `projectRoot`, refusing anything that escapes it.
27
+ * Plain `startsWith(root)` would wrongly admit a sibling folder that merely
28
+ * shares `root` as a string prefix (e.g. root `/a/b` and filePath `/a/bc/evil`)
29
+ * — the boundary must fall on a real path separator (or be an exact match).
30
+ * Returns `null` for an escape attempt.
31
+ */
32
+ function resolveInsideProjectRoot(projectRoot: string, rel: string): string | null {
33
+ const root = resolve(projectRoot);
34
+ const filePath = normalize(join(root, rel));
35
+ if (filePath === root || filePath.startsWith(root + sep)) return filePath;
36
+ return null;
37
+ }
38
+
39
+ /** `req.url`'s path portion (query stripped), project-root-relative (leading
40
+ * slash removed). Empty for the bare mount path (`/project-game-static`
41
+ * itself, with nothing after it). */
42
+ function requestRelPath(url: string | undefined): string {
43
+ // `.split('?')` always yields at least one element — `noUncheckedIndexedAccess`
44
+ // types index access as possibly-undefined regardless, so fall back to ''.
45
+ const path = (url ?? '').split('?')[0] ?? '';
46
+ return path.startsWith('/') ? path.slice(1) : path;
47
+ }
48
+
49
+ /**
50
+ * One `Range: bytes=…` header against a known size. Returns the inclusive
51
+ * range to send, `null` for "send the whole file" (absent, malformed, or a
52
+ * form this route does not implement — a multi-range request is legal to
53
+ * answer with the full body), or `'unsatisfiable'` for a start past the end,
54
+ * which must be a 416 rather than a silently clamped success.
55
+ */
56
+ export function parseByteRange(
57
+ header: string | string[] | undefined,
58
+ size: number,
59
+ ): { start: number; end: number } | 'unsatisfiable' | null {
60
+ if (typeof header !== 'string') return null;
61
+ const match = /^bytes=(\d*)-(\d*)$/.exec(header.trim());
62
+ if (!match) return null;
63
+ const [, rawStart, rawEnd] = match;
64
+ if (rawStart === '' && rawEnd === '') return null;
65
+ // A suffix range (`bytes=-500`) asks for the LAST n bytes.
66
+ const start = rawStart === '' ? Math.max(0, size - Number(rawEnd)) : Number(rawStart);
67
+ const end = rawStart === '' || rawEnd === '' ? size - 1 : Math.min(Number(rawEnd), size - 1);
68
+ if (!Number.isFinite(start) || !Number.isFinite(end)) return null;
69
+ if (size === 0 || start >= size || start > end) return 'unsatisfiable';
70
+ return { start, end };
71
+ }
72
+
73
+ export function projectGameStaticPlugin(getProjectRoot: () => string | undefined): Plugin {
74
+ return {
75
+ name: 'vgai-project-game-static',
76
+ configureServer(server) {
77
+ server.middlewares.use('/project-game-static', async (req, res, next) => {
78
+ const projectRoot = getProjectRoot();
79
+ if (!projectRoot) return next(); // no project open — nothing to serve
80
+
81
+ const rel = requestRelPath(req.url);
82
+ if (!rel) return next();
83
+
84
+ const filePath = resolveInsideProjectRoot(projectRoot, rel);
85
+ if (!filePath) {
86
+ res.statusCode = 403;
87
+ res.end('forbidden');
88
+ return;
89
+ }
90
+
91
+ try {
92
+ const buf = await readFile(filePath);
93
+ res.setHeader('Content-Type', MIME[extname(filePath)] ?? 'application/octet-stream');
94
+ res.setHeader('Cache-Control', 'no-cache');
95
+ // RANGE, and it is load-bearing for video. A `<video>` element seeks by
96
+ // asking for a byte range, and a route that answers every request with
97
+ // the whole file and no `Accept-Ranges` cannot be seeked at all: the
98
+ // clip's own first frame never paints (measured — a reference tile and
99
+ // its Asset Lab document both showed black over a bright opening
100
+ // frame), and the scrubber does nothing. Everything else is unaffected:
101
+ // a request with no `Range` still gets the ordinary 200 below.
102
+ res.setHeader('Accept-Ranges', 'bytes');
103
+ const range = parseByteRange(req.headers['range'], buf.byteLength);
104
+ if (range === 'unsatisfiable') {
105
+ res.statusCode = 416;
106
+ res.setHeader('Content-Range', `bytes */${buf.byteLength}`);
107
+ res.end();
108
+ return;
109
+ }
110
+ if (range) {
111
+ res.statusCode = 206;
112
+ res.setHeader('Content-Range', `bytes ${range.start}-${range.end}/${buf.byteLength}`);
113
+ res.setHeader('Content-Length', range.end - range.start + 1);
114
+ res.end(buf.subarray(range.start, range.end + 1));
115
+ return;
116
+ }
117
+ res.statusCode = 200;
118
+ res.end(buf);
119
+ } catch {
120
+ next();
121
+ }
122
+ });
123
+ },
124
+ };
125
+ }