@vgai/editor 0.2.0 → 0.4.0-canary.20260715.1

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 (430) hide show
  1. package/README.md +24 -0
  2. package/dist/assets/axe-CyiTVRi6.js +30 -0
  3. package/dist/assets/browserAll-fGZ_P1P8.js +1 -0
  4. package/dist/assets/create-runtime-BzSHBTYw.js +1 -0
  5. package/dist/assets/game-DQ7YHNS8.js +1 -0
  6. package/dist/assets/game-DX6Obomf.js +1 -0
  7. package/dist/assets/game-DoUJj8vY.js +1 -0
  8. package/dist/assets/{game-xsOho_wg.js → game-HqybI_X7.js} +3 -3
  9. package/dist/assets/game-NUAnyPkS.js +1 -0
  10. package/dist/assets/game-ck_dNIE6.js +1 -0
  11. package/dist/assets/{game-pt_1lQLv.js → game-hIf5LD4E.js} +1 -1
  12. package/dist/assets/game-loop-o2CcBMFY.js +1 -0
  13. package/dist/assets/{game-source-CvidN7AB.js → game-source-C8HM7gbP.js} +1 -1
  14. package/dist/assets/{game-BI111o5f.js → game-uR_lv3Mp.js} +3 -3
  15. package/dist/assets/index-B-HA1uu3.js +15412 -0
  16. package/dist/assets/{index-Bp5cecD6.js → index-CSBAZwMx.js} +2 -2
  17. package/dist/assets/{index-DL7RcQ0n.js → index-CoSRCKPS.js} +1 -1
  18. package/dist/assets/{index-Cs8xwv3e.js → index-D93bBuUl.js} +1 -1
  19. package/dist/assets/index-bu01fqch.css +1 -0
  20. package/dist/assets/ingest-siblings-CCkkE2h7.js +1 -0
  21. package/dist/assets/mount-manifest-B2ECssU2.js +1 -0
  22. package/dist/assets/react-18-Bmj05S8J.js +1 -0
  23. package/dist/assets/webworkerAll-BC6gMOLZ.js +1 -0
  24. package/dist/assets/world-documents-DXPcAEA0.js +1 -0
  25. package/dist/index.html +15 -13
  26. package/dist/ingest/racing-game/vgai.game.json +5 -4
  27. package/dist/ingest/simcity/vgai.game.json +5 -4
  28. package/dist/ingest/tanks/vgai.game.json +5 -4
  29. package/dist/project-scripts.bundle.js +3917 -0
  30. package/dist/scenes/untitled.vscn.json +2 -0
  31. package/dist-server/packaged.mjs +7718 -3436
  32. package/package.json +31 -4
  33. package/scripts/probe-reporter.ts +349 -0
  34. package/scripts/run-probe.ts +2260 -0
  35. package/server/asset-catalog-audit.ts +268 -0
  36. package/server/asset-catalog-v2.ts +146 -0
  37. package/server/asset-library-routes.ts +276 -58
  38. package/server/canonical-path.ts +1 -1
  39. package/server/dev.ts +148 -44
  40. package/server/editor-server.ts +888 -61
  41. package/server/editor-sse.ts +115 -4
  42. package/server/harness-chat-service.ts +796 -0
  43. package/server/local-asset-catalog.ts +157 -22
  44. package/server/packaged.ts +71 -21
  45. package/server/process-shutdown.ts +136 -0
  46. package/server/prod.ts +9 -6
  47. package/server/project-hmr-files.ts +41 -0
  48. package/server/project-operations.ts +343 -0
  49. package/server/project-optimize-deps-entries.ts +4 -4
  50. package/server/project-output-writer.ts +156 -0
  51. package/server/project-validation.ts +140 -0
  52. package/server/project-view.ts +8 -50
  53. package/server/server-utils.ts +75 -10
  54. package/server/session-registry.ts +12 -0
  55. package/src/EditorContext.tsx +107 -3
  56. package/src/action-registry.ts +115 -17
  57. package/src/adapter-resolver.ts +213 -478
  58. package/src/asset-events.ts +64 -1
  59. package/src/asset-preview.ts +906 -0
  60. package/src/asset-selection.ts +121 -0
  61. package/src/asset-workflow/asset-capabilities.ts +259 -0
  62. package/src/asset-workflow/asset-editor-errors.ts +46 -0
  63. package/src/asset-workflow/asset-import-pipeline.ts +176 -0
  64. package/src/asset-workflow/asset-library-query.ts +107 -0
  65. package/src/asset-workflow/asset-types.ts +192 -0
  66. package/src/asset-workflow/asset-workflow-quality.ts +65 -0
  67. package/src/asset-workflow/import-contract.ts +113 -0
  68. package/src/asset-workflow/model-conversion.ts +126 -0
  69. package/src/asset-workflow/model-inspection.ts +185 -0
  70. package/src/asset-workflow/project-asset-commands.ts +23 -0
  71. package/src/asset-workflow/project-asset-health.ts +153 -0
  72. package/src/asset-workflow/project-asset-operations.ts +119 -0
  73. package/src/asset-workflow/thumbnail-system.ts +172 -0
  74. package/src/authoring/active-systems.ts +15 -0
  75. package/src/authoring/boundary-authoring-adapter.ts +16 -5
  76. package/src/authoring/composite-authoring-adapter.ts +305 -124
  77. package/src/authoring/design-time-layers.ts +300 -117
  78. package/src/authoring/edit-mode-authoring.ts +278 -293
  79. package/src/authoring/embed-only-adapter.ts +4 -2
  80. package/src/authoring/first-party-hierarchy-menu.ts +7 -2
  81. package/src/authoring/first-party-inspector/AddSectionMenu.tsx +5 -12
  82. package/src/authoring/first-party-inspector/EnvironmentSection.tsx +53 -126
  83. package/src/authoring/first-party-inspector/HeaderSection.tsx +54 -65
  84. package/src/authoring/first-party-inspector/is-first-party-selection.ts +30 -11
  85. package/src/authoring/first-party-inspector/register.tsx +13 -2
  86. package/src/authoring/ingest-authoring-adapter.ts +142 -45
  87. package/src/authoring/mount-failure-report.ts +5 -5
  88. package/src/authoring/provenance.ts +41 -0
  89. package/src/authoring/react-dom-authoring-adapter.ts +92 -92
  90. package/src/authoring/react-inspector-section.tsx +489 -51
  91. package/src/authoring/react-world-authoring-adapter.ts +541 -306
  92. package/src/authoring/story-overlay.ts +1 -1
  93. package/src/authoring/story-types.ts +11 -0
  94. package/src/authoring/vgai-scene-authoring-adapter.ts +54 -25
  95. package/src/authoring/viewport-tool-context.ts +78 -0
  96. package/src/authoring/world-canvas-viewport-state.ts +35 -0
  97. package/src/authoring/world-hidden-viewport.ts +186 -0
  98. package/src/authoring/world-pan-state.ts +33 -17
  99. package/src/authoring/world-session-state.ts +1 -1
  100. package/src/authoring/world2d-authoring-adapter.ts +109 -52
  101. package/src/availability-tick.ts +56 -0
  102. package/src/browser-play-entry.ts +5 -5
  103. package/src/browser-project-scripts.ts +1 -0
  104. package/src/build-identity.ts +15 -0
  105. package/src/command-listener.ts +893 -19
  106. package/src/components/AlignToolbar.tsx +74 -63
  107. package/src/components/AppRoot.tsx +193 -26
  108. package/src/components/ApplicationMenus.tsx +272 -0
  109. package/src/components/AssetBrowser.tsx +1236 -296
  110. package/src/components/AssetEditorShell.tsx +141 -0
  111. package/src/components/AssetImportDetails.tsx +218 -0
  112. package/src/components/AssetLibraryPanel.tsx +14 -0
  113. package/src/components/CameraInfo.tsx +11 -20
  114. package/src/components/CenterDocuments.tsx +585 -0
  115. package/src/components/CommandPalette.tsx +75 -30
  116. package/src/components/ConsolePanel.css +55 -0
  117. package/src/components/ConsolePanel.tsx +57 -112
  118. package/src/components/DebugConsolePanel.tsx +461 -0
  119. package/src/components/DebuggerPanel.tsx +165 -0
  120. package/src/components/DefaultEditorLayout.tsx +167 -231
  121. package/src/components/GameHierarchy.tsx +873 -290
  122. package/src/components/GamePerformanceOverlay.tsx +46 -0
  123. package/src/components/HarnessChatPanel.tsx +2352 -0
  124. package/src/components/HistoryPanel.tsx +226 -0
  125. package/src/components/Inspector.tsx +153 -99
  126. package/src/components/InspectorToolSection.tsx +6 -4
  127. package/src/components/MountFailureBanner.tsx +31 -48
  128. package/src/components/NetworkSection.tsx +25 -14
  129. package/src/components/OnlineAssetBrowser.tsx +1116 -344
  130. package/src/components/OverlayReportBanner.tsx +38 -64
  131. package/src/components/PerformancePanel.tsx +206 -0
  132. package/src/components/PlayBar.tsx +93 -263
  133. package/src/components/PrefabSaveDialog.tsx +55 -127
  134. package/src/components/ProjectHeader.css +60 -0
  135. package/src/components/ProjectHeader.tsx +170 -105
  136. package/src/components/ProjectScreen.tsx +246 -184
  137. package/src/components/ReactCanvasControls.tsx +185 -0
  138. package/src/components/ResolutionPicker.tsx +85 -0
  139. package/src/components/RootActivateDialog.tsx +39 -68
  140. package/src/components/SaveDialog.tsx +55 -127
  141. package/src/components/SaveStatus.tsx +11 -29
  142. package/src/components/StartupLoadingScreen.tsx +96 -0
  143. package/src/components/StateWatchPanel.tsx +302 -0
  144. package/src/components/StatsOverlay.tsx +12 -5
  145. package/src/components/StatusBar.tsx +64 -0
  146. package/src/components/ThemeManagerDialog.css +89 -0
  147. package/src/components/ThemeManagerDialog.tsx +371 -0
  148. package/src/components/ToolHost.tsx +26 -15
  149. package/src/components/Toolbar.tsx +117 -214
  150. package/src/components/VgaiVoxelLogo.tsx +89 -0
  151. package/src/components/ViewportOverlay.tsx +97 -172
  152. package/src/components/ViewportPanel.tsx +130 -31
  153. package/src/components/WorkspaceDock.tsx +891 -0
  154. package/src/components/WorldSelectionOverlay.tsx +51 -63
  155. package/src/components/WorldTextEditor.tsx +9 -5
  156. package/src/components/asset-documents.tsx +390 -0
  157. package/src/components/asset-editor-persistence.ts +44 -0
  158. package/src/components/asset-selection-section.tsx +338 -0
  159. package/src/components/asset-viewers/AudioViewer.tsx +73 -21
  160. package/src/components/asset-viewers/GenericJsonViewer.tsx +26 -11
  161. package/src/components/asset-viewers/ImageViewer.tsx +43 -11
  162. package/src/components/asset-viewers/InputMapViewer.tsx +512 -134
  163. package/src/components/asset-viewers/MaterialAssetEditor.tsx +540 -0
  164. package/src/components/asset-viewers/ModelViewer.tsx +805 -121
  165. package/src/components/asset-viewers/OnlineAssetDetail.tsx +177 -60
  166. package/src/components/asset-viewers/SourceAssetViewer.tsx +121 -0
  167. package/src/components/asset-workflow.css +620 -0
  168. package/src/components/build-documents.tsx +696 -0
  169. package/src/components/core-utilities.tsx +75 -0
  170. package/src/components/data-documents.tsx +364 -0
  171. package/src/components/{DataPanel.tsx → data-editor.tsx} +138 -288
  172. package/src/components/debugger-panel-state.ts +57 -0
  173. package/src/components/inspector-widgets/AlignmentGrid.tsx +8 -14
  174. package/src/components/inspector-widgets/BorderEditor.tsx +41 -33
  175. package/src/components/inspector-widgets/ColorPicker.tsx +39 -39
  176. package/src/components/inspector-widgets/FontPicker.tsx +13 -21
  177. package/src/components/inspector-widgets/GradientEditor.tsx +11 -19
  178. package/src/components/inspector-widgets/ScrubbableInput.tsx +6 -3
  179. package/src/components/inspector-widgets/ShadowEditor.tsx +20 -33
  180. package/src/components/inspector-widgets/shared.tsx +90 -49
  181. package/src/components/inspectors/AnimationSection.tsx +39 -40
  182. package/src/components/inspectors/AudioSection.tsx +28 -39
  183. package/src/components/inspectors/BoneAttachmentSection.tsx +19 -24
  184. package/src/components/inspectors/CameraSection.tsx +14 -23
  185. package/src/components/inspectors/ComponentsSection.tsx +39 -43
  186. package/src/components/inspectors/JointsSection.tsx +34 -43
  187. package/src/components/inspectors/LightSection.tsx +90 -35
  188. package/src/components/inspectors/MaterialSection.tsx +137 -174
  189. package/src/components/inspectors/MeshSection.tsx +9 -17
  190. package/src/components/inspectors/NavigationSection.tsx +8 -15
  191. package/src/components/inspectors/ParticleSection.tsx +91 -76
  192. package/src/components/inspectors/PhysicsSection.tsx +42 -46
  193. package/src/components/inspectors/PostProcessingSection.tsx +28 -36
  194. package/src/components/inspectors/RenderingSection.tsx +12 -20
  195. package/src/components/inspectors/ShadowSection.tsx +7 -8
  196. package/src/components/inspectors/SplineSection.tsx +31 -42
  197. package/src/components/inspectors/TransformSection.tsx +14 -22
  198. package/src/components/patterns/Dialog.tsx +95 -0
  199. package/src/components/patterns/Fields.tsx +44 -0
  200. package/src/components/patterns/List.tsx +25 -0
  201. package/src/components/patterns/StateSurface.tsx +40 -0
  202. package/src/components/patterns/Surfaces.tsx +115 -0
  203. package/src/components/patterns/Tabs.tsx +80 -0
  204. package/src/components/patterns/Toolbar.tsx +51 -0
  205. package/src/components/patterns/Tree.tsx +72 -0
  206. package/src/components/primitives/Button.tsx +46 -0
  207. package/src/components/primitives/ColorInput.tsx +11 -47
  208. package/src/components/primitives/EditorIcon.tsx +99 -0
  209. package/src/components/primitives/FormControls.tsx +71 -0
  210. package/src/components/primitives/JsonInput.tsx +15 -2
  211. package/src/components/primitives/Layout.tsx +100 -0
  212. package/src/components/primitives/Menu.tsx +105 -0
  213. package/src/components/primitives/NumberInput.tsx +8 -35
  214. package/src/components/primitives/Panel.tsx +49 -44
  215. package/src/components/primitives/SectionHeader.tsx +10 -28
  216. package/src/components/primitives/Text.tsx +46 -0
  217. package/src/components/primitives/Tooltip.tsx +20 -12
  218. package/src/components/primitives/Vec3Input.tsx +3 -0
  219. package/src/components/primitives/banner-tones.ts +33 -0
  220. package/src/components/primitives/editor-icons.ts +102 -0
  221. package/src/components/primitives/panel-header-styles.ts +30 -0
  222. package/src/components/project-operation-documents.tsx +226 -0
  223. package/src/components/status-contributions.tsx +175 -0
  224. package/src/components/story-documents-register.ts +15 -0
  225. package/src/components/story-documents.tsx +1185 -0
  226. package/src/components/tool-documents.tsx +110 -0
  227. package/src/components/workspace-dock.css +293 -0
  228. package/src/components/workspace-history.ts +33 -0
  229. package/src/components/world-documents.tsx +145 -0
  230. package/src/components/xstate-documents.tsx +209 -0
  231. package/src/composite-screenshot.ts +248 -0
  232. package/src/design-system/index.ts +70 -0
  233. package/src/design-system-stories/Foundation.stories.tsx +183 -0
  234. package/src/design-system-stories/Patterns.stories.tsx +251 -0
  235. package/src/design-system-stories/Workspace.stories.tsx +538 -0
  236. package/src/doctor/report.ts +57 -13
  237. package/src/editor-api.ts +295 -31
  238. package/src/editor-compatibility.ts +200 -0
  239. package/src/editor-console.ts +35 -17
  240. package/src/editor-hotkeys.ts +85 -33
  241. package/src/editor-store.ts +538 -233
  242. package/src/editor-viewport.ts +160 -34
  243. package/src/entity-factory.ts +14 -3
  244. package/src/gizmo-registry.ts +21 -5
  245. package/src/harness-chat-editor-context.ts +37 -0
  246. package/src/harness-chat-indicator.ts +68 -0
  247. package/src/harness-chat-layout.ts +53 -0
  248. package/src/harness-chat-lifecycle.ts +170 -0
  249. package/src/harness-chat-reconnect.ts +85 -0
  250. package/src/harness-chat-types.ts +409 -0
  251. package/src/hierarchy-drop.ts +50 -0
  252. package/src/hierarchy-expansion-state.ts +100 -0
  253. package/src/hierarchy-menu-registry.ts +1 -1
  254. package/src/hierarchy-projection.ts +76 -0
  255. package/src/history/editor-session.ts +21 -0
  256. package/src/history/history-commands.ts +147 -0
  257. package/src/history/history-service.ts +904 -0
  258. package/src/history/json-history-resource.ts +165 -0
  259. package/src/history/persistence-coordinator.ts +35 -0
  260. package/src/history/project-file-history.ts +266 -0
  261. package/src/history/project-root-history-backends.ts +53 -0
  262. package/src/history/resource-registry.ts +209 -0
  263. package/src/history/snapshot-store.ts +108 -0
  264. package/src/history/source-history-backend.ts +374 -0
  265. package/src/history/types.ts +100 -0
  266. package/src/hmr-registration-group.ts +67 -0
  267. package/src/hmr-stable-react-context.ts +23 -0
  268. package/src/hosted-example.ts +12 -2
  269. package/src/hotkeys.ts +89 -18
  270. package/src/ingest/discovery-react.ts +9 -10
  271. package/src/ingest/discovery.ts +4 -4
  272. package/src/ingest/discovery2d.ts +5 -5
  273. package/src/ingest/games/bloom-composer/vgai.game.json +3 -3
  274. package/src/ingest/games/embed-bundle/vgai.game.json +3 -3
  275. package/src/ingest/games/games-fps/vgai.game.json +3 -3
  276. package/src/ingest/games/iframe-reachable/vgai.game.json +3 -3
  277. package/src/ingest/games/interactive-cubes/vgai.game.json +3 -3
  278. package/src/ingest/games/mismatched-three/vgai.game.json +3 -3
  279. package/src/ingest/games/own-three-bundled/vgai.game.json +3 -3
  280. package/src/ingest/games/pointerlock-maze/vgai.game.json +7 -4
  281. package/src/ingest/games-2d/bubbo-bubbo/vgai.game.json +3 -3
  282. package/src/ingest/games-2d/bunnymark/vgai.game.json +3 -3
  283. package/src/ingest/games-2d/flappy/vgai.game.json +3 -3
  284. package/src/ingest/games-2d/flappy-pixi/vgai.game.json +3 -3
  285. package/src/ingest/games-2d/puzzling-potions/vgai.game.json +3 -3
  286. package/src/ingest/games-2d/tilemap-camera/vgai.game.json +3 -3
  287. package/src/ingest/games-react/react-rpg/vgai.game.json +3 -3
  288. package/src/ingest/types.ts +1 -1
  289. package/src/ingest-mode.ts +47 -52
  290. package/src/ingest-siblings.ts +23 -33
  291. package/src/initial-scene.ts +1 -2
  292. package/src/main.tsx +16 -8
  293. package/src/manifest-project.ts +10 -12
  294. package/src/model-thumbnail.ts +261 -26
  295. package/src/module-mode.ts +44 -50
  296. package/src/play-log-events.ts +26 -0
  297. package/src/play-mode.ts +495 -401
  298. package/src/play-scene-adoption.ts +23 -0
  299. package/src/playground/main.ts +68 -24
  300. package/src/playwright-shim.ts +473 -0
  301. package/src/project-manager.ts +90 -10
  302. package/src/project-operations.ts +112 -0
  303. package/src/project-story-discovery.ts +25 -0
  304. package/src/project-tool-discovery.ts +43 -0
  305. package/src/scene-serializer.ts +0 -6
  306. package/src/scene-sync.ts +7 -2
  307. package/src/script-loader.ts +3 -3
  308. package/src/skeleton-helper.ts +57 -0
  309. package/src/storage/seed.ts +68 -8
  310. package/src/stories/StoryPreviewMount.tsx +265 -0
  311. package/src/stories/action-stories.fixture.tsx +44 -0
  312. package/src/stories/button-stories.fixture.tsx +50 -0
  313. package/src/stories/compose-project-stories.ts +182 -0
  314. package/src/stories/loader-stories.fixture.tsx +53 -0
  315. package/src/stories/story-discovery.ts +130 -0
  316. package/src/stories/story-registry.ts +146 -0
  317. package/src/theme-css.ts +1049 -0
  318. package/src/theme-library.ts +238 -0
  319. package/src/theme-preference.ts +130 -0
  320. package/src/theme.ts +527 -0
  321. package/src/tool-loader.ts +80 -24
  322. package/src/ui-source/inspect.ts +27 -4
  323. package/src/ui-source/source-write-backend.ts +83 -22
  324. package/src/widgets/index.ts +9 -18
  325. package/src/workspace-aux-commands.ts +11 -0
  326. package/src/workspace-dock-controller.ts +64 -0
  327. package/src/workspace-document-ids.ts +5 -0
  328. package/src/workspace-document-registry.ts +367 -0
  329. package/src/workspace-state-persistence.ts +455 -0
  330. package/src/workspace-status-registry.ts +110 -0
  331. package/src/workspace-utility-commands.ts +49 -0
  332. package/src/workspace-utility-registry.ts +161 -0
  333. package/src/world-document-routing.ts +16 -0
  334. package/src/xstate-inspect/XStateMachineInspector.tsx +544 -0
  335. package/src/xstate-inspect/character-animation-machine.fixture.ts +74 -0
  336. package/src/xstate-inspect/use-live-actor-state.ts +39 -0
  337. package/src/xstate-inspect/xstate-graph.ts +265 -0
  338. package/src/xstate-inspect/xstate-layout.ts +76 -0
  339. package/src/z-index.ts +26 -0
  340. package/template/.claude/skills/editor/SKILL.md +129 -90
  341. package/template/AGENTS.md +1110 -0
  342. package/template/CLAUDE.md +1 -512
  343. package/template/IDIOMS.md +50 -0
  344. package/template/check-idioms.ts +706 -0
  345. package/template/manifest-entry-modules-plugin.ts +53 -0
  346. package/template/package.json +13 -4
  347. package/template/public/scenes/default.scn2d.json +6 -0
  348. package/template/public/scenes/default.vscn.json +7 -1
  349. package/template/public/scenes/untitled.vscn.json +10 -0
  350. package/template/scripts/playtest.ts +40 -0
  351. package/template/server/loopback.ts +75 -0
  352. package/template/server/rooms/arena-room.ts +69 -1
  353. package/template/server/rooms/game-room.ts +68 -1
  354. package/template/src/data/README.md +9 -4
  355. package/template/src/data/data-ref.ts +35 -0
  356. package/template/src/data/tuning.schema.ts +1 -1
  357. package/template/src/main.ts +41 -62
  358. package/template/src/manifest-entry-modules.d.ts +3 -0
  359. package/template/src/operations/README.md +88 -0
  360. package/template/src/runtime/pixi-adapter.ts +24 -0
  361. package/template/src/scripts/components/data-spinner.ts +43 -2
  362. package/template/src/scripts/components/spin-lap-math.ts +27 -0
  363. package/template/src/tools/README.md +5 -3
  364. package/template/src/tools/example.tool.tsx +13 -7
  365. package/template/src/ui/Button.stories.tsx +66 -0
  366. package/template/src/ui/RebindPanel.tsx +2 -6
  367. package/template/src/ui/game.tsx +17 -0
  368. package/template/tests/acceptance/example.spec.ts +64 -0
  369. package/template/tests/logic/example.test.ts +31 -0
  370. package/template/tests/logic/room.test.ts +100 -0
  371. package/template/tests/tsconfig.json +30 -0
  372. package/template/validate-manifest.ts +5 -5
  373. package/template/validate-scenes.ts +50 -18
  374. package/template/vgai.game.json +20 -13
  375. package/template/vite.config.ts +77 -16
  376. package/vite-plugin-ui-oid.ts +261 -17
  377. package/dist/assets/CCDIKSolver-Dz-ysxZF.js +0 -1
  378. package/dist/assets/SelectionBox-BXsv_6aH.js +0 -1
  379. package/dist/assets/browser-project-scripts-DOru4L1x.js +0 -2
  380. package/dist/assets/browserAll-CEkWYlFk.js +0 -1
  381. package/dist/assets/create-runtime-DYIWr3va.js +0 -1
  382. package/dist/assets/data-asset-Bb9sIM7i.js +0 -5
  383. package/dist/assets/game-8SDZPPgH.js +0 -1
  384. package/dist/assets/game-CevorxyV.js +0 -1
  385. package/dist/assets/game-Di7XlywD.js +0 -1
  386. package/dist/assets/game-DjnCaw8R.js +0 -1
  387. package/dist/assets/game-Q9A0aXSV.js +0 -1
  388. package/dist/assets/index-CPVV6pjw.js +0 -1
  389. package/dist/assets/index-CpOnYyeD.js +0 -213
  390. package/dist/assets/index-Dr8H_6Rl.js +0 -1
  391. package/dist/assets/index-_bCaipUk.js +0 -13650
  392. package/dist/assets/ingest-siblings-Dz8eEqrV.js +0 -1
  393. package/dist/assets/mount-manifest-Bhk0ohsl.js +0 -1
  394. package/dist/assets/scene-query-BivAHhJu.js +0 -1
  395. package/dist/assets/webworkerAll-BLrH0F6F.js +0 -1
  396. package/dist/assets/xstate-animation-binding-1NGLmw6y.js +0 -1
  397. package/dist/assets/xstate.esm-BgUD33nl.js +0 -3
  398. package/src/authoring/scene-ui-layer.ts +0 -485
  399. package/src/authoring/ui-authoring-adapter.ts +0 -325
  400. package/src/authoring/ui-hierarchy-menu.ts +0 -40
  401. package/src/authoring/ui-inspector-sections.tsx +0 -156
  402. package/src/authoring/undo-timeline.ts +0 -145
  403. package/src/components/BottomPanel.tsx +0 -326
  404. package/src/components/BuildPanel.tsx +0 -455
  405. package/src/components/FolderTree.tsx +0 -179
  406. package/src/components/RightPanel.tsx +0 -166
  407. package/src/components/WorldContextMenu.tsx +0 -257
  408. package/src/components/asset-viewers/AssetViewer.tsx +0 -38
  409. package/src/ingest/games-react/react-rpg/src/ui/game-state.tsx +0 -129
  410. package/src/scene-ui-mode/active-scene-ui.ts +0 -58
  411. package/src/scene-ui-mode/scene-ui-palette-panel.tsx +0 -152
  412. package/src/scene-ui-mode/scene-ui-timeline-tab.tsx +0 -29
  413. package/src/scene-ui-mode/ui-prefab-dialog-host.tsx +0 -74
  414. package/src/scene-ui-mode/ui-prefab-hierarchy-menu.ts +0 -49
  415. package/src/scene-ui-mode/ui-prefab-io.ts +0 -76
  416. package/src/ui-editor/inspector.tsx +0 -563
  417. package/src/ui-editor/node-ops.ts +0 -266
  418. package/src/ui-editor/overlay.tsx +0 -380
  419. package/src/ui-editor/palette.tsx +0 -114
  420. package/src/ui-editor/react-store.ts +0 -78
  421. package/src/ui-editor/timeline-panel.tsx +0 -443
  422. package/src/ui-editor/ui-edit-store.ts +0 -552
  423. package/src/ui-editor/ui-prefab.ts +0 -95
  424. package/template/project.json +0 -9
  425. package/template/src/scripts/main.ts +0 -94
  426. package/template/src/ui/DefaultHud.tsx +0 -40
  427. package/template/src/ui/game-state.tsx +0 -37
  428. package/template/src/ui/mount-default-hud.tsx +0 -19
  429. package/template/src/ui/mount-ui.ts +0 -15
  430. package/vite-plugin-react-world-provider.ts +0 -81
