@vgai/editor 0.2.0

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 (519) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +35 -0
  3. package/dist/a/b/c/test-nested.json +1 -0
  4. package/dist/assets/CCDIKSolver-Dz-ysxZF.js +1 -0
  5. package/dist/assets/SelectionBox-BXsv_6aH.js +1 -0
  6. package/dist/assets/browser-project-scripts-DOru4L1x.js +2 -0
  7. package/dist/assets/browserAll-CEkWYlFk.js +1 -0
  8. package/dist/assets/collision-world-DniMB0qq.glb +0 -0
  9. package/dist/assets/create-runtime-DYIWr3va.js +1 -0
  10. package/dist/assets/data-asset-Bb9sIM7i.js +5 -0
  11. package/dist/assets/esbuild-BHljloGq.wasm +0 -0
  12. package/dist/assets/fake-three-BMTQ9rl_.js +1 -0
  13. package/dist/assets/game-8SDZPPgH.js +1 -0
  14. package/dist/assets/game-BI111o5f.js +10 -0
  15. package/dist/assets/game-CevorxyV.js +1 -0
  16. package/dist/assets/game-Di1H0gFj.js +1 -0
  17. package/dist/assets/game-Di7XlywD.js +1 -0
  18. package/dist/assets/game-DjnCaw8R.js +1 -0
  19. package/dist/assets/game-Q9A0aXSV.js +1 -0
  20. package/dist/assets/game-pt_1lQLv.js +1 -0
  21. package/dist/assets/game-source-CvidN7AB.js +1 -0
  22. package/dist/assets/game-xsOho_wg.js +83 -0
  23. package/dist/assets/index-Bp5cecD6.js +12 -0
  24. package/dist/assets/index-CPVV6pjw.js +1 -0
  25. package/dist/assets/index-CpOnYyeD.js +213 -0
  26. package/dist/assets/index-Cs8xwv3e.js +1 -0
  27. package/dist/assets/index-DL7RcQ0n.js +27 -0
  28. package/dist/assets/index-Dr8H_6Rl.js +1 -0
  29. package/dist/assets/index-_bCaipUk.js +13650 -0
  30. package/dist/assets/ingest-siblings-Dz8eEqrV.js +1 -0
  31. package/dist/assets/mount-manifest-Bhk0ohsl.js +1 -0
  32. package/dist/assets/recast-navigation.wasm-compat-CvP4UGK6.js +1 -0
  33. package/dist/assets/scene-query-BivAHhJu.js +1 -0
  34. package/dist/assets/stats.module--VATS4Kh.js +1 -0
  35. package/dist/assets/webworkerAll-BLrH0F6F.js +1 -0
  36. package/dist/assets/xstate-animation-binding-1NGLmw6y.js +1 -0
  37. package/dist/assets/xstate.esm-BgUD33nl.js +3 -0
  38. package/dist/index.html +37 -0
  39. package/dist/ingest/racing-game/UPSTREAM.md +68 -0
  40. package/dist/ingest/racing-game/a/Inter-Black.woff +0 -0
  41. package/dist/ingest/racing-game/a/Inter-Black.woff2 +0 -0
  42. package/dist/ingest/racing-game/a/Inter-BlackItalic.woff +0 -0
  43. package/dist/ingest/racing-game/a/Inter-BlackItalic.woff2 +0 -0
  44. package/dist/ingest/racing-game/a/Inter-Bold.woff +0 -0
  45. package/dist/ingest/racing-game/a/Inter-Bold.woff2 +0 -0
  46. package/dist/ingest/racing-game/a/Inter-BoldItalic.woff +0 -0
  47. package/dist/ingest/racing-game/a/Inter-BoldItalic.woff2 +0 -0
  48. package/dist/ingest/racing-game/a/Inter-ExtraBold.woff +0 -0
  49. package/dist/ingest/racing-game/a/Inter-ExtraBold.woff2 +0 -0
  50. package/dist/ingest/racing-game/a/Inter-ExtraBoldItalic.woff +0 -0
  51. package/dist/ingest/racing-game/a/Inter-ExtraBoldItalic.woff2 +0 -0
  52. package/dist/ingest/racing-game/a/Inter-ExtraLight.woff +0 -0
  53. package/dist/ingest/racing-game/a/Inter-ExtraLight.woff2 +0 -0
  54. package/dist/ingest/racing-game/a/Inter-ExtraLightItalic.woff +0 -0
  55. package/dist/ingest/racing-game/a/Inter-ExtraLightItalic.woff2 +0 -0
  56. package/dist/ingest/racing-game/a/Inter-Italic.woff +0 -0
  57. package/dist/ingest/racing-game/a/Inter-Italic.woff2 +0 -0
  58. package/dist/ingest/racing-game/a/Inter-Light.woff +0 -0
  59. package/dist/ingest/racing-game/a/Inter-Light.woff2 +0 -0
  60. package/dist/ingest/racing-game/a/Inter-LightItalic.woff +0 -0
  61. package/dist/ingest/racing-game/a/Inter-LightItalic.woff2 +0 -0
  62. package/dist/ingest/racing-game/a/Inter-Medium.woff +0 -0
  63. package/dist/ingest/racing-game/a/Inter-Medium.woff2 +0 -0
  64. package/dist/ingest/racing-game/a/Inter-MediumItalic.woff +0 -0
  65. package/dist/ingest/racing-game/a/Inter-MediumItalic.woff2 +0 -0
  66. package/dist/ingest/racing-game/a/Inter-Regular.woff +0 -0
  67. package/dist/ingest/racing-game/a/Inter-Regular.woff2 +0 -0
  68. package/dist/ingest/racing-game/a/Inter-SemiBold.woff +0 -0
  69. package/dist/ingest/racing-game/a/Inter-SemiBold.woff2 +0 -0
  70. package/dist/ingest/racing-game/a/Inter-SemiBoldItalic.woff +0 -0
  71. package/dist/ingest/racing-game/a/Inter-SemiBoldItalic.woff2 +0 -0
  72. package/dist/ingest/racing-game/a/Inter-Thin.woff +0 -0
  73. package/dist/ingest/racing-game/a/Inter-Thin.woff2 +0 -0
  74. package/dist/ingest/racing-game/a/Inter-ThinItalic.woff +0 -0
  75. package/dist/ingest/racing-game/a/Inter-ThinItalic.woff2 +0 -0
  76. package/dist/ingest/racing-game/a/Inter-italic.var.woff2 +0 -0
  77. package/dist/ingest/racing-game/a/Inter-roman.var.woff2 +0 -0
  78. package/dist/ingest/racing-game/a/Inter.var.woff2 +0 -0
  79. package/dist/ingest/racing-game/a/index.css +1 -0
  80. package/dist/ingest/racing-game/images/bronze.png +0 -0
  81. package/dist/ingest/racing-game/images/gold.png +0 -0
  82. package/dist/ingest/racing-game/images/silver.png +0 -0
  83. package/dist/ingest/racing-game/index.html +15 -0
  84. package/dist/ingest/racing-game/models/chassis-draco.glb +0 -0
  85. package/dist/ingest/racing-game/models/track-draco.glb +0 -0
  86. package/dist/ingest/racing-game/models/wheel-draco.glb +0 -0
  87. package/dist/ingest/racing-game/rg-entry.js +1 -0
  88. package/dist/ingest/racing-game/sounds/accelerate.mp3 +0 -0
  89. package/dist/ingest/racing-game/sounds/boost.mp3 +0 -0
  90. package/dist/ingest/racing-game/sounds/crash.mp3 +0 -0
  91. package/dist/ingest/racing-game/sounds/engine.mp3 +0 -0
  92. package/dist/ingest/racing-game/sounds/honk.mp3 +0 -0
  93. package/dist/ingest/racing-game/sounds/tire-brake.mp3 +0 -0
  94. package/dist/ingest/racing-game/sounds/train.mp3 +0 -0
  95. package/dist/ingest/racing-game/sounds/water.mp3 +0 -0
  96. package/dist/ingest/racing-game/textures/cursor.svg +3 -0
  97. package/dist/ingest/racing-game/textures/dikhololo_night_1k.hdr +0 -0
  98. package/dist/ingest/racing-game/textures/heightmap_1024.png +0 -0
  99. package/dist/ingest/racing-game/textures/mask.svg +11 -0
  100. package/dist/ingest/racing-game/textures/no_sound.png +0 -0
  101. package/dist/ingest/racing-game/three-r139.module.js +50617 -0
  102. package/dist/ingest/racing-game/vendor.js +179 -0
  103. package/dist/ingest/racing-game/vgai.game.json +20 -0
  104. package/dist/ingest/simcity/UPSTREAM.md +65 -0
  105. package/dist/ingest/simcity/favicon.ico +0 -0
  106. package/dist/ingest/simcity/fonts/Bebas-Regular.otf +0 -0
  107. package/dist/ingest/simcity/fonts/Digitalt.otf +0 -0
  108. package/dist/ingest/simcity/fonts/Stanberry.ttf +0 -0
  109. package/dist/ingest/simcity/icons/bulldozer-color.png +0 -0
  110. package/dist/ingest/simcity/icons/bulldozer.png +0 -0
  111. package/dist/ingest/simcity/icons/calendar.png +0 -0
  112. package/dist/ingest/simcity/icons/factory-color.png +0 -0
  113. package/dist/ingest/simcity/icons/factory.png +0 -0
  114. package/dist/ingest/simcity/icons/house-color.png +0 -0
  115. package/dist/ingest/simcity/icons/house.png +0 -0
  116. package/dist/ingest/simcity/icons/job.png +0 -0
  117. package/dist/ingest/simcity/icons/office.png +0 -0
  118. package/dist/ingest/simcity/icons/pause-color.png +0 -0
  119. package/dist/ingest/simcity/icons/pause.png +0 -0
  120. package/dist/ingest/simcity/icons/person.png +0 -0
  121. package/dist/ingest/simcity/icons/play-color.png +0 -0
  122. package/dist/ingest/simcity/icons/play.png +0 -0
  123. package/dist/ingest/simcity/icons/power-color.png +0 -0
  124. package/dist/ingest/simcity/icons/power-line-color.png +0 -0
  125. package/dist/ingest/simcity/icons/power.png +0 -0
  126. package/dist/ingest/simcity/icons/road-color.png +0 -0
  127. package/dist/ingest/simcity/icons/road.png +0 -0
  128. package/dist/ingest/simcity/icons/select-color.png +0 -0
  129. package/dist/ingest/simcity/icons/select.png +0 -0
  130. package/dist/ingest/simcity/icons/store-color.png +0 -0
  131. package/dist/ingest/simcity/index.html +94 -0
  132. package/dist/ingest/simcity/index.js +58 -0
  133. package/dist/ingest/simcity/main.css +233 -0
  134. package/dist/ingest/simcity/models/armored-truck.glb +0 -0
  135. package/dist/ingest/simcity/models/building-block-4floor-corner.glb +0 -0
  136. package/dist/ingest/simcity/models/building-block-4floor-short.glb +0 -0
  137. package/dist/ingest/simcity/models/building-block-5floor.glb +0 -0
  138. package/dist/ingest/simcity/models/building-burger-joint.glb +0 -0
  139. package/dist/ingest/simcity/models/building-cafe.glb +0 -0
  140. package/dist/ingest/simcity/models/building-casino.glb +0 -0
  141. package/dist/ingest/simcity/models/building-cinema.glb +0 -0
  142. package/dist/ingest/simcity/models/building-house-block-big.glb +0 -0
  143. package/dist/ingest/simcity/models/building-house-family-large.glb +0 -0
  144. package/dist/ingest/simcity/models/building-house-family-small.glb +0 -0
  145. package/dist/ingest/simcity/models/building-office-balcony.glb +0 -0
  146. package/dist/ingest/simcity/models/building-office-big.glb +0 -0
  147. package/dist/ingest/simcity/models/building-office-pyramid.glb +0 -0
  148. package/dist/ingest/simcity/models/building-office-tall.glb +0 -0
  149. package/dist/ingest/simcity/models/building-office.glb +0 -0
  150. package/dist/ingest/simcity/models/building-restaurant.glb +0 -0
  151. package/dist/ingest/simcity/models/building-skyscraper.glb +0 -0
  152. package/dist/ingest/simcity/models/car-ambulance-pickup.glb +0 -0
  153. package/dist/ingest/simcity/models/car-baywatch.glb +0 -0
  154. package/dist/ingest/simcity/models/car-hippie-van.glb +0 -0
  155. package/dist/ingest/simcity/models/car-passenger-race.glb +0 -0
  156. package/dist/ingest/simcity/models/car-passenger.glb +0 -0
  157. package/dist/ingest/simcity/models/car-police.glb +0 -0
  158. package/dist/ingest/simcity/models/car-taxi.glb +0 -0
  159. package/dist/ingest/simcity/models/car-tow-truck.glb +0 -0
  160. package/dist/ingest/simcity/models/car-truck-dump.glb +0 -0
  161. package/dist/ingest/simcity/models/car-veteran.glb +0 -0
  162. package/dist/ingest/simcity/models/construction-small.glb +0 -0
  163. package/dist/ingest/simcity/models/data-center.glb +0 -0
  164. package/dist/ingest/simcity/models/industry-factory-old.glb +0 -0
  165. package/dist/ingest/simcity/models/industry-factory.glb +0 -0
  166. package/dist/ingest/simcity/models/industry-refinery.glb +0 -0
  167. package/dist/ingest/simcity/models/industry-warehouse.glb +0 -0
  168. package/dist/ingest/simcity/models/power_line_pole_modified.glb +0 -0
  169. package/dist/ingest/simcity/models/tile-plain_grass.glb +0 -0
  170. package/dist/ingest/simcity/models/tile-road-curve.glb +0 -0
  171. package/dist/ingest/simcity/models/tile-road-end.glb +0 -0
  172. package/dist/ingest/simcity/models/tile-road-intersection-t.glb +0 -0
  173. package/dist/ingest/simcity/models/tile-road-intersection.glb +0 -0
  174. package/dist/ingest/simcity/models/tile-road-straight.glb +0 -0
  175. package/dist/ingest/simcity/models/truck.glb +0 -0
  176. package/dist/ingest/simcity/statusIcons/no-power.png +0 -0
  177. package/dist/ingest/simcity/statusIcons/no-road-access.png +0 -0
  178. package/dist/ingest/simcity/textures/base.png +0 -0
  179. package/dist/ingest/simcity/textures/grid.png +0 -0
  180. package/dist/ingest/simcity/textures/specular.png +0 -0
  181. package/dist/ingest/simcity/three-r155.module.js +51466 -0
  182. package/dist/ingest/simcity/vgai.game.json +20 -0
  183. package/dist/ingest/tanks/UPSTREAM.md +69 -0
  184. package/dist/ingest/tanks/index.html +214 -0
  185. package/dist/ingest/tanks/models/pixelTank.fbx +0 -0
  186. package/dist/ingest/tanks/tanks-entry.js +92 -0
  187. package/dist/ingest/tanks/three-r170.module.js +54571 -0
  188. package/dist/ingest/tanks/vgai.game.json +20 -0
  189. package/dist/inputmaps/default.inputmap.json +41 -0
  190. package/dist/jsm/libs/draco/gltf/draco_decoder.js +33 -0
  191. package/dist/jsm/libs/draco/gltf/draco_decoder.wasm +0 -0
  192. package/dist/jsm/libs/draco/gltf/draco_wasm_wrapper.js +116 -0
  193. package/dist/scenes/untitled.vscn.json +29 -0
  194. package/dist/textures/waternormals.jpg +0 -0
  195. package/dist-server/packaged.mjs +18155 -0
  196. package/package.json +36 -0
  197. package/server/asset-library-routes.ts +833 -0
  198. package/server/canonical-path.ts +50 -0
  199. package/server/cloud-asset-catalog.ts +101 -0
  200. package/server/dev.ts +350 -0
  201. package/server/editor-server.ts +1537 -0
  202. package/server/editor-sse.ts +73 -0
  203. package/server/game-globals-shadow.ts +58 -0
  204. package/server/local-asset-catalog.ts +163 -0
  205. package/server/packaged.ts +571 -0
  206. package/server/prod.ts +75 -0
  207. package/server/project-optimize-deps-entries.ts +149 -0
  208. package/server/project-view.ts +65 -0
  209. package/server/server-utils.ts +430 -0
  210. package/server/session-registry.ts +93 -0
  211. package/src/EditorContext.tsx +87 -0
  212. package/src/achieved-tier.ts +126 -0
  213. package/src/action-registry.ts +268 -0
  214. package/src/adapter-resolver.ts +1858 -0
  215. package/src/asset-events.ts +100 -0
  216. package/src/authoring/active-adapter.ts +98 -0
  217. package/src/authoring/active-systems.ts +50 -0
  218. package/src/authoring/boundary-authoring-adapter.ts +178 -0
  219. package/src/authoring/composite-authoring-adapter.ts +891 -0
  220. package/src/authoring/design-time-layers.ts +776 -0
  221. package/src/authoring/edit-mode-authoring.ts +643 -0
  222. package/src/authoring/embed-only-adapter.ts +57 -0
  223. package/src/authoring/ephemeral-persistence.ts +26 -0
  224. package/src/authoring/eyedropper-session.ts +69 -0
  225. package/src/authoring/first-party-hierarchy-menu.ts +74 -0
  226. package/src/authoring/first-party-inspector/AddSectionMenu.tsx +118 -0
  227. package/src/authoring/first-party-inspector/EnvironmentSection.tsx +550 -0
  228. package/src/authoring/first-party-inspector/HeaderSection.tsx +329 -0
  229. package/src/authoring/first-party-inspector/is-first-party-selection.ts +44 -0
  230. package/src/authoring/first-party-inspector/register.tsx +108 -0
  231. package/src/authoring/ingest-authoring-adapter.ts +475 -0
  232. package/src/authoring/ingest-capture.ts +94 -0
  233. package/src/authoring/ingest-game-adapter.ts +291 -0
  234. package/src/authoring/ingest-iframe-adapter.ts +38 -0
  235. package/src/authoring/ingest-iframe-reachable-adapter.ts +401 -0
  236. package/src/authoring/ingest-overlay.ts +193 -0
  237. package/src/authoring/layered-pick.ts +87 -0
  238. package/src/authoring/mount-failure-report.ts +112 -0
  239. package/src/authoring/overlay-report.ts +52 -0
  240. package/src/authoring/project-scenes.ts +111 -0
  241. package/src/authoring/react-dom-authoring-adapter.ts +795 -0
  242. package/src/authoring/react-inspector-section.tsx +1041 -0
  243. package/src/authoring/react-world-authoring-adapter.ts +2400 -0
  244. package/src/authoring/root-activation.ts +61 -0
  245. package/src/authoring/scene-ui-layer.ts +485 -0
  246. package/src/authoring/story-overlay.ts +48 -0
  247. package/src/authoring/ui-authoring-adapter.ts +325 -0
  248. package/src/authoring/ui-hierarchy-menu.ts +40 -0
  249. package/src/authoring/ui-inspector-sections.tsx +156 -0
  250. package/src/authoring/undo-timeline.ts +145 -0
  251. package/src/authoring/vgai-scene-authoring-adapter.ts +746 -0
  252. package/src/authoring/viewport-pick-context.ts +31 -0
  253. package/src/authoring/viewport-raycast.ts +80 -0
  254. package/src/authoring/world-overlay.ts +76 -0
  255. package/src/authoring/world-pan-state.ts +115 -0
  256. package/src/authoring/world-session-state.ts +102 -0
  257. package/src/authoring/world2d-authoring-adapter.ts +313 -0
  258. package/src/browser-external-watch.ts +98 -0
  259. package/src/browser-play-entry.ts +112 -0
  260. package/src/browser-project-scripts.ts +112 -0
  261. package/src/browser-transpile.ts +246 -0
  262. package/src/browser-watch-reload.ts +100 -0
  263. package/src/command-listener.ts +326 -0
  264. package/src/components/AlignToolbar.tsx +189 -0
  265. package/src/components/AppRoot.tsx +73 -0
  266. package/src/components/AssetBrowser.tsx +502 -0
  267. package/src/components/BottomPanel.tsx +326 -0
  268. package/src/components/BuildPanel.tsx +455 -0
  269. package/src/components/CameraInfo.tsx +56 -0
  270. package/src/components/CommandPalette.tsx +265 -0
  271. package/src/components/ConsolePanel.tsx +272 -0
  272. package/src/components/DataPanel.tsx +1268 -0
  273. package/src/components/DefaultEditorLayout.tsx +509 -0
  274. package/src/components/FolderTree.tsx +179 -0
  275. package/src/components/GameHierarchy.tsx +1349 -0
  276. package/src/components/Inspector.tsx +671 -0
  277. package/src/components/InspectorToolSection.tsx +74 -0
  278. package/src/components/MountFailureBanner.tsx +110 -0
  279. package/src/components/NetworkSection.tsx +109 -0
  280. package/src/components/OnlineAssetBrowser.tsx +448 -0
  281. package/src/components/OverlayReportBanner.tsx +122 -0
  282. package/src/components/PlayBar.tsx +356 -0
  283. package/src/components/PrefabSaveDialog.tsx +201 -0
  284. package/src/components/ProjectHeader.tsx +174 -0
  285. package/src/components/ProjectScreen.tsx +1004 -0
  286. package/src/components/RightPanel.tsx +166 -0
  287. package/src/components/RootActivateDialog.tsx +105 -0
  288. package/src/components/SaveDialog.tsx +197 -0
  289. package/src/components/SaveStatus.tsx +69 -0
  290. package/src/components/StatsOverlay.tsx +35 -0
  291. package/src/components/ToolHost.tsx +80 -0
  292. package/src/components/Toolbar.tsx +307 -0
  293. package/src/components/ViewportOverlay.tsx +234 -0
  294. package/src/components/ViewportPanel.tsx +369 -0
  295. package/src/components/WorldContextMenu.tsx +257 -0
  296. package/src/components/WorldSelectionOverlay.tsx +2003 -0
  297. package/src/components/WorldTextEditor.tsx +86 -0
  298. package/src/components/asset-viewers/AssetViewer.tsx +38 -0
  299. package/src/components/asset-viewers/AudioViewer.tsx +149 -0
  300. package/src/components/asset-viewers/GenericJsonViewer.tsx +77 -0
  301. package/src/components/asset-viewers/ImageViewer.tsx +65 -0
  302. package/src/components/asset-viewers/InputMapViewer.tsx +206 -0
  303. package/src/components/asset-viewers/ModelViewer.tsx +180 -0
  304. package/src/components/asset-viewers/OnlineAssetDetail.tsx +236 -0
  305. package/src/components/data-csv.ts +301 -0
  306. package/src/components/entity-name-commit.ts +18 -0
  307. package/src/components/inspector-property-grouping.ts +65 -0
  308. package/src/components/inspector-widgets/AlignmentGrid.tsx +188 -0
  309. package/src/components/inspector-widgets/BorderEditor.tsx +305 -0
  310. package/src/components/inspector-widgets/ColorPicker.tsx +548 -0
  311. package/src/components/inspector-widgets/FilterEditor.tsx +108 -0
  312. package/src/components/inspector-widgets/FontPicker.tsx +196 -0
  313. package/src/components/inspector-widgets/GradientEditor.tsx +277 -0
  314. package/src/components/inspector-widgets/ScrubbableInput.tsx +152 -0
  315. package/src/components/inspector-widgets/ShadowEditor.tsx +332 -0
  316. package/src/components/inspector-widgets/color-utils.ts +202 -0
  317. package/src/components/inspector-widgets/gallery-main.tsx +167 -0
  318. package/src/components/inspector-widgets/index.ts +22 -0
  319. package/src/components/inspector-widgets/shared.tsx +135 -0
  320. package/src/components/inspectors/AnimationSection.tsx +143 -0
  321. package/src/components/inspectors/AudioSection.tsx +215 -0
  322. package/src/components/inspectors/BoneAttachmentSection.tsx +82 -0
  323. package/src/components/inspectors/CameraSection.tsx +105 -0
  324. package/src/components/inspectors/ComponentsSection.tsx +358 -0
  325. package/src/components/inspectors/JointsSection.tsx +255 -0
  326. package/src/components/inspectors/LightSection.tsx +116 -0
  327. package/src/components/inspectors/MaterialSection.tsx +1189 -0
  328. package/src/components/inspectors/MeshSection.tsx +99 -0
  329. package/src/components/inspectors/NavigationSection.tsx +58 -0
  330. package/src/components/inspectors/ParticleSection.tsx +681 -0
  331. package/src/components/inspectors/PhysicsSection.tsx +326 -0
  332. package/src/components/inspectors/PostProcessingSection.tsx +1290 -0
  333. package/src/components/inspectors/RenderingSection.tsx +109 -0
  334. package/src/components/inspectors/ShadowSection.tsx +84 -0
  335. package/src/components/inspectors/SplineSection.tsx +191 -0
  336. package/src/components/inspectors/TransformSection.tsx +191 -0
  337. package/src/components/inspectors/json-schema-fields.ts +281 -0
  338. package/src/components/inspectors/multi-edit-utils.ts +49 -0
  339. package/src/components/inspectors/zod-fields.ts +184 -0
  340. package/src/components/primitives/ColorInput.tsx +109 -0
  341. package/src/components/primitives/JsonInput.tsx +98 -0
  342. package/src/components/primitives/NumberInput.tsx +164 -0
  343. package/src/components/primitives/Panel.tsx +68 -0
  344. package/src/components/primitives/SectionHeader.tsx +45 -0
  345. package/src/components/primitives/Tooltip.tsx +82 -0
  346. package/src/components/primitives/Vec3Input.tsx +62 -0
  347. package/src/components/world-overlay-gestures.ts +1438 -0
  348. package/src/doctor/data-checks.ts +285 -0
  349. package/src/doctor/report.ts +386 -0
  350. package/src/editor-api.ts +700 -0
  351. package/src/editor-console.ts +194 -0
  352. package/src/editor-hotkeys.ts +441 -0
  353. package/src/editor-layers.ts +2 -0
  354. package/src/editor-mode.ts +28 -0
  355. package/src/editor-store.ts +2225 -0
  356. package/src/editor-viewport.ts +1924 -0
  357. package/src/entity-factory.ts +221 -0
  358. package/src/game-globals-prelude.ts +27 -0
  359. package/src/gated-globals.ts +131 -0
  360. package/src/generated/setup-by-example.generated.ts +53 -0
  361. package/src/gizmo-registry.ts +608 -0
  362. package/src/handle-system.ts +221 -0
  363. package/src/hierarchy-menu-registry.ts +70 -0
  364. package/src/hierarchy-rows.ts +73 -0
  365. package/src/hosted-example.ts +160 -0
  366. package/src/hotkeys.ts +142 -0
  367. package/src/ingest/discovery-react.ts +132 -0
  368. package/src/ingest/discovery.ts +205 -0
  369. package/src/ingest/discovery2d.ts +204 -0
  370. package/src/ingest/esm-entry-resolution.ts +102 -0
  371. package/src/ingest/games/bloom-composer/game.js +99 -0
  372. package/src/ingest/games/bloom-composer/vgai.game.json +21 -0
  373. package/src/ingest/games/embed-bundle/embed.html +10 -0
  374. package/src/ingest/games/embed-bundle/vgai.game.json +21 -0
  375. package/src/ingest/games/games-fps/assets/collision-world.glb +0 -0
  376. package/src/ingest/games/games-fps/game.js +479 -0
  377. package/src/ingest/games/games-fps/vgai.game.json +24 -0
  378. package/src/ingest/games/iframe-reachable/game-source.js +58 -0
  379. package/src/ingest/games/iframe-reachable/vgai.game.json +21 -0
  380. package/src/ingest/games/interactive-cubes/game.js +139 -0
  381. package/src/ingest/games/interactive-cubes/vgai.game.json +21 -0
  382. package/src/ingest/games/mismatched-three/fake-three.js +38 -0
  383. package/src/ingest/games/mismatched-three/game.js +10 -0
  384. package/src/ingest/games/mismatched-three/vgai.game.json +22 -0
  385. package/src/ingest/games/own-three-bundled/game.js +43 -0
  386. package/src/ingest/games/own-three-bundled/vgai.game.json +21 -0
  387. package/src/ingest/games/pointerlock-maze/game.js +288 -0
  388. package/src/ingest/games/pointerlock-maze/vgai.game.json +22 -0
  389. package/src/ingest/games-2d/_fixtures/first-party-scene.scn2d.json +124 -0
  390. package/src/ingest/games-2d/bubbo-bubbo/vgai.game.json +25 -0
  391. package/src/ingest/games-2d/bunnymark/game.ts +88 -0
  392. package/src/ingest/games-2d/bunnymark/vgai.game.json +21 -0
  393. package/src/ingest/games-2d/flappy/game.ts +148 -0
  394. package/src/ingest/games-2d/flappy/vgai.game.json +21 -0
  395. package/src/ingest/games-2d/flappy-pixi/vgai.game.json +25 -0
  396. package/src/ingest/games-2d/puzzling-potions/vgai.game.json +25 -0
  397. package/src/ingest/games-2d/tilemap-camera/game.ts +115 -0
  398. package/src/ingest/games-2d/tilemap-camera/vgai.game.json +21 -0
  399. package/src/ingest/games-react/react-rpg/entry.tsx +185 -0
  400. package/src/ingest/games-react/react-rpg/shims.d.ts +26 -0
  401. package/src/ingest/games-react/react-rpg/src/ui/game-state.tsx +129 -0
  402. package/src/ingest/games-react/react-rpg/vgai.game.json +21 -0
  403. package/src/ingest/host-namespace-registry.ts +196 -0
  404. package/src/ingest/types.ts +127 -0
  405. package/src/ingest-hierarchy-rows.ts +207 -0
  406. package/src/ingest-mode.ts +2092 -0
  407. package/src/ingest-siblings.ts +466 -0
  408. package/src/initial-scene.ts +194 -0
  409. package/src/inspector-section-registry.ts +117 -0
  410. package/src/interactive-edit-scope.ts +34 -0
  411. package/src/main.tsx +23 -0
  412. package/src/manifest-project.ts +43 -0
  413. package/src/model-thumbnail.ts +156 -0
  414. package/src/module-mode.ts +513 -0
  415. package/src/navmesh-handler.ts +94 -0
  416. package/src/packaged-runtime.ts +49 -0
  417. package/src/play-mode.ts +1148 -0
  418. package/src/playground/main.ts +206 -0
  419. package/src/project-manager.ts +173 -0
  420. package/src/scene-diff.ts +112 -0
  421. package/src/scene-serializer.ts +144 -0
  422. package/src/scene-sync.ts +587 -0
  423. package/src/scene-ui-mode/active-scene-ui.ts +58 -0
  424. package/src/scene-ui-mode/scene-ui-palette-panel.tsx +152 -0
  425. package/src/scene-ui-mode/scene-ui-timeline-tab.tsx +29 -0
  426. package/src/scene-ui-mode/ui-prefab-dialog-host.tsx +74 -0
  427. package/src/scene-ui-mode/ui-prefab-hierarchy-menu.ts +49 -0
  428. package/src/scene-ui-mode/ui-prefab-io.ts +76 -0
  429. package/src/script-loader.ts +143 -0
  430. package/src/storage/fsa-storage.ts +55 -0
  431. package/src/storage/handle-storage.ts +150 -0
  432. package/src/storage/handle-store.ts +116 -0
  433. package/src/storage/http-storage.ts +137 -0
  434. package/src/storage/index.ts +147 -0
  435. package/src/storage/mem-storage.ts +135 -0
  436. package/src/storage/opfs-storage.ts +25 -0
  437. package/src/storage/paths.ts +26 -0
  438. package/src/storage/seed.ts +106 -0
  439. package/src/storage/types.ts +110 -0
  440. package/src/tool-loader.ts +291 -0
  441. package/src/ui-editor/inspector.tsx +563 -0
  442. package/src/ui-editor/node-ops.ts +266 -0
  443. package/src/ui-editor/overlay.tsx +380 -0
  444. package/src/ui-editor/palette.tsx +114 -0
  445. package/src/ui-editor/react-store.ts +78 -0
  446. package/src/ui-editor/timeline-panel.tsx +443 -0
  447. package/src/ui-editor/ui-edit-store.ts +552 -0
  448. package/src/ui-editor/ui-prefab.ts +95 -0
  449. package/src/ui-source/inspect.ts +544 -0
  450. package/src/ui-source/oid-transform.ts +133 -0
  451. package/src/ui-source/source-write-backend.ts +203 -0
  452. package/src/ui-source/tailwind-map.ts +174 -0
  453. package/src/ui-source/writer.ts +1175 -0
  454. package/src/widgets/index.ts +73 -0
  455. package/template/.claude/skills/editor/SKILL.md +252 -0
  456. package/template/CLAUDE.md +512 -0
  457. package/template/LICENSE +30 -0
  458. package/template/emit-schemas.ts +42 -0
  459. package/template/index.html +17 -0
  460. package/template/package.json +53 -0
  461. package/template/project.json +9 -0
  462. package/template/public/audio/ambient-arena.wav +0 -0
  463. package/template/public/audio/ambient-music.wav +0 -0
  464. package/template/public/audio/ambient-nature.wav +0 -0
  465. package/template/public/audio/ambient-wind.wav +0 -0
  466. package/template/public/inputmaps/default.inputmap.json +41 -0
  467. package/template/public/jsm/libs/draco/gltf/draco_decoder.js +33 -0
  468. package/template/public/jsm/libs/draco/gltf/draco_decoder.wasm +0 -0
  469. package/template/public/jsm/libs/draco/gltf/draco_encoder.js +33 -0
  470. package/template/public/jsm/libs/draco/gltf/draco_wasm_wrapper.js +116 -0
  471. package/template/public/scenes/default.vscn.json +43 -0
  472. package/template/public/scenes/untitled.vscn.json +29 -0
  473. package/template/public/textures/waternormals.jpg +0 -0
  474. package/template/server/colyseus-setup.ts +85 -0
  475. package/template/server/main.ts +34 -0
  476. package/template/server/rooms/arena-room.ts +420 -0
  477. package/template/server/rooms/game-room.ts +162 -0
  478. package/template/server/rooms.ts +15 -0
  479. package/template/server/tsconfig.json +19 -0
  480. package/template/src/data/README.md +40 -0
  481. package/template/src/data/assets.ts +31 -0
  482. package/template/src/data/tuning.data.json +5 -0
  483. package/template/src/data/tuning.schema.json +21 -0
  484. package/template/src/data/tuning.schema.ts +34 -0
  485. package/template/src/data/tuning.ts +24 -0
  486. package/template/src/main.ts +157 -0
  487. package/template/src/scripts/components/data-spinner.ts +45 -0
  488. package/template/src/scripts/components/scene-camera.ts +40 -0
  489. package/template/src/scripts/main.ts +94 -0
  490. package/template/src/scripts/registry.ts +46 -0
  491. package/template/src/tools/README.md +14 -0
  492. package/template/src/tools/example.tool.tsx +91 -0
  493. package/template/src/tools/spin.tool.tsx +101 -0
  494. package/template/src/ui/Button.tsx +27 -0
  495. package/template/src/ui/DefaultHud.tsx +40 -0
  496. package/template/src/ui/KeyHint.tsx +25 -0
  497. package/template/src/ui/Panel.tsx +52 -0
  498. package/template/src/ui/RebindPanel.tsx +129 -0
  499. package/template/src/ui/Slider.tsx +28 -0
  500. package/template/src/ui/StatusDot.tsx +22 -0
  501. package/template/src/ui/Toggle.tsx +19 -0
  502. package/template/src/ui/game-state.tsx +37 -0
  503. package/template/src/ui/index.ts +7 -0
  504. package/template/src/ui/mount-default-hud.tsx +19 -0
  505. package/template/src/ui/mount-ui.ts +15 -0
  506. package/template/tsconfig.json +36 -0
  507. package/template/validate-asset-content.ts +78 -0
  508. package/template/validate-manifest.ts +55 -0
  509. package/template/validate-scenes.ts +211 -0
  510. package/template/vgai.game.json +21 -0
  511. package/template/vite.config.ts +128 -0
  512. package/vite-plugin-example-assets.ts +60 -0
  513. package/vite-plugin-game-globals.ts +46 -0
  514. package/vite-plugin-game-static.ts +71 -0
  515. package/vite-plugin-project-game-static.ts +84 -0
  516. package/vite-plugin-react-game-static.ts +98 -0
  517. package/vite-plugin-react-world-provider.ts +81 -0
  518. package/vite-plugin-react-world-runtime.ts +76 -0
  519. package/vite-plugin-ui-oid.ts +561 -0
