@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,31 @@
1
+ /**
2
+ * Viewport pick context (B4, D12) — the camera/canvas seam that
3
+ * `VgaiSceneAuthoringAdapter.pickable.pick` needs but cannot own itself: both
4
+ * live on `EditorViewport`, not on the adapter (the adapter only ever held a
5
+ * `store` — see its own doc comment). A tiny module-level slot, same shape as
6
+ * `./active-systems.ts`: `EditorViewport`'s constructor sets it once its
7
+ * camera/canvas exist; its `dispose()` clears it.
8
+ *
9
+ * Absent (module load, a headless unit test that builds the adapter with no
10
+ * live viewport, or after `dispose()`) ⇒ `pick()` returns `null` — an honest
11
+ * degrade, never a throw.
12
+ */
13
+
14
+ import type * as THREE from 'three';
15
+
16
+ export interface ViewportPickContext {
17
+ readonly camera: THREE.Camera;
18
+ readonly canvas: HTMLCanvasElement;
19
+ }
20
+
21
+ let _ctx: ViewportPickContext | null = null;
22
+
23
+ /** Install/clear the live viewport's pick context (`EditorViewport` ctor/dispose). */
24
+ export function setViewportPickContext(ctx: ViewportPickContext | null): void {
25
+ _ctx = ctx;
26
+ }
27
+
28
+ /** The live viewport's camera/canvas, or `null` when none is mounted. */
29
+ export function getViewportPickContext(): ViewportPickContext | null {
30
+ return _ctx;
31
+ }
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Shared threejs viewport raycast pick (B4, D12) — the adapter-AGNOSTIC
3
+ * entity-under-the-pointer raycast, extracted verbatim from
4
+ * `editor-viewport.ts`'s former `_raycastEntity` so EVERY threejs-backed
5
+ * authoring adapter whose live objects sit in `store.objectMap` reuses the
6
+ * exact same logic:
7
+ * - first-party `VgaiSceneAuthoringAdapter` (edit mode's focused world),
8
+ * - `IngestAuthoringAdapter` (an ingested foreign threejs game — bare ingest
9
+ * mode AND the threejs child of a multi-world PLAY composite).
10
+ *
11
+ * Pre-B4, `_onPointerUp` ran this raycast UNCONDITIONALLY against
12
+ * `store.objectMap` regardless of which adapter was active, so an ingest/
13
+ * multi-world-play canvas click selected the object under the pointer. B4's
14
+ * `pickTopmost` routes through the active adapter's `pickable` instead, so
15
+ * that behavior only survives if each threejs adapter exposes a `pickable`
16
+ * backed by THIS helper (the raycast never depended on `SceneEntity`/`.vscn` —
17
+ * only on `store.objectMap` + `userData.entityId` + `store.isEntityLocked`,
18
+ * all of which an ingest mount populates identically to a first-party one).
19
+ *
20
+ * The camera/canvas live only on `EditorViewport`, reached through the
21
+ * `viewport-pick-context.ts` seam (its ctor/`dispose()` set/clear it). Absent
22
+ * (a headless unit test, or no live viewport mounted) ⇒ `null`, an honest
23
+ * degrade rather than a throw. Uses its OWN `THREE.Raycaster` with
24
+ * `layers.enableAll()` replicated so it hits gizmo-adjacent EDITOR_LAYER-tagged
25
+ * geometry exactly like the original.
26
+ */
27
+
28
+ import { getUserData } from '@engine/scene/user-data';
29
+ import * as THREE from 'three';
30
+ import type { EditorStore } from '../editor-store';
31
+ import { getViewportPickContext } from './viewport-pick-context';
32
+
33
+ /** Raycast `store.objectMap` and return the entity id under `(clientX,
34
+ * clientY)`, or `null`. Skips editor-helper geometry and locked entities,
35
+ * identical to the pre-B4 viewport raycast. */
36
+ export function raycastPick(store: EditorStore, clientX: number, clientY: number): string | null {
37
+ const ctx = getViewportPickContext();
38
+ if (!ctx) return null; // no live viewport mounted — honest degrade
39
+ const rect = ctx.canvas.getBoundingClientRect();
40
+ const mouse = new THREE.Vector2(
41
+ ((clientX - rect.left) / rect.width) * 2 - 1,
42
+ -((clientY - rect.top) / rect.height) * 2 + 1,
43
+ );
44
+ const raycaster = new THREE.Raycaster();
45
+ raycaster.layers.enableAll();
46
+ raycaster.setFromCamera(mouse, ctx.camera);
47
+
48
+ const entityObjects: THREE.Object3D[] = [];
49
+ for (const obj of store.objectMap.values()) entityObjects.push(obj);
50
+
51
+ const intersects = raycaster.intersectObjects(entityObjects, true);
52
+ for (const isect of intersects) {
53
+ // Skip editor helper geometry (wireframes, frustum lines, etc.) — these
54
+ // are visual-only; selection should go through the entity mesh or icon
55
+ // billboard.
56
+ let isHelper = false;
57
+ let walk: THREE.Object3D | null = isect.object;
58
+ while (walk) {
59
+ if (getUserData(walk, 'editorHelper')) {
60
+ isHelper = true;
61
+ break;
62
+ }
63
+ if (getUserData(walk, 'entityId')) break;
64
+ walk = walk.parent;
65
+ }
66
+ if (isHelper) continue;
67
+
68
+ // Walk up to find the entity root.
69
+ let hit: THREE.Object3D | null = isect.object;
70
+ while (hit && !getUserData(hit, 'entityId')) {
71
+ hit = hit.parent;
72
+ }
73
+ if (hit) {
74
+ const eid = getUserData(hit, 'entityId') as string;
75
+ // Skip locked entities in viewport selection.
76
+ if (!store.isEntityLocked(eid)) return eid;
77
+ }
78
+ }
79
+ return null;
80
+ }
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Manifest-era world overlay persistence (T6.1 slice 3, docs/MULTI-WORLD-DESIGN.md
3
+ * §1.G) — overlay storage for a `WorldMountSpec` id in the multi-world play path,
4
+ * keyed by the manifest's own `world.id` (unlike `ingest-overlay.ts`'s game id or
5
+ * `world2d-overlay.ts`'s `2d-`-prefixed silo id). Same overlay-file MECHANICS as
6
+ * those two (a JSON blob keyed by structural-path ids, reapplied on remount), but
7
+ * a DIFFERENT root: `.vgai/overlays/<world-id>.json` under the PROJECT ROOT, not
8
+ * under `public/`.
9
+ *
10
+ * Why a separate root from the (now-deleted) `world2d-overlay.ts`'s `2d-`-prefixed
11
+ * silo: those overlays went through `StorageBackend` (`getStorageBackend()`), and
12
+ * in server mode that is `HttpStorage`, which is hard-rooted at `<projectRoot>/public/`
13
+ * (its own doc comment says so) — so a `.vgai/overlays/<id>.json` written through
14
+ * it actually landed at `<projectRoot>/public/.vgai/overlays/<id>.json`, contradicting
15
+ * the overlay path functions' "project-root-relative" doc comments. That finding is
16
+ * recorded in `docs/BACKBONE-TASKS.md`'s T3.3 close-out. This module was the first
17
+ * "unify toward one namespace" half of §1.G: NEW manifest-world-id overlays are
18
+ * honestly project-root-relative from the start, using:
19
+ * - server mode: the dedicated `/__editor/vgai-file` route pair
20
+ * (`editor-server.ts`), which reads/writes `<projectRoot>/.vgai/...` directly
21
+ * via `node:fs` — the SAME root the editor-state/thumbnail machinery already
22
+ * uses, bypassing `HttpStorage`'s `public/` rooting entirely.
23
+ * - browser mode: `getStorageBackend()` directly — `OpfsStorage`/`FsaStorage`
24
+ * (`HandleStorage`) root at the TRUE project folder (OPFS root / the
25
+ * FSA-picked directory), with no `public/` insertion at all, so no duality
26
+ * exists there to work around.
27
+ * `ingest-overlay.ts`'s `loadOverlay`/`saveOverlay` later adopted this EXACT
28
+ * mode-branched pattern too (the T3.3 finding's remediation) — both overlay
29
+ * families now share the one project-root `.vgai/` namespace, via the SAME
30
+ * `/__editor/vgai-file` route pair in server mode.
31
+ */
32
+
33
+ import { getEditorMode } from '../editor-mode';
34
+ import { getStorageBackend } from '../storage';
35
+
36
+ const BASE = '/__editor';
37
+
38
+ /** Where a manifest world's overlay lives, project-root-relative (§1.G). */
39
+ export function worldOverlayPath(worldId: string): string {
40
+ return `.vgai/overlays/${worldId}.json`;
41
+ }
42
+
43
+ /** Load a manifest world's saved overlay, or `{}` if none exists / is unreadable. */
44
+ export async function loadWorldOverlay<T extends object = Record<string, unknown>>(
45
+ worldId: string,
46
+ ): Promise<T> {
47
+ const path = worldOverlayPath(worldId);
48
+ try {
49
+ if (getEditorMode() === 'browser') {
50
+ const backend = getStorageBackend();
51
+ if (!(await backend.exists(path))) return {} as T;
52
+ return JSON.parse(await backend.read(path)) as T;
53
+ }
54
+ const res = await fetch(`${BASE}/vgai-file?${new URLSearchParams({ path })}`);
55
+ if (!res.ok) return {} as T;
56
+ return JSON.parse(await res.text()) as T;
57
+ } catch {
58
+ return {} as T;
59
+ }
60
+ }
61
+
62
+ /** Persist a manifest world's overlay (§1.G — project-root `.vgai/overlays/`). */
63
+ export async function saveWorldOverlay(worldId: string, overlay: object): Promise<void> {
64
+ const path = worldOverlayPath(worldId);
65
+ const content = JSON.stringify(overlay, null, 2);
66
+ if (getEditorMode() === 'browser') {
67
+ await getStorageBackend().write(path, content);
68
+ return;
69
+ }
70
+ const res = await fetch(`${BASE}/vgai-file`, {
71
+ method: 'POST',
72
+ headers: { 'Content-Type': 'application/json' },
73
+ body: JSON.stringify({ path, content }),
74
+ });
75
+ if (!res.ok) throw new Error(`saveWorldOverlay '${worldId}': HTTP ${res.status}`);
76
+ }
@@ -0,0 +1,115 @@
1
+ /**
2
+ * World pan state (spec27 §8 "space-pan" row, D4 rebuild —
3
+ * docs/unified-world-editor/27-visual-react-editing.md) — a module-level
4
+ * subscribable singleton (mirrors `eyedropper-session.ts`'s "bare singleton +
5
+ * own listener set" shape) holding the CURRENT SHARED pan translate `(x, y)`
6
+ * applied, in LOCKSTEP, to both every design-time world-layer host
7
+ * (`design-time-layers.ts`'s `createLayerElement`-produced react/pixi layers)
8
+ * and `WorldSelectionOverlay`'s own outer wrapper.
9
+ *
10
+ * SOUNDNESS (why lockstep preserves the "zero-correction" host-relative rect
11
+ * invariant `WorldSelectionOverlay.tsx`'s own doc comment establishes):
12
+ * `RectProvider.rect(id)` is computed as `el.getBoundingClientRect()` MINUS
13
+ * the owning world's own root/host `getBoundingClientRect()`
14
+ * (`react-world-authoring-adapter.ts`'s `toHostRelative`/`hostRect` — `this
15
+ * .root` IS the exact layer div `createLayerElement` produces). A CSS
16
+ * `transform: translate()` applied directly to that host element shifts the
17
+ * host's OWN rendered rect AND every descendant's rendered rect by the
18
+ * IDENTICAL `(x, y)` delta — a rigid subtree translation — so the
19
+ * subtraction is invariant under pan: `rect(id)` returns the SAME
20
+ * host-relative numbers at any pan offset, unmodified, with no pan-awareness
21
+ * needed in the adapter, `inspect.ts`'s geometry math, or any of the ~14
22
+ * overlay chrome consumers. `PickProvider.pick` needs no changes either — it
23
+ * hit-tests real rendered rects against the real client cursor position,
24
+ * both of which already reflect the applied transform natively.
25
+ *
26
+ * Applying the exact SAME transform to `WorldSelectionOverlay`'s own outer
27
+ * wrapper (a SIBLING of every world-layer host inside the SAME
28
+ * `ViewportPanel` containerRef parent — see that file's own mount-site doc
29
+ * comment) shifts the overlay's local coordinate origin by the identical
30
+ * `(x, y)` — so drawing a chrome element at `rect(id)`'s (pan-invariant)
31
+ * host-relative `(x, y)` inside the panned overlay wrapper lands it at the
32
+ * SAME screen position as the panned live element it describes. This is the
33
+ * entire "lockstep" contract: every consumer on both sides of the pan reads
34
+ * ONE shared value (`getWorldPan()`) and applies it through the ONE shared
35
+ * pure helper (`panTransformValue`) — never two independently-computed
36
+ * transforms that could drift.
37
+ */
38
+
39
+ export interface WorldPan {
40
+ readonly x: number;
41
+ readonly y: number;
42
+ }
43
+
44
+ const ZERO_PAN: WorldPan = { x: 0, y: 0 };
45
+
46
+ let _pan: WorldPan = ZERO_PAN;
47
+ const listeners = new Set<() => void>();
48
+
49
+ function notify(): void {
50
+ for (const l of listeners) l();
51
+ }
52
+
53
+ /** The current shared pan translate, in CSS px. */
54
+ export function getWorldPan(): WorldPan {
55
+ return _pan;
56
+ }
57
+
58
+ /** Set the shared pan translate to an absolute `(x, y)`. */
59
+ export function setWorldPan(x: number, y: number): void {
60
+ if (_pan.x === x && _pan.y === y) return;
61
+ _pan = { x, y };
62
+ notify();
63
+ }
64
+
65
+ /** Set the shared pan translate by a RELATIVE `(dx, dy)` — a convenience
66
+ * wrapper over `setWorldPan` (not used by `WorldSelectionOverlay`'s own
67
+ * space-drag, which composes onto a captured drag-start snapshot instead —
68
+ * see its own doc comment — but kept here as the natural pure counterpart
69
+ * for any future incremental caller, e.g. a nudge-pan keybinding). */
70
+ export function panWorldBy(dx: number, dy: number): void {
71
+ setWorldPan(_pan.x + dx, _pan.y + dy);
72
+ }
73
+
74
+ /** Reset pan to `(0, 0)` — called on a world-layer remount (`design-time-
75
+ * layers.ts`'s `mountDesignTimeLayers`, invoked on initial edit-mode install
76
+ * AND every `'editor:edit-mode-rebuild'`), so switching/reloading the active
77
+ * world set never leaves a stale pan offset applied over a DIFFERENT layer
78
+ * stack. A no-op (no `notify()`) when already at rest, so a fresh session
79
+ * never fires a spurious subscriber tick. */
80
+ export function resetWorldPan(): void {
81
+ if (_pan.x === 0 && _pan.y === 0) return;
82
+ _pan = ZERO_PAN;
83
+ notify();
84
+ }
85
+
86
+ /** Subscribe to pan changes — both `design-time-layers.ts` (imperative DOM
87
+ * style writes) and `WorldSelectionOverlay` (`useSyncExternalStore`) bind
88
+ * this so every lockstep mount point re-applies the SAME new value the
89
+ * instant it changes. */
90
+ export function subscribeWorldPan(listener: () => void): () => void {
91
+ listeners.add(listener);
92
+ return () => listeners.delete(listener);
93
+ }
94
+
95
+ /**
96
+ * The ONE shared CSS `transform` value both lockstep mount points apply —
97
+ * pure, so a unit test can assert the world-layer host and the overlay
98
+ * wrapper are handed byte-identical strings for any given pan (the actual
99
+ * "lockstep" proof). `undefined` at rest `(0, 0)` so neither mount point ever
100
+ * carries a no-op `transform: translate(0px, 0px)` — keeps every pre-pan
101
+ * pixel-position snapshot (the full 27x suite, pinned at pan=0) byte-identical
102
+ * to its pre-this-feature output.
103
+ */
104
+ export function panTransformValue(pan: WorldPan): string | undefined {
105
+ if (pan.x === 0 && pan.y === 0) return undefined;
106
+ return `translate(${pan.x}px, ${pan.y}px)`;
107
+ }
108
+
109
+ /** Test-only reset (mirrors `eyedropper-session.ts`'s/`world-session-
110
+ * state.ts`'s identical helpers) — drops pan + every subscriber so unit
111
+ * tests don't leak state across cases. */
112
+ export function _resetWorldPanStateForTest(): void {
113
+ _pan = ZERO_PAN;
114
+ listeners.clear();
115
+ }
@@ -0,0 +1,102 @@
1
+ /**
2
+ * World session state (B1, docs/unified-world-editor/26-unified-editor-spec.md
3
+ * §3 B1 · D9) — a module-level subscribable singleton (same shape as
4
+ * `./mount-failure-report.ts`: a bare get/set slot, no subscribe of its own —
5
+ * every caller that mutates it follows up with `store.notifyIngestEdit()`,
6
+ * which every panel already re-renders off via `useSyncExternalStore(store.subscribe,
7
+ * …)`) holding THREE session-local, per-worldId toggles that are NEVER
8
+ * serialized/persisted (D9: "eye = session-local viewport visibility, never
9
+ * serialized" — generalized here to all three, none of which is an authored
10
+ * property):
11
+ *
12
+ * - `hidden` — the eye (A2/D9). LIFTED out of `GameHierarchy.tsx`'s former
13
+ * local `useState<Set<string>> hiddenWorldIds` (module-private React state
14
+ * the design-time layer stack could never see) so `design-time-layers.ts`
15
+ * can hide/show a world's actual DOM layer, not just dim its hierarchy row.
16
+ * - `interactive` — forwards real pointer events to the layer (for testing
17
+ * hover/press states at design time); off by default (`pointer-events:none`
18
+ * is the layer's resting state — see `design-time-layers.ts`).
19
+ * - `pickLock` — stored here for B4 to consume (layered viewport picking,
20
+ * D12): a pick-locked layer is skipped by the topmost-first pick walk.
21
+ * B1 only stores/exposes the toggle; nothing reads it yet.
22
+ *
23
+ * Keyed by the RAW manifest world id (`CompositeChild.worldId` /
24
+ * `ResolvedWorldEntry.id`) — the SAME id `design-time-layers.ts` gets from
25
+ * `composite.childAdapters()`, NOT the composite's synthetic `world:<id>`
26
+ * group-node id. `GameHierarchy.tsx` (whose rows ARE keyed by the group-node
27
+ * id) resolves the raw worldId via `compositeGroupBadge`'s `worldId` field
28
+ * before calling into this module — see that file's row component.
29
+ *
30
+ * A process-lifetime singleton (not project-scoped): switching projects
31
+ * within the same tab does not reset these toggles. That's a deliberate
32
+ * relaxation of the former per-mount-React-state behavior (which reset on
33
+ * every `GameHierarchy` remount) — "session-local" here means "this browser
34
+ * tab's session", matching D9's own framing; nothing depends on a
35
+ * project-switch reset.
36
+ */
37
+
38
+ export interface WorldSessionState {
39
+ readonly hidden: boolean;
40
+ readonly interactive: boolean;
41
+ readonly pickLock: boolean;
42
+ }
43
+
44
+ const DEFAULT_STATE: WorldSessionState = { hidden: false, interactive: false, pickLock: false };
45
+
46
+ const _states = new Map<string, WorldSessionState>();
47
+
48
+ function get(worldId: string): WorldSessionState {
49
+ return _states.get(worldId) ?? DEFAULT_STATE;
50
+ }
51
+
52
+ function patch(worldId: string, partial: Partial<WorldSessionState>): void {
53
+ _states.set(worldId, { ...get(worldId), ...partial });
54
+ }
55
+
56
+ /** The eye (A2/D9): true while `worldId`'s design-time layer is hidden. */
57
+ export function isWorldHidden(worldId: string): boolean {
58
+ return get(worldId).hidden;
59
+ }
60
+
61
+ export function setWorldHidden(worldId: string, hidden: boolean): void {
62
+ patch(worldId, { hidden });
63
+ }
64
+
65
+ export function toggleWorldHidden(worldId: string): void {
66
+ setWorldHidden(worldId, !isWorldHidden(worldId));
67
+ }
68
+
69
+ /** True while `worldId`'s layer forwards real pointer events (design-time
70
+ * hover/press testing) instead of its resting `pointer-events:none`. */
71
+ export function isWorldInteractive(worldId: string): boolean {
72
+ return get(worldId).interactive;
73
+ }
74
+
75
+ export function setWorldInteractive(worldId: string, interactive: boolean): void {
76
+ patch(worldId, { interactive });
77
+ }
78
+
79
+ export function toggleWorldInteractive(worldId: string): void {
80
+ setWorldInteractive(worldId, !isWorldInteractive(worldId));
81
+ }
82
+
83
+ /** B4 will read this to skip a layer in the topmost-first pick walk; B1 only
84
+ * stores/exposes the toggle. */
85
+ export function isWorldPickLocked(worldId: string): boolean {
86
+ return get(worldId).pickLock;
87
+ }
88
+
89
+ export function setWorldPickLock(worldId: string, pickLock: boolean): void {
90
+ patch(worldId, { pickLock });
91
+ }
92
+
93
+ export function toggleWorldPickLock(worldId: string): void {
94
+ setWorldPickLock(worldId, !isWorldPickLocked(worldId));
95
+ }
96
+
97
+ /** Test-only: drop every world's session state back to defaults so unit
98
+ * tests don't leak toggles across cases (this module is a process-lifetime
99
+ * singleton — see the header comment). */
100
+ export function _resetWorldSessionStateForTest(): void {
101
+ _states.clear();
102
+ }