@@ -0,0 +1,100 @@
1
+ declare const resourceKeyBrand: unique symbol;
2
+
3
+ /** Stable for the lifetime of one open project session, including across file moves. */
4
+ export type ResourceKey = string & { readonly [resourceKeyBrand]: true };
5
+
6
+ export type ResourceKind =
7
+ | 'scene'
8
+ | 'prefab'
9
+ | 'ui-tree'
10
+ | 'material'
11
+ | 'data'
12
+ | 'manifest'
13
+ | 'settings'
14
+ | 'source'
15
+ | 'overlay'
16
+ | 'project-file'
17
+ | 'session-state';
18
+
19
+ export interface ResourceDescriptor {
20
+ readonly key: ResourceKey;
21
+ readonly kind: ResourceKind;
22
+ readonly scope: 'project' | 'session';
23
+ readonly displayName: string;
24
+ readonly location: string | null;
25
+ readonly sessionId: string | null;
26
+ }
27
+
28
+ export interface ResourceSnapshot {
29
+ readonly revision: number;
30
+ readonly contentType: string;
31
+ readonly bytes: Uint8Array;
32
+ readonly sha256: string;
33
+ }
34
+
35
+ export interface SnapshotRef {
36
+ readonly revision: number;
37
+ readonly contentType: string;
38
+ readonly sha256: string;
39
+ readonly blobKey: string;
40
+ readonly byteLength: number;
41
+ }
42
+
43
+ export type PreflightResult =
44
+ | { readonly ok: true }
45
+ | {
46
+ readonly ok: false;
47
+ readonly reason: 'missing' | 'revision-conflict' | 'content-conflict' | 'expired';
48
+ readonly actualRevision?: number;
49
+ readonly actualSha256?: string;
50
+ };
51
+
52
+ export interface ResourceDriver {
53
+ readonly descriptor: ResourceDescriptor;
54
+ capture(): Promise<ResourceSnapshot>;
55
+ preflight(expected: SnapshotRef): Promise<PreflightResult>;
56
+ restore(snapshot: SnapshotRef): Promise<void>;
57
+ estimateBytes(snapshot: SnapshotRef): number;
58
+ }
59
+
60
+ export type HistoryStatus =
61
+ | 'committed'
62
+ | 'undoing'
63
+ | 'undone'
64
+ | 'redoing'
65
+ | 'failed'
66
+ | 'failed-partial'
67
+ | 'expired';
68
+
69
+ export interface HistoryError {
70
+ readonly code:
71
+ | 'busy'
72
+ | 'conflict'
73
+ | 'expired'
74
+ | 'apply-failed'
75
+ | 'compensation-failed'
76
+ | 'history-limit';
77
+ readonly message: string;
78
+ readonly resources: readonly ResourceKey[];
79
+ readonly cause?: unknown;
80
+ }
81
+
82
+ export interface ResourceChange {
83
+ readonly resource: ResourceKey;
84
+ readonly before: SnapshotRef;
85
+ readonly after: SnapshotRef;
86
+ }
87
+
88
+ export interface HistoryTransaction {
89
+ readonly id: string;
90
+ readonly label: string;
91
+ readonly detail: string | null;
92
+ readonly timestamp: number;
93
+ readonly scope: 'project' | 'session';
94
+ readonly sessionId: string | null;
95
+ readonly changes: readonly ResourceChange[];
96
+ readonly byteSize: number;
97
+ readonly mergeKey: string | null;
98
+ readonly status: HistoryStatus;
99
+ readonly error: HistoryError | null;
100
+ }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Owns a module's registry contributions across Vite Fast Refresh.
3
+ *
4
+ * A module-local `registered` boolean is not sufficient: Vite may reload the
5
+ * contributor without reloading the registry (duplicates), or reload the
6
+ * registry without reloading the contributor (missing entries). Tracking the
7
+ * unregister callbacks in `import.meta.hot.data` gives the contribution one
8
+ * explicit lifetime and keeps strict duplicate-id checks meaningful.
9
+ */
10
+
11
+ export interface HmrRegistrationContext {
12
+ readonly data?: Record<string, unknown>;
13
+ dispose(callback: (data: Record<string, unknown>) => void): void;
14
+ }
15
+
16
+ export interface HmrRegistrationGroup {
17
+ ensure(register: (track: (unregister: () => void) => void) => void): void;
18
+ reset(): void;
19
+ }
20
+
21
+ interface PersistedRegistrationGroup {
22
+ dispose(): void;
23
+ }
24
+
25
+ export function createHmrRegistrationGroup(
26
+ hot: HmrRegistrationContext | undefined,
27
+ key: string,
28
+ ): HmrRegistrationGroup {
29
+ const persistedKey = `vgai:registration-group:${key}`;
30
+ // Test runners and non-Vite hosts can expose a partial `import.meta.hot`
31
+ // shim without `data`. In that case the group still owns its local
32
+ // registrations, but there is no cross-refresh persistence to maintain.
33
+ const hotData = hot?.data;
34
+ const previous = hotData?.[persistedKey] as PersistedRegistrationGroup | undefined;
35
+ previous?.dispose();
36
+
37
+ let active = false;
38
+ let unregisters: Array<() => void> = [];
39
+
40
+ const reset = () => {
41
+ active = false;
42
+ const owned = unregisters;
43
+ unregisters = [];
44
+ for (let i = owned.length - 1; i >= 0; i--) owned[i]!();
45
+ };
46
+
47
+ const group: HmrRegistrationGroup = {
48
+ ensure(register) {
49
+ if (active) return;
50
+ active = true;
51
+ try {
52
+ register((unregister) => unregisters.push(unregister));
53
+ } catch (error) {
54
+ reset();
55
+ throw error;
56
+ }
57
+ },
58
+ reset,
59
+ };
60
+
61
+ if (hotData) {
62
+ hotData[persistedKey] = { dispose: reset } satisfies PersistedRegistrationGroup;
63
+ hot.dispose(reset);
64
+ }
65
+
66
+ return group;
67
+ }
@@ -0,0 +1,23 @@
1
+ import { type Context, createContext } from 'react';
2
+
3
+ /**
4
+ * Preserve a React context object across Vite module replacement.
5
+ *
6
+ * A provider from the previous module generation can remain mounted while a
7
+ * freshly imported consumer renders. If both generations call
8
+ * `createContext()`, the consumer observes a different context and falsely
9
+ * reports that it is outside the provider. Vite keeps `import.meta.hot.data`
10
+ * for exactly this kind of module-local state handoff.
11
+ */
12
+ export function createHmrStableReactContext<T>(
13
+ hotData: Record<string, unknown> | undefined,
14
+ key: string,
15
+ defaultValue: T,
16
+ ): Context<T> {
17
+ const existing = hotData?.[key];
18
+ if (existing) return existing as Context<T>;
19
+
20
+ const context = createContext(defaultValue);
21
+ if (hotData) hotData[key] = context;
22
+ return context;
23
+ }
@@ -27,6 +27,8 @@
27
27
 