@@ -0,0 +1,127 @@
1
+ import type { ExtraDepsResolution2D } from '@engine/world2d/ingest2d';
2
+
3
+ /**
4
+ * The `IngestGame` descriptor — the mountable shape `ingest-mode.ts`
5
+ * (`enterIngestModeWithGame`) and `authoring/ingest-game-adapter.ts`
6
+ * (`mountIngestGame`) consume, regardless of where it came from.
7
+ *
8
+ * T3.3 slice 3 (docs/CLI-ON-FOLDER-DESIGN.md §1E) moved this type out of the
9
+ * now-deleted `ingest/games/registry.ts` (the static `INGEST_GAMES` array) —
10
+ * it used to be registry-specific; now it is the common contract BOTH
11
+ * discovery frontends build: `ingest/discovery.ts`'s glob-based discovery of
12
+ * the in-tree fixture games under `ingest/games/<id>/vgai.game.json`, and
13
+ * `adapter-resolver.ts`'s `resolveIngestDescriptor`, which builds the same
14
+ * shape from an arbitrary manifest's `ingest-three` world (the CLI-on-folder
15
+ * route, for a game folder never registered in source).
16
+ *
17
+ * D-W1/D-W2 (docs/WAVE4-FTUE-HARDENING-DESIGN.md) add the PREBUILT-BUNDLE
18
+ * iframe-reachable fields (`bundleUrl`/`baseHref`/`assetBaseUrl`/`bodyHtml`/
19
+ * `extraDeps`) — the three-side mirror of `IngestGame2D`'s Track-P fields
20
+ * (`@engine/world2d/ingest2d.ts`) — and widen `embedHtml` to admit a LAZY
21
+ * thunk alongside its original plain-string form (see that field's own doc
22
+ * comment for why both shapes must keep working).
23
+ */
24
+ export interface IngestGame {
25
+ /** Stable id (used by the launcher + conformance test; == the manifest world id). */
26
+ id: string;
27
+ /** Human label shown in the editor's "Ingest game" menu (== the manifest's game name). */
28
+ name: string;
29
+ /** One-line description (== the manifest world's optional `description`, or `''`). */
30
+ description: string;
31
+ /**
32
+ * Dynamically import + run the unmodified game module (shared-`three`/deduped path).
33
+ * Omitted for `embedHtml`/`iframeReachableSrc` games (opaque-embed/iframe-reachable).
34
+ */
35
+ load?: () => Promise<unknown>;
36
+ /**
37
+ * Self-contained HTML for an OPAQUE prebuilt bundle (its own inlined renderer,
38
+ * `three` unreachable). The host runs it in an iframe at the embed-only floor
39
+ * (Tier 0–1): hosted + sized + disposed, but its scene is NOT introspectable.
40
+ * Mutually exclusive with `load`. See docs/ADAPTER-ARCHITECTURE.md §2.3.
41
+ *
42
+ * Two shapes, both legal (D-W2, docs/WAVE4-FTUE-HARDENING-DESIGN.md):
43
+ * - a plain `string` — the file's contents ALREADY READ (the in-tree
44
+ * fixture glob route, `ingest/discovery.ts`, which Vite reads eagerly at
45
+ * build/dev time via `import.meta.glob(..., { query: '?raw' })`); or
46
+ * - a lazy `() => Promise<string>` thunk — a MANIFEST-DRIVEN external
47
+ * folder (`adapter-resolver.ts`'s `resolveIngestDescriptor`), which reads
48
+ * the declared `entryHtml` file's bytes through the
49
+ * `/project-game-static/` route only when the game is actually mounted,
50
+ * never eagerly at resolve time (mirrors `bundleUrl`'s own laziness).
51
+ * `enterIngestModeWithGame` (ingest-mode.ts) resolves either form to a
52
+ * plain string before handing it to `mountIngestGameEmbed`.
53
+ */
54
+ embedHtml?: string | (() => Promise<string>);
55
+ /**
56
+ * Source of a PREBUILT bundle whose `three` is REACHABLE. The host runs it in a
57
+ * same-origin iframe whose importmap resolves `three` to the HOST instance (blob
58
+ * re-export), captures its live scene in-realm, and edits it fully (tier 2–3).
59
+ * Mutually exclusive with `load`/`embedHtml`. See ingest-iframe-reachable-adapter.ts.
60
+ */
61
+ iframeReachableSrc?: string;
62
+ /** Capture timeout (ms) before degrading to embed-only — short for the
63
+ * mismatched-three demo whose `three` is deliberately unreachable. */
64
+ captureTimeoutMs?: number;
65
+ /**
66
+ * Map of game-relative-path substring → served asset URL. The ingest adapter
67
+ * installs a `THREE.DefaultLoadingManager` URL modifier that rewrites any
68
+ * requested URL containing a key to its value.
69
+ */
70
+ assets?: Record<string, string>;
71
+ /**
72
+ * Element ids the game expects to already exist in the DOM (e.g. an FPS game's
73
+ * `#blocker`/`#instructions` overlay). The host creates hidden stub elements
74
+ * with these ids before running the game, so DOM-dependent games stay
75
+ * unmodified (study §4D).
76
+ */
77
+ domStubs?: string[];
78
+ /**
79
+ * The game's own manifest `version` (D9, docs/DECISIONS-PENDING.md §D9 —
80
+ * orphan/mismatch detection), when this descriptor was built straight from
81
+ * a manifest that has one. `ingest/discovery.ts`'s in-tree fixture route
82
+ * sets this from the parsed manifest's `version`; `adapter-resolver.ts`'s
83
+ * `resolveIngestDescriptor` (the CLI-on-folder / manifest-world route)
84
+ * cannot — it only has a `ResolvedWorldEntry`, not the manifest's top-level
85
+ * `version` — so `ingest-mode.ts`'s `enterIngestModeFromManifestWorld`
86
+ * threads the resolved manifest's `version` through as an explicit
87
+ * parameter instead, taking precedence over this field where both exist.
88
+ */
89
+ gameVersion?: string;
90
+
91
+ // ---------------------------------------------------------------------
92
+ // D-W1 (docs/WAVE4-FTUE-HARDENING-DESIGN.md) — IFRAME-REACHABLE
93
+ // PREBUILT-BUNDLE mount fields, the three-side mirror of `IngestGame2D`'s
94
+ // Track-P fields (`@engine/world2d/ingest2d.ts`). Populated only when
95
+ // `iframeReachableSrc`/`load` are both absent and the world's manifest
96
+ // strategy is `iframe-reachable` with a `bundleUrl` (see
97
+ // `adapter-resolver.ts`'s `resolveIngestDescriptor`). The bundle MUST
98
+ // externalize `three` (a bare, un-rewritten `import 'three'`) — same bar
99
+ // as pixi's D-X5/D-Z4 — so it resolves through the importmap below to the
100
+ // HOST's `three`, not an inlined copy the capture trap can't see.
101
+ // ---------------------------------------------------------------------
102
+ /**
103
+ * Absolute URL of the externalized built game bundle, mounted via
104
+ * `<script type="module" src=...>` instead of an inline source string
105
+ * (`mountIngestGameIframeReachableBundle`, `ingest-iframe-reachable-adapter.ts`).
106
+ */
107
+ bundleUrl?: string;
108
+ /** `<base href>` for the iframe so the game's relative asset URLs resolve. */
109
+ baseHref?: string;
110
+ /**
111
+ * Host-side asset URL remap forced onto the host THREE's
112
+ * `DefaultLoadingManager.setURLModifier` — the three analog of pixi's
113
+ * `Assets.init` basePath wrap (a document.write iframe keeps the PARENT's
114
+ * `window.location`, so a relative asset request would otherwise resolve
115
+ * against the parent page, not the served bundle dir).
116
+ */
117
+ assetBaseUrl?: string;
118
+ /** DOM injected into the iframe body before the bundle's script boots (e.g. a `<div id="game-root">` it expects to find). */
119
+ bodyHtml?: string;
120
+ /**
121
+ * Lazily resolve this game's bare-specifier -> extraDeps resolution (D-Z3,
122
+ * the SAME `ExtraDepsResolution2D` shape the pixi/world2d side uses —
123
+ * namespaces + verbatim URLs) via the editor's host-namespace registry.
124
+ * Absent means no extra externalized deps beyond `three` itself.
125
+ */
126
+ extraDeps?: () => Promise<ExtraDepsResolution2D>;
127
+ }
@@ -0,0 +1,207 @@
1
+ /**
2
+ * Pure row-flattening for `IngestHierarchy` (no React) — D-W4 (F14/F18,
3
+ * docs/WAVE4-FTUE-HARDENING-DESIGN.md §D-W4), extracted the same way
4
+ * `hierarchy-rows.ts` extracts `SceneHierarchy`'s equivalent, so the
5
+ * key/collapse/cycle-guard logic is unit-testable without rendering.
6
+ *
7
+ * §0.5's ground truth: an ingested game's structural ids
8
+ * (`ingest:<path>:<type>:<name>`, `@engine/adapter/ingest/overlay-apply.ts`'s
9
+ * `assignStructuralIds`) are baked ONCE at capture and are the overlay
10
+ * PERSISTENCE key (overlay-apply.ts:45-51) — never touched here. But
11
+ * `IngestHierarchy` re-reads the LIVE `Object3D` tree every render
12
+ * (`adapter.hierarchy.node(id)`), and a live game can reorder or clone
13
+ * subtrees after capture, so the SAME baked id can legitimately show up in
14
+ * more than one place in a single walk — `EditorNode.id` alone is no longer
15
+ * a safe React key, and naively recursing `childIds` with no guard can loop
16
+ * forever if a stale/duplicated id ever points back at one of its own
17
+ * ancestors.
18
+ *
19
+ * Wave-7 (docs/WAVE7-HIERARCHY-CAP-DESIGN.md §1 D-C1..D-C6): per-parent
20
+ * child cap, copied from `hierarchy-rows.ts`'s `flattenVisibleRows`/
21
+ * `CHILD_CAP`/`MORE_ID_PREFIX` (same constants, no drift). Unlike
22
+ * first-party (which only caps in play mode), the adapter panel's tree is
23
+ * BY DEFINITION a live game scene graph, so `capEnabled` defaults to
24
+ * `false` here (matching this function's PRE-cap behavior byte-for-byte —
25
+ * every existing caller/test that doesn't pass the new params keeps working
26
+ * unchanged) and `IngestHierarchy` explicitly turns it on for the browse
27
+ * view. Search bypasses the cap by calling with `capEnabled=false` (D-C4) —
28
+ * the exact same "flatten UNCAPPED, filter flat" shape this module already
29
+ * used for search before the cap existed.
30
+ */
31
+
32
+ import type { EditorNode, HierarchyProvider } from '@engine/adapter';
33
+ import { CHILD_CAP, MORE_ID_PREFIX } from './hierarchy-rows';
34
+
35
+ /** One flattened, render-ready row over an ingested game's live hierarchy. */
36
+ export interface IngestRow {
37
+ readonly node: EditorNode;
38
+ readonly depth: number;
39
+ /**
40
+ * Render key material: the walk path (root index, then child index at
41
+ * each level) — NOT `node.id` alone. Stays unique across a render even
42
+ * when the id scheme collides, because it is derived from POSITION in
43
+ * the walk, not from the adapter's (potentially stale/duplicated) data.
44
+ */
45
+ readonly pathKey: string;
46
+ readonly hasChildren: boolean;
47
+ /** True when an ANCESTOR's `pathKey` is in the caller's collapsed-set —
48
+ * i.e. this row is inside a collapsed subtree (F18). The row itself is
49
+ * still included in the returned array (so a search can still find it);
50
+ * the component filters it out when not searching. */
51
+ readonly hiddenByCollapse: boolean;
52
+ /** Present on a synthetic "… N more" row that reveals capped siblings
53
+ * (D-C2) — `parentPathKey` is the capped parent's `pathKey`, `hidden` is
54
+ * how many of its children are not shown. Never present on a real row. */
55
+ readonly more?: { readonly parentPathKey: string; readonly hidden: number };
56
+ }
57
+
58
+ /**
59
+ * Backstop against a childIds list this guard's own dedup somehow doesn't
60
+ * anticipate (e.g. a very deep but genuinely acyclic live tree) — ingested
61
+ * games are not expected to nest anywhere near this deep; this is a second,
62
+ * independent safety net, not the primary guard (see `visited` below).
63
+ */
64
+ const MAX_DEPTH = 500;
65
+
66
+ /** How many of a parent's children to walk (D-C1/D-C3) — split out of `walk`
67
+ * below purely to keep that function's cognitive-complexity score down. */
68
+ function childLimit(
69
+ capEnabled: boolean,
70
+ revealed: ReadonlyMap<string, number>,
71
+ parentPathKey: string,
72
+ ): number {
73
+ return capEnabled
74
+ ? Math.max(CHILD_CAP, revealed.get(parentPathKey) ?? CHILD_CAP)
75
+ : Number.POSITIVE_INFINITY;
76
+ }
77
+
78
+ /** The synthetic "… N more" row for a capped parent (D-C2) — a render-only
79
+ * stub, never fed back to the adapter. Split out of `walk` below purely to
80
+ * keep that function's cognitive-complexity score down. */
81
+ function buildMoreRow(
82
+ parentPathKey: string,
83
+ depth: number,
84
+ parentId: string,
85
+ hiddenByCollapse: boolean,
86
+ hidden: number,
87
+ ): IngestRow {
88
+ return {
89
+ node: {
90
+ id: `${MORE_ID_PREFIX}${parentPathKey}`,
91
+ label: '',
92
+ kind: 'object',
93
+ parentId,
94
+ childIds: [],
95
+ flags: {},
96
+ },
97
+ depth,
98
+ pathKey: `${parentPathKey}/__more__`,
99
+ hasChildren: false,
100
+ hiddenByCollapse,
101
+ more: { parentPathKey, hidden },
102
+ };
103
+ }
104
+
105
+ /**
106
+ * Flatten an ingest adapter's hierarchy into display rows.
107
+ *
108
+ * F14 cycle/dup guard: `visited` tracks every `node.id` already emitted in
109
+ * THIS walk. A live game reordering/cloning objects can make the same baked
110
+ * id reachable from more than one place (a real duplicate) or, in principle,
111
+ * from one of its own descendants (a cycle) — either way the id is stale
112
+ * data describing the CURRENT live scene, not a second logical node. The
113
+ * chosen semantics: render the first occurrence encountered (root-first,
114
+ * then depth-first child order) and silently skip every later one — no
115
+ * second row, and a cycle can never recurse forever. `collapsedKeys` is
116
+ * keyed by `pathKey`, not `node.id` (F18) — a walk-path is stable for "this
117
+ * position in the tree shape", which is what "collapsed" means to a user
118
+ * looking at the panel; keying by id would let a stale/reused id apply a
119
+ * collapse to the WRONG node after a live reorder, or fail to distinguish
120
+ * two positions that happen to share a duplicated id.
121
+ *
122
+ * D-C1/D-C3 cap: when `capEnabled`, each parent's children are limited to
123
+ * `max(CHILD_CAP, revealed.get(parentPathKey) ?? CHILD_CAP)` and a synthetic
124
+ * more-row is appended when some are hidden (D-C2). D-C5: children beyond
125
+ * the limit are never walked, so never added to `visited` — a duplicate id
126
+ * whose first structural occurrence was capped away still renders at its
127
+ * next reachable occurrence (the dedup guard's "once, not zero times"
128
+ * guarantee holds). D-C6: a COLLAPSED parent (its own `pathKey` is in
129
+ * `collapsedKeys`) contributes no child rows and no more-row at all when
130
+ * capped — the walk stops at the parent itself rather than descending and
131
+ * relying on `hiddenByCollapse` filtering, since a more-row would otherwise
132
+ * still need suppressing. Uncapped calls (search, D-C4) are unaffected:
133
+ * collapse only ever gates recursion when `capEnabled`, so a collapsed
134
+ * subtree's matches stay reachable when searching, exactly as before.
135
+ */
136
+ export function flattenIngestRows(
137
+ hierarchy: Pick<HierarchyProvider, 'roots' | 'node'>,
138
+ collapsedKeys: ReadonlySet<string>,
139
+ revealed: ReadonlyMap<string, number> = new Map(),
140
+ capEnabled = false,
141
+ ): IngestRow[] {
142
+ const rows: IngestRow[] = [];
143
+ const visited = new Set<string>();
144
+
145
+ const walk = (node: EditorNode, depth: number, pathKey: string, parentHidden: boolean): void => {
146
+ if (visited.has(node.id) || depth > MAX_DEPTH) return;
147
+ visited.add(node.id);
148
+
149
+ const hasChildren = node.childIds.length > 0;
150
+ rows.push({ node, depth, pathKey, hasChildren, hiddenByCollapse: parentHidden });
151
+
152
+ const isCollapsed = collapsedKeys.has(pathKey);
153
+ if (capEnabled && isCollapsed) return; // D-C6: nothing of a collapsed subtree renders.
154
+
155
+ const childHidden = parentHidden || isCollapsed;
156
+ const shown = Math.min(node.childIds.length, childLimit(capEnabled, revealed, pathKey));
157
+
158
+ for (let i = 0; i < shown; i++) {
159
+ const child = hierarchy.node(node.childIds[i]!);
160
+ if (child) walk(child, depth + 1, `${pathKey}.${i}`, childHidden);
161
+ }
162
+
163
+ if (capEnabled && node.childIds.length > shown) {
164
+ rows.push(
165
+ buildMoreRow(pathKey, depth + 1, node.id, childHidden, node.childIds.length - shown),
166
+ );
167
+ }
168
+ };
169
+
170
+ hierarchy.roots().forEach((root, i) => {
171
+ walk(root, 0, `r${i}`, false);
172
+ });
173
+ return rows;
174
+ }
175
+
176
+ /** Stable React key for a row — walk path + id, so it never collides even
177
+ * when the underlying id scheme does (F14). */
178
+ export function ingestRowKey(row: Pick<IngestRow, 'pathKey' | 'node'>): string {
179
+ return `${row.pathKey}:${row.node.id}`;
180
+ }
181
+
182
+ /**
183
+ * Wave-18 (docs/WAVE18-INGEST-HIERARCHY-VIRTUALIZATION-DESIGN.md): the pure
184
+ * start/end row-index math for `IngestHierarchy`'s scroll-windowed rendering.
185
+ * Kept here (not inlined in the component) for two reasons: it is
186
+ * unit-testable standalone with no React/jsdom involved, and a tamper test
187
+ * can `vi.mock` this ONE function to neutralize windowing (return the full
188
+ * range) and prove the render-bounding behavior actually depends on it, not
189
+ * on some other accidental cap.
190
+ *
191
+ * `overscan` extra rows are kept rendered on each side of the visible band
192
+ * so a fast scroll or keyboard nav doesn't flash empty space before the next
193
+ * paint catches up. `end` is clamped to `totalRows`; `start` is clamped to 0
194
+ * (never negative near the top of the list).
195
+ */
196
+ export function ingestRowWindow(
197
+ totalRows: number,
198
+ scrollTop: number,
199
+ viewportPx: number,
200
+ rowH: number,
201
+ overscan: number,
202
+ ): { start: number; end: number } {
203
+ const start = Math.max(0, Math.floor(scrollTop / rowH) - overscan);
204
+ const visibleCount = Math.ceil(viewportPx / rowH) + overscan * 2;
205
+ const end = Math.min(totalRows, start + visibleCount);
206
+ return { start, end };
207
+ }