@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,93 @@
1
+ /**
2
+ * Editor session registry — the file-backed ledger of live editor dev servers
3
+ * (D12, docs/EDITOR-FIRST-DEV.md). Written by THIS package (dev.ts registers
4
+ * on listen, re-registers on project switch, unregisters on shutdown); read by
5
+ * the vgai CLI (its own light reader in packages/vgai-cli/src/editor-sessions.ts —
6
+ * the CLI deliberately has no editor-package dependency, so the FILE FORMAT
7
+ * here is the contract: keep the two in sync).
8
+ *
9
+ * Format: `~/.vgai/editor-sessions.json`, a JSON array of EditorSession.
10
+ * Entries are best-effort — every reader must PID-liveness-filter (a crashed
11
+ * server can't unregister itself), and writers sweep dead entries on write.
12
+ */
13
+
14
+ import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
15
+ import { homedir } from 'node:os';
16
+ import { join } from 'node:path';
17
+
18
+ export interface EditorSession {
19
+ /** Canonical project root currently open, or null when none. */
20
+ project: string | null;
21
+ port: number;
22
+ /** PID of the dev-server process (dev.ts's own process.pid). */
23
+ pid: number;
24
+ /** ISO timestamp of server start. */
25
+ startedAt: string;
26
+ }
27
+
28
+ const REGISTRY_DIR = join(homedir(), '.vgai');
29
+ const REGISTRY_FILE = join(REGISTRY_DIR, 'editor-sessions.json');
30
+
31
+ export function sessionRegistryPath(): string {
32
+ return REGISTRY_FILE;
33
+ }
34
+
35
+ function isSession(v: unknown): v is EditorSession {
36
+ if (typeof v !== 'object' || v === null) return false;
37
+ const s = v as Record<string, unknown>;
38
+ return (
39
+ (typeof s['project'] === 'string' || s['project'] === null) &&
40
+ typeof s['port'] === 'number' &&
41
+ typeof s['pid'] === 'number' &&
42
+ typeof s['startedAt'] === 'string'
43
+ );
44
+ }
45
+
46
+ export function pidAlive(pid: number): boolean {
47
+ try {
48
+ process.kill(pid, 0);
49
+ return true;
50
+ } catch {
51
+ return false;
52
+ }
53
+ }
54
+
55
+ /** All recorded sessions, unvalidated beyond shape (callers liveness-filter). */
56
+ export function readSessions(): EditorSession[] {
57
+ try {
58
+ const raw: unknown = JSON.parse(readFileSync(REGISTRY_FILE, 'utf8'));
59
+ return Array.isArray(raw) ? raw.filter(isSession) : [];
60
+ } catch {
61
+ return [];
62
+ }
63
+ }
64
+
65
+ /** Sessions whose server process is still alive. */
66
+ export function liveSessions(): EditorSession[] {
67
+ return readSessions().filter((s) => pidAlive(s.pid));
68
+ }
69
+
70
+ /**
71
+ * Record (or refresh) this process's session. Sweeps dead entries and any
72
+ * stale claim on the same port while it's here.
73
+ */
74
+ export function registerSession(session: EditorSession): void {
75
+ try {
76
+ mkdirSync(REGISTRY_DIR, { recursive: true });
77
+ const rest = readSessions().filter(
78
+ (s) => s.pid !== session.pid && s.port !== session.port && pidAlive(s.pid),
79
+ );
80
+ writeFileSync(REGISTRY_FILE, `${JSON.stringify([...rest, session], null, 2)}\n`);
81
+ } catch {
82
+ // Registry is best-effort — never let bookkeeping kill the server.
83
+ }
84
+ }
85
+
86
+ export function unregisterSession(pid: number): void {
87
+ try {
88
+ const rest = readSessions().filter((s) => s.pid !== pid);
89
+ writeFileSync(REGISTRY_FILE, `${JSON.stringify(rest, null, 2)}\n`);
90
+ } catch {
91
+ // Best-effort (see registerSession).
92
+ }
93
+ }
@@ -0,0 +1,87 @@
1
+ import { createContext, type ReactNode, Suspense, useContext, useEffect, useRef } from 'react';
2
+ import { connectCommandListener } from './command-listener';
3
+ import { EditorStore } from './editor-store';
4
+ import { initProject } from './initial-scene';
5
+ import { type InteractiveEditScope, InteractiveEditScopeContext } from './interactive-edit-scope';
6
+
7
+ export interface EditorStats {
8
+ fps: number;
9
+ frameTime: number;
10
+ drawCalls: number;
11
+ triangles: number;
12
+ cameraPosition: { x: number; y: number; z: number };
13
+ cameraTarget: { x: number; y: number; z: number };
14
+ }
15
+
16
+ interface EditorContextValue {
17
+ store: EditorStore;
18
+ stats: EditorStats;
19
+ initPromise: Promise<void>;
20
+ }
21
+
22
+ const EditorContext = createContext<EditorContextValue | null>(null);
23
+
24
+ export function EditorProvider({ children }: { children: ReactNode }) {
25
+ const storeRef = useRef<EditorStore | null>(null);
26
+ if (!storeRef.current) storeRef.current = new EditorStore();
27
+
28
+ const statsRef = useRef<EditorStats | null>(null);
29
+ if (!statsRef.current) {
30
+ statsRef.current = {
31
+ fps: 0,
32
+ frameTime: 0,
33
+ drawCalls: 0,
34
+ triangles: 0,
35
+ cameraPosition: { x: 0, y: 0, z: 0 },
36
+ cameraTarget: { x: 0, y: 0, z: 0 },
37
+ };
38
+ }
39
+
40
+ const initRef = useRef<Promise<void> | null>(null);
41
+ if (!initRef.current) {
42
+ initRef.current = initProject();
43
+ }
44
+
45
+ // The shallow undo-gesture seam the shared widget kit consumes instead of
46
+ // this (deep) context — see interactive-edit-scope.ts's doc comment (W3).
47
+ const editScopeRef = useRef<InteractiveEditScope | null>(null);
48
+ if (!editScopeRef.current) {
49
+ const store = storeRef.current;
50
+ editScopeRef.current = {
51
+ begin: () => store.beginInteractiveEdit(),
52
+ end: () => store.endInteractiveEdit(),
53
+ };
54
+ }
55
+
56
+ useEffect(() => {
57
+ return connectCommandListener(storeRef.current!);
58
+ }, []);
59
+
60
+ return (
61
+ <EditorContext.Provider
62
+ value={{ store: storeRef.current, stats: statsRef.current, initPromise: initRef.current }}
63
+ >
64
+ <InteractiveEditScopeContext.Provider value={editScopeRef.current}>
65
+ <Suspense>{children}</Suspense>
66
+ </InteractiveEditScopeContext.Provider>
67
+ </EditorContext.Provider>
68
+ );
69
+ }
70
+
71
+ export function useEditorStore(): EditorStore {
72
+ const ctx = useContext(EditorContext);
73
+ if (!ctx) throw new Error('useEditorStore must be used within <EditorProvider>');
74
+ return ctx.store;
75
+ }
76
+
77
+ export function useEditorStats(): EditorStats {
78
+ const ctx = useContext(EditorContext);
79
+ if (!ctx) throw new Error('useEditorStats must be used within <EditorProvider>');
80
+ return ctx.stats;
81
+ }
82
+
83
+ export function useEditorInit(): Promise<void> {
84
+ const ctx = useContext(EditorContext);
85
+ if (!ctx) throw new Error('useEditorInit must be used within <EditorProvider>');
86
+ return ctx.initPromise;
87
+ }
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Achieved-tier verification — T3.4 slice 1 (docs/ADAPTER-AUTHORING-DESIGN.md
3
+ * §1.C). A `{ module }` adapter self-certifies its `capabilities.{local,hosted}`
4
+ * tier at manifest-author time (the loader requires it explicitly — there is no
5
+ * derivable ceiling, `packages/engine/src/manifest/load.ts`'s `resolveCapabilities`).
6
+ * Nothing checks that self-certification against reality UNTIL NOW: this module
7
+ * computes the tier a `MountedGame` ACTUALLY reaches, straight from the
8
+ * `AuthoringAdapter` surface it returned from `mount()`, and logs a shortfall
9
+ * loudly (never silently) when achieved < declared.
10
+ *
11
+ * The three-band mapping (§1.C, "roughly: full authoring incl.
12
+ * transforms+inspector+persistence -> first-party reach; hierarchy-only ->
13
+ * shared-tier reach; no authoring -> opaque-embed reach") is made exact here:
14
+ *
15
+ * - no `authoring` at all -> 'opaque-embed'
16
+ * (docs/CAPABILITY-TIERS.md §b: "None — embed + lifecycle only ... no
17
+ * reachable scene to capture").
18
+ * - `authoring` present, but missing `transforms`, `inspector`, OR
19
+ * `persistence` -> 'shared'
20
+ * (§b: "Full — in-realm capture + editing" is `shared`'s row; a partial
21
+ * authoring surface still reaches in-realm editing on whatever it DOES
22
+ * provide, so it is not honestly opaque, but it has not earned the
23
+ * `first-party` floor's full round-trip either).
24
+ * - `authoring` with ALL of `transforms`+`inspector`+`persistence`
25
+ * -> 'first-party'
26
+ * (§b: "Full — native SceneEntity + gizmo ... .vscn is the source of
27
+ * truth" — a module adapter obviously has no `.vscn`, but this is the
28
+ * ceiling band a custom adapter can claim: full editing + full
29
+ * persistence route, mirrored for a non-first-party mount).
30
+ *
31
+ * `docs/achieved-tier-doc-pin.test.ts`-style coverage lives in
32
+ * `packages/engine/test/capability-tiers-achieved-mapping-doc-pin.test.ts`,
33
+ * pinning this banding's tier names + the doc's per-tier "Inspector / gizmo
34
+ * editing" language against this file, the same way
35
+ * `capability-tiers-doc-pin.test.ts` pins the ceiling table.
36
+ */
37
+
38
+ import type { MountedGame } from '@engine/adapter';
39
+ import type { Tier } from '@engine/manifest/schema';
40
+
41
+ // Deliberately NO import of `./editor-console` here: that module touches
42
+ // `window` unconditionally at its top level (a house rule this file must
43
+ // respect — `adapter-resolver.ts`, this module's first caller, is imported
44
+ // by headless Node/vitest suites with no `window` stub, e.g.
45
+ // `adapter-resolver.test.ts`/`adapter-resolver-pixi.test.ts`). This module
46
+ // stays a PURE computation + message-formatting library; callers that already
47
+ // own an `editorConsole` import (or a browser environment) do the actual
48
+ // logging (see `adapter-resolver.ts`'s `withAchievedTierCheck` and
49
+ // `ingest-mode.ts`'s embed-only retrofit).
50
+
51
+ /** The exact three achieved bands this slice's check can produce. */
52
+ export type AchievedTier = Extract<Tier, 'first-party' | 'shared' | 'opaque-embed'>;
53
+
54
+ /** Total order over `Tier` — same ranking as `CAPABILITY_CEILINGS`'s consumer
55
+ * (docs/CAPABILITY-TIERS.md §a: `first-party > shared ~= deduped >
56
+ * iframe-reachable > opaque-embed > unsupported`). Duplicated (not imported)
57
+ * because `packages/engine/src/manifest/load.ts`'s `TIER_RANK` is module-private. */
58
+ const TIER_RANK: Record<Tier, number> = {
59
+ 'first-party': 5,
60
+ shared: 4,
61
+ deduped: 4,
62
+ 'iframe-reachable': 3,
63
+ 'opaque-embed': 2,
64
+ unsupported: 1,
65
+ };
66
+
67
+ /**
68
+ * Compute the ACHIEVED tier from a mounted game's actual `authoring` surface
69
+ * (§1.C's exact banding — see this file's doc comment). Pure function of the
70
+ * `MountedGame` shape; does not itself log — call {@link reportTierShortfall}
71
+ * with the result to get the structured log this slice's AC requires.
72
+ */
73
+ export function computeAchievedTier(mounted: Pick<MountedGame, 'authoring'>): AchievedTier {
74
+ const { authoring } = mounted;
75
+ if (!authoring) return 'opaque-embed';
76
+ if (authoring.transforms && authoring.inspector && authoring.persistence) return 'first-party';
77
+ return 'shared';
78
+ }
79
+
80
+ /**
81
+ * Structured shortfall payload — ONE shape, greppable, used by BOTH the
82
+ * module-adapter achieved-tier check (adapter-resolver.ts) and the ingest
83
+ * embed-only degradation retrofit (ingest-mode.ts's
84
+ * `enterIngestModeWithGame`), per §1.C: "mirroring the ingest `embedOnly`
85
+ * precedent but carrying the actual enum values ... the existing embed-only
86
+ * fallback gains the same structured tier log." A no-op (`null`) when
87
+ * `achieved` is not below `declared` (over-claiming survives silently right
88
+ * up until it's caught — under-claiming, including exact matches, is never
89
+ * reported as a shortfall).
90
+ */
91
+ export interface TierShortfallReport {
92
+ worldId: string;
93
+ declaredTier: Tier;
94
+ achievedTier: Tier;
95
+ }
96
+
97
+ /** Greppable prefix shared by every shortfall log line this slice produces. */
98
+ export const TIER_SHORTFALL_PREFIX = 'tier-shortfall';
99
+
100
+ /**
101
+ * Compute the shortfall report (or `null` if there is none) — pure, no
102
+ * logging. `formatTierShortfallMessage` turns a non-null report into the ONE
103
+ * log-line shape; callers own the actual `editorConsole.warn(...)` call (see
104
+ * this file's doc comment for why the logging call isn't made HERE).
105
+ */
106
+ export function computeTierShortfall(
107
+ worldId: string,
108
+ declared: Tier,
109
+ achieved: Tier,
110
+ ): TierShortfallReport | null {
111
+ const achievedRank: number = TIER_RANK[achieved];
112
+ const declaredRank: number = TIER_RANK[declared];
113
+ if (achievedRank >= declaredRank) return null;
114
+ return { worldId, declaredTier: declared, achievedTier: achieved };
115
+ }
116
+
117
+ /** The one shared message shape: `tier-shortfall world "<id>" declared "<X>"
118
+ * but only achieved "<Y>" ... tier-shortfall {"worldId":...}` (greppable on
119
+ * the `tier-shortfall` prefix, JSON-parseable on the trailing payload). */
120
+ export function formatTierShortfallMessage(report: TierShortfallReport): string {
121
+ return (
122
+ `${TIER_SHORTFALL_PREFIX} world "${report.worldId}" declared "${report.declaredTier}" but ` +
123
+ `only achieved "${report.achievedTier}" — mounting at the achieved tier ` +
124
+ `(docs/ADAPTER-AUTHORING-DESIGN.md §1.C). ${TIER_SHORTFALL_PREFIX} ${JSON.stringify(report)}`
125
+ );
126
+ }
@@ -0,0 +1,268 @@
1
+ import { timelineRedo, timelineUndo } from './authoring/undo-timeline';
2
+ import type { EditorStore } from './editor-store';
3
+
4
+ export interface EditorAction {
5
+ id: string;
6
+ label: string;
7
+ category: 'action' | 'entity' | 'asset';
8
+ shortcut?: string;
9
+ execute: () => void;
10
+ }
11
+
12
+ const RECENT_KEY = 'editor:recent-actions';
13
+ const MAX_RECENT = 10;
14
+
15
+ export function getRecentActionIds(): string[] {
16
+ try {
17
+ return JSON.parse(localStorage.getItem(RECENT_KEY) ?? '[]') as string[];
18
+ } catch {
19
+ return [];
20
+ }
21
+ }
22
+
23
+ export function pushRecentAction(id: string): void {
24
+ const recent = getRecentActionIds().filter((r) => r !== id);
25
+ recent.unshift(id);
26
+ if (recent.length > MAX_RECENT) recent.length = MAX_RECENT;
27
+ localStorage.setItem(RECENT_KEY, JSON.stringify(recent));
28
+ }
29
+
30
+ /** Build the static list of editor command actions. */
31
+ export function buildStaticActions(store: EditorStore): EditorAction[] {
32
+ const isMac = navigator.platform.includes('Mac');
33
+ const mod = isMac ? '\u2318' : 'Ctrl+';
34
+
35
+ return [
36
+ {
37
+ id: 'editor.undo',
38
+ label: 'Undo',
39
+ category: 'action',
40
+ shortcut: `${mod}Z`,
41
+ // T3.2 slice 2: through the editor-global timeline, NOT `store.undo()`
42
+ // directly \u2014 same reasoning as the Ctrl+Z hotkey (docs/
43
+ // PERSISTENCE-PROVIDER-DESIGN.md \u00A73): whichever adapter (first-party/
44
+ // ingest/UI) recorded the most recent op, not always the first-party store.
45
+ execute: () => timelineUndo(),
46
+ },
47
+ {
48
+ id: 'editor.redo',
49
+ label: 'Redo',
50
+ category: 'action',
51
+ shortcut: `${mod}\u21E7Z`,
52
+ execute: () => timelineRedo(),
53
+ },
54
+ {
55
+ id: 'editor.copy',
56
+ label: 'Copy',
57
+ category: 'action',
58
+ shortcut: `${mod}C`,
59
+ execute: () => {
60
+ if (store.selectedEntityIds.size > 0) store.copyEntities();
61
+ },
62
+ },
63
+ {
64
+ id: 'editor.cut',
65
+ label: 'Cut',
66
+ category: 'action',
67
+ shortcut: `${mod}X`,
68
+ execute: () => {
69
+ if (store.selectedEntityIds.size > 0) store.cutEntities();
70
+ },
71
+ },
72
+ {
73
+ id: 'editor.paste',
74
+ label: 'Paste',
75
+ category: 'action',
76
+ shortcut: `${mod}V`,
77
+ execute: () => {
78
+ if (store.hasClipboard) store.pasteEntities();
79
+ },
80
+ },
81
+ {
82
+ id: 'editor.duplicate',
83
+ label: 'Duplicate',
84
+ category: 'action',
85
+ shortcut: `${mod}D`,
86
+ execute: () => {
87
+ for (const id of store.selectedEntityIds) store.duplicateEntity(id);
88
+ },
89
+ },
90
+ {
91
+ id: 'editor.delete',
92
+ label: 'Delete Selected',
93
+ category: 'action',
94
+ shortcut: 'Del',
95
+ execute: () => {
96
+ if (store.selectedEntityIds.size > 0) store.deleteEntities([...store.selectedEntityIds]);
97
+ },
98
+ },
99
+ {
100
+ id: 'editor.select-all',
101
+ label: 'Select All',
102
+ category: 'action',
103
+ shortcut: `${mod}A`,
104
+ execute: () => store.selectAll(),
105
+ },
106
+ {
107
+ id: 'editor.deselect',
108
+ label: 'Deselect All',
109
+ category: 'action',
110
+ shortcut: 'Esc',
111
+ execute: () => store.select(null),
112
+ },
113
+ {
114
+ id: 'mode.translate',
115
+ label: 'Translate Mode',
116
+ category: 'action',
117
+ shortcut: 'W',
118
+ execute: () => store.setTransformMode('translate'),
119
+ },
120
+ {
121
+ id: 'mode.rotate',
122
+ label: 'Rotate Mode',
123
+ category: 'action',
124
+ shortcut: 'E',
125
+ execute: () => store.setTransformMode('rotate'),
126
+ },
127
+ {
128
+ id: 'mode.scale',
129
+ label: 'Scale Mode',
130
+ category: 'action',
131
+ shortcut: 'R',
132
+ execute: () => store.setTransformMode('scale'),
133
+ },
134
+ {
135
+ id: 'mode.world',
136
+ label: 'World Space',
137
+ category: 'action',
138
+ execute: () => store.setTransformSpace('world'),
139
+ },
140
+ {
141
+ id: 'mode.local',
142
+ label: 'Local Space',
143
+ category: 'action',
144
+ execute: () => store.setTransformSpace('local'),
145
+ },
146
+ {
147
+ id: 'toggle.grid',
148
+ label: 'Toggle Grid',
149
+ category: 'action',
150
+ execute: () => store.toggleGrid(),
151
+ },
152
+ {
153
+ id: 'toggle.helpers',
154
+ label: 'Toggle Helpers',
155
+ category: 'action',
156
+ execute: () => store.toggleHelpers(),
157
+ },
158
+ {
159
+ id: 'toggle.stats',
160
+ label: 'Toggle Stats Overlay',
161
+ category: 'action',
162
+ execute: () => store.toggleStats(),
163
+ },
164
+ {
165
+ id: 'toggle.snap',
166
+ label: 'Toggle Snap',
167
+ category: 'action',
168
+ execute: () => store.toggleSnap(),
169
+ },
170
+ {
171
+ id: 'toggle.surface-snap',
172
+ label: 'Toggle Surface Snap',
173
+ category: 'action',
174
+ execute: () => store.toggleSnapToSurface(),
175
+ },
176
+ {
177
+ id: 'shading.solid',
178
+ label: 'Solid Shading',
179
+ category: 'action',
180
+ execute: () => store.setShadingMode('solid'),
181
+ },
182
+ {
183
+ id: 'shading.wireframe',
184
+ label: 'Wireframe Shading',
185
+ category: 'action',
186
+ execute: () => store.setShadingMode('wireframe'),
187
+ },
188
+ {
189
+ id: 'shading.unlit',
190
+ label: 'Unlit Shading',
191
+ category: 'action',
192
+ execute: () => store.setShadingMode('unlit'),
193
+ },
194
+ {
195
+ id: 'view.top',
196
+ label: 'Top View',
197
+ category: 'action',
198
+ shortcut: 'Num7',
199
+ execute: () => store.setViewPreset('top'),
200
+ },
201
+ {
202
+ id: 'view.front',
203
+ label: 'Front View',
204
+ category: 'action',
205
+ shortcut: 'Num1',
206
+ execute: () => store.setViewPreset('front'),
207
+ },
208
+ {
209
+ id: 'view.right',
210
+ label: 'Right View',
211
+ category: 'action',
212
+ shortcut: 'Num3',
213
+ execute: () => store.setViewPreset('right'),
214
+ },
215
+ {
216
+ id: 'view.perspective',
217
+ label: 'Perspective View',
218
+ category: 'action',
219
+ shortcut: 'Num5',
220
+ execute: () => store.setViewPreset('perspective'),
221
+ },
222
+ {
223
+ id: 'focus.selected',
224
+ label: 'Focus Selected',
225
+ category: 'action',
226
+ shortcut: 'F',
227
+ execute: () => store.focusOnSelection(),
228
+ },
229
+ {
230
+ id: 'toggle.console',
231
+ label: 'Toggle Console',
232
+ category: 'action',
233
+ shortcut: '`',
234
+ execute: () => {
235
+ window.dispatchEvent(new CustomEvent('editor:toggle-console'));
236
+ },
237
+ },
238
+ {
239
+ id: 'build.web',
240
+ label: 'Build for Web (itch.io)',
241
+ category: 'action',
242
+ execute: () => {
243
+ window.dispatchEvent(new CustomEvent('editor:show-build-tab'));
244
+ },
245
+ },
246
+ {
247
+ id: 'build.steam',
248
+ label: 'Build for Desktop (Steam)',
249
+ category: 'action',
250
+ execute: () => {
251
+ window.dispatchEvent(new CustomEvent('editor:show-build-tab'));
252
+ },
253
+ },
254
+ ];
255
+ }
256
+
257
+ /** Build dynamic entity actions from the current scene. */
258
+ export function buildEntityActions(store: EditorStore): EditorAction[] {
259
+ return store.allEntities().map((entity) => ({
260
+ id: `entity:${entity.id}`,
261
+ label: entity.name,
262
+ category: 'entity' as const,
263
+ execute: () => {
264
+ store.select(entity.id!);
265
+ store.focusOnEntity(entity.id!);
266
+ },
267
+ }));
268
+ }