28
28
  import { setAssetPrefix } from '@engine/loader';
29
29
  import { GameManifestSchema } from '@engine/manifest/schema';
30
+ import { BUNDLED_EDITOR_COMPATIBILITY } from './build-identity';
31
+ import { assertProjectCompatibility } from './editor-compatibility';
30
32
  import type { ActiveProject } from './project-manager';
31
33
 
32
34
  /** Folder-name shape shared by every `examples/<id>/` — also a path-safety gate. */
@@ -44,7 +46,12 @@ export async function openExampleProject(exampleId: string): Promise<ActiveProje
44
46
  if (!res.ok) {
45
47
  throw new Error(`HTTP ${res.status} fetching ${manifestUrl} — not a bundled example?`);
46
48
  }
47
- const manifest = GameManifestSchema.parse(await res.json());
49
+ const rawManifest: unknown = await res.json();
50
+ assertProjectCompatibility(
51
+ rawManifest && typeof rawManifest === 'object' ? rawManifest : {},
52
+ BUNDLED_EDITOR_COMPATIBILITY,
53
+ );
54
+ const manifest = GameManifestSchema.parse(rawManifest);
48
55
 
49
56
  // Namespace relative asset resolution to this example's staged public/ —
50
57
  // the same prefix `browser-play-entry.ts` sets at play dispatch, applied
