@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,99 @@
1
+ // A minimal, real three.js game rendering through its OWN EffectComposer
2
+ // (RenderPass + UnrealBloomPass) — the F13 repro fixture (Wave 14,
3
+ // docs/WAVE14-F13-BLOOM-COMPOSER-REPRO-DESIGN.md). Not an upstream title; a
4
+ // genuine, self-contained bloom program standing in for any source-available
5
+ // game that post-processes through its own composer — same standin spirit as
6
+ // `own-three-bundled` (sanctioned in ADAPTER-MAXIMAL-SPEC.json
7
+ // coverage_standins for the dedupe rung; this fixture exists to prove a
8
+ // SEPARATE bug — the host resize path never touching a game's composer —
9
+ // rather than to prove the dedupe collapse itself).
10
+ //
11
+ // Byte-unmodified, standalone-correct three.js: this file behaves exactly as
12
+ // it would running as a plain page (own renderer, own composer, own
13
+ // `window.resize` handler that resizes BOTH). The bug this exists to expose
14
+ // lives entirely in the HOST's ingest resize path
15
+ // (`ingest-mode.ts` ResizeObserver -> `ingest-game-adapter.ts`'s
16
+ // `resize: (w, h) => rt.renderer.setSize(w, h, false)`), which sizes only the
17
+ // captured renderer's drawing buffer and never calls back into this game to
18
+ // resize its composer — this game's OWN resize handler is correct and is
19
+ // simply never invoked by the host path under ingest.
20
+ import * as THREE from 'three';
21
+ import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js';
22
+ import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass.js';
23
+ import { UnrealBloomPass } from 'three/examples/jsm/postprocessing/UnrealBloomPass.js';
24
+
25
+ const pixelRatio = window.devicePixelRatio || 1;
26
+
27
+ const renderer = new THREE.WebGLRenderer({ antialias: true });
28
+ renderer.setPixelRatio(pixelRatio);
29
+ renderer.setSize(window.innerWidth, window.innerHeight);
30
+ (document.getElementById('container') || document.body).appendChild(renderer.domElement);
31
+
32
+ const scene = new THREE.Scene();
33
+ scene.background = new THREE.Color(0x05050a);
34
+
35
+ const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 100);
36
+ camera.position.set(0, 1.2, 4.5);
37
+
38
+ const light = new THREE.DirectionalLight(0xffffff, 0.6);
39
+ light.position.set(2, 3, 4);
40
+ light.name = 'KeyLight';
41
+ scene.add(light);
42
+
43
+ // Unlit + bright: a common bloom-demo technique — MeshBasicMaterial ignores
44
+ // lighting and feeds full-bright color straight into UnrealBloomPass's
45
+ // luminance threshold, so the emissive look needs no real light contribution.
46
+ const core = new THREE.Mesh(
47
+ new THREE.IcosahedronGeometry(1, 1),
48
+ new THREE.MeshBasicMaterial({ color: 0xfff2b0 }),
49
+ );
50
+ core.name = 'BloomCore';
51
+ scene.add(core);
52
+
53
+ // The composer — sized and pixel-ratio'd against the STANDALONE canvas at
54
+ // construction time, exactly as a well-behaved standalone game would.
55
+ const composer = new EffectComposer(renderer);
56
+ composer.setPixelRatio(pixelRatio);
57
+ composer.setSize(window.innerWidth, window.innerHeight);
58
+ composer.addPass(new RenderPass(scene, camera));
59
+ const bloomPass = new UnrealBloomPass(
60
+ new THREE.Vector2(window.innerWidth, window.innerHeight),
61
+ 1.6,
62
+ 0.5,
63
+ 0.1,
64
+ );
65
+ composer.addPass(bloomPass);
66
+
67
+ // Standalone-correct resize handling: a real game resizes BOTH the renderer
68
+ // AND its composer (plus the camera aspect) on a window resize. This is what
69
+ // the host's ingest resize path (ingest-game-adapter.ts's `resize: (w, h) =>
70
+ // rt.renderer.setSize(w, h, false)`) fails to drive — it calls the
71
+ // renderer's setSize directly, bypassing this handler entirely, so the
72
+ // composer's render targets go stale under a host container resize.
73
+ window.addEventListener('resize', () => {
74
+ camera.aspect = window.innerWidth / window.innerHeight;
75
+ camera.updateProjectionMatrix();
76
+ renderer.setSize(window.innerWidth, window.innerHeight);
77
+ composer.setSize(window.innerWidth, window.innerHeight);
78
+ });
79
+
80
+ // D-B2 dev-only inspection hook: THIS fixture exposing its OWN internals for
81
+ // the F13 repro proof — no host/adapter code learns anything about
82
+ // composers (anti-shim stays intact). Reads the composer's actual
83
+ // render-target pixel dimensions (`writeBuffer.width/height`, three.js
84
+ // EffectComposer's real backing WebGLRenderTarget) against the renderer's
85
+ // actual drawing-buffer pixel dimensions (`domElement.width/height`) — both
86
+ // in device pixels, directly comparable.
87
+ window.__vgaiBloomComposer = {
88
+ composerSize: () => [composer.writeBuffer.width, composer.writeBuffer.height],
89
+ rendererSize: () => [renderer.domElement.width, renderer.domElement.height],
90
+ pixelRatio: () => renderer.getPixelRatio(),
91
+ };
92
+
93
+ let t = 0;
94
+ renderer.setAnimationLoop(() => {
95
+ t += 0.01;
96
+ core.rotation.y = t;
97
+ core.rotation.x = t * 0.6;
98
+ composer.render();
99
+ });
@@ -0,0 +1,21 @@
1
+ {
2
+ "manifestVersion": 1,
3
+ "name": "Bloom EffectComposer repro standin (F13)",
4
+ "version": "0.1.0",
5
+ "engine": {
6
+ "version": "0.1.0"
7
+ },
8
+ "worlds": [
9
+ {
10
+ "id": "bloom-composer",
11
+ "kind": "threejs",
12
+ "description": "A self-made, source-available three.js game that renders through its OWN EffectComposer (RenderPass + UnrealBloomPass) — a repro standin for F13 (docs/FTUE-EXTERNAL-R3F-GAME.md), NOT an upstream title (sanctioned stand-in precedent: ADAPTER-MAXIMAL-SPEC.json coverage_standins, same spirit as own-three-bundled). Exposes a dev-only window.__vgaiBloomComposer inspection hook reading its own composer's real render-target size. Used to prove the host ingest resize path never drives a game's own composer (docs/WAVE14-F13-BLOOM-COMPOSER-REPRO-DESIGN.md).",
13
+ "adapter": {
14
+ "ingest": {
15
+ "strategy": "deduped"
16
+ }
17
+ },
18
+ "entry": "game.js"
19
+ }
20
+ ]
21
+ }
@@ -0,0 +1,10 @@
1
+ <!doctype html><html><head><meta charset="utf-8">
2
+ <style>html,body{margin:0;height:100%;background:#0e0e16;overflow:hidden}canvas{display:block}</style>
3
+ </head><body><canvas id="c"></canvas><script>
4
+ const c=document.getElementById('c'),x=c.getContext('2d');
5
+ function rs(){c.width=innerWidth;c.height=innerHeight}rs();addEventListener('resize',rs);
6
+ let t=0;(function f(){t+=0.02;x.fillStyle='#0e0e16';x.fillRect(0,0,c.width,c.height);
7
+ x.save();x.translate(c.width/2,c.height/2);x.rotate(t);
8
+ x.fillStyle='hsl('+((t*40)%360)+',70%,55%)';x.fillRect(-90,-90,180,180);x.restore();
9
+ requestAnimationFrame(f)})();
10
+ </script></body></html>
@@ -0,0 +1,21 @@
1
+ {
2
+ "manifestVersion": 1,
3
+ "name": "Opaque bundle (embed-only floor)",
4
+ "version": "0.1.0",
5
+ "engine": {
6
+ "version": "0.1.0"
7
+ },
8
+ "worlds": [
9
+ {
10
+ "id": "embed-bundle",
11
+ "kind": "threejs",
12
+ "description": "A self-contained opaque bundle (a dependency-free canvas app) standing in for any prebuilt bundle whose renderer the editor cannot reach. Demonstrates the iframe embed/lifecycle FLOOR (Tier 0–1): hosted + sized + disposed, scene NOT introspectable. Payload-agnostic — a real opaque three.js bundle (own realm-local three) is hosted identically.",
13
+ "adapter": {
14
+ "ingest": {
15
+ "strategy": "opaque-embed",
16
+ "entryHtml": "embed.html"
17
+ }
18
+ }
19
+ }
20
+ ]
21
+ }
@@ -0,0 +1,479 @@
1
+ // UNMODIFIED three.js game — `examples/games_fps` from mrdoob/three.js (r170), MIT.
2
+ //
3
+ // This is the EXACT body of the upstream example's `<script type="module">`,
4
+ // byte-for-byte. The game's logic is untouched. The only thing dropped is the
5
+ // surrounding HTML + importmap: the bare `three` / `three/addons/` specifiers
6
+ // are resolved by the host bundler to the editor's shared three instance (which
7
+ // is what lets the editor's render-trap capture this game's live scene). The
8
+ // relative asset path (`./models/gltf/collision-world.glb`) is redirected by the
9
+ // ingest adapter's THREE.DefaultLoadingManager URL modifier — again, no edit to
10
+ // the code below.
11
+ //
12
+ // Provenance: https://github.com/mrdoob/three.js/blob/r170/examples/games_fps.html
13
+
14
+
15
+ import * as THREE from 'three';
16
+
17
+ import Stats from 'three/addons/libs/stats.module.js';
18
+
19
+ import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
20
+
21
+ import { Octree } from 'three/addons/math/Octree.js';
22
+ import { OctreeHelper } from 'three/addons/helpers/OctreeHelper.js';
23
+
24
+ import { Capsule } from 'three/addons/math/Capsule.js';
25
+
26
+ import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
27
+
28
+ const clock = new THREE.Clock();
29
+
30
+ const scene = new THREE.Scene();
31
+ scene.background = new THREE.Color( 0x88ccee );
32
+ scene.fog = new THREE.Fog( 0x88ccee, 0, 50 );
33
+
34
+ const camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.1, 1000 );
35
+ camera.rotation.order = 'YXZ';
36
+
37
+ const fillLight1 = new THREE.HemisphereLight( 0x8dc1de, 0x00668d, 1.5 );
38
+ fillLight1.position.set( 2, 1, 1 );
39
+ scene.add( fillLight1 );
40
+
41
+ const directionalLight = new THREE.DirectionalLight( 0xffffff, 2.5 );
42
+ directionalLight.position.set( - 5, 25, - 1 );
43
+ directionalLight.castShadow = true;
44
+ directionalLight.shadow.camera.near = 0.01;
45
+ directionalLight.shadow.camera.far = 500;
46
+ directionalLight.shadow.camera.right = 30;
47
+ directionalLight.shadow.camera.left = - 30;
48
+ directionalLight.shadow.camera.top = 30;
49
+ directionalLight.shadow.camera.bottom = - 30;
50
+ directionalLight.shadow.mapSize.width = 1024;
51
+ directionalLight.shadow.mapSize.height = 1024;
52
+ directionalLight.shadow.radius = 4;
53
+ directionalLight.shadow.bias = - 0.00006;
54
+ scene.add( directionalLight );
55
+
56
+ const container = document.getElementById( 'container' );
57
+
58
+ const renderer = new THREE.WebGLRenderer( { antialias: true } );
59
+ renderer.setPixelRatio( window.devicePixelRatio );
60
+ renderer.setSize( window.innerWidth, window.innerHeight );
61
+ renderer.setAnimationLoop( animate );
62
+ renderer.shadowMap.enabled = true;
63
+ renderer.shadowMap.type = THREE.VSMShadowMap;
64
+ renderer.toneMapping = THREE.ACESFilmicToneMapping;
65
+ container.appendChild( renderer.domElement );
66
+
67
+ const stats = new Stats();
68
+ stats.domElement.style.position = 'absolute';
69
+ stats.domElement.style.top = '0px';
70
+ container.appendChild( stats.domElement );
71
+
72
+ const GRAVITY = 30;
73
+
74
+ const NUM_SPHERES = 100;
75
+ const SPHERE_RADIUS = 0.2;
76
+
77
+ const STEPS_PER_FRAME = 5;
78
+
79
+ const sphereGeometry = new THREE.IcosahedronGeometry( SPHERE_RADIUS, 5 );
80
+ const sphereMaterial = new THREE.MeshLambertMaterial( { color: 0xdede8d } );
81
+
82
+ const spheres = [];
83
+ let sphereIdx = 0;
84
+
85
+ for ( let i = 0; i < NUM_SPHERES; i ++ ) {
86
+
87
+ const sphere = new THREE.Mesh( sphereGeometry, sphereMaterial );
88
+ sphere.castShadow = true;
89
+ sphere.receiveShadow = true;
90
+
91
+ scene.add( sphere );
92
+
93
+ spheres.push( {
94
+ mesh: sphere,
95
+ collider: new THREE.Sphere( new THREE.Vector3( 0, - 100, 0 ), SPHERE_RADIUS ),
96
+ velocity: new THREE.Vector3()
97
+ } );
98
+
99
+ }
100
+
101
+ const worldOctree = new Octree();
102
+
103
+ const playerCollider = new Capsule( new THREE.Vector3( 0, 0.35, 0 ), new THREE.Vector3( 0, 1, 0 ), 0.35 );
104
+
105
+ const playerVelocity = new THREE.Vector3();
106
+ const playerDirection = new THREE.Vector3();
107
+
108
+ let playerOnFloor = false;
109
+ let mouseTime = 0;
110
+
111
+ const keyStates = {};
112
+
113
+ const vector1 = new THREE.Vector3();
114
+ const vector2 = new THREE.Vector3();
115
+ const vector3 = new THREE.Vector3();
116
+
117
+ document.addEventListener( 'keydown', ( event ) => {
118
+
119
+ keyStates[ event.code ] = true;
120
+
121
+ } );
122
+
123
+ document.addEventListener( 'keyup', ( event ) => {
124
+
125
+ keyStates[ event.code ] = false;
126
+
127
+ } );
128
+
129
+ container.addEventListener( 'mousedown', () => {
130
+
131
+ document.body.requestPointerLock();
132
+
133
+ mouseTime = performance.now();
134
+
135
+ } );
136
+
137
+ document.addEventListener( 'mouseup', () => {
138
+
139
+ if ( document.pointerLockElement !== null ) throwBall();
140
+
141
+ } );
142
+
143
+ document.body.addEventListener( 'mousemove', ( event ) => {
144
+
145
+ if ( document.pointerLockElement === document.body ) {
146
+
147
+ camera.rotation.y -= event.movementX / 500;
148
+ camera.rotation.x -= event.movementY / 500;
149
+
150
+ }
151
+
152
+ } );
153
+
154
+ window.addEventListener( 'resize', onWindowResize );
155
+
156
+ function onWindowResize() {
157
+
158
+ camera.aspect = window.innerWidth / window.innerHeight;
159
+ camera.updateProjectionMatrix();
160
+
161
+ renderer.setSize( window.innerWidth, window.innerHeight );
162
+
163
+ }
164
+
165
+ function throwBall() {
166
+
167
+ const sphere = spheres[ sphereIdx ];
168
+
169
+ camera.getWorldDirection( playerDirection );
170
+
171
+ sphere.collider.center.copy( playerCollider.end ).addScaledVector( playerDirection, playerCollider.radius * 1.5 );
172
+
173
+ // throw the ball with more force if we hold the button longer, and if we move forward
174
+
175
+ const impulse = 15 + 30 * ( 1 - Math.exp( ( mouseTime - performance.now() ) * 0.001 ) );
176
+
177
+ sphere.velocity.copy( playerDirection ).multiplyScalar( impulse );
178
+ sphere.velocity.addScaledVector( playerVelocity, 2 );
179
+
180
+ sphereIdx = ( sphereIdx + 1 ) % spheres.length;
181
+
182
+ }
183
+
184
+ function playerCollisions() {
185
+
186
+ const result = worldOctree.capsuleIntersect( playerCollider );
187
+
188
+ playerOnFloor = false;
189
+
190
+ if ( result ) {
191
+
192
+ playerOnFloor = result.normal.y > 0;
193
+
194
+ if ( ! playerOnFloor ) {
195
+
196
+ playerVelocity.addScaledVector( result.normal, - result.normal.dot( playerVelocity ) );
197
+
198
+ }
199
+
200
+ if ( result.depth >= 1e-10 ) {
201
+
202
+ playerCollider.translate( result.normal.multiplyScalar( result.depth ) );
203
+
204
+ }
205
+
206
+ }
207
+
208
+ }
209
+
210
+ function updatePlayer( deltaTime ) {
211
+
212
+ let damping = Math.exp( - 4 * deltaTime ) - 1;
213
+
214
+ if ( ! playerOnFloor ) {
215
+
216
+ playerVelocity.y -= GRAVITY * deltaTime;
217
+
218
+ // small air resistance
219
+ damping *= 0.1;
220
+
221
+ }
222
+
223
+ playerVelocity.addScaledVector( playerVelocity, damping );
224
+
225
+ const deltaPosition = playerVelocity.clone().multiplyScalar( deltaTime );
226
+ playerCollider.translate( deltaPosition );
227
+
228
+ playerCollisions();
229
+
230
+ camera.position.copy( playerCollider.end );
231
+
232
+ }
233
+
234
+ function playerSphereCollision( sphere ) {
235
+
236
+ const center = vector1.addVectors( playerCollider.start, playerCollider.end ).multiplyScalar( 0.5 );
237
+
238
+ const sphere_center = sphere.collider.center;
239
+
240
+ const r = playerCollider.radius + sphere.collider.radius;
241
+ const r2 = r * r;
242
+
243
+ // approximation: player = 3 spheres
244
+
245
+ for ( const point of [ playerCollider.start, playerCollider.end, center ] ) {
246
+
247
+ const d2 = point.distanceToSquared( sphere_center );
248
+
249
+ if ( d2 < r2 ) {
250
+
251
+ const normal = vector1.subVectors( point, sphere_center ).normalize();
252
+ const v1 = vector2.copy( normal ).multiplyScalar( normal.dot( playerVelocity ) );
253
+ const v2 = vector3.copy( normal ).multiplyScalar( normal.dot( sphere.velocity ) );
254
+
255
+ playerVelocity.add( v2 ).sub( v1 );
256
+ sphere.velocity.add( v1 ).sub( v2 );
257
+
258
+ const d = ( r - Math.sqrt( d2 ) ) / 2;
259
+ sphere_center.addScaledVector( normal, - d );
260
+
261
+ }
262
+
263
+ }
264
+
265
+ }
266
+
267
+ function spheresCollisions() {
268
+
269
+ for ( let i = 0, length = spheres.length; i < length; i ++ ) {
270
+
271
+ const s1 = spheres[ i ];
272
+
273
+ for ( let j = i + 1; j < length; j ++ ) {
274
+
275
+ const s2 = spheres[ j ];
276
+
277
+ const d2 = s1.collider.center.distanceToSquared( s2.collider.center );
278
+ const r = s1.collider.radius + s2.collider.radius;
279
+ const r2 = r * r;
280
+
281
+ if ( d2 < r2 ) {
282
+
283
+ const normal = vector1.subVectors( s1.collider.center, s2.collider.center ).normalize();
284
+ const v1 = vector2.copy( normal ).multiplyScalar( normal.dot( s1.velocity ) );
285
+ const v2 = vector3.copy( normal ).multiplyScalar( normal.dot( s2.velocity ) );
286
+
287
+ s1.velocity.add( v2 ).sub( v1 );
288
+ s2.velocity.add( v1 ).sub( v2 );
289
+
290
+ const d = ( r - Math.sqrt( d2 ) ) / 2;
291
+
292
+ s1.collider.center.addScaledVector( normal, d );
293
+ s2.collider.center.addScaledVector( normal, - d );
294
+
295
+ }
296
+
297
+ }
298
+
299
+ }
300
+
301
+ }
302
+
303
+ function updateSpheres( deltaTime ) {
304
+
305
+ spheres.forEach( sphere => {
306
+
307
+ sphere.collider.center.addScaledVector( sphere.velocity, deltaTime );
308
+
309
+ const result = worldOctree.sphereIntersect( sphere.collider );
310
+
311
+ if ( result ) {
312
+
313
+ sphere.velocity.addScaledVector( result.normal, - result.normal.dot( sphere.velocity ) * 1.5 );
314
+ sphere.collider.center.add( result.normal.multiplyScalar( result.depth ) );
315
+
316
+ } else {
317
+
318
+ sphere.velocity.y -= GRAVITY * deltaTime;
319
+
320
+ }
321
+
322
+ const damping = Math.exp( - 1.5 * deltaTime ) - 1;
323
+ sphere.velocity.addScaledVector( sphere.velocity, damping );
324
+
325
+ playerSphereCollision( sphere );
326
+
327
+ } );
328
+
329
+ spheresCollisions();
330
+
331
+ for ( const sphere of spheres ) {
332
+
333
+ sphere.mesh.position.copy( sphere.collider.center );
334
+
335
+ }
336
+
337
+ }
338
+
339
+ function getForwardVector() {
340
+
341
+ camera.getWorldDirection( playerDirection );
342
+ playerDirection.y = 0;
343
+ playerDirection.normalize();
344
+
345
+ return playerDirection;
346
+
347
+ }
348
+
349
+ function getSideVector() {
350
+
351
+ camera.getWorldDirection( playerDirection );
352
+ playerDirection.y = 0;
353
+ playerDirection.normalize();
354
+ playerDirection.cross( camera.up );
355
+
356
+ return playerDirection;
357
+
358
+ }
359
+
360
+ function controls( deltaTime ) {
361
+
362
+ // gives a bit of air control
363
+ const speedDelta = deltaTime * ( playerOnFloor ? 25 : 8 );
364
+
365
+ if ( keyStates[ 'KeyW' ] ) {
366
+
367
+ playerVelocity.add( getForwardVector().multiplyScalar( speedDelta ) );
368
+
369
+ }
370
+
371
+ if ( keyStates[ 'KeyS' ] ) {
372
+
373
+ playerVelocity.add( getForwardVector().multiplyScalar( - speedDelta ) );
374
+
375
+ }
376
+
377
+ if ( keyStates[ 'KeyA' ] ) {
378
+
379
+ playerVelocity.add( getSideVector().multiplyScalar( - speedDelta ) );
380
+
381
+ }
382
+
383
+ if ( keyStates[ 'KeyD' ] ) {
384
+
385
+ playerVelocity.add( getSideVector().multiplyScalar( speedDelta ) );
386
+
387
+ }
388
+
389
+ if ( playerOnFloor ) {
390
+
391
+ if ( keyStates[ 'Space' ] ) {
392
+
393
+ playerVelocity.y = 15;
394
+
395
+ }
396
+
397
+ }
398
+
399
+ }
400
+
401
+ const loader = new GLTFLoader().setPath( './models/gltf/' );
402
+
403
+ loader.load( 'collision-world.glb', ( gltf ) => {
404
+
405
+ scene.add( gltf.scene );
406
+
407
+ worldOctree.fromGraphNode( gltf.scene );
408
+
409
+ gltf.scene.traverse( child => {
410
+
411
+ if ( child.isMesh ) {
412
+
413
+ child.castShadow = true;
414
+ child.receiveShadow = true;
415
+
416
+ if ( child.material.map ) {
417
+
418
+ child.material.map.anisotropy = 4;
419
+
420
+ }
421
+
422
+ }
423
+
424
+ } );
425
+
426
+ const helper = new OctreeHelper( worldOctree );
427
+ helper.visible = false;
428
+ scene.add( helper );
429
+
430
+ const gui = new GUI( { width: 200 } );
431
+ gui.add( { debug: false }, 'debug' )
432
+ .onChange( function ( value ) {
433
+
434
+ helper.visible = value;
435
+
436
+ } );
437
+
438
+ } );
439
+
440
+ function teleportPlayerIfOob() {
441
+
442
+ if ( camera.position.y <= - 25 ) {
443
+
444
+ playerCollider.start.set( 0, 0.35, 0 );
445
+ playerCollider.end.set( 0, 1, 0 );
446
+ playerCollider.radius = 0.35;
447
+ camera.position.copy( playerCollider.end );
448
+ camera.rotation.set( 0, 0, 0 );
449
+
450
+ }
451
+
452
+ }
453
+
454
+
455
+ function animate() {
456
+
457
+ const deltaTime = Math.min( 0.05, clock.getDelta() ) / STEPS_PER_FRAME;
458
+
459
+ // we look for collisions in substeps to mitigate the risk of
460
+ // an object traversing another too quickly for detection.
461
+
462
+ for ( let i = 0; i < STEPS_PER_FRAME; i ++ ) {
463
+
464
+ controls( deltaTime );
465
+
466
+ updatePlayer( deltaTime );
467
+
468
+ updateSpheres( deltaTime );
469
+
470
+ teleportPlayerIfOob();
471
+
472
+ }
473
+
474
+ renderer.render( scene, camera );
475
+
476
+ stats.update();
477
+
478
+ }
479
+
@@ -0,0 +1,24 @@
1
+ {
2
+ "manifestVersion": 1,
3
+ "name": "three.js — Octree FPS (games_fps)",
4
+ "version": "0.1.0",
5
+ "engine": {
6
+ "version": "0.1.0"
7
+ },
8
+ "worlds": [
9
+ {
10
+ "id": "games-fps",
11
+ "kind": "threejs",
12
+ "description": "Upstream mrdoob/three.js example: octree collisions, GLTF world, 100 physics spheres, pointer-lock FPS. Own scene/camera/renderer/rAF/input.",
13
+ "adapter": {
14
+ "ingest": {
15
+ "strategy": "shared",
16
+ "assets": {
17
+ "models/gltf/collision-world.glb": "assets/collision-world.glb"
18
+ }
19
+ }
20
+ },
21
+ "entry": "game.js"
22
+ }
23
+ ]
24
+ }