@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,185 @@
1
+ /**
2
+ * Host shim for the vendored react-rpg ingest (Track N, N2 —
3
+ * docs/REACT-INGEST-LANDING-DESIGN.md D-N2/D-N3/D-N7). Composes the vendored
4
+ * game's own `App` + Redux `store`/`persistor` — NO game-source edits, ever
5
+ * (the anti-shim rule). Default-exports the composed component, which
6
+ * `resolveIngestReactAdapter` (`adapter-resolver.ts`, Part G) wraps in
7
+ * `<GameProvider game={game}>` and mounts via `createRoot` into the T6.2
8
+ * react-world host stack — same mechanism `default-react` uses, restricted
9
+ * to the `'deduped'` strategy rung.
10
+ *
11
+ * The vendored game's OWN standalone entry
12
+ * (`vendor/react-games/react-rpg/src/index.jsx`, a React-17 `ReactDOM.render`
13
+ * call) is vendored but NEVER imported here — D-N2 is explicit that entry
14
+ * point must never run through this path. Reading it instead (for reference
15
+ * only) to find exactly what page environment it sets up, this shim
16
+ * replicates the minimum, D-N7:
17
+ *
18
+ * 1. `id="window"` — `features/player/controls.jsx`'s hammerjs binding does
19
+ * `new Hammer(document.getElementById('window'))`. Upstream satisfies
20
+ * this by stamping `id="window"` on the `<html>` tag itself
21
+ * (`index.html`); we can't safely do that to the EDITOR's own `<html>`,
22
+ * so this shim renders an equivalent wrapping element instead.
23
+ * 2. `id="react-rpg"` — a FOURTH host-env assumption beyond D-N7's named
24
+ * three, found by reading `App.jsx` itself (not just `index.jsx`):
25
+ * `App.jsx`'s own `useEffect` calls
26
+ * `disableBodyScroll(document.getElementById('react-rpg'))`
27
+ * (`body-scroll-lock`) against the id upstream's `index.html` gives its
28
+ * React mount target (`<div id="react-rpg">`, matching `index.jsx`'s
29
+ * `ReactDOM.render(<ConnectedApp/>, document.getElementById('react-rpg'))`).
30
+ * Nested exactly like upstream's real DOM (`<html id="window"><body>
31
+ * <div id="react-rpg">`), so both lookups succeed.
32
+ * 3. `react-sound`'s `soundManager` global (`index.jsx`'s
33
+ * `soundManager.setup({...})`) — needed before any `<Sound>` component
34
+ * (`features/game-menus/game-music`, `features/player`) renders. Called
35
+ * at MODULE TOP LEVEL (not inside an effect), mirroring `index.jsx`
36
+ * exactly — a module only ever evaluates once, so this never re-runs on
37
+ * an in-page remount either.
38
+ * 4. `public/tiles/**`/`public/logo-no-bg.png` asset serving — handled
39
+ * SERVER-SIDE (`packages/editor/vite-plugin-react-game-static.ts`), not
40
+ * in this shim; `config/constants.js`'s `GET_REF_URL()` computes an
41
+ * absolute tile-asset base URL from its own `import.meta.url` (locating
42
+ * the literal substring `'src'` in it) — see that plugin's doc comment
43
+ * for exactly which URL this resolves to and why keeping the vendored
44
+ * folder named `src/` (not renamed) is load-bearing for this to even be
45
+ * a VALID URL, not just a differently-located one.
46
+ * 5. The typeface imports (`typeface-montserrat`/`typeface-roboto`/
47
+ * `typeface-roboto-mono`) and the game's global `index.scss` reset —
48
+ * `index.jsx` imports these before mounting; replicated here for visual
49
+ * fidelity (R-N1: accepted global-SCSS-bleed risk, v1).
50
+ *
51
+ * R-N2 (react-ga4) — VERIFIED INERT: `grep -rn react-ga4` over the vendored
52
+ * tree finds exactly ONE reference, `src/index.jsx`'s own
53
+ * `ReactGA.initialize(...)`/`ReactGA.send(...)` calls — that file is vendored
54
+ * but never imported (see above), so `react-ga4` never initializes and never
55
+ * fires a network request through this ingestion path. No stub/neutralization
56
+ * needed; recorded here rather than assumed.
57
+ *
58
+ * TWO DIFFERENT "avoid strict-TS-resolution" idioms are in play below, and
59
+ * they are NOT interchangeable — an empirical finding from the real dev
60
+ * server (a mocked-createRoot unit test can't catch this; only a real
61
+ * browser import actually attempts network resolution):
62
+ * - The vendored game's own `App.jsx`/`config/store.js` are imported via a
63
+ * dynamic `import()` whose specifier is a plain RELATIVE path built from a
64
+ * `const` (not a string literal at the call site, `/* @vite-ignore *\/`)
65
+ * — `tsc` skips module resolution for a non-literal specifier (mirrors
66
+ * every `fsImportPath`-built dynamic import in `adapter-resolver.ts`), and
67
+ * the BROWSER resolves a relative URL natively with no bundler help
68
+ * needed — both sides work.
69
+ * - `react-sound` and `redux-persist/integration/react` are BARE package
70
+ * specifiers instead — a bare specifier has NO meaning to a browser's
71
+ * native `import()` at all (unlike a relative URL) unless Vite's dev
72
+ * server rewrites it to `/node_modules/.vite/deps/...`, which Vite only
73
+ * does for imports it can STATICALLY analyze. `/* @vite-ignore *\/`
74
+ * explicitly tells Vite to skip that analysis — so applying the SAME
75
+ * dynamic-import trick to these two bare specifiers throws
76
+ * `Failed to resolve module specifier` at runtime (verified against the
77
+ * real dev server). The fix: import these two STATICALLY (letting Vite's
78
+ * normal analysis/rewrite handle them) and silence `tsc`'s missing-`.d.ts`
79
+ * complaint with the ambient module declarations in `./shims.d.ts`
80
+ * instead of a specifier trick.
81
+ */
82
+ import { type ComponentType, type CSSProperties, useEffect, useState } from 'react';
83
+ import { Provider } from 'react-redux';
84
+ import { PersistGate } from 'redux-persist/integration/react';
85
+ import 'react-sound';
86
+ import 'typeface-montserrat';
87
+ import 'typeface-roboto';
88
+ import 'typeface-roboto-mono';
89
+ import '../../../../../../vendor/react-games/react-rpg/src/index.scss';
90
+
91
+ const GAME_ROOT = '../../../../../../vendor/react-games/react-rpg/src';
92
+
93
+ const FULL_SIZE: CSSProperties = { width: '100%', height: '100%' };
94
+ // The T6.2 host stack's per-world DOM-root layer defaults to
95
+ // `pointer-events: none` (mountOneReactWorld, create-runtime.ts) — the right
96
+ // default for a HUD overlaid on a canvas world, letting clicks fall through
97
+ // to the canvas below by default and opting specific elements back IN. An
98
+ // INGESTED full-game react world has no canvas underneath it to fall through
99
+ // to — nothing in react-rpg's own foreign JSX knows about vgai's opt-in
100
+ // convention, so without this the entire game is unclickable. This is the
101
+ // documented mechanism (create-runtime.ts: "the mounted react tree opts
102
+ // specific elements back in with pointer-events:auto") applied at the
103
+ // shim's own outermost element — opts the WHOLE ingested tree back in, no
104
+ // engine change needed.
105
+ const OUTER_STYLE: CSSProperties = { ...FULL_SIZE, pointerEvents: 'auto' };
106
+
107
+ interface ReactRpgModules {
108
+ App: ComponentType;
109
+ store: unknown;
110
+ persistor: { persist: () => void };
111
+ }
112
+
113
+ // D-N7 item 3 — see module doc comment: called once, at module evaluation
114
+ // time, exactly mirroring `index.jsx`'s own top-level
115
+ // `import 'react-sound'; soundManager.setup({...});` sequence.
116
+ (globalThis as unknown as { soundManager?: { setup: (o: object) => void } }).soundManager?.setup({
117
+ debugMode: false,
118
+ ignoreMobileRestrictions: true,
119
+ });
120
+
121
+ const APP_SPECIFIER = `${GAME_ROOT}/App.jsx`;
122
+ const STORE_SPECIFIER = `${GAME_ROOT}/config/store.js`;
123
+
124
+ let modulesPromise: Promise<ReactRpgModules> | null = null;
125
+ /** Import the vendored game's own `App` + `store`/`persistor` — cached so a
126
+ * dispose -> remount cycle doesn't re-fetch. */
127
+ function loadReactRpgModules(): Promise<ReactRpgModules> {
128
+ if (!modulesPromise) {
129
+ modulesPromise = (async () => {
130
+ const [appMod, storeMod] = await Promise.all([
131
+ import(/* @vite-ignore */ APP_SPECIFIER) as Promise<{
132
+ default: ComponentType;
133
+ }>,
134
+ import(/* @vite-ignore */ STORE_SPECIFIER) as Promise<{
135
+ default: unknown;
136
+ persistor: { persist: () => void };
137
+ }>,
138
+ ]);
139
+ return {
140
+ App: appMod.default,
141
+ store: storeMod.default,
142
+ persistor: storeMod.persistor,
143
+ };
144
+ })();
145
+ }
146
+ return modulesPromise;
147
+ }
148
+
149
+ /** The host shim, default-exported (D-N2's contract — a react world's `entry`
150
+ * module default-exports a component, `loadReactEntryComponent`). Renders
151
+ * `null` until the vendored modules resolve (they're ordinary same-origin
152
+ * Vite-served modules — no capture/timeout machinery needed, unlike the
153
+ * three/pixi ingest tiers). */
154
+ export default function ReactRpgHostShim() {
155
+ const [mods, setMods] = useState<ReactRpgModules | null>(null);
156
+
157
+ useEffect(() => {
158
+ let cancelled = false;
159
+ void loadReactRpgModules().then((m) => {
160
+ if (!cancelled) setMods(m);
161
+ });
162
+ return () => {
163
+ cancelled = true;
164
+ };
165
+ }, []);
166
+
167
+ if (!mods) return null;
168
+ const { App, store, persistor } = mods;
169
+
170
+ // D-N7 items 1/2: nested id="window" > id="react-rpg", mirroring upstream's
171
+ // real <html id="window"><body><div id="react-rpg"> structure so both
172
+ // `document.getElementById('window')` (hammerjs) and
173
+ // `document.getElementById('react-rpg')` (body-scroll-lock, App.jsx) resolve.
174
+ return (
175
+ <div id="window" style={OUTER_STYLE}>
176
+ <div id="react-rpg" style={FULL_SIZE}>
177
+ <Provider store={store as never}>
178
+ <PersistGate loading={null} persistor={persistor}>
179
+ <App />
180
+ </PersistGate>
181
+ </Provider>
182
+ </div>
183
+ </div>
184
+ );
185
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Ambient module declarations for two bare packages `entry.tsx` imports
3
+ * STATICALLY (Track N, N2 — see that file's doc comment for why these two
4
+ * specifically must be static, not the dynamic-`/* @vite-ignore *\/` idiom
5
+ * used for the vendored game's own `App.jsx`/`config/store.js`):
6
+ *
7
+ * - `react-sound` ships no types at all (no `@types/react-sound` on npm) —
8
+ * imported only for its side effect (attaching `window.soundManager`).
9
+ * - `redux-persist`'s root package ships types (`types:
10
+ * './types/index.d.ts'`) but has no `exports`/`typesVersions` map for
11
+ * this subpath, so `tsc` can't find a declaration file for it even though
12
+ * one exists on disk (`redux-persist/types/integration/react.d.ts`).
13
+ */
14
+ declare module 'react-sound';
15
+
16
+ declare module 'redux-persist/integration/react' {
17
+ import type { ComponentType, ReactNode } from 'react';
18
+
19
+ export interface PersistGateProps {
20
+ loading?: ReactNode;
21
+ persistor: unknown;
22
+ children?: ReactNode;
23
+ onBeforeLift?: () => void | Promise<void>;
24
+ }
25
+ export const PersistGate: ComponentType<PersistGateProps>;
26
+ }
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Track N, N2 — verbatim copy of the template's `GameProvider` seam
3
+ * (`packages/editor/template/src/ui/game-state.tsx`), present here
4
+ * ONLY because `adapter-resolver.ts`'s `loadProjectGameProvider` (shared by
5
+ * `default-react` and `ingest-react`, T6.2/Track N) hard-requires
6
+ * `src/ui/game-state.tsx` under whatever `projectRoot` an
7
+ * `ingest-react` world resolves against — see
8
+ * `vite-plugin-react-world-provider.ts`'s literal `/src/ui/
9
+ * game-state.tsx` path. This folder (`games-react/react-rpg/`) IS that
10
+ * world's `projectRoot` (its `vgai.game.json`'s `entry` — `../entry.tsx` —
11
+ * resolves relative to it too), so it needs its own copy, exactly like every
12
+ * scaffolded project gets one (`create-vgai-project`'s `scaffoldProject`).
13
+ *
14
+ * The vendored react-rpg game itself never reads `useGameState`/`useGame` —
15
+ * D-N2's host shim (`../../entry.tsx`) only composes the vendored game's OWN
16
+ * `<Provider store><PersistGate persistor><App/></PersistGate></Provider>`,
17
+ * with `<GameProvider>` wrapped around that AUTOMATICALLY by the resolver
18
+ * (context-only, harmless to a foreign tree, per D-N2). This file is
19
+ * therefore present purely to satisfy the resolver's lookup, not because the
20
+ * ingested game consumes it — kept byte-identical to the template's copy so
21
+ * a future react-ingest game that DOES want the state bridge (e.g. an
22
+ * ingest-authoring follow-on, D-N8) gets it for free.
23
+ */
24
+
25
+ import type { WorldStateObserver } from '@engine/adapter';
26
+ import {
27
+ createFrameSelectorCache,
28
+ type Equals,
29
+ shallow,
30
+ } from '@engine/runtime/frame-selector-cache';
31
+ import type { Game } from '@engine/runtime/game';
32
+ import { createContext, type ReactNode, useContext, useRef, useSyncExternalStore } from 'react';
33
+
34
+ /** Re-exported for convenience — the opt-in equality for selectors that
35
+ * return a fresh object/array/tuple every call (default is `Object.is`). */
36
+ export { shallow };
37
+
38
+ const GameContext = createContext<Game | null>(null);
39
+
40
+ /** Provide the `Game` to `useGameState`/`useGame` for everything mounted
41
+ * beneath it. Does not replace or wrap `mountUI` — compose it around the
42
+ * element passed to `mountUI` (see the module doc comment above). */
43
+ export function GameProvider({ game, children }: { game: Game; children: ReactNode }) {
44
+ return <GameContext.Provider value={game}>{children}</GameContext.Provider>;
45
+ }
46
+
47
+ /** Read the `Game` provided by the nearest `GameProvider`. Throws
48
+ * descriptively when called outside one — matching the repo's loud-failure
49
+ * habit rather than silently returning `null`. */
50
+ export function useGame(): Game {
51
+ const game = useContext(GameContext);
52
+ if (!game) {
53
+ throw new Error(
54
+ 'useGame: no Game in context — wrap this component in <GameProvider game={ctx.game!}>.',
55
+ );
56
+ }
57
+ return game;
58
+ }
59
+
60
+ /**
61
+ * Subscribe to a selected slice of game state (`docs/REACT-STATE-BRIDGE.md`
62
+ * §3). Re-renders only when the selected value changes: the selector re-runs
63
+ * at most once per completed frame (`game.state.frameVersion`), and
64
+ * `equals` (default `Object.is`; pass {@link shallow} for tuples/objects)
65
+ * gates whether the fresh result actually counts as a change.
66
+ */
67
+ export function useGameState<T>(selector: (game: Game) => T, equals: Equals<T> = Object.is): T {
68
+ const game = useGame();
69
+ const cacheRef = useRef<ReturnType<typeof createFrameSelectorCache<T>> | null>(null);
70
+ if (cacheRef.current === null) {
71
+ cacheRef.current = createFrameSelectorCache<T>(equals);
72
+ }
73
+
74
+ return useSyncExternalStore(
75
+ (onStoreChange) => game.state.subscribe(onStoreChange),
76
+ () => cacheRef.current!.get(game.state.frameVersion, () => selector(game)),
77
+ );
78
+ }
79
+
80
+ /**
81
+ * Pure, react-free lookup for the `useWorldObservation` hook below — see the
82
+ * template's copy of this file for the full doc comment (byte-identical
83
+ * logic, kept here only so this folder's `GameProvider` lookup resolves).
84
+ */
85
+ export function requireWorldObserver(game: Game, worldId: string): WorldStateObserver {
86
+ const world = game.world(worldId);
87
+ if (!world) {
88
+ throw new Error(
89
+ `useWorldObservation: no world registered with id "${worldId}" — check game.worlds for the ` +
90
+ 'ids actually registered.',
91
+ );
92
+ }
93
+ const observer = world.mounted.observe;
94
+ if (!observer) {
95
+ throw new Error(
96
+ `useWorldObservation: world "${worldId}" (kind: ${world.kind}, adapter: "${world.adapter.id}") ` +
97
+ 'has no state bridge — its mount has no `observe` (WorldStateObserver). This world cannot ' +
98
+ 'be observed from React (docs/REACT-STATE-BRIDGE.md §4).',
99
+ );
100
+ }
101
+ return observer;
102
+ }
103
+
104
+ /**
105
+ * Subscribe to a selected slice of a FOREIGN (non-first-party) world's
106
+ * observed state — see the template's copy for the full doc comment.
107
+ */
108
+ export function useWorldObservation<T>(
109
+ worldId: string,
110
+ selector: (snapshot: unknown) => T,
111
+ equals: Equals<T> = Object.is,
112
+ ): T {
113
+ const game = useGame();
114
+ const observer = requireWorldObserver(game, worldId);
115
+ const cacheRef = useRef<ReturnType<typeof createFrameSelectorCache<T>> | null>(null);
116
+ if (cacheRef.current === null) {
117
+ cacheRef.current = createFrameSelectorCache<T>(equals);
118
+ }
119
+ const versionRef = useRef(0);
120
+
121
+ return useSyncExternalStore(
122
+ (onStoreChange) =>
123
+ observer.subscribe(() => {
124
+ versionRef.current++;
125
+ onStoreChange();
126
+ }),
127
+ () => cacheRef.current!.get(versionRef.current, () => selector(observer.snapshot())),
128
+ );
129
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "manifestVersion": 1,
3
+ "name": "React RPG: 2e (real OSS game)",
4
+ "version": "2.0.0",
5
+ "engine": {
6
+ "version": "0.1.0"
7
+ },
8
+ "worlds": [
9
+ {
10
+ "id": "react-rpg",
11
+ "kind": "react",
12
+ "description": "REAL unmodified native-React OSS game — ASteinheiser/react-rpg.com, vendored byte-for-byte under vendor/react-games/react-rpg (MIT) and mounted via the ingest-react identity (Track N, D-N1/D-N2/D-N3). No authoring in v1 (D-N8) — this world is ingested read-only, no scene/write-back surface.",
13
+ "adapter": {
14
+ "ingest": {
15
+ "strategy": "deduped"
16
+ }
17
+ },
18
+ "entry": "entry.tsx"
19
+ }
20
+ ]
21
+ }
@@ -0,0 +1,196 @@
1
+ /**
2
+ * Host-namespace registry — Track P (docs/PIXI-INGEST-LANDING-DESIGN.md §2,
3
+ * D-P1): the editor-side half of `extraDeps` being DATA, not code. A manifest
4
+ * can only carry `extraDeps: string[]` (bare specifiers) — a JSON value has
5
+ * no way to carry a live ES module namespace object. This module owns the
6
+ * ONE static, known mapping from a bare specifier to a dynamically-imported
7
+ * HOST module namespace (the same instance the trapped pixi's extensions
8
+ * register against — see `ingest-iframe-2d.ts`'s `IframeReachableMultiOpts.
9
+ * extraDeps` doc comment), so `resolveIngest2DDescriptor`/`discovery2d.ts`
10
+ * can turn a manifest's `extraDeps` into the `ExtraDepsResolution2D` shape
11
+ * `mountIngestGame2DIframeReachableMulti` actually takes.
12
+ *
13
+ * Anti-shim (repo rule): a manifest naming a specifier this registry doesn't
14
+ * know THROWS at resolve, naming the specifier and listing every known one —
15
+ * never a silent stub/no-op namespace.
16
+ *
17
+ * Dynamic `import()` (not a static top-level import) for every entry: most
18
+ * editor sessions never ingest a pixi game that needs `@pixi/sound`/
19
+ * `@pixi/ui`/`gsap`/spine at all, so a static import would pull all four into
20
+ * every editor bundle. The registry of KNOWN specifiers below is still
21
+ * static (a plain object/Set of importer functions) — only the actual module
22
+ * evaluation is deferred to first use.
23
+ *
24
+ * D-Z3 (docs/WAVE3-ADAPTER-PLUMBING-DESIGN.md) — the registry pins stay
25
+ * authoritative and UNCHANGED (resolution order step 1 below); a specifier
26
+ * this registry doesn't know is no longer an immediate throw — it FALLS BACK
27
+ * to probing the OPEN PROJECT's own `node_modules/<specifier>/package.json`
28
+ * through the dev-server-only `/project-game-static` route (step 2), and
29
+ * only throws the anti-shim error if that fallback also comes up empty (step
30
+ * 3). This keeps the anti-shim doctrine (never fabricate/stub a dep) while
31
+ * admitting an external unmodified game's OWN deps beyond the four-entry
32
+ * registry, resolved as verbatim iframe importmap URL entries (never
33
+ * imported host-side — see `ingest-iframe-2d.ts`'s `extraDepUrls`).
34
+ *
35
+ * D-Z4 (docs/WAVE3-ADAPTER-PLUMBING-DESIGN.md §1) — `vgai bundle` needs the
36
+ * SAME two questions ("is this specifier registry-known?" / "does the
37
+ * project's own node_modules have a resolvable ESM entry for it?") answered
38
+ * from a plain Node CLI script, not a browser realm — see
39
+ * `knownHostNamespaceSpecifiers`/`isKnownHostNamespaceSpecifier` (pure, no
40
+ * I/O) and `packages/editor/scripts/run-bundle.ts`'s own fs-based sibling of
41
+ * `probeProjectNodeModules`, below. The exports-subset parsing itself lives
42
+ * in `./esm-entry-resolution` so both the fetch-based (here) and fs-based
43
+ * (there) probes share byte-identical semantics.
44
+ */
45
+
46
+ import type { ExtraDepsResolution2D } from '@engine/world2d/ingest2d';
47
+ import { probePackageJsonForEsmEntry } from './esm-entry-resolution';
48
+
49
+ /** Every specifier this registry can resolve, and how to import it. */
50
+ const KNOWN_IMPORTERS: Readonly<Record<string, () => Promise<Record<string, unknown>>>> = {
51
+ '@pixi/sound': () => import('@pixi/sound'),
52
+ '@pixi/ui': () => import('@pixi/ui'),
53
+ gsap: () => import('gsap'),
54
+ // Pinned EXACTLY 4.2.95 (packages root package.json) — 4.3.x fails to parse
55
+ // the puzzling-potions vendored game's skeleton data (docs/PIXI-INGEST-
56
+ // LANDING-DESIGN.md §3 D-P1). Do not bump without re-verifying that fixture.
57
+ '@esotericsoftware/spine-pixi-v8': () => import('@esotericsoftware/spine-pixi-v8'),
58
+ };
59
+
60
+ /** Every specifier this registry knows how to resolve (for error messages / introspection). */
61
+ export function knownHostNamespaceSpecifiers(): string[] {
62
+ return Object.keys(KNOWN_IMPORTERS);
63
+ }
64
+
65
+ /**
66
+ * Pure membership check (no dynamic `import()`, no side effect) — D-Z4's
67
+ * `vgai bundle` pre-build extraDeps validation needs to know whether a
68
+ * specifier is registry-known WITHOUT actually loading the module (it never
69
+ * needs the namespace, only "is this specifier legal to externalize").
70
+ */
71
+ export function isKnownHostNamespaceSpecifier(specifier: string): boolean {
72
+ return specifier in KNOWN_IMPORTERS;
73
+ }
74
+
75
+ /**
76
+ * Resolve ONE bare specifier to its host module namespace. Throws, naming the
77
+ * specifier and the known list, if `specifier` isn't in the static registry
78
+ * above (anti-shim: never silently stub an unknown dep). Registry-only — no
79
+ * project-node_modules fallback here; that lives in `resolveExtraDeps` below
80
+ * (this function's contract — "a KNOWN specifier's host namespace" — stays
81
+ * exactly what it was before D-Z3).
82
+ */
83
+ export async function resolveHostNamespace(specifier: string): Promise<Record<string, unknown>> {
84
+ const importer = KNOWN_IMPORTERS[specifier];
85
+ if (!importer) {
86
+ throw new Error(
87
+ `host-namespace-registry: unknown extraDeps specifier "${specifier}" — known specifiers ` +
88
+ `are: ${knownHostNamespaceSpecifiers().join(', ')}. A manifest naming an unregistered ` +
89
+ 'specifier must not silently mount without it (anti-shim); register it here first.',
90
+ );
91
+ }
92
+ return importer();
93
+ }
94
+
95
+ const PROJECT_STATIC_NODE_MODULES_PREFIX = '/project-game-static/node_modules/';
96
+
97
+ type ProbeResult =
98
+ | { kind: 'not-found' }
99
+ | { kind: 'cjs-only'; found: Record<string, unknown> }
100
+ | { kind: 'url'; url: string };
101
+
102
+ /**
103
+ * Probe the OPEN project's own `node_modules/<specifier>/package.json`
104
+ * through the dev-server-only `/project-game-static` route (D-Z3 fallback,
105
+ * resolution-order step 2) and resolve its ESM entry. `specifier` may be a
106
+ * scoped package (`@scope/name`, one embedded slash) — the URL path segment
107
+ * is built straight from the specifier, which already contains the correct
108
+ * `@scope/name` shape for a `node_modules/@scope/name/...` filesystem path.
109
+ * Never throws: every failure mode (no project open, dep not installed,
110
+ * network error, unparsable JSON) collapses to `{ kind: 'not-found' }` — the
111
+ * caller (`resolveExtraDeps`) decides how to report "not installed" vs
112
+ * "installed but CJS-only" (only the latter came from an actually-parsed
113
+ * package.json, hence the two distinct named errors, D-Z3 step 3). The
114
+ * exports-subset parsing itself is shared with `run-bundle.ts`'s fs-based
115
+ * sibling via `./esm-entry-resolution` (D-Z4).
116
+ */
117
+ async function probeProjectNodeModules(specifier: string): Promise<ProbeResult> {
118
+ if (typeof fetch !== 'function') return { kind: 'not-found' };
119
+ const pkgUrl = `${PROJECT_STATIC_NODE_MODULES_PREFIX}${specifier}/package.json`;
120
+ let pkg: Record<string, unknown>;
121
+ try {
122
+ const res = await fetch(pkgUrl);
123
+ if (!res.ok) return { kind: 'not-found' };
124
+ pkg = (await res.json()) as Record<string, unknown>;
125
+ } catch {
126
+ return { kind: 'not-found' };
127
+ }
128
+
129
+ const probed = probePackageJsonForEsmEntry(pkg);
130
+ if (probed.kind === 'cjs-only') return probed;
131
+ return {
132
+ kind: 'url',
133
+ url: `${PROJECT_STATIC_NODE_MODULES_PREFIX}${specifier}/${probed.entryPath}`,
134
+ };
135
+ }
136
+
137
+ /**
138
+ * Resolve ONE specifier that ISN'T in the static registry via the D-Z3
139
+ * project-node_modules fallback (resolution-order steps 2/3): a
140
+ * `/project-game-static/node_modules/<spec>/<esm entry>` URL on success; the
141
+ * SAME named anti-shim throw as before (extended to say the project
142
+ * node_modules was probed too) when nothing usable was found ANYWHERE; a
143
+ * DISTINCT named throw when the dep IS installed but has no ESM entry
144
+ * (never silently serve CJS as ESM).
145
+ */
146
+ async function resolveProjectNodeModulesUrl(specifier: string): Promise<string> {
147
+ const probe = await probeProjectNodeModules(specifier);
148
+
149
+ if (probe.kind === 'url') return probe.url;
150
+
151
+ if (probe.kind === 'cjs-only') {
152
+ throw new Error(
153
+ `host-namespace-registry: extraDeps specifier "${specifier}" is installed in the open ` +
154
+ "project's node_modules but has no ESM entry — checked package.json's " +
155
+ '`exports["."]` import/module/default conditions (string or object form) and the ' +
156
+ `top-level \`module\` field; found: ${JSON.stringify(probe.found)}. Never silently serve ` +
157
+ 'CJS as ESM (anti-shim, degrade loudly): ship/vendor an ESM build of ' +
158
+ `"${specifier}", or register it in host-namespace-registry.ts if it should resolve to a ` +
159
+ 'host-provided namespace instead.',
160
+ );
161
+ }
162
+
163
+ throw new Error(
164
+ `host-namespace-registry: unknown extraDeps specifier "${specifier}" — known specifiers are: ` +
165
+ `${knownHostNamespaceSpecifiers().join(', ')}. Also probed the open project's own ` +
166
+ `\`node_modules/${specifier}/package.json\` (via /project-game-static, D-Z3 fallback) and ` +
167
+ 'found nothing usable there either. A manifest naming an unregistered/uninstalled ' +
168
+ 'specifier must not silently mount without it (anti-shim); register it in ' +
169
+ "host-namespace-registry.ts, or add it to the open project's own node_modules with a " +
170
+ 'resolvable ESM entry.',
171
+ );
172
+ }
173
+
174
+ /**
175
+ * Resolve every specifier in `specifiers` (a manifest's `ingest.extraDeps`)
176
+ * into the `ExtraDepsResolution2D` shape
177
+ * `mountIngestGame2DIframeReachableMulti`'s `extraDeps`/`extraDepUrls`
178
+ * options take: registry-known specifiers resolve to `namespaces` (unchanged
179
+ * from before D-Z3 — zero behavior change), everything else resolves via the
180
+ * D-Z3 project-node_modules fallback into `urls` (or throws, see
181
+ * `resolveProjectNodeModulesUrl`).
182
+ */
183
+ export async function resolveExtraDeps(
184
+ specifiers: readonly string[],
185
+ ): Promise<ExtraDepsResolution2D> {
186
+ const namespaces: Record<string, Record<string, unknown>> = {};
187
+ const urls: Record<string, string> = {};
188
+ for (const spec of specifiers) {
189
+ if (spec in KNOWN_IMPORTERS) {
190
+ namespaces[spec] = await resolveHostNamespace(spec);
191
+ continue;
192
+ }
193
+ urls[spec] = await resolveProjectNodeModulesUrl(spec);
194
+ }
195
+ return { namespaces, urls };
196
+ }