@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,27 @@
1
+ interface ButtonProps {
2
+ label: string;
3
+ onClick: () => void;
4
+ disabled?: boolean;
5
+ }
6
+
7
+ export function Button({ label, onClick, disabled = false }: ButtonProps) {
8
+ return (
9
+ <button
10
+ type="button"
11
+ onClick={onClick}
12
+ disabled={disabled}
13
+ style={{
14
+ background: disabled ? '#222' : '#2a3a4a',
15
+ color: disabled ? '#555' : '#9cf',
16
+ border: '1px solid #445',
17
+ borderRadius: 3,
18
+ padding: '3px 10px',
19
+ fontFamily: 'monospace',
20
+ fontSize: 12,
21
+ cursor: disabled ? 'not-allowed' : 'pointer',
22
+ }}
23
+ >
24
+ {label}
25
+ </button>
26
+ );
27
+ }
@@ -0,0 +1,40 @@
1
+ import { useState } from 'react';
2
+ import { Button } from './Button';
3
+ import { Panel } from './Panel';
4
+
5
+ export interface DefaultHudProps {
6
+ /** Panel title — plain prop, no VGAI binding-expression language. */
7
+ title: string;
8
+ }
9
+
10
+ /**
11
+ * The template's default game HUD (C1,
12
+ * docs/AI-NATIVE-AUTHORING-IMPLEMENTATION-SPEC.md §9 "Make React the
13
+ * Template Default" / §5.1 React UI Contract): ordinary React — a plain
14
+ * `.tsx` component driven by props and a `useState` hook, normal inline
15
+ * styling (no CSS files), no `UINode`/Scene UI binding language.
16
+ *
17
+ * Mounted through the existing overlay seam — `mountUI(ctx.uiContainer, ...)`
18
+ * — by `mount-default-hud.tsx`, called from `../scripts/main.ts`'s `setup()`.
19
+ * Replace or delete this component freely; it exists to prove (and
20
+ * demonstrate) the React-HUD-by-default path, not to be load-bearing
21
+ * gameplay UI.
22
+ */
23
+ export function DefaultHud({ title }: DefaultHudProps) {
24
+ const [paused, setPaused] = useState(false);
25
+
26
+ return (
27
+ <Panel title={title} position="top-left">
28
+ <div
29
+ data-testid="default-hud-status"
30
+ style={{ color: paused ? '#dd3d3d' : '#3ddc65', fontSize: 12 }}
31
+ >
32
+ {paused ? 'Paused' : 'Running'}
33
+ </div>
34
+ <Button
35
+ label={paused ? 'Resume' : 'Pause'}
36
+ onClick={() => setPaused((wasPaused) => !wasPaused)}
37
+ />
38
+ </Panel>
39
+ );
40
+ }
@@ -0,0 +1,25 @@
1
+ interface KeyHintProps {
2
+ keys: string;
3
+ label?: string;
4
+ }
5
+
6
+ export function KeyHint({ keys, label }: KeyHintProps) {
7
+ return (
8
+ <span style={{ display: 'flex', alignItems: 'center', gap: 4, color: '#888' }}>
9
+ <kbd
10
+ style={{
11
+ background: '#333',
12
+ border: '1px solid #555',
13
+ borderRadius: 3,
14
+ padding: '1px 5px',
15
+ fontFamily: 'monospace',
16
+ fontSize: 11,
17
+ color: '#ccc',
18
+ }}
19
+ >
20
+ {keys}
21
+ </kbd>
22
+ {label && <span>{label}</span>}
23
+ </span>
24
+ );
25
+ }
@@ -0,0 +1,52 @@
1
+ import type { ReactNode } from 'react';
2
+
3
+ type Position = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
4
+
5
+ interface PanelProps {
6
+ title: string;
7
+ position?: Position;
8
+ children: ReactNode;
9
+ }
10
+
11
+ const positionStyles: Record<Position, React.CSSProperties> = {
12
+ 'top-left': { top: 8, left: 8 },
13
+ 'top-right': { top: 8, right: 8 },
14
+ 'bottom-left': { bottom: 8, left: 8 },
15
+ 'bottom-right': { bottom: 8, right: 8 },
16
+ };
17
+
18
+ export function Panel({ title, position = 'bottom-left', children }: PanelProps) {
19
+ return (
20
+ <div
21
+ style={{
22
+ position: 'absolute',
23
+ ...positionStyles[position],
24
+ background: 'rgba(18,18,18,0.88)',
25
+ border: '1px solid #444',
26
+ borderRadius: 4,
27
+ padding: '8px 12px',
28
+ fontFamily: 'monospace',
29
+ fontSize: 12,
30
+ color: '#ddd',
31
+ minWidth: 180,
32
+ pointerEvents: 'auto',
33
+ userSelect: 'none',
34
+ }}
35
+ >
36
+ <div
37
+ style={{
38
+ color: '#aaa',
39
+ fontSize: 10,
40
+ textTransform: 'uppercase',
41
+ letterSpacing: 1,
42
+ marginBottom: 8,
43
+ borderBottom: '1px solid #333',
44
+ paddingBottom: 4,
45
+ }}
46
+ >
47
+ {title}
48
+ </div>
49
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>{children}</div>
50
+ </div>
51
+ );
52
+ }
@@ -0,0 +1,129 @@
1
+ import type { InputManager } from '@engine/input/input-manager';
2
+ import { RebindController, type RebindState } from '@engine/input/rebind-controller';
3
+ import { useCallback, useEffect, useReducer, useRef, useState } from 'react';
4
+ import { Button } from './Button';
5
+ import { Panel } from './Panel';
6
+
7
+ export interface RebindPanelProps {
8
+ /** The running game's InputManager (`ctx.input`) — this component reads
9
+ * and mutates it directly through F3's public rebinding API
10
+ * (`getBindings`/`replaceBinding`/`resetBindings`/`getPrompt`), the same
11
+ * API a CLI/SDK caller would use at the file level via B2's
12
+ * `project.inputMap.*` operations. */
13
+ input: InputManager;
14
+ /** Which registered actions to list/rebind (e.g. the game's own
15
+ * `input.actionNames()`, or a curated subset for this HUD). */
16
+ actionNames: string[];
17
+ }
18
+
19
+ /**
20
+ * F3 (spec §12 "Add Rebinding and Prompts") — a keyboard rebinding panel,
21
+ * demonstrating the AC "Rebinding UI is normal React, not Scene UI": this is
22
+ * an ordinary `.tsx` component (props + `useState`/`useReducer`/`useEffect`,
23
+ * plain inline styling via the C1 kit's `Panel`/`Button`) with no
24
+ * `@vgai/scene-ui` import and no `UINode` anywhere — mount it exactly like
25
+ * `DefaultHud` (`mountUI(ctx.uiContainer, <RebindPanel input={ctx.input}
26
+ * actionNames={[...]} />)`).
27
+ *
28
+ * All the actual rebind LOGIC (listening -> capture -> apply, with a
29
+ * collision surfaced structurally instead of silently applied) lives in the
30
+ * framework-free `RebindController` (`@engine/input/rebind-controller`) —
31
+ * this component is a thin wire-up: it forwards a captured `keydown` to
32
+ * `controller.capture()` while listening, and renders whatever `RebindState`
33
+ * comes back. That split is what makes the interaction itself unit-testable
34
+ * with no DOM (`packages/engine/test/rebind-controller.test.ts`); this file
35
+ * only needs a structural check
36
+ * (`packages/engine/test/input-rebind-panel-structural.test.ts`) that it
37
+ * really does wire up that controller instead of reinventing the state
38
+ * machine inline.
39
+ */
40
+ export function RebindPanel({ input, actionNames }: RebindPanelProps) {
41
+ const controllerRef = useRef<RebindController | null>(null);
42
+ if (!controllerRef.current) controllerRef.current = new RebindController(input);
43
+ const controller = controllerRef.current;
44
+
45
+ const [rebindState, setRebindState] = useState<RebindState>(() => controller.getState());
46
+ // Bindings/prompts are read straight off `input` (mutable, not React
47
+ // state) on every render — this reducer's only job is forcing a re-render
48
+ // after a mutation (reset/apply) that doesn't itself change `rebindState`
49
+ // in a way React would otherwise notice.
50
+ const [, forceRefresh] = useReducer((n: number) => n + 1, 0);
51
+
52
+ useEffect(() => {
53
+ if (rebindState.status !== 'listening') return undefined;
54
+ const onKeyDown = (e: KeyboardEvent) => {
55
+ e.preventDefault();
56
+ setRebindState(controller.capture({ type: 'key', code: e.code }));
57
+ forceRefresh();
58
+ };
59
+ window.addEventListener('keydown', onKeyDown);
60
+ return () => window.removeEventListener('keydown', onKeyDown);
61
+ }, [rebindState.status, controller]);
62
+
63
+ const startListening = useCallback(
64
+ (actionName: string) => {
65
+ controller.listen(actionName, 'replace', 0);
66
+ setRebindState(controller.getState());
67
+ },
68
+ [controller],
69
+ );
70
+
71
+ const cancelListening = useCallback(() => {
72
+ controller.cancel();
73
+ setRebindState(controller.getState());
74
+ }, [controller]);
75
+
76
+ const overrideConflict = useCallback(() => {
77
+ setRebindState(controller.resolveOverride());
78
+ forceRefresh();
79
+ }, [controller]);
80
+
81
+ const resetAction = useCallback(
82
+ (actionName: string) => {
83
+ input.resetBindings(actionName);
84
+ forceRefresh();
85
+ },
86
+ [input],
87
+ );
88
+
89
+ const isListening = rebindState.status === 'listening';
90
+
91
+ return (
92
+ <Panel title="Rebind Controls" position="top-right">
93
+ {actionNames.map((actionName) => {
94
+ const listeningForThis = isListening && rebindState.actionName === actionName;
95
+ const bindings = input.getBindings(actionName);
96
+ const prompt = input.getPrompt(actionName, 'keyboard');
97
+ const currentLabel = listeningForThis
98
+ ? 'Press a key…'
99
+ : (prompt?.label ?? (bindings.length > 0 ? bindings[0]!.type : 'Unbound'));
100
+ return (
101
+ <div key={actionName} style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
102
+ <span style={{ flex: 1, color: '#ccc' }}>{actionName}</span>
103
+ <span style={{ color: '#9cf', minWidth: 72, textAlign: 'right' }}>{currentLabel}</span>
104
+ <Button
105
+ label="Rebind"
106
+ onClick={() => startListening(actionName)}
107
+ disabled={isListening}
108
+ />
109
+ <Button label="Reset" onClick={() => resetAction(actionName)} disabled={isListening} />
110
+ </div>
111
+ );
112
+ })}
113
+ {rebindState.status === 'conflict' && (
114
+ <div style={{ color: '#f66', display: 'flex', flexDirection: 'column', gap: 4 }}>
115
+ <span>Conflicts with: {rebindState.conflicts.map((c) => c.actionName).join(', ')}</span>
116
+ <div style={{ display: 'flex', gap: 6 }}>
117
+ <Button label="Use Anyway" onClick={overrideConflict} />
118
+ <Button label="Cancel" onClick={cancelListening} />
119
+ </div>
120
+ </div>
121
+ )}
122
+ {isListening && (
123
+ <div style={{ display: 'flex' }}>
124
+ <Button label="Cancel" onClick={cancelListening} />
125
+ </div>
126
+ )}
127
+ </Panel>
128
+ );
129
+ }
@@ -0,0 +1,28 @@
1
+ interface SliderProps {
2
+ label: string;
3
+ value: number;
4
+ min: number;
5
+ max: number;
6
+ step?: number;
7
+ onChange: (value: number) => void;
8
+ }
9
+
10
+ export function Slider({ label, value, min, max, step = 0.01, onChange }: SliderProps) {
11
+ return (
12
+ <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
13
+ <span style={{ minWidth: 90, color: '#ccc' }}>{label}</span>
14
+ <input
15
+ type="range"
16
+ min={min}
17
+ max={max}
18
+ step={step}
19
+ value={value}
20
+ onChange={(e) => onChange(parseFloat(e.target.value))}
21
+ style={{ flex: 1, accentColor: '#4af', cursor: 'pointer' }}
22
+ />
23
+ <span style={{ minWidth: 36, textAlign: 'right', color: '#aaa' }}>
24
+ {value.toFixed(step < 0.1 ? 2 : 1)}
25
+ </span>
26
+ </div>
27
+ );
28
+ }
@@ -0,0 +1,22 @@
1
+ interface StatusDotProps {
2
+ color: string;
3
+ label: string;
4
+ }
5
+
6
+ export function StatusDot({ color, label }: StatusDotProps) {
7
+ return (
8
+ <span style={{ display: 'flex', alignItems: 'center', gap: 6, color: '#ccc' }}>
9
+ <span
10
+ style={{
11
+ width: 8,
12
+ height: 8,
13
+ borderRadius: '50%',
14
+ background: color,
15
+ flexShrink: 0,
16
+ boxShadow: `0 0 4px ${color}`,
17
+ }}
18
+ />
19
+ {label}
20
+ </span>
21
+ );
22
+ }
@@ -0,0 +1,19 @@
1
+ interface ToggleProps {
2
+ label: string;
3
+ value: boolean;
4
+ onChange: (value: boolean) => void;
5
+ }
6
+
7
+ export function Toggle({ label, value, onChange }: ToggleProps) {
8
+ return (
9
+ <label style={{ display: 'flex', alignItems: 'center', gap: 8, cursor: 'pointer' }}>
10
+ <span style={{ flex: 1, color: '#ccc' }}>{label}</span>
11
+ <input
12
+ type="checkbox"
13
+ checked={value}
14
+ onChange={(e) => onChange(e.target.checked)}
15
+ style={{ accentColor: '#4af', width: 14, height: 14, cursor: 'pointer' }}
16
+ />
17
+ </label>
18
+ );
19
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Thin re-export of the engine-published state bridge (D-Z5,
3
+ * `docs/WAVE3-ADAPTER-PLUMBING-DESIGN.md` §D-Z5) — `GameProvider`/`useGame`/
4
+ * `useGameState`/`useWorldObservation` now live canonically at
5
+ * `@engine/react/game-state` (`packages/engine/src/react/game-state.tsx`,
6
+ * the spec this file used to BE before D-Z5; see that module's doc comment
7
+ * for the full implementation and the context-identity rule it documents).
8
+ *
9
+ * This file KEEPS EXISTING on purpose — every scaffolded project still has
10
+ * `src/ui/game-state.tsx`, so:
11
+ * - `packages/editor/vite-plugin-react-world-provider.ts`'s virtual module
12
+ * (`export { GameProvider } from '/@fs/<root>/src/ui/game-state.tsx'`)
13
+ * keeps working byte-for-byte — it re-exports from THIS file, which now
14
+ * re-exports from the engine, but the file it points at (and the
15
+ * identity `useGame()` resolves against) is unchanged.
16
+ * - a react-world entry's own relative `import { useGameState } from
17
+ * './ui/game-state'` keeps resolving here too — both routes still
18
+ * converge on ONE module instance (this file), which itself resolves the
19
+ * engine's `@engine/react/game-state` exactly once, so `createContext()`
20
+ * runs exactly once per project. No context split.
21
+ *
22
+ * Adoption of the engine module is an OPTION, not a migration: existing
23
+ * projects that already have their OWN full copy of this file (their own
24
+ * `createContext`) are untouched by this change — only NEW projects
25
+ * scaffolded from the template get this canonical re-export. A project that
26
+ * wants a customized bridge can still replace this file with its own full
27
+ * implementation, exactly as before.
28
+ */
29
+
30
+ export {
31
+ GameProvider,
32
+ requireWorldObserver,
33
+ shallow,
34
+ useGame,
35
+ useGameState,
36
+ useWorldObservation,
37
+ } from '@engine/react/game-state';
@@ -0,0 +1,7 @@
1
+ export { Button } from './Button';
2
+ export { KeyHint } from './KeyHint';
3
+ export { Panel } from './Panel';
4
+ export { RebindPanel } from './RebindPanel';
5
+ export { Slider } from './Slider';
6
+ export { StatusDot } from './StatusDot';
7
+ export { Toggle } from './Toggle';
@@ -0,0 +1,19 @@
1
+ import { DefaultHud } from './DefaultHud';
2
+ import { mountUI } from './mount-ui';
3
+
4
+ /**
5
+ * Mounts the template's default React HUD into the shared UI overlay
6
+ * (`ctx.uiContainer` — `pointer-events:none`; `Panel`/`Button` inside opt
7
+ * back in via `pointer-events:auto`, so the game canvas keeps receiving
8
+ * pointer events everywhere except the HUD's own controls) and returns an
9
+ * unmount function. Kept as its own `.tsx` module so `../scripts/main.ts` —
10
+ * the game SETUP script, not a component — never needs JSX syntax itself.
11
+ *
12
+ * Usage (see `../scripts/main.ts`):
13
+ * const unmountHud = mountDefaultHud(ctx.uiContainer);
14
+ * // ... later, in the returned GameCleanup:
15
+ * // dispose() { unmountHud(); sceneInstance.dispose(); }
16
+ */
17
+ export function mountDefaultHud(container: HTMLDivElement): () => void {
18
+ return mountUI(container, <DefaultHud title="Game Status" />);
19
+ }
@@ -0,0 +1,15 @@
1
+ import type { ReactNode } from 'react';
2
+ import { createRoot } from 'react-dom/client';
3
+
4
+ /**
5
+ * Mount a React element into a container div and return a cleanup function.
6
+ *
7
+ * Usage in example dispose():
8
+ * const unmount = mountUI(ctx.uiContainer, <MyHUD />);
9
+ * return { dispose: unmount };
10
+ */
11
+ export function mountUI(container: HTMLDivElement, element: ReactNode): () => void {
12
+ const root = createRoot(container);
13
+ root.render(element);
14
+ return () => root.unmount();
15
+ }
@@ -0,0 +1,36 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
7
+ "strict": true,
8
+ "noUncheckedIndexedAccess": true,
9
+ "noFallthroughCasesInSwitch": true,
10
+ "noPropertyAccessFromIndexSignature": true,
11
+ "exactOptionalPropertyTypes": true,
12
+ "experimentalDecorators": true,
13
+ "useDefineForClassFields": false,
14
+ "noUnusedLocals": true,
15
+ "noUnusedParameters": true,
16
+ "verbatimModuleSyntax": true,
17
+ "esModuleInterop": true,
18
+ "forceConsistentCasingInFileNames": true,
19
+ "resolveJsonModule": true,
20
+ "isolatedModules": true,
21
+ "skipLibCheck": true,
22
+ "noEmit": true,
23
+ "jsx": "react-jsx",
24
+ "types": ["vite/client"],
25
+ "baseUrl": ".",
26
+ "paths": {
27
+ "@engine/*": ["../../engine/src/*"],
28
+ "@editor/*": ["../src/*"]
29
+ }
30
+ },
31
+ "files": [
32
+ "../../engine/src/types-n8ao.d.ts",
33
+ "../../engine/src/types-realism-effects.d.ts"
34
+ ],
35
+ "include": ["src"]
36
+ }
@@ -0,0 +1,78 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { InputMapFileSchema } from '@vgai/engine/input/schema';
3
+ import { parseInstancesFile, parseMaterialFile, SceneParseError } from '@vgai/engine/scene/parse';
4
+
5
+ // ---------------------------------------------------------------------------
6
+ // Content validation for the fetched-asset formats (`.mat.json` /
7
+ // `.inputmap.json` / `.instances.json`), through the SAME
8
+ // engine Zod schemas the runtime rejects them with at fetch time. Used by
9
+ // `validate-scenes.ts` (the `npm run validate-scenes` command —
10
+ // previously these formats were only existence-checked when a scene
11
+ // referenced them, so a present-but-malformed asset passed the command and
12
+ // failed at load) and directly unit-testable against a tmpdir
13
+ // (`packages/editor/test/validate-asset-content.test.ts`) so broken fixtures
14
+ // never need to live inside the template.
15
+ //
16
+ // Separate module (rather than inline in validate-scenes.ts) because
17
+ // validate-scenes.ts is a top-level script — importing it executes it.
18
+ // ---------------------------------------------------------------------------
19
+
20
+ /** The asset formats this module content-validates (engine Zod schemas). */
21
+ export const ASSET_CONTENT_EXTENSIONS = ['.mat.json', '.inputmap.json', '.instances.json'] as const;
22
+
23
+ /**
24
+ * Content-parse one asset file through its engine Zod schema. Returns error
25
+ * strings in validate-scenes' established `${file}: ${path}: ${message}`
26
+ * format (empty array = valid). Throws only on a programming error (a path
27
+ * that isn't one of the three supported formats).
28
+ */
29
+ export function validateAssetContentFile(path: string): string[] {
30
+ let raw: unknown;
31
+ try {
32
+ raw = JSON.parse(readFileSync(path, 'utf-8'));
33
+ } catch (e) {
34
+ return [`${path}: invalid JSON — ${e instanceof Error ? e.message : String(e)}`];
35
+ }
36
+
37
+ const errors: string[] = [];
38
+ if (path.endsWith('.mat.json')) {
39
+ // The engine has a ready-made SceneParseError-throwing wrapper for
40
+ // materials — reuse it (same function the runtime's fetch path uses).
41
+ try {
42
+ parseMaterialFile(raw, path);
43
+ } catch (e) {
44
+ if (e instanceof SceneParseError) {
45
+ for (const issue of e.issues) {
46
+ errors.push(`${path}: ${issue.path.join('.')}: ${issue.message}`);
47
+ }
48
+ } else {
49
+ errors.push(`${path}: ${e}`);
50
+ }
51
+ }
52
+ } else if (path.endsWith('.inputmap.json')) {
53
+ const result = InputMapFileSchema.safeParse(raw);
54
+ if (!result.success) {
55
+ for (const issue of result.error.issues) {
56
+ errors.push(`${path}: ${issue.path.join('.')}: ${issue.message}`);
57
+ }
58
+ }
59
+ } else if (path.endsWith('.instances.json')) {
60
+ // Same ready-made SceneParseError-throwing wrapper pattern as .mat.json (F3).
61
+ try {
62
+ parseInstancesFile(raw, path);
63
+ } catch (e) {
64
+ if (e instanceof SceneParseError) {
65
+ for (const issue of e.issues) {
66
+ errors.push(`${path}: ${issue.path.join('.')}: ${issue.message}`);
67
+ }
68
+ } else {
69
+ errors.push(`${path}: ${e}`);
70
+ }
71
+ }
72
+ } else {
73
+ throw new Error(
74
+ `validateAssetContentFile: "${path}" is not one of the supported formats (${ASSET_CONTENT_EXTENSIONS.join(', ')})`,
75
+ );
76
+ }
77
+ return errors;
78
+ }
@@ -0,0 +1,55 @@
1
+ import { resolve } from 'node:path';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { loadGameManifestFile } from '@vgai/engine/manifest/load-file';
4
+
5
+ // ---------------------------------------------------------------------------
6
+ // Usage: npx tsx validate-manifest.ts [manifestPath...]
7
+ //
8
+ // Single source of truth for game-manifest validation, shipped IN the
9
+ // project template (mirrors validate-scenes.ts) so every scaffolded game
10
+ // gets a working `npm run validate-manifest`. Validates each given
11
+ // `vgai.game.json` path via `loadGameManifestFile` (parse -> cross-field
12
+ // checks -> resolution, see docs/GAME-MANIFEST-DESIGN.md §5) and prints the
13
+ // resolved world list (id, kind, resolved adapter identity, per-context
14
+ // capability tiers) on success. Any failure prints a descriptive error and
15
+ // exits 1.
16
+ //
17
+ // Defaults to THIS template's own manifest (`vgai.game.json`, a sibling of
18
+ // this script) when no path is given, so `npm run validate-manifest` works
19
+ // out of the box both from the monorepo root and from a scaffolded project.
20
+ // ---------------------------------------------------------------------------
21
+
22
+ const defaultManifestPath = fileURLToPath(new URL('./vgai.game.json', import.meta.url));
23
+
24
+ const args = process.argv.slice(2);
25
+ const manifestPaths = args.length > 0 ? args.map((p) => resolve(p)) : [defaultManifestPath];
26
+
27
+ let hadError = false;
28
+
29
+ for (const manifestPath of manifestPaths) {
30
+ try {
31
+ const resolved = loadGameManifestFile(manifestPath);
32
+ console.log(
33
+ `${manifestPath}: OK — "${resolved.name}" v${resolved.version} (engine ${resolved.engine.version})`,
34
+ );
35
+ for (const world of resolved.worlds) {
36
+ const { adapter } = world;
37
+ const adapterLabel =
38
+ adapter.type === 'ingest' ? `${adapter.identity} (${adapter.strategy})` : adapter.identity;
39
+ console.log(
40
+ ` world "${world.id}" kind=${world.kind} adapter=${adapterLabel} ` +
41
+ `tiers={local: ${world.capabilities.local}, hosted: ${world.capabilities.hosted}}`,
42
+ );
43
+ }
44
+ } catch (e) {
45
+ hadError = true;
46
+ console.error(`${manifestPath}: FAILED`);
47
+ console.error(` ${e instanceof Error ? e.message : String(e)}`);
48
+ }
49
+ }
50
+
51
+ if (hadError) {
52
+ process.exit(1);
53
+ } else {
54
+ console.log(`Validated ${manifestPaths.length} manifest(s) — all OK`);
55
+ }