@@ -55,8 +62,11 @@ export async function openExampleProject(exampleId: string): Promise<ActiveProje
55
62
  return {
56
63
  rootPath: `/examples/${exampleId}`,
57
64
  config: {
65
+ manifestVersion: manifest.manifestVersion,
58
66
  name: manifest.name,
59
- defaultScene: manifest.worlds[0]?.scene ?? null,
67
+ version: manifest.version,
68
+ engine: manifest.engine,
69
+ defaultScene: manifest.roots[0]?.scene ?? null,
60
70
  ...(manifest.resolution ? { resolution: manifest.resolution } : {}),
61
71
  },
62
72
  exampleId,
package/src/hotkeys.ts CHANGED
@@ -4,7 +4,22 @@ import { useEffect } from 'react';
4
4
  // Types
5
5
  // ---------------------------------------------------------------------------
6
6
 
7
- export type HotkeyScope = 'viewport' | 'hierarchy' | 'inspector' | 'asset-browser' | 'global';
7
+ export type HotkeyScope =
8
+ | 'viewport'
9
+ | 'hierarchy'
10
+ | 'inspector'
11
+ | 'asset-browser'
12
+ | 'workspace'
13
+ | 'global';
14
+
15
+ const HOTKEY_SCOPES = new Set<HotkeyScope>([
16
+ 'viewport',
17
+ 'hierarchy',
18
+ 'inspector',
19
+ 'asset-browser',
20
+ 'workspace',
21
+ 'global',
22
+ ]);
8
23
 
9
24
  export interface HotkeyBinding {
10
25
  /** The key to match (`e.key`, lowercase). Ignored when `code` is set. */
@@ -17,10 +32,17 @@ export interface HotkeyBinding {
17
32
  shift?: boolean;
18
33
  /** Require Alt/Option (D4 — `wrap`'s `Ctrl+Alt+G`). */
19
34
  alt?: boolean;
20
- /** Scope this binding belongs to. `'global'` bindings fire regardless of panel focus. */
21
- scope: HotkeyScope;
35
+ /** Scope(s) this binding belongs to. `'global'` bindings fire regardless of panel focus. */
36
+ scope: HotkeyScope | readonly HotkeyScope[];
22
37
  /** Action to execute when the binding matches. */
23
38
  action: (e: KeyboardEvent) => void;
39
+ /** Optional runtime gate. When it returns false, the binding yields to the
40
+ * browser and does not call preventDefault(). Use this for commands whose
41
+ * shortcut overlaps native behavior, such as Copy with a DOM text selection. */
42
+ when?: (e: KeyboardEvent) => boolean;
43
+ /** Allow this binding while a form control/contenteditable owns focus.
44
+ * Reserved for commands such as Save that are expected inside editors. */
45
+ allowInEditable?: boolean;
24
46
  /** Human-readable label for menus / tooltips. */
25
47
  label?: string;
26
48
  }
@@ -31,12 +53,58 @@ export interface HotkeyBinding {
31
53
 
32
54
  let _activeScope: HotkeyScope = 'viewport';
33
55
 
56
+ const ACTIVE_SCOPE_DATA_KEY = 'editorActiveHotkeyScope';
57
+
34
58
  export function getActiveScope(): HotkeyScope {
59
+ const shared = document.documentElement.dataset[ACTIVE_SCOPE_DATA_KEY];
60
+ if (shared && HOTKEY_SCOPES.has(shared as HotkeyScope)) return shared as HotkeyScope;
35
61
  return _activeScope;
36
62
  }
37
63
 
38
64
  export function setActiveScope(scope: HotkeyScope): void {
39
65
  _activeScope = scope;
66
+ // Vite can temporarily retain both pre- and post-HMR module instances.
67
+ // The editor shell is the durable ownership authority, so mirror the value
68
+ // onto the shared document rather than trusting one module-local singleton.
69
+ document.documentElement.dataset[ACTIVE_SCOPE_DATA_KEY] = scope;
70
+ }
71
+
72
+ /** True when a DOM target belongs to a native text-editing surface. Shared
73
+ * by the global dispatcher and panel-local handlers so bubbled Backspace,
74
+ * Delete, and clipboard shortcuts cannot mutate editor state while typing. */
75
+ export function isEditableTarget(target: EventTarget | null): boolean {
76
+ if (!(target instanceof Element)) return false;
77
+ if (
78
+ target instanceof HTMLInputElement ||
79
+ target instanceof HTMLTextAreaElement ||
80
+ target instanceof HTMLSelectElement
81
+ ) {
82
+ return true;
83
+ }
84
+ if (target instanceof HTMLElement && target.isContentEditable) return true;
85
+ return Boolean(target.closest('[contenteditable]:not([contenteditable="false"])'));
86
+ }
87
+
88
+ function scopeFromOwnershipEvent(event: Event): HotkeyScope | null {
89
+ for (const target of event.composedPath()) {
90
+ if (!(target instanceof HTMLElement)) continue;
91
+ // Dockview moves focus through internal navigation sentinels that sit
92
+ // directly under the shell. A focusin on that infrastructure must not
93
+ // erase the concrete panel established by the preceding pointerdown.
94
+ // Pointerdown still uses the fallback, so genuinely clicking unclaimed
95
+ // chrome neutralizes authoring commands as intended.
96
+ if (event.type === 'focusin' && target.hasAttribute('data-editor-hotkey-fallback')) continue;
97
+ const candidate = target.dataset['editorHotkeyScope'];
98
+ if (candidate && HOTKEY_SCOPES.has(candidate as HotkeyScope)) {
99
+ return candidate as HotkeyScope;
100
+ }
101
+ }
102
+ return null;
103
+ }
104
+
105
+ function handleOwnershipEvent(event: Event): void {
106
+ const scope = scopeFromOwnershipEvent(event);
107
+ if (scope) setActiveScope(scope);
40
108
  }
41
109
 
42
110
  // ---------------------------------------------------------------------------
@@ -63,37 +131,32 @@ export function registerHotkeys(bindings: HotkeyBinding[]): () => void {
63
131
  // ---------------------------------------------------------------------------
64
132
 
65
133
  function handleKeyDown(e: KeyboardEvent): void {
66
- // Skip when typing in form inputs — D4 (spec27 §6 D4 "each shortcut fires
67
- // only when not typing") widens this to `[contenteditable]` too (no
68
- // in-repo editor uses one today — `WorldTextEditor`/`GameHierarchy`'s
69
- // rename both use a real `<textarea>`/`<input>`, already covered above —
70
- // but the guard should hold for a future contentEditable surface without
71
- // needing another fix here).
72
- if (
73
- e.target instanceof HTMLInputElement ||
74
- e.target instanceof HTMLTextAreaElement ||
75
- e.target instanceof HTMLSelectElement ||
76
- (e.target instanceof HTMLElement && e.target.isContentEditable)
77
- )
78
- return;
134
+ // Skip ordinary editor commands while typing — D4 (spec27 §6 D4 "each
135
+ // shortcut fires only when not typing") covers form fields and future
136
+ // contentEditable surfaces. A binding must explicitly opt in when its
137
+ // conventional behavior belongs inside an editor too (currently Save).
138
+ const editableTarget = isEditableTarget(e.target);
79
139
 
80
140
  const mod = e.metaKey || e.ctrlKey;
81
141
  const key = e.key.toLowerCase();
82
142
  const code = e.code;
83
- const scope = _activeScope;
143
+ const scope = getActiveScope();
84
144
 
85
145
  // Check scoped bindings first, then global
86
146
  const passes: HotkeyScope[] = scope === 'global' ? ['global'] : [scope, 'global'];
87
147
 
88
148
  for (const pass of passes) {
89
149
  for (const b of _bindings) {
90
- if (b.scope !== pass) continue;
150
+ const bindingScopes = Array.isArray(b.scope) ? b.scope : [b.scope];
151
+ if (!bindingScopes.includes(pass)) continue;
152
+ if (editableTarget && !b.allowInEditable) continue;
91
153
 
92
154
  const keyMatch = b.code ? b.code === code : b.key === key;
93
155
  if (!keyMatch) continue;
94
156
  if ((b.mod ?? false) !== mod) continue;
95
157
  if ((b.shift ?? false) !== e.shiftKey) continue;
96
158
  if ((b.alt ?? false) !== e.altKey) continue;
159
+ if (b.when && !b.when(e)) continue;
97
160
 
98
161
  e.preventDefault();
99
162
  b.action(e);
@@ -107,12 +170,20 @@ let _installed = false;
107
170
  /** Attach the global keydown listener. Call once at startup. */
108
171
  export function installHotkeys(): void {
109
172
  if (_installed) return;
173
+ // Capture ownership before React's panel-local bubble handlers run. The
174
+ // closest declarative scope in the composed path wins; the shell's
175
+ // `workspace` marker is therefore a safe neutral fallback for menus,
176
+ // utilities, document editors, and unclaimed chrome.
177
+ window.addEventListener('pointerdown', handleOwnershipEvent, true);
178
+ window.addEventListener('focusin', handleOwnershipEvent, true);
110
179
  window.addEventListener('keydown', handleKeyDown);
111
180
  _installed = true;
112
181
  }
113
182
 
114
183
  /** Detach the global keydown listener. */
115
184
  export function uninstallHotkeys(): void {
185
+ window.removeEventListener('pointerdown', handleOwnershipEvent, true);
186
+ window.removeEventListener('focusin', handleOwnershipEvent, true);
116
187
  window.removeEventListener('keydown', handleKeyDown);
117
188
  _installed = false;
118
189
  }
@@ -9,7 +9,7 @@
9
9
  *
10
10
  * UNLIKE `discovery.ts`/`discovery2d.ts`, this module does NOT also glob the
11
11
  * entry module itself: an `ingest-react` world mounts through
12
- * `resolveWorldAdapter` (`adapter-resolver.ts`'s `resolveIngestReactAdapter`,
12
+ * `resolveRootAdapter` (`adapter-resolver.ts`'s `resolveIngestReactAdapter`,
13
13
  * N1) — the SAME `/@fs/`-dynamic-import + `createRoot` host stack
14
14
  * `default-react` uses — rather than a capture-based bridge, so there is no
15
15
  * "build an `IngestGame`/`IngestGame2D` descriptor with its own `load`
@@ -17,7 +17,7 @@
17
17
  * `games-react/*\/vgai.game.json`, validate its single world is a real
18
18
  * `ingest-react` `'deduped'` world, and hand back the parsed
19
19
  * `ResolvedGameManifest` + that world's absolute on-disk folder (the
20
- * `projectRoot` `resolveWorldAdapter` needs for its `entry`'s `/@fs/`
20
+ * `projectRoot` `resolveRootAdapter` needs for its `entry`'s `/@fs/`
21
21
  * dynamic import and its `loadProjectGameProvider` lookup) — see
22
22
  * `ingest-mode.ts`'s `enterIngestModeReact` for the mount step.
23
23
  *
@@ -62,21 +62,21 @@ export interface IngestGameReact {
62
62
 
63
63
  function buildIngestGameReact(folderId: string, raw: unknown): IngestGameReact {
64
64
  const manifest = loadGameManifest(raw);
65
- if (manifest.worlds.length !== 1) {
65
+ if (manifest.roots.length !== 1) {
66
66
  throw new Error(
67
67
  `react ingest discovery: "${folderId}/vgai.game.json" must declare exactly one world ` +
68
- `(found ${manifest.worlds.length}).`,
68
+ `(found ${manifest.roots.length}).`,
69
69
  );
70
70
  }
71
- const world = manifest.worlds[0]!;
71
+ const world = manifest.roots[0]!;
72
72
  if (
73
- world.kind !== 'react' ||
73
+ world.surface !== 'react' ||
74
74
  world.adapter.type !== 'ingest' ||
75
75
  world.adapter.identity !== 'ingest-react'
76
76
  ) {
77
77
  throw new Error(
78
78
  `react ingest discovery: "${folderId}/vgai.game.json"'s world must be a react { ingest } ` +
79
- `world (found kind "${world.kind}", adapter identity "${world.adapter.identity}").`,
79
+ `world (found kind "${world.surface}", adapter identity "${world.adapter.identity}").`,
80
80
  );
81
81
  }
82
82
  if (world.adapter.strategy !== 'deduped') {
@@ -117,9 +117,8 @@ export function getIngestGameReact(folderId: string): IngestGameReact | undefine
117
117
 
118
118
  /**
119
119
  * The absolute on-disk `projectRoot` for a discovered react ingest game's
120
- * folder — what `resolveWorldAdapter`/`resolveAllWorlds` need to resolve its
121
- * `entry` (and, transitively, `loadProjectGameProvider`'s
122
- * `src/ui/game-state.tsx` lookup). `undefined` when
120
+ * folder — what `resolveRootAdapter`/`resolveAllWorlds` need to resolve its
121
+ * `entry`. `undefined` when
123
122
  * `__VGAI_ENGINE_ROOT__` isn't defined (browser-mode static build — no dev
124
123
  * server, no `/@fs/` route to resolve through anyway).
125
124
  */
@@ -98,7 +98,7 @@ function buildModuleLoadedGame(
98
98
  if (!world.entry) {
99
99
  throw new Error(
100
100
  `ingest discovery: "${folderId}" (strategy "${strategy}") has no \`entry\` — ` +
101
- "shared/deduped ingest worlds need the game module's folder-relative path there.",
101
+ "shared/deduped ingest roots need the game module's folder-relative path there.",
102
102
  );
103
103
  }
104
104
  const key = `./games/${folderId}/${world.entry}`;
@@ -139,13 +139,13 @@ function buildFileBackedGame(
139
139
 
140
140
  function buildIngestGame(folderId: string, raw: unknown): IngestGame {
141
141
  const manifest = loadGameManifest(raw);
142
- if (manifest.worlds.length !== 1) {
142
+ if (manifest.roots.length !== 1) {
143
143
  throw new Error(
144
144
  `ingest discovery: "${folderId}/vgai.game.json" must declare exactly one world ` +
145
- `(found ${manifest.worlds.length}).`,
145
+ `(found ${manifest.roots.length}).`,
146
146
  );
147
147
  }
148
- const world = manifest.worlds[0]!;
148
+ const world = manifest.roots[0]!;
149
149
  if (world.adapter.type !== 'ingest' || world.adapter.identity !== 'ingest-three') {
150
150
  throw new Error(
151
151
  `ingest discovery: "${folderId}/vgai.game.json"'s world must be a threejs { ingest } ` +
@@ -69,7 +69,7 @@ function buildModuleLoadedGame2D(
69
69
  if (!world.entry) {
70
70
  throw new Error(
71
71
  `world2d ingest discovery: "${folderId}" (strategy "${strategy}") has no \`entry\` — ` +
72
- "shared/deduped ingest-pixi worlds need the game module's folder-relative path there.",
72
+ "shared/deduped ingest-pixi roots need the game module's folder-relative path there.",
73
73
  );
74
74
  }
75
75
  const key = `./games-2d/${folderId}/${world.entry}`;
@@ -88,7 +88,7 @@ function buildModuleLoadedGame2D(
88
88
  * the manifest's Track P fields (docs/PIXI-INGEST-LANDING-DESIGN.md §2) —
89
89
  * `bundleUrl` is required by the schema's cross-field check for this
90
90
  * strategy (exactly one of `bundleUrl`/`entryHtml`); `entryHtml`-only
91
- * iframe-reachable worlds still have no builder here (mirrors the
91
+ * iframe-reachable roots still have no builder here (mirrors the
92
92
  * `resolveIngestDescriptor`/three-side gap: reading a raw HTML/inline-source
93
93
  * file's contents needs a runtime fetch this synchronous builder doesn't do).
94
94
  * `extraDeps`/`pixiModuleUrl` become LAZY thunks (`IngestGame2D.extraDeps`/
@@ -131,13 +131,13 @@ export function buildIframeReachableGame2D(
131
131
 
132
132
  function buildIngestGame2D(folderId: string, raw: unknown): IngestGame2D {
133
133
  const manifest = loadGameManifest(raw);
134
- if (manifest.worlds.length !== 1) {
134
+ if (manifest.roots.length !== 1) {
135
135
  throw new Error(
136
136
  `world2d ingest discovery: "${folderId}/vgai.game.json" must declare exactly one world ` +
137
- `(found ${manifest.worlds.length}).`,
137
+ `(found ${manifest.roots.length}).`,
138
138
  );
139
139
  }
140
- const world = manifest.worlds[0]!;
140
+ const world = manifest.roots[0]!;
141
141
  if (world.adapter.type !== 'ingest' || world.adapter.identity !== 'ingest-pixi') {
142
142
  throw new Error(
143
143
  `world2d ingest discovery: "${folderId}/vgai.game.json"'s world must be a pixijs ` +
@@ -1,16 +1,16 @@
1
1
  {
2
- "manifestVersion": 1,
2
+ "manifestVersion": 2,
3
3
  "name": "Bloom EffectComposer repro standin (F13)",
4
4
  "version": "0.1.0",
5
5
  "engine": {
6
6
  "version": "0.1.0"
7
7
  },
8
- "worlds": [
8
+ "roots": [
9
9
  {
10
10
  "id": "bloom-composer",
11
- "kind": "threejs",
12
11
  "description": "A self-made, source-available three.js game that renders through its OWN EffectComposer (RenderPass + UnrealBloomPass) — a repro standin for F13 (docs/FTUE-EXTERNAL-R3F-GAME.md), NOT an upstream title (sanctioned stand-in precedent: ADAPTER-MAXIMAL-SPEC.json coverage_standins, same spirit as own-three-bundled). Exposes a dev-only window.__vgaiBloomComposer inspection hook reading its own composer's real render-target size. Used to prove the host ingest resize path never drives a game's own composer (docs/WAVE14-F13-BLOOM-COMPOSER-REPRO-DESIGN.md).",
13
12
  "adapter": {
13
+ "surface": "threejs",
14
14
  "ingest": {
15
15
  "strategy": "deduped"
16
16
  }
@@ -1,16 +1,16 @@
1
1
  {
2
- "manifestVersion": 1,
2
+ "manifestVersion": 2,
3
3
  "name": "Opaque bundle (embed-only floor)",
4
4
  "version": "0.1.0",
5
5
  "engine": {
6
6
  "version": "0.1.0"
7
7
  },
8
- "worlds": [
8
+ "roots": [
9
9
  {
10
10
  "id": "embed-bundle",
11
- "kind": "threejs",
12
11
  "description": "A self-contained opaque bundle (a dependency-free canvas app) standing in for any prebuilt bundle whose renderer the editor cannot reach. Demonstrates the iframe embed/lifecycle FLOOR (Tier 0–1): hosted + sized + disposed, scene NOT introspectable. Payload-agnostic — a real opaque three.js bundle (own realm-local three) is hosted identically.",
13
12
  "adapter": {
13
+ "surface": "threejs",
14
14
  "ingest": {
15
15
  "strategy": "opaque-embed",
16
16
  "entryHtml": "embed.html"
@@ -1,16 +1,16 @@
1
1
  {
2
- "manifestVersion": 1,
2
+ "manifestVersion": 2,
3
3
  "name": "three.js — Octree FPS (games_fps)",
4
4
  "version": "0.1.0",
5
5
  "engine": {
6
6
  "version": "0.1.0"
7
7
  },
8
- "worlds": [
8
+ "roots": [
9
9
  {
10
10
  "id": "games-fps",
11
- "kind": "threejs",
12
11
  "description": "Upstream mrdoob/three.js example: octree collisions, GLTF world, 100 physics spheres, pointer-lock FPS. Own scene/camera/renderer/rAF/input.",
13
12
  "adapter": {
13
+ "surface": "threejs",
14
14
  "ingest": {
15
15
  "strategy": "shared",
16
16
  "assets": {
@@ -1,16 +1,16 @@
1
1
  {
2
- "manifestVersion": 1,
2
+ "manifestVersion": 2,
3
3
  "name": "Prebuilt bundle in iframe (reachable three)",
4
4
  "version": "0.1.0",
5
5
  "engine": {
6
6
  "version": "0.1.0"
7
7
  },
8
- "worlds": [
8
+ "roots": [
9
9
  {
10
10
  "id": "iframe-reachable",
11
- "kind": "threejs",
12
11
  "description": "A prebuilt bundle hosted in its OWN iframe document, but whose three is REACHABLE: the iframe importmap resolves `three` to the host instance (blob re-export), so its scene is captured in-realm and edited live in the editor (cov-iframe-reachable, tier 2–3). The middle tier between shared-ESM and opaque embed.",
13
12
  "adapter": {
13
+ "surface": "threejs",
14
14
  "ingest": {
15
15
  "strategy": "iframe-reachable",
16
16
  "entryHtml": "game-source.js"
@@ -1,16 +1,16 @@
1
1
  {
2
- "manifestVersion": 1,
2
+ "manifestVersion": 2,
3
3
  "name": "three.js — Interactive Cubes",
4
4
  "version": "0.1.0",
5
5
  "engine": {
6
6
  "version": "0.1.0"
7
7
  },
8
- "worlds": [
8
+ "roots": [
9
9
  {
10
10
  "id": "interactive-cubes",
11
- "kind": "threejs",
12
11
  "description": "Upstream webgl_interactive_cubes: 2000 procedurally-placed cubes, orbiting camera, per-frame raycaster hover-highlight. Own scene/camera/renderer/rAF. No external assets.",
13
12
  "adapter": {
13
+ "surface": "threejs",
14
14
  "ingest": {
15
15
  "strategy": "shared"
16
16
  }
@@ -1,16 +1,16 @@
1
1
  {
2
- "manifestVersion": 1,
2
+ "manifestVersion": 2,
3
3
  "name": "Mismatched/bundled three (graceful degrade)",
4
4
  "version": "0.1.0",
5
5
  "engine": {
6
6
  "version": "0.1.0"
7
7
  },
8
- "worlds": [
8
+ "roots": [
9
9
  {
10
10
  "id": "mismatched-three",
11
- "kind": "threejs",
12
11
  "description": "A game that uses a SEPARATE (non-host) three — stands in for a bundled/mismatched three version the capture trap cannot instrument. The editor detects the capture failure and degrades to embed-only (cov-mismatched-three) — never a silent failure.",
13
12
  "adapter": {
13
+ "surface": "threejs",
14
14
  "ingest": {
15
15
  "strategy": "shared",
16
16
  "captureTimeoutMs": 2500
@@ -1,16 +1,16 @@
1
1
  {
2
- "manifestVersion": 1,
2
+ "manifestVersion": 2,
3
3
  "name": "Bundles-own-three (build-time dedupe)",
4
4
  "version": "0.1.0",
5
5
  "engine": {
6
6
  "version": "0.1.0"
7
7
  },
8
- "worlds": [
8
+ "roots": [
9
9
  {
10
10
  "id": "own-three-bundled",
11
- "kind": "threejs",
12
11
  "description": "A source-available game that ships its OWN nested node_modules/three. Build-time dedupe (resolve.dedupe:[three]) collapses it to the editor instance → LIVE capture + edit (cov-bundled-dedupe). A passing live ingest proves the collapse (else the bare import would hit the nested stub and capture would fail).",
13
12
  "adapter": {
13
+ "surface": "threejs",
14
14
  "ingest": {
15
15
  "strategy": "deduped"
16
16
  }