@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,512 @@
1
+ # CLAUDE.md — VGAI Game Project
2
+
3
+ ## The acceptance bar: feature-complete, bot-proven, great-looking
4
+
5
+ This project is not done at a vertical slice. It is done when the **whole
6
+ game** — every feature in the game's maximal spec/ROADMAP, enumerated up
7
+ front — ships, and every one of those features has a **bot-played
8
+ acceptance criterion** proving it works on the real client (see "Autoplay
9
+ bots" below). Two bars, non-negotiable:
10
+
11
+ - **Completeness.** Write the maximal spec/ROADMAP before or alongside the
12
+ first line of code — every feature the game needs, not just the ones
13
+ that are easy or exciting. **No descopes, no "for now," no
14
+ vertical-slice-and-ship.** A core-only build with the rest deferred to
15
+ "later" is not done; it's a partial delivery wearing a done label. If
16
+ scope turns out to be wrong, revise the spec explicitly and say so — do
17
+ not quietly narrow it by shipping less.
18
+ - **Visual quality.** "Great-looking" is a claim you DEMONSTRATE, never one
19
+ you assert. Every visual milestone ships a real, inspectable artifact —
20
+ screenshots and a gameplay video captured from the actual running client
21
+ (`npm run game`, not a mockup) — judged against this game's own
22
+ reference/style bar. "It renders" or "looks good" in prose is not proof;
23
+ if you can't point at the recording, it isn't shown.
24
+
25
+ Both bars are proven the same way the autoplay-bot doctrine below proves
26
+ everything else: **the bot plays the real game and the run is the
27
+ evidence.** A skill/feature isn't complete until a bot has played it
28
+ end-to-end and the logs/recording show it working — that's what turns
29
+ "I built X" and "X looks great" from a claim into a demonstrated fact on
30
+ the real product surface.
31
+
32
+ ## Before Writing Any Code
33
+
34
+ 0. **Launch the editor and keep it running.** `vgai edit` (run it in the
35
+ background) — the editor is the authoring surface AND the verification
36
+ loop: `vgai status` / `vgai play` / `vgai select` / `vgai apply-diff` and
37
+ the `/editor` skill all drive it. Tell the user the URL `vgai edit` prints
38
+ (default `http://localhost:5173`, but NOT always — see the port caveat
39
+ below) so they can watch the game take shape. This step applies to agents
40
+ too, headless or not; if part of the editor loop genuinely doesn't fit your
41
+ game (e.g. fully procedural world, no scene to author), say so explicitly
42
+ instead of silently skipping the editor.
43
+ **Port cross-talk caveat:** the default port (5173) is shared across every
44
+ vgai project on this machine. `vgai edit` will not silently retarget
45
+ another project's already-running editor — if a DIFFERENT project's
46
+ editor already holds 5173, this one starts a second instance on a fresh
47
+ free port instead and prints THAT url. If you (or the user) already have
48
+ another vgai project's editor tab open in the browser, don't assume it's
49
+ this project — read the printed URL/port, or pass `vgai edit --port <n>`
50
+ to pin a specific port for this project, so an old tab left open from a
51
+ different project doesn't get mistaken for this session (see the
52
+ `/editor` skill's CLI Reference for `--port` and `vgai sessions`).
53
+ 1. **Read an example.** A plain scaffold ships only a minimal default scene — no example content. The worked implementations (FPS, vehicle, third-person, RTS, multiplayer arena, IK, one-concept tutorials — see the Examples Catalog below) are standalone projects in the vgai monorepo's `examples/<id>/`. Scaffold one directly to read/copy its code: `npx create-vgai-project <name> --example <id>` (e.g. `--example third-person`) makes a correctly-rewritten standalone copy of that example, `vgai.game.json` and all. You can also open any of them live in the hosted editor at `https://vgai-editor.pages.dev/?project=<id>` (read-only — scaffold to keep edits). Otherwise, build gameplay from the Components section below.
54
+ 2. **Read the schema.** Scene format is defined by the engine's Zod schemas; the generated JSON Schema is `schemas/vscn.schema.json` inside the engine package (your tsconfig `paths` / vite alias points at the engine — the schema sits next to its `src/`). Read it before writing or editing any `.vscn.json` file. Wrong field names (e.g. `type` instead of `bodyType` in physics) silently break things. Do **not** author fields the runtime doesn't read: `gamepad_axis_pair`/`mouse_move` input bindings — these (like dead `.vscn` fields) **throw at parse** — the engine ships Zod schemas for every fetched asset format (`inputmap.schema.json` sits beside `vscn.schema.json` in the engine package). Discrete character animation (idle/walk/run/jump) is an XState machine + `bindXStateAnimation` in your own component code, not a `.vscn` field — see the engine's `packages/engine/src/animation/xstate-animation-binding.ts` and a scaffolded `--example third-person`'s `src/components.ts`.
55
+ 3. **Read `src/scripts/registry.ts`.** Every component used in a scene must be registered here. Unregistered components fail with "Component not found in registry".
56
+
57
+ ## Commands
58
+
59
+ ```bash
60
+ vgai edit # Launch the editor for this project (opens browser)
61
+ vgai play # Enter play mode
62
+ # Play-mode (and ingest-mode) edit policy:
63
+ # - LIVE-BUT-DISCARDED: gizmo transforms, rename,
64
+ # visibility, environment tuning — applied to the
65
+ # running scene, thrown away on stop.
66
+ # - BLOCKED (console warning): saving (Cmd/Ctrl+S),
67
+ # structural ops (add/delete/cut/copy/paste/reparent),
68
+ # inspector edits that rebuild the object (mesh,
69
+ # material, physics, ...), undo/redo, opening files.
70
+ # Nothing you change during play can leak into your
71
+ # .vscn. Stop play mode to persist edits.
72
+ vgai status # Check editor state
73
+ vgai apply-diff <scene.vscn.json> <patch.json> [--report]
74
+ # The canonical programmatic edit op: apply a
75
+ # JSON SceneDiff patch (add/remove/update/move ops +
76
+ # environment/name) to a scene file. Validates the
77
+ # scene, the patch, AND the result through the engine's
78
+ # Zod schemas, and dereferences every asset reference
79
+ # the diff introduces (existence for all; schema parse
80
+ # for .mat/.prefab refs) — nothing is
81
+ # written on any failure.
82
+ # --report: validate + summarize only, never write.
83
+ # Prefer this over hand-editing .vscn JSON in scripts.
84
+ npm run dev # Open the EDITOR on this project (delegates to `vgai edit .`) —
85
+ # the authoring surface; press Play (or `vgai play`) to run the game
86
+ npm run game # Vite dev server for the STANDALONE game page (no editor) — the
87
+ # ship-shaped form, for player-view testing/bots/CI, not authoring
88
+ npm run build # tsc + vite build
89
+ npm run typecheck # Type-check
90
+ ```
91
+
92
+ ## Project Structure
93
+
94
+ ```
95
+ public/
96
+ scenes/ .vscn.json scene files (entities, transforms, components)
97
+ audio/ Audio assets
98
+ src/
99
+ main.ts Entry point — creates game runtime
100
+ data/ Data assets: <name>.schema.ts + emitted .schema.json + .data.json
101
+ (tuning.* ships as the worked example; see src/data/README.md)
102
+ tools/ Project tools: <name>.tool.tsx editor panels (dock tab or
103
+ inspector section) — editor-only, never bundled
104
+ (example.tool.tsx + spin.tool.tsx ship; see src/tools/README.md)
105
+ scripts/
106
+ main.ts Game setup — loads scenes, registers components, mounts the default HUD (keep .ts — its path is pinned in vgai.game.json + src/main.ts ENTRY_MODULES; see the React rule)
107
+ registry.ts Component registry (GameComponent classes)
108
+ components/ Custom GameComponent classes
109
+ ui/ React HUD kit (Panel/Button/Toggle/Slider/...) + DefaultHud.tsx, mount-ui.ts
110
+ server/
111
+ rooms/ Colyseus multiplayer rooms
112
+ project.json Project metadata (name, resolution, default scene)
113
+ ```
114
+
115
+ ## Key Concepts
116
+
117
+ The engine has six fundamental primitives — everything you build is one of
118
+ these, and each has exactly one home:
119
+
120
+ - **Worlds** — the composition units (`vgai.game.json`): `threejs` / `react` /
121
+ `pixijs`, each with an `entry`; a game is one or more worlds composed by the
122
+ runtime and the editor alike.
123
+ - **Scenes** — *where things are*: `.vscn.json` files in `public/scenes/`
124
+ defining entity hierarchies with transforms, meshes, materials, lights,
125
+ cameras, physics, and components. **Prefabs** (`.prefab.json`) are reusable
126
+ entity templates.
127
+ - **GameComponents** — *how things behave*: per-entity classes with
128
+ `init`/`update`/`dispose` and a `static schema` (Zod) for per-entity config
129
+ (see Components below).
130
+ - **Loop hooks** — *when things run*: per-frame system phases `input` →
131
+ `prePhysics` → `physics` → `postPhysics` → `gameLogic` → `animation` →
132
+ `preRender` → `render`, via `GameComponent.phase` or `ctx.systems.add`.
133
+ **Every `setup()` must return a `dispose()`** that cleans up all objects,
134
+ bodies, listeners, and UI.
135
+ - **Data** — *what things are*: schema'd JSON in `src/data/`, the layer the
136
+ inspector (and designers, and VS Code) edit — shared/global definitions and
137
+ tuning, as opposed to per-entity component config. See "Tunable values → a
138
+ data asset" under One Canonical Way.
139
+ - **Tools** — *how you tune it*: project-authored React panels
140
+ (`src/tools/*.tool.tsx`) the editor discovers automatically. Two
141
+ placements: `placement: 'dock'` (a ⚙ tab after the built-in bottom tabs —
142
+ project-global dashboards) and `placement: 'inspector'` with a
143
+ `match: (node, adapter) => boolean` predicate (a ⚙ section in the Inspector
144
+ for matching selections). Each tool file exports `tool = defineTool({...})`
145
+ (from `@engine/tools/define-tool`) plus a default React component; build
146
+ the panel from `@editor/widgets` (the editor's own widget kit + THEME
147
+ tokens) so it looks native. `src/tools/example.tool.tsx` (dock) and
148
+ `spin.tool.tsx` (inspector) ship as worked examples — both live-tune
149
+ `src/data/tuning.data.json` through `useData`/`writeData`
150
+ (`@engine/react/use-data`) and the running game follows via HMR. An
151
+ inspector tool can also read the selected entity's OWN component config —
152
+ `useSelection()` (`@engine/react/use-selection`) returns the selected node,
153
+ its attached components, and each component's authored config, live.
154
+ Tools are editor-only dev surfaces, stripped from shipped games by
155
+ construction: `npm run build` bundles only what `index.html` →
156
+ `src/main.ts` imports, and nothing in game code imports `src/tools/`.
157
+
158
+ ## Components
159
+
160
+ All per-entity behavior is a **GameComponent class** — an OOP class with an `init`/`update`/`dispose` lifecycle. The Object3D *is* the entity (there is no ECS / no `eid`): inside a component, `this.object3D`, `this.rigidBody`, and `this.collider` are wired up for you. **Every component referenced by a scene must be registered in `src/scripts/registry.ts`** — unregistered components cause "Component not found in registry" at play time.
161
+
162
+ | | GameComponent Class |
163
+ |---|---|
164
+ | **What** | OOP class extending `GameComponent` with lifecycle (`init`/`update`/`dispose`, optional `onTriggerEnter`/`onTriggerExit`) |
165
+ | **Use for** | All gameplay behavior — controllers, cameras, AI, pickups, tags |
166
+ | **Access** | `this.object3D` / `this.rigidBody` / `this.collider`; config fields from `static schema` (Zod) |
167
+ | **Editable fields** | Declare a `static schema = z.object({...})` with `.describe()` + `.default()` — these become typed, documented widgets in the editor inspector and are validated on load |
168
+ | **HMR** | Yes (prototype swap preserves instance state on live edit) |
169
+ | **Reference** | `src/scripts/components/scene-camera.ts` (`SceneCamera` — declares `static phase` + `static schema`) in this project; for richer patterns, scaffold a worked example (`npx create-vgai-project <name> --example fps`, `--example vehicle`, `--example third-person`, ...) and read its `src/components.ts`; base class at `packages/engine/src/ecs/game-component.ts` |
170
+
171
+ **Before creating a component:** read the reference above (or a scaffolded example's, per the "Read an example" step) and copy the pattern (`static phase`, `static schema`, `init`/`update`). Don't author ad-hoc `ctx.systems.add` closures for gameplay — they're neither editable nor hot-reloadable; reserve `systems.add` for non-gameplay infra (audio mixers, network send, etc.).
172
+
173
+ **Procedural games (no scene file):** components also attach at runtime to
174
+ code-created objects — construct the instance yourself and call
175
+ `ctx.components.attach(object3D, instance)`; the component manager runs `init`
176
+ and the per-frame lifecycle exactly as for scene-authored components. A fully
177
+ procedural world (voxel terrain, roguelike floors, …) legitimately has a
178
+ manifest world with an `entry` and **no `scene`**, and skips `.vscn` authoring
179
+ entirely — registry registration is only *required* for components referenced
180
+ by scene files. The editor still works on such games: play mode adopts the
181
+ live scene graph into the hierarchy/inspector.
182
+
183
+ **Registration:** `src/scripts/registry.ts` exports two maps:
184
+ - `componentRegistry` — **all** GameComponent classes referenced by scene files (used by the loader + scene validator)
185
+ - `gameComponents` — the same classes, for HMR
186
+
187
+ **In scene JSON**, components are an object keyed by name: `"components": { "Checkpoint": {}, "MarbleController": { "forceStrength": 12 } }`. Names must match `componentRegistry` keys; field names must match the component's `static schema`. Empty `{}` for tag components (no schema).
188
+
189
+ **System phases** (for `ctx.systems.add` and `GameComponent.phase`): `input` → `prePhysics` → `physics` → `postPhysics` → `gameLogic` (default) → `animation` → `preRender` → `render`
190
+
191
+ ## One Canonical Way Per Task
192
+
193
+ For each common job there is exactly ONE recommended approach. Use it — competing paths cause ambiguity and non-determinism.
194
+
195
+ - **Camera → a camera GameComponent.** Attach a component that positions/aims `ctx.camera` (the shipped patterns to copy: `FPSCamera` in a `--example fps` scaffold's `src/components.ts`, `ChaseCamera` in `--example vehicle`, `CameraTarget` in `--example third-person` — all schema-declared and driven in `preRender`). This project also registers a minimal `SceneCamera` (`src/scripts/components/scene-camera.ts` — schema-declared position + look-at target). Precedence is fixed and intentional:
196
+
197
+ `editor viewport camera < scene-defined camera < camera GameComponent`
198
+
199
+ The editor's viewport transform is only the *initial* viewpoint, so a scene-defined or component-driven camera always wins (this is why play mode uses your scene's camera, not the editor's orbit camera). Do **not** also write an ad-hoc `ctx.systems.add('preRender', ...)` camera closure — put the camera logic in the component.
200
+
201
+ - **Gameplay behavior → a GameComponent.** Never an ad-hoc `ctx.systems.add` closure (those are neither editable nor hot-reloadable). Reserve `systems.add` for non-gameplay infra only (audio mixers, network send, debug overlays). See the Components section above.
202
+
203
+ - **Tunable values → a data asset, never a constant.** If a designer (or you,
204
+ while tuning) should be able to change a value without editing game code, it
205
+ lives in `src/data/` as JSON governed by a Zod schema — not as a constant in
206
+ a component or `setup()`. Per-entity config stays in the component's
207
+ `static schema` (see Components); data assets are the shared/global layer:
208
+ feel tuning, economy numbers, tables of game definitions.
209
+
210
+ Two blessed shapes, and only these (they're what the editor's DATA tab can
211
+ render as real widgets): a **singleton** — one `z.object` config whose
212
+ fields are scalars (number/string/boolean/enum), optionally grouped one or
213
+ two levels deep in nested `z.object`s (the tab renders groups as sub-forms)
214
+ — or a **table** — `z.record(z.string(), rowSchema)` with a flat row schema,
215
+ rendered as a grid (this Zod version's `z.record` takes a key schema AND a
216
+ value schema — the single-arg `z.record(rowSchema)` shorthand from Zod 3
217
+ throws here). Anything the tab can't type (arrays, deep nesting, unions)
218
+ degrades to a raw-JSON cell that refuses invalid commits — prefer
219
+ flattening, or a table, when a designer should tune it. Tables also get a
220
+ spreadsheet-friendly bulk-edit path: the DATA tab's **Export CSV** /
221
+ **Import CSV** buttons round-trip the whole table (header `key,<row
222
+ fields>`). Import is a WHOLE-TABLE REPLACE (a row the sheet doesn't mention
223
+ is deleted) and ATOMIC (any cell that fails to coerce to its field's kind —
224
+ e.g. non-numeric text in a `number` column — writes NOTHING; fix the sheet
225
+ and re-import). `"$schema"` is never a CSV column; it's carried over from
226
+ the file automatically.
227
+
228
+ ```ts
229
+ // src/data/tuning.schema.ts — engineer-owned: the contract
230
+ import { z } from 'zod'
231
+ export const tuningSchema = z.object({
232
+ gravity: z.number().min(0).max(50).default(9.8).describe('m/s², downward'),
233
+ })
234
+ ```
235
+ ```jsonc
236
+ // src/data/tuning.data.json — designer-owned: the values
237
+ { "$schema": "./tuning.schema.json", "gravity": 9.8 }
238
+ ```
239
+ ```ts
240
+ // src/data/tuning.ts — the live handle (engine defineData, W1)
241
+ import { defineData } from '@engine/data/data-asset'
242
+ import raw from './tuning.data.json'
243
+ import { tuningSchema } from './tuning.schema'
244
+ export const tuning = defineData(tuningSchema, raw, 'src/data/tuning.data.json')
245
+ // ['default'] not .default: the template tsconfig's
246
+ // noPropertyAccessFromIndexSignature applies to Vite's ModuleNamespace
247
+ import.meta.hot?.accept('./tuning.data.json', (m) => tuning.hotSwap(m?.['default']))
248
+ ```
249
+ Read `tuning.get()` live where the value is used (e.g. each frame) — don't
250
+ copy fields out at init, or HMR edits won't reach them. `subscribe(fn)` fires
251
+ on every hot edit. **This project ships the pattern working**: the trio in
252
+ `src/data/` (`tuning.schema.ts` / emitted `tuning.schema.json` /
253
+ `tuning.data.json`), the handle (`src/data/tuning.ts`), and a consumer
254
+ (`DataSpinner` on the default scene's Box — press ▶, edit the JSON, watch it
255
+ change live). Add a data asset by copying that trio AND registering it in
256
+ `src/data/assets.ts` (the one shared list); after every schema change run
257
+ `npm run emit-schemas` (commits the emitted `.schema.json` so VS Code
258
+ validates the data file with no dev server). Rows in table-shaped assets
259
+ are referenced as `"file#key"` strings — declare a cross-asset field with
260
+ `dataRef('items')` (`@engine/data/data-ref`) instead of a bare `z.string()`:
261
+ the emitted schema gets a real `pattern` AND the editor's Data tab renders
262
+ it as a `stem#key` PICKER (a plain string still works, but has no picker
263
+ and doesn't survive a target-file rename in `vgai doctor`'s checks). Read
264
+ the referenced row with `getRef(itemsHandle, enemy.drop)` — pass the
265
+ TARGET's own handle, not a stem string; it resolves live off `.get()`, same
266
+ HMR doctrine as everything else in this file. Data assets are immutable at
267
+ runtime — runtime state lives in your game's own state, never written back
268
+ into data files. Enforcement is automatic: `npm run build` fails loud on a
269
+ data file that no longer matches its schema, a dangling `"file#key"` ref (or,
270
+ for a declared `dataRef` field, a target file that no longer exists at all),
271
+ or tool code reaching the shipped bundle, and `vgai doctor <folder>` runs
272
+ the same data checks terminal-side.
273
+ (The editor's Data dock tab edits these files in place, and project
274
+ tools (`src/tools/`, see Key Concepts) tune them live through the same
275
+ file-write path. WSL note: if this project lives on `/mnt/c` (drvfs — no
276
+ inotify), set `VGAI_WATCH_POLL=1` in the environment; the editor dev server
277
+ AND this project's standalone `npm run game` both honor it, and without it
278
+ external edits to `.data.json` never hot-reload into the running game.)
279
+
280
+ - **Material → inline `material` OR `materialRef`, never both.** An entity uses one or the other: inline `material` for a one-off look, or `materialRef` pointing at a shared `.mat.json` when several entities share a material. Setting both is a hard load-time validation error (enforced by a Zod refine in the engine schema) — there is no silent precedence to memorize.
281
+
282
+ ## Rules
283
+
284
+ - **The engine is source-linked, not copied.** `@vgai/engine` resolves as a
285
+ symlink back into the vgai checkout you scaffolded from (a `file:`
286
+ dependency plus `@engine/*` aliases into `<checkout>/packages/engine/src`).
287
+ The engine source is yours to read — but **editing it edits the shared
288
+ checkout**, instantly affecting every project scaffolded from it. A game
289
+ that truly needs a divergent engine forks the checkout. Your manifest's
290
+ `engine.version` records which engine version this project was scaffolded
291
+ or last upgraded against; after updating the checkout, run `vgai upgrade`
292
+ (report first; `--report` for report-only) to re-sync untouched template
293
+ files and re-pin — your own edits are never overwritten.
294
+ **drvfs caveat (WSL, project on /mnt/c):** npm materializes the `file:`
295
+ dependency as a COPY there, not a symlink — after engine changes, code that
296
+ resolves through `node_modules/@vgai/engine` (root scripts like
297
+ `emit-schemas.ts`/`validate-scenes.ts`) sees a STALE engine until you
298
+ refresh it: `rm -rf node_modules/@vgai/engine && npm install`. The
299
+ `@engine/*` tsc/vite aliases always see the live checkout and are
300
+ unaffected.
301
+ - **Use engine/library APIs directly.** No wrappers around Three.js or Rapier.
302
+ - **GameComponents are for gameplay entities only.** Static scenery, lights, and UI are plain Three.js objects.
303
+ - **React: HUD overlay via `mountUI(ctx.uiContainer, <Component />)` (inline styles, no CSS files), OR a full react world — declare `kind: "react"` + `entry` in `vgai.game.json` and default-export a component (JSX is truth, no scene file; GameComponents can't attach to react world nodes). The UI container is reset between scene mounts — a react WORLD is the persistent-UI (title-screen shell) pattern: it lives at world scope, not scene scope.** This project ships one HUD overlay out of the box — `src/ui/DefaultHud.tsx` (ordinary props/`useState`, normal inline styling, no Scene UI `UINode`), mounted by `src/ui/mount-default-hud.tsx` and wired into `src/scripts/main.ts`'s `setup()`/`dispose()`. Edit or delete it freely; nothing else in the template depends on it. Do **not** author a `.vscn` top-level `ui` field or import `@vgai/scene-ui` for new gameplay UI — that data-language path is being retired (spec `docs/AI-NATIVE-AUTHORING-IMPLEMENTATION-SPEC.md` §9 C1/C5); use ordinary React instead.
304
+
305
+ To bridge live game state (a singleton gameplay component's score/lives/wave)
306
+ into the HUD, don't poll — wrap the HUD in `<GameProvider game={ctx.game!}>`
307
+ and read with `useGameState((g) => g.queryByComponent(MyComponent)[0]?.field)`;
308
+ both ship in this project's `src/ui/game-state.tsx` (a re-export of
309
+ `@engine/react/game-state`), and the selector re-runs at most once per frame.
310
+ Worked reference: the `hp-hud` example's `src/hud.tsx`.
311
+
312
+ Mounting that HUD from `src/scripts/main.ts`: keep it a `.ts` file. Its exact
313
+ path string is load-bearing in TWO places — `vgai.game.json`'s `entry` and the
314
+ `ENTRY_MODULES` key in `src/main.ts` — and only the standalone build
315
+ (`npm run game`) throws on a mismatch; the editor resolves the entry itself,
316
+ so a `.tsx` rename looks fine in `vgai edit` and breaks later. Since a `.ts`
317
+ file can't contain JSX, keep the JSX in a sibling `.tsx` (like hp-hud's
318
+ `hud.tsx`) and mount with
319
+ `mountUI(ctx.uiContainer, React.createElement(GameProvider, { game: ctx.game! }, React.createElement(MyHud)))`.
320
+ - **Multiplayer → Colyseus directly.** vgai deliberately has no engine-level networking wrapper. Typed `joinOrCreate<T>` + the v0.17 Callbacks API (`onAdd`/`onChange`/`onRemove`; per-field `listen` — but see the P2P caveat below before using it); dynamic-import `@colyseus/sdk` so single-player bundles stay clean. Read live schema properties inside `onChange`; never destructure schema fields into local copies. The worked reference is `network.ts` in a `--example third-person-arena` scaffold (raw Callbacks + an ambient type mirror of the server schema; the engine's old `net/` wrapper is deleted).
321
+ - **P2P mode (browser-hosted rooms) → write dual-target code.** Your room can
322
+ also run browser-hosted over WebRTC via `@vgai/p2p-colyseus`: build/serve
323
+ with `VGAI_P2P=1` (this project's `vite.config.ts` aliases the Colyseus
324
+ packages onto browser-safe compat shims only then) and launch with
325
+ `?net=p2p-host` / `?net=p2p-join&roomId=…`. The same room class still runs
326
+ on a real server (`npm run server`), so keep room + client code inside the
327
+ two runtimes' intersection — full rules with rationale in the engine
328
+ checkout's `docs/P2P-COLYSEUS-MIGRATION.md` ("Dual-Target Portability
329
+ Rules"); the short list:
330
+ - No `$.listen` in the compat layer — read root-state fields inside
331
+ `room.onStateChange` (use `.once(...)`, not its return value: the real
332
+ SDK returns an EventEmitter, the compat an unsubscribe function).
333
+ - No `this.clock` on the compat `Room` — drive all timing from
334
+ `setSimulationInterval` (tick counters for delays).
335
+ - Never send messages from `onJoin` (dropped under P2P) — catch-up is
336
+ client-initiated: register handlers, then send a `sync_req`; reply in
337
+ bounded batches.
338
+ - Keep bulky world data OUT of room state (the P2P runtime diffs the whole
339
+ state per client per tick) — state carries players/actors + small
340
+ scalars; the world is a seed + an event log sent as messages.
341
+ - Relay budget ~30 messages/peer/sec, 16 KB max envelope — throttle moves
342
+ (~10 Hz) and batch bulk sync under the cap.
343
+
344
+ ## Editor Control
345
+
346
+ Use the `/editor` skill to control the visual editor (select entities, focus camera, play/stop, toggle display modes). The skill documents the `vgai` CLI and `@vgai/editor-sdk`.
347
+
348
+ ### Quick examples:
349
+ ```bash
350
+ # Select and focus an entity after editing its scene file
351
+ vgai select <entity-id> && vgai focus <entity-id>
352
+
353
+ # Test gameplay
354
+ vgai play
355
+
356
+ # Check editor state
357
+ vgai status
358
+ ```
359
+
360
+ ## Autoplay bots — testing your game in cycles
361
+
362
+ The highest-leverage test harness for a vgai game is a **synthetic player**:
363
+ a bot that plays the game the way a human does. The full doctrine and the
364
+ evidence behind it live in the engine checkout's
365
+ `docs/SYNTHETIC-PLAYER-DESIGN.md`; this section is the practical playbook.
366
+
367
+ **The principle: synthesized input in, observable state out, no backdoors.**
368
+ The bot presses the same virtual keys and reads the same game state a player
369
+ sees. It never teleports the player, calls gameplay methods directly, or
370
+ writes inventory outside a declared test fixture. To the extent the bot
371
+ cannot cheat, every *gameplay* failure it hits is a real player-facing
372
+ defect — a physics gap, a missing line-of-sight check, a UI-sequencing bug.
373
+ (The bot has its own bug class too — planner/executor defects. A red run is
374
+ a lead, not a verdict; the logs below are how you tell the buckets apart.)
375
+ If some capability forces a compromise (e.g. headless pages have no pointer
376
+ lock, so mouse-look may need a direct write), DECLARE it in your docs as a
377
+ known violation — never let backdoors accumulate silently.
378
+
379
+ **Actuation** — the engine's `InputManager` already ships the seam:
380
+ - `input.setVirtualKey(code, pressed)` — synthesizes key state through the
381
+ real action-binding path.
382
+ - `input.setLookStick(x, y)` — virtual look input, injected as mouse delta
383
+ during `poll()` (the headless-friendly alternative to pointer lock).
384
+ Run the bot against `npm run game` (the standalone player-view page — that's
385
+ what it's for), gated behind a query param like `?bot=1&goal=<skill>&reps=N`.
386
+
387
+ **Perception** — read the game's own observable state (the same objects and
388
+ state your HUD reads), plus a debug handle you expose on `window` for the
389
+ harness (e.g. `__myGame = { gameState, bot }`). World queries that scan
390
+ through terrain/content the player has never seen are X-ray — assisted
391
+ perception. Sometimes pragmatic, but declare it.
392
+
393
+ **Test in layers — never debug a pure-logic bug through the browser:**
394
+ 1. **L1 — headless logic tests.** Extract pure models (movement/physics
395
+ stepping, pathfinding, world rules) into functions a Node script can call
396
+ with no browser, no renderer. Seconds per run; this is where most bugs
397
+ should be found and fixed.
398
+ 2. **L2 — goal isolation.** One skill, from a fresh fixture, N repetitions,
399
+ under a time cap (e.g. a `bot-probe` script that boots the game page
400
+ headless, runs `?bot=1&goal=chop-wood&reps=3`, and greps the event log).
401
+ A skill isn't done until it passes ~3×3 across ≥3 world seeds/fixtures.
402
+ 3. **L3 — full mission.** The bot plays start-to-goal. Only run this when
403
+ the isolated skills underneath are green — otherwise every failure is
404
+ ambiguous.
405
+
406
+ **Logs and analytics from day one — they ARE the iteration loop:**
407
+ - **`lastFail` on every skill**: whenever a bot skill gives up, it records a
408
+ one-line reason with coordinates/state (`"mineBlock 4,61,-1: crosshair on
409
+ 4,62,-1"`). A probe that ends `goal-failed` with no `lastFail` is a
410
+ harness bug.
411
+ - **A trace ring buffer** (last ~60 bot decisions: step taken, expected vs
412
+ actual result) so a failure comes with its recent history attached.
413
+ - **A structured event log** (`goal-passed`/`goal-failed`/`mission-complete`
414
+ + timestamp + position/hp), printed to console so a headless harness can
415
+ grep it, plus periodic screenshots if you drive via Playwright.
416
+ - The iteration cycle is: red run → read `lastFail` + trace → reproduce at
417
+ the LOWEST layer that exhibits it → fix → re-run the isolation → re-run
418
+ the full matrix. Without the logs, step two is guesswork.
419
+
420
+ **Two hard-won invariants** (each cost a debugging session to learn):
421
+ - If your bot is a generator/coroutine stepped once per frame, every loop
422
+ iteration must `yield`. A loop that can re-enter without yielding (e.g.
423
+ "plan failed → retry") is a synchronous freeze that pins the renderer.
424
+ - Never edit source files watched by a running dev server mid-probe — the
425
+ hot reload kills the run and the result is garbage either way.
426
+ - If you drive either dev server (`vgai edit`/`npm run dev`, or `npm run
427
+ game`) with Playwright, use `page.goto(url, { waitUntil: 'load' })`, never
428
+ `'networkidle'` — the dev server keeps a live SSE/websocket/HMR
429
+ connection open, so the network never goes idle and `'networkidle'`
430
+ hangs forever.
431
+
432
+ **Multiplayer without multiplayer**: N synthetic players in N headless pages
433
+ against your Colyseus room is a real multiplayer session — same input paths,
434
+ same netcode, no humans needed. This is the cheapest way to soak-test rooms.
435
+
436
+ ## Examples Catalog
437
+
438
+ Nothing example-shaped ships inside this project — every example is a
439
+ standalone project in the vgai monorepo's `examples/<id>/`, with its own
440
+ `src/`, scenes, `vgai.game.json`, and (where multiplayer) `server/`. Get one's
441
+ code by scaffolding it: `npx create-vgai-project <name> --example <id>` (e.g.
442
+ `--example third-person`) — a correctly-rewritten standalone copy. Or open it
443
+ live in the hosted editor at `https://vgai-editor.pages.dev/?project=<id>`
444
+ (read-only; scaffold to keep edits).
445
+
446
+ **Gameplay examples:**
447
+ - `third-person` — orbit camera, WASD movement, XState animation machine, AI chase
448
+ - `fps` — pointer lock, throwable projectiles, dynamic physics
449
+ - `vehicle` — Rapier raycast-vehicle suspension, steering, chase camera
450
+ - `rts` — top-down camera, box selection, navmesh crowd pathfinding
451
+ - `third-person-arena` — multiplayer tag with AI bots: client-authoritative movement, server-authoritative game state (tag/phases); ships its own `server/`
452
+ - `starfighter` — flight controller with schema-declared tuning fields
453
+ - `ik` — skeletal IK (CCDIKSolver) on a code-built rig
454
+
455
+ **Scene & technique showcases:**
456
+ - `editor-tutorial` — feature-showcase scene: meshes, materials, lights, physics, particles, audio, bloom
457
+ - `feature-scenes` — six technique scenes in one project: instancing, terrain, ocean, particles, custom water shader, HDR skybox
458
+ - `littlest-tokyo` — GLTF model scene (Draco-compressed; ships its decoder assets)
459
+ - `learn-joints`, `learn-matfiles`, `learn-triggers`, `learn-splines` — one-concept tutorials (physics joints, shared `.mat.json` materials, sensor triggers, spline motion)
460
+
461
+ **UI / multi-world examples:**
462
+ - `hp-hud` — React HUD reading live game state via `<GameProvider>` + `useGameState` (selectors call `g.queryByComponent(...)`) (the HUD-overlay pattern on a threejs world — for a `kind: "react"` WORLD example, see `tri-world`)
463
+ - `tri-world` — one manifest, three world kinds side by side (threejs + pixijs + react)
464
+
465
+ **Multiplayer note:** this project already ships a generic `server/` (a
466
+ `GameRoom` in `server/rooms/`, registered in `server/rooms.ts`), but the
467
+ Colyseus server is **not** started by `npm run dev`/`npm run game`. Run `npm run server` to
468
+ boot it standalone — it starts `server/main.ts` on `ws://localhost:2567` and
469
+ shuts down cleanly on Ctrl-C. Start it before connecting, or the client will
470
+ fail to connect. (The script runs tsx against `server/tsconfig.json`, not the
471
+ app tsconfig — `@colyseus/schema`'s legacy `@type` decorators need
472
+ `experimentalDecorators`, which only the server tsconfig sets.) The
473
+ `third-person-arena` example (`--example third-person-arena`) ships its own
474
+ richer `server/` (an `ArenaRoom` with tag/phase state) in place of this
475
+ generic one.
476
+
477
+ ## Scene File Format
478
+
479
+ Entities in `.vscn.json` have these optional fields:
480
+ - `id` — UUID. The **editor** generates one when it creates an entity, and the
481
+ runtime loader auto-generates a random one for id-less entities at load (so
482
+ every loaded object carries an entity descriptor and appears in the play-mode
483
+ hierarchy). But a random id can't be *referenced*: anything targeted from
484
+ elsewhere (joints, god-rays, etc.) still needs an AUTHORED id.
485
+ - `name` — display name
486
+ - `transform` — `{ position: [x,y,z], rotation: [x,y,z,w], scale: [x,y,z] }`
487
+ - `mesh` — `{ type: 'box'|'sphere'|'plane'|'cylinder'|... }`
488
+ - `material` — `{ type: 'standard'|'physical', color, metalness, roughness, ... }` (inline material)
489
+ - `materialRef` — path to a shared `.mat.json` asset. **Mutually exclusive with `material`** — set one or the other, never both (load-time error).
490
+ - `light` — `{ type: 'directional'|'point'|'spot'|'ambient', ... }`
491
+ - `camera` — `{ type: 'perspective'|'orthographic', ... }`
492
+ - `physics` — `{ bodyType: 'dynamic'|'fixed'|'kinematic', collider: { type: 'cuboid'|'ball'|'capsule', halfExtents?, radius?, friction?, restitution?, density? }, mass? }`
493
+
494
+ **Physics contracts (current):**
495
+ - Physics entities may be nested under transformed parents: the loader
496
+ composes the full parent chain and spawns the body at the WORLD
497
+ transform. One exception, enforced loudly: a `dynamic` body under an
498
+ ancestor that itself has a `dynamic`/`kinematic` body is a load error
499
+ (Rapier has no parent/child body relationship).
500
+ - Collider dimensions (`halfExtents`, `radius`) are authored in local units
501
+ and **scale with the entity's composed world scale** (per-axis for
502
+ cuboids; round colliders require uniform scale on their round axes —
503
+ non-uniform is a loud load error). The editor's collider gizmo renders
504
+ the same computed dimensions the runtime uses.
505
+ - Collision events fire for all scene-loaded colliders: solid-solid
506
+ contacts reach `ctx.collisions.onCollision`; **sensor** colliders
507
+ additionally dispatch `onTriggerEnter/Exit` on components.
508
+ - `components` — `{ "ComponentName": { prop: value, ... }, ... }` (see Components section above)
509
+ - `children` — nested entity array
510
+
511
+ Scene files also carry a top-level `ui` field (React UI roots authored via the
512
+ editor's UI edit mode); it survives undo/redo and asset moves.
@@ -0,0 +1,30 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Volter AI, Inc.
4
+
5
+ This MIT license covers the vgai game-project template (this directory) — the
6
+ starter code scaffolded into your project. It is intentionally permissive so that
7
+ the game you build with vgai, and anything you generate from this template, is
8
+ YOURS, free of any obligations to us. You may relicense your generated game
9
+ under any terms you choose.
10
+
11
+ (The vgai engine and tooling — everything outside this directory — are licensed
12
+ per component: Apache-2.0 core, AGPL-3.0 editor. See the repository LICENSE.md.)
13
+
14
+ Permission is hereby granted, free of charge, to any person obtaining a copy
15
+ of this software and associated documentation files (the "Software"), to deal
16
+ in the Software without restriction, including without limitation the rights
17
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18
+ copies of the Software, and to permit persons to whom the Software is
19
+ furnished to do so, subject to the following conditions:
20
+
21
+ The above copyright notice and this permission notice shall be included in all
22
+ copies or substantial portions of the Software.
23
+
24
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30
+ SOFTWARE.
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Emits `src/data/*.schema.json` from the Zod schemas — the schema-interchange
3
+ * step of docs/DATA-TOOLS-DESIGN.md §2.1 / D4 (in the engine checkout).
4
+ * The emitted artifact is committed so VS Code validates/autocompletes every
5
+ * `*.data.json` (via its `"$schema"` first line) with no dev server running.
6
+ *
7
+ * Also VALIDATES each asset's current `.data.json` against its schema and
8
+ * fails loud (the terminal half of the §6 doctor check, usable today) — a
9
+ * schema change that orphans existing data is caught here, not at runtime.
10
+ * The same list drives the BUILD-time check (`vite.config.ts` →
11
+ * `vgaiDataCheck`), and `vgai doctor <folder>` re-runs schema + ref
12
+ * validation from outside the project.
13
+ *
14
+ * Run after every schema change: `npm run emit-schemas`
15
+ * Register new data assets in `src/data/assets.ts` (the one shared list).
16
+ */
17
+ import { readFileSync, writeFileSync } from 'node:fs';
18
+ import path from 'node:path';
19
+ import { fileURLToPath } from 'node:url';
20
+ import { parseDataJson, toDataJsonSchema } from '@vgai/engine/data/data-asset';
21
+ import { dataAssets } from './src/data/assets';
22
+
23
+ const here = path.dirname(fileURLToPath(import.meta.url));
24
+
25
+ let failed = false;
26
+ for (const { name, schema } of dataAssets) {
27
+ const out = `src/data/${name}.schema.json`;
28
+ const data = `src/data/${name}.data.json`;
29
+ writeFileSync(path.join(here, out), `${JSON.stringify(toDataJsonSchema(schema), null, 2)}\n`);
30
+ console.log(`emit-schemas: wrote ${out}`);
31
+
32
+ // parseDataJson = the exact parse defineData runs at load (incl. the
33
+ // "$schema"-line strip), so this check can never disagree with runtime.
34
+ try {
35
+ parseDataJson(schema, JSON.parse(readFileSync(path.join(here, data), 'utf8')), data);
36
+ console.log(`emit-schemas: ${data} validates`);
37
+ } catch (err) {
38
+ failed = true;
39
+ console.error(String(err));
40
+ }
41
+ }
42
+ if (failed) process.exit(1);
@@ -0,0 +1,17 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" />
6
+ <title>My Game</title>
7
+ <style>
8
+ * { margin: 0; padding: 0; box-sizing: border-box; }
9
+ html, body { width: 100%; height: 100%; overflow: hidden; background: #000; }
10
+ #game-canvas { width: 100%; height: 100%; position: relative; }
11
+ </style>
12
+ </head>
13
+ <body>
14
+ <div id="game-canvas"></div>
15
+ <script type="module" src="/src/main.ts"></script>
16
+ </body>
17
+ </html>