@volter/game-editor 0.5.65

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 (653) hide show
  1. package/BUNDLED_NOTICES +11228 -0
  2. package/LICENSE +686 -0
  3. package/LICENSE-BLENDER +1409 -0
  4. package/LICENSE-MCP +21 -0
  5. package/NOTICE +21 -0
  6. package/catalog/entries/audio.json +14 -0
  7. package/catalog/entries/bake.json +36 -0
  8. package/catalog/entries/blender.json +17 -0
  9. package/catalog/entries/react-root.json +24 -0
  10. package/catalog/entries/reflections.json +29 -0
  11. package/catalog/entries/static-batch.json +25 -0
  12. package/catalog/project-source/LICENSE +37 -0
  13. package/catalog/project-source/src/contributions/bake.kind.ts +40 -0
  14. package/catalog/project-source/src/contributions/builder-document.tsx +65 -0
  15. package/catalog/project-source/src/contributions/builder-state.ts +27 -0
  16. package/catalog/project-source/src/contributions/builder-ui.tsx +61 -0
  17. package/catalog/project-source/src/contributions/module-source.ts +502 -0
  18. package/catalog/project-source/src/contributions/pages.finder.ts +61 -0
  19. package/catalog/project-source/src/lib/audio/sfx.ts +255 -0
  20. package/catalog/project-source/src/lib/bake/asset-seed.ts +128 -0
  21. package/catalog/project-source/src/lib/bake/bake-schema.ts +65 -0
  22. package/catalog/project-source/src/lib/bake/clip-layering.ts +203 -0
  23. package/catalog/project-source/src/lib/bake/gltf-bake.ts +657 -0
  24. package/catalog/project-source/src/lib/bake/mesh-slice.ts +157 -0
  25. package/catalog/project-source/src/lib/bake/node-image.ts +463 -0
  26. package/catalog/project-source/src/lib/bake/object3d-bake.ts +121 -0
  27. package/catalog/project-source/src/lib/bake/object3d-lifecycle.ts +15 -0
  28. package/catalog/project-source/src/lib/bake/object3d-source.ts +8 -0
  29. package/catalog/project-source/src/lib/bake/params.ts +75 -0
  30. package/catalog/project-source/src/lib/bake/rest-relative-animation.ts +217 -0
  31. package/catalog/project-source/src/lib/bake/use-model.ts +95 -0
  32. package/catalog/project-source/src/lib/react-root/index.ts +20 -0
  33. package/catalog/project-source/src/lib/react-root/react-root-adapter.tsx +57 -0
  34. package/catalog/project-source/src/lib/reflections/ReflectionProbe.tsx +201 -0
  35. package/catalog/project-source/src/lib/reflections/index.ts +19 -0
  36. package/catalog/project-source/src/lib/reflections/probe-controller.ts +75 -0
  37. package/catalog/project-source/src/lib/reflections/reflection-probe-registry.ts +402 -0
  38. package/catalog/project-source/src/lib/reflections/volume-reflection-material.ts +416 -0
  39. package/catalog/project-source/src/lib/static-batch/Frozen.tsx +91 -0
  40. package/catalog/project-source/src/lib/static-batch/freeze.ts +579 -0
  41. package/catalog/project-source/src/lib/static-batch/index.ts +44 -0
  42. package/catalog/project-source/src/lib/static-batch/mutation-watch.ts +149 -0
  43. package/catalog/project-source/src/lib/static-batch/shadow-cache.ts +171 -0
  44. package/catalog/project-source/src/tools/bake-module.tool.ts +139 -0
  45. package/catalog/project-source/src/tools/bake-preview.tool.ts +475 -0
  46. package/dist/.vite/manifest.json +8304 -0
  47. package/dist/assets/AssetBudgetPanel-J9--TZPU.js +23 -0
  48. package/dist/assets/AudioViewer-CR7333fe.js +1 -0
  49. package/dist/assets/BVHLoader-6bQIXhMX.js +1 -0
  50. package/dist/assets/BufferGeometryUtils-Nz37EVXf.js +1 -0
  51. package/dist/assets/CCDIKSolver-CD7vLpsK.js +1 -0
  52. package/dist/assets/CSS3DRenderer-CL7ABLVK.js +1 -0
  53. package/dist/assets/CanvasSceneViewport-Bpi6gVTC.js +1 -0
  54. package/dist/assets/ColladaLoader-aVOPIsCh.js +3 -0
  55. package/dist/assets/ColorInput-DQBNrW-K.js +1 -0
  56. package/dist/assets/ConvexGeometry-CAzXlPVG.js +1 -0
  57. package/dist/assets/ConvexHull-BINCESFp.js +1 -0
  58. package/dist/assets/CopyShader-BzTUYzf6.js +24 -0
  59. package/dist/assets/DecalGeometry-160KRdfg.js +1 -0
  60. package/dist/assets/EXRLoader-Cdans_oJ.js +1 -0
  61. package/dist/assets/EffectComposer-DQxfsXBZ.js +1 -0
  62. package/dist/assets/EntityModelDocument-Ccvw66N9.js +1 -0
  63. package/dist/assets/EnvironmentAssetDocument-Dg-Qq6O6.js +1 -0
  64. package/dist/assets/FBXLoader-B4MoUtAn.js +1 -0
  65. package/dist/assets/Fbo-Dz-Soul3.js +1 -0
  66. package/dist/assets/FontLoader-CvGoVI5a.js +2 -0
  67. package/dist/assets/GLTFExporter-HgrCle4L.js +1 -0
  68. package/dist/assets/GameplaySessionTimeline-B52W3FVZ.js +1 -0
  69. package/dist/assets/Gltf-UHVWKz65.js +2 -0
  70. package/dist/assets/HDRLoader-THU88oVD.js +5 -0
  71. package/dist/assets/ImageViewer-Tn7s_MnW.js +1 -0
  72. package/dist/assets/InspectorCanvasPreview-CEr_Kxna.js +1 -0
  73. package/dist/assets/InspectorObjectPreview-CVejvLRg.js +1 -0
  74. package/dist/assets/JsonAssetDocument-C7VGcLhu.js +3 -0
  75. package/dist/assets/LineSegments2-CsOpKSiM.js +370 -0
  76. package/dist/assets/MTLLoader-_Xzd4_0p.js +2 -0
  77. package/dist/assets/MarchingCubes-Bsp4wrzd.js +1 -0
  78. package/dist/assets/MeshBVH-BiDHDcu-.js +1 -0
  79. package/dist/assets/ModelAssetDocument-F5GACirk.js +1 -0
  80. package/dist/assets/NonThreeAuthoringBootstrap-C3woOMxX.js +1 -0
  81. package/dist/assets/OBJLoader-BhIC6Hwo.js +5 -0
  82. package/dist/assets/Object3DDocumentViewport-DB7T0NTl.js +2 -0
  83. package/dist/assets/Object3DPreview-DL8oi7Xs.js +2 -0
  84. package/dist/assets/OnlineAssetDetail-C6z9RvYK.js +2 -0
  85. package/dist/assets/OrbitControls-CM3bPray.js +1 -0
  86. package/dist/assets/OrbitControls-DLpayAaK.js +1 -0
  87. package/dist/assets/OrthographicCamera-bQozawrh.js +1 -0
  88. package/dist/assets/PLYLoader-DYQqs5Ik.js +2 -0
  89. package/dist/assets/PerspectiveCamera-CQ2lh01o.js +1 -0
  90. package/dist/assets/PlayBar-BR-Vg3Jb.js +2 -0
  91. package/dist/assets/RGBELoader-BgBcQv8j.js +1 -0
  92. package/dist/assets/RectAreaLightUniformsLib-CMMoWfll.js +1 -0
  93. package/dist/assets/RenderPass-DPrn-Uky.js +1 -0
  94. package/dist/assets/ResolutionPicker-C67vs1F3.js +1 -0
  95. package/dist/assets/RootSelectionOverlay-BZPlxmXU.js +1 -0
  96. package/dist/assets/RoundedBox-BDGBg6QZ.js +1 -0
  97. package/dist/assets/RoundedBoxGeometry-CyUuYPfW.js +1 -0
  98. package/dist/assets/STLLoader-Dyv3lsxY.js +1 -0
  99. package/dist/assets/SelectionBox-D_75KrNW.js +1 -0
  100. package/dist/assets/ShaderPass-QYRpPuFJ.js +1 -0
  101. package/dist/assets/ShadowEditor-DkImwu1Y.js +1 -0
  102. package/dist/assets/SimplifyModifier-C8ayvRzd.js +1 -0
  103. package/dist/assets/SkeletonUtils-Cps8GOC6.js +1 -0
  104. package/dist/assets/Sky-CQKCgYDs.js +154 -0
  105. package/dist/assets/SourceAssetViewer-2SWQoUut.js +12 -0
  106. package/dist/assets/StageHost-BN-IoTef.js +2 -0
  107. package/dist/assets/StoryPreviewMount-DjyxRCXu.js +1 -0
  108. package/dist/assets/TDSLoader-D_T8XJ81.js +1 -0
  109. package/dist/assets/TextGeometry-DOWAEUV0.js +1 -0
  110. package/dist/assets/ThreeBoardDocument-CVncZyIq.js +2 -0
  111. package/dist/assets/ThreeIsolationSceneContent-C8C8whSF.js +1 -0
  112. package/dist/assets/ToolObject3DPreview-BRoDWe4Q.js +1 -0
  113. package/dist/assets/TrackballControls-DfznuQTh.js +1 -0
  114. package/dist/assets/TransientHint-BB1fwrvK.js +1 -0
  115. package/dist/assets/UnrealBloomPass-CR-cS_K5.js +83 -0
  116. package/dist/assets/VideoViewer-C6kocgIU.js +1 -0
  117. package/dist/assets/_commonjsHelpers-D6-XlEtG.js +1 -0
  118. package/dist/assets/active-ingest-CT6jSGhr.js +3 -0
  119. package/dist/assets/adapter-surface-Y37Nzcyw.js +1 -0
  120. package/dist/assets/after-paint-CB4bz1-e.js +1 -0
  121. package/dist/assets/agx-base-srgb-BjWZJgrZ.lut +0 -0
  122. package/dist/assets/agx-look-medium-high-contrast-D5F_ob1L.lut +0 -0
  123. package/dist/assets/agx-look-punchy-dxsnycNs.lut +0 -0
  124. package/dist/assets/animation-clock-CnjZqfJp.js +1 -0
  125. package/dist/assets/asset-budget-asset.menu-Di3KiQCd.js +1 -0
  126. package/dist/assets/asset-budget.action-DCzzcuTh.js +1 -0
  127. package/dist/assets/asset-budget.document-BWU8wnVW.js +1 -0
  128. package/dist/assets/asset-budget.menu-BGZpT_31.js +1 -0
  129. package/dist/assets/asset-editor-persistence-BBaONOJt.js +1 -0
  130. package/dist/assets/asset-loaders-BOy5Ss8k.js +2 -0
  131. package/dist/assets/asset-parse-error-BHMwBRU3.js +3 -0
  132. package/dist/assets/assets-BuSoGjBX.js +1 -0
  133. package/dist/assets/audio-meter-CyiToeUW.js +1 -0
  134. package/dist/assets/audio-unlock.service-CfUgUQVy.js +1 -0
  135. package/dist/assets/audio.utility-C6K6jem8.js +1 -0
  136. package/dist/assets/authoring-CgcOFhGS.js +1 -0
  137. package/dist/assets/autoplay.service-BZBGNSvt.js +1 -0
  138. package/dist/assets/axe-LkjAB6Lv.js +30 -0
  139. package/dist/assets/babylon-authoring-adapter-CL02gWDn.js +1 -0
  140. package/dist/assets/binding-Bmxqznjk.js +1 -0
  141. package/dist/assets/binding-identity-DcTpbvyg.js +1 -0
  142. package/dist/assets/binding-resolver-Dsh-6Vor.js +2 -0
  143. package/dist/assets/blender-emscripten-engine-9ZIRYNhe.js +2 -0
  144. package/dist/assets/blender-node-editor.document-iIDkB9sI.js +1 -0
  145. package/dist/assets/blender-properties-tab-C5CyPydi.js +3 -0
  146. package/dist/assets/blender-runtime-host-BpBwGv7r.js +4 -0
  147. package/dist/assets/blender-runtime-skin-DyQ9B6CR.js +7140 -0
  148. package/dist/assets/blender-runtime.document-lIYhhPtv.js +8 -0
  149. package/dist/assets/blender-timeline.document-77fx96N7.js +1 -0
  150. package/dist/assets/blender-uv-editor.document-fsT7B4gV.js +1 -0
  151. package/dist/assets/blender-version.status-o6dBm3n6.js +1 -0
  152. package/dist/assets/blender-wali-engine-wTOcrOMC.js +2 -0
  153. package/dist/assets/blender.command-BtJeWk-A.js +1 -0
  154. package/dist/assets/blender.keymap-GAQgeklK.js +1 -0
  155. package/dist/assets/blender.status-ujwGU6dU.js +1 -0
  156. package/dist/assets/blender.style-Dcem5f_T.js +1 -0
  157. package/dist/assets/board-guides-DziKSTss.js +1 -0
  158. package/dist/assets/body-marks-h_xDxiDE.js +1 -0
  159. package/dist/assets/bridge.command-o5gDNEwa.js +3 -0
  160. package/dist/assets/browserAll-DeWblVez.js +1 -0
  161. package/dist/assets/build-profiles.document-kW8iw8Xj.js +2 -0
  162. package/dist/assets/build-progress.status-BNRLytg2.js +1 -0
  163. package/dist/assets/build-session-C_sg3CEn.js +9 -0
  164. package/dist/assets/build.action-lYjTLb7K.js +1 -0
  165. package/dist/assets/build.command-DIGgUPU_.js +1 -0
  166. package/dist/assets/build.header-CKajx5U3.js +1 -0
  167. package/dist/assets/build.menu-BdU0QXny.js +1 -0
  168. package/dist/assets/build.service-CbBAyeu3.js +1 -0
  169. package/dist/assets/bus-mixer-CGfWDP3C.js +1 -0
  170. package/dist/assets/camera-KEsKvOL7.js +1 -0
  171. package/dist/assets/camera-runtime.inspector-B7unX4g1.js +1 -0
  172. package/dist/assets/canvas-entry-runtime-SfBxaR9M.js +2 -0
  173. package/dist/assets/capability-coverage-Czas4C18.js +7 -0
  174. package/dist/assets/chrome-trace-YZHMz60-.js +1 -0
  175. package/dist/assets/client-DNXj_opT.js +25 -0
  176. package/dist/assets/clip-planes-CnAI6DZn.js +1 -0
  177. package/dist/assets/collaboration-presence-DLoZ7EA3.js +1 -0
  178. package/dist/assets/collider-Bw0mXlsW.js +1 -0
  179. package/dist/assets/collider-dimensions-9xoFADXN.js +1 -0
  180. package/dist/assets/collision-system-DpNUJRJ3.js +1 -0
  181. package/dist/assets/command-results-CUQD49AB.js +1 -0
  182. package/dist/assets/component-board-registry-DrIa2csL.js +1 -0
  183. package/dist/assets/component-board.service-DCwcUssB.js +2 -0
  184. package/dist/assets/component-board.service-DidCyM4O.js +2 -0
  185. package/dist/assets/component-verbs.command-7xzfjGMZ.js +1 -0
  186. package/dist/assets/component-verbs.service-Bv9jId3q.js +1 -0
  187. package/dist/assets/config-CEZk921y.js +6 -0
  188. package/dist/assets/configurations-DTBMdaTL.js +1 -0
  189. package/dist/assets/connection.status-BifnQdOs.js +1 -0
  190. package/dist/assets/console-bridge-CHcb-xk5.js +1 -0
  191. package/dist/assets/constraint-De8f1Uiq.js +1 -0
  192. package/dist/assets/constraints.inspector-B9U9Yj-u.js +1 -0
  193. package/dist/assets/countdown-timer-CUm74dom.js +1 -0
  194. package/dist/assets/coverage.service-VTX5Mcsx.js +3 -0
  195. package/dist/assets/crash-null-boundary-v3a0uEgw.js +1 -0
  196. package/dist/assets/create-runtime-CVCc1BDx.js +1 -0
  197. package/dist/assets/curve-7Q79VgU4.js +1 -0
  198. package/dist/assets/data-asset-4hjS642k.js +5 -0
  199. package/dist/assets/data-check-core-CQEjuFyt.js +1 -0
  200. package/dist/assets/data-ref-CQI28C0D.js +1 -0
  201. package/dist/assets/debug-bridge-CCohG-d-.js +1 -0
  202. package/dist/assets/debug-registry-Dgvitx8M.js +1 -0
  203. package/dist/assets/defaults-DKiBJCPN.js +1 -0
  204. package/dist/assets/deferred-commands-CEMmvL47.js +1 -0
  205. package/dist/assets/deferred-ingest-play-DCJi_Pgu.js +2 -0
  206. package/dist/assets/design-time-layers-wYgOTgni.js +1 -0
  207. package/dist/assets/design-time-mount-registry-DUpXCg1U.js +1 -0
  208. package/dist/assets/design-time-mount.service-BzY21e1F.js +2 -0
  209. package/dist/assets/design-time-react-mount-DM9WLrF2.js +1 -0
  210. package/dist/assets/dev-build-gDYrq68M.js +1 -0
  211. package/dist/assets/directional-shadow-fit-BVkOKAv2.js +1 -0
  212. package/dist/assets/document-preview-three-Kbg2GCLm.js +1 -0
  213. package/dist/assets/dom-authoring-adapter-CY8C7f4T.js +1 -0
  214. package/dist/assets/draco3d-BBUTcNkz.js +1 -0
  215. package/dist/assets/draco_decoder-DsQ12WqX.wasm +0 -0
  216. package/dist/assets/draco_encoder-2Tcju8Ns.wasm +0 -0
  217. package/dist/assets/edit-mode-audio.service-Bzetwd5B.js +1 -0
  218. package/dist/assets/edit-mode-authoring-B47TfLqu.js +1 -0
  219. package/dist/assets/edit-mode-networking.service-YCX6RRb_.js +1 -0
  220. package/dist/assets/editor-api-BoJIcyZG.js +1 -0
  221. package/dist/assets/editor-port-C_FeBdeV.js +1 -0
  222. package/dist/assets/editor-presentation-activity-C7SNSmTd.js +1 -0
  223. package/dist/assets/entry-adjudication-Cq8Yeb74.js +1 -0
  224. package/dist/assets/environment-capture-7himRh2L.js +1 -0
  225. package/dist/assets/esbuild-BHljloGq.wasm +0 -0
  226. package/dist/assets/events-156d8d12.esm-ErOhDXXB.js +36 -0
  227. package/dist/assets/extend-B-eOccUm.js +36 -0
  228. package/dist/assets/extends-CF3RwP-h.js +1 -0
  229. package/dist/assets/eyedropper-session-bjPXnfeX.js +1 -0
  230. package/dist/assets/fflate.module-DPuTF8aG.js +6 -0
  231. package/dist/assets/filmic-srgb-Ct35FIH6.lut +0 -0
  232. package/dist/assets/first-party-audio-system-DxnGJOER.js +1 -0
  233. package/dist/assets/first-party-navigation-system-CL5Bquub.js +1 -0
  234. package/dist/assets/fork-menu-BoVyw2Wu.js +1 -0
  235. package/dist/assets/frame-debugger-store-D1Mf_5up.js +1 -0
  236. package/dist/assets/frame-delta-D2nsw_Ht.js +1 -0
  237. package/dist/assets/frame-pacing-D5acoOzO.js +1 -0
  238. package/dist/assets/frame-selector-cache-cCeUbcjG.js +1 -0
  239. package/dist/assets/game-DHOZVb-7.js +1 -0
  240. package/dist/assets/game-contract-seams-a5YXejOu.js +1 -0
  241. package/dist/assets/game-css-scope-transform-Eng4wS8E.js +33 -0
  242. package/dist/assets/game-document.service-DbRfx2V0.js +1 -0
  243. package/dist/assets/game-eval.command-D-7Dxbj_.js +2 -0
  244. package/dist/assets/game-input-seams-CIQdetRw.js +1 -0
  245. package/dist/assets/game-loop-CZvXlY00.js +1 -0
  246. package/dist/assets/game-module-access-B2mFxv-i.js +1 -0
  247. package/dist/assets/game.layout-CBASrvQu.js +1 -0
  248. package/dist/assets/gameplay-export-BoKXm51x.js +1 -0
  249. package/dist/assets/gameplay-replay-e5umMlXv.js +1 -0
  250. package/dist/assets/gameplay-rng-trap-CTNhm-UW.js +3 -0
  251. package/dist/assets/gameplay.command-DxcVYX6F.js +1 -0
  252. package/dist/assets/generation-DhwCUHPf.css +1 -0
  253. package/dist/assets/generation-jobs-BQrXbGp_.js +1 -0
  254. package/dist/assets/generation.service-CDIgObuw.js +1 -0
  255. package/dist/assets/generations-DzUogZsM.js +1 -0
  256. package/dist/assets/generations.status-CgOUBCum.js +1 -0
  257. package/dist/assets/hierarchy-marks-BLPfSIym.js +1 -0
  258. package/dist/assets/host-pointer-DbGSCjE9.js +1 -0
  259. package/dist/assets/hosted-asset-materialization-CiIvWkGU.js +2 -0
  260. package/dist/assets/ibl-override-material-BlmCxFKq.js +6 -0
  261. package/dist/assets/index-96FBF1Oj.js +1 -0
  262. package/dist/assets/index-BAWkB0dv.js +1 -0
  263. package/dist/assets/index-BDnS2b6S.js +1 -0
  264. package/dist/assets/index-BHp07vN0.js +2 -0
  265. package/dist/assets/index-BMxv2MNV.js +1 -0
  266. package/dist/assets/index-BP6wv2A0.js +5 -0
  267. package/dist/assets/index-BcCBqgM_.js +952 -0
  268. package/dist/assets/index-Bge9JUr6.js +1 -0
  269. package/dist/assets/index-BjTCPEQ7.js +134 -0
  270. package/dist/assets/index-BncK9THk.js +1 -0
  271. package/dist/assets/index-CJbYy-CF.js +3 -0
  272. package/dist/assets/index-CVCb_ImQ.js +1 -0
  273. package/dist/assets/index-CZd9o7Lu.js +1 -0
  274. package/dist/assets/index-CanA16PU.js +2 -0
  275. package/dist/assets/index-CinJrH5C.js +9 -0
  276. package/dist/assets/index-CtzuWnCS.js +1 -0
  277. package/dist/assets/index-D2fNXpHa.css +1 -0
  278. package/dist/assets/index-DUpHH6JR.js +3120 -0
  279. package/dist/assets/index-DUqP1RMl.js +1 -0
  280. package/dist/assets/index-D_NuPfjr.js +9 -0
  281. package/dist/assets/index-Da9JhEvW.js +25 -0
  282. package/dist/assets/index-DgapqSPi.js +7 -0
  283. package/dist/assets/index-FUuS4qwW.js +562 -0
  284. package/dist/assets/index-GIL7oGEO.js +4894 -0
  285. package/dist/assets/index-IEjydI9d.js +1 -0
  286. package/dist/assets/index-OrYXPk3Z.js +487 -0
  287. package/dist/assets/index-V1R-e5Bd.js +1 -0
  288. package/dist/assets/index-bQE2NA0D.js +1 -0
  289. package/dist/assets/index-gHZae-lw.js +13 -0
  290. package/dist/assets/index-mjWQmGhM.js +1 -0
  291. package/dist/assets/index-nmcBqr7Y.js +1 -0
  292. package/dist/assets/inference-diagnostics-Dhmtfbq_.js +1 -0
  293. package/dist/assets/ingest-BbYMC2vQ.js +1 -0
  294. package/dist/assets/ingest-boot-viewport-D5rI_Kk_.js +1 -0
  295. package/dist/assets/ingest-siblings-Bop2kqVl.js +1 -0
  296. package/dist/assets/ingest-source-persistence-C_6Hiyra.js +1 -0
  297. package/dist/assets/ingest.service-BTDnQfM1.js +1 -0
  298. package/dist/assets/input-manager-DH_hGW6d.js +1 -0
  299. package/dist/assets/input-router-BNQvtIqw.js +1 -0
  300. package/dist/assets/inspect-BZfi3mmo.js +1 -0
  301. package/dist/assets/inspection-CObLhnrs.js +1 -0
  302. package/dist/assets/instance-fork-actions-D3sRzS3K.js +1 -0
  303. package/dist/assets/instances.command-D6UkZNO8.js +1 -0
  304. package/dist/assets/instruments-CKR02Y8I.js +1 -0
  305. package/dist/assets/json-history-resource-BbxllWfV.js +1 -0
  306. package/dist/assets/jsx-runtime-DPjLkJKQ.js +9 -0
  307. package/dist/assets/light-D-_wsKTq.js +1 -0
  308. package/dist/assets/light-camera-factory-CWbbe9gI.js +1 -0
  309. package/dist/assets/lil-gui.module.min-BF55BEwA.js +10 -0
  310. package/dist/assets/live-behaviors-Bxq49Maz.js +1 -0
  311. package/dist/assets/live-gesture-lock-DJbrjOqf.js +1 -0
  312. package/dist/assets/loader-CaF_I7Yt.js +1 -0
  313. package/dist/assets/logger-Dqis-7W1.js +1 -0
  314. package/dist/assets/loop-gate-report-N52EWFGD.js +1 -0
  315. package/dist/assets/matcap-texture-CVfalpWT.js +1 -0
  316. package/dist/assets/material-CpAdjDxn.js +1 -0
  317. package/dist/assets/material-factory-Bz6h__6g.js +1 -0
  318. package/dist/assets/mesh-B3WPtNKO.js +1 -0
  319. package/dist/assets/mesh-shadow-CZnXrw_l.js +1 -0
  320. package/dist/assets/mikktspace.module-DO88SLib.js +1 -0
  321. package/dist/assets/model-asset-sections-CFvvihfx.css +1 -0
  322. package/dist/assets/model-asset-sections.service-CHhFS3ZX.js +1 -0
  323. package/dist/assets/model.layout-BJUEQYUI.js +1 -0
  324. package/dist/assets/models.finder-G2jQgIRu.js +1 -0
  325. package/dist/assets/module-mode-DVBLT9d-.js +2 -0
  326. package/dist/assets/mount-canvas-ingest-root-DDuAWf_C.js +2 -0
  327. package/dist/assets/mount-dom-ingest-root-D_EiBgpn.js +2 -0
  328. package/dist/assets/mount-game-6t9cKNo4.js +1 -0
  329. package/dist/assets/mount-ingest-root-glv2SSWf.js +2 -0
  330. package/dist/assets/mount-manifest-CGVxhmAw.js +1 -0
  331. package/dist/assets/mount-readiness-Ds0HvvLH.js +4 -0
  332. package/dist/assets/mount-three-ingest-root-hrUt9VVU.js +1 -0
  333. package/dist/assets/mounted-authoring-Dmg5xmhP.js +1 -0
  334. package/dist/assets/mounted-story-viewport-source-DjP6RA9U.js +1 -0
  335. package/dist/assets/native-debug-module-CWicoSGD.js +1 -0
  336. package/dist/assets/native-entry-surface-BE8LJNdu.js +1 -0
  337. package/dist/assets/navigation-CIiCx-SM.js +1 -0
  338. package/dist/assets/navmesh-workflow-store-Cmnm57TB.js +1 -0
  339. package/dist/assets/navmesh.menu-CAKiH8PW.js +1 -0
  340. package/dist/assets/navmesh.service-jgDWlgj1.js +1 -0
  341. package/dist/assets/network.utility-CEu5nHf7.js +1 -0
  342. package/dist/assets/object-marks-DwvIEBOK.js +1 -0
  343. package/dist/assets/object3d-authoring-subject-CH5sI2oP.js +1 -0
  344. package/dist/assets/output-DK8waum9.js +195 -0
  345. package/dist/assets/particles-Y626p22p.js +1 -0
  346. package/dist/assets/particles-factory-DnLOHXT8.js +1 -0
  347. package/dist/assets/pasteboard-materialize-BqSS4QzV.js +20 -0
  348. package/dist/assets/pasteboard.action-DU3UHtJG.js +2 -0
  349. package/dist/assets/performance-profiler-D_Jey87L.js +1 -0
  350. package/dist/assets/physics-registry-B2Jkp8e6.js +1 -0
  351. package/dist/assets/physics-registry-CUB9cT9p.js +1 -0
  352. package/dist/assets/pixi-authoring-adapter-CjibysC3.js +1 -0
  353. package/dist/assets/pixi-live-write-target-DuWydlWb.js +1 -0
  354. package/dist/assets/pixi-primitive-DlWbUPN9.js +1 -0
  355. package/dist/assets/pixi-react-root-factory-DYsznYRQ.js +1 -0
  356. package/dist/assets/pixi-story-model-DNkfnWUV.js +1 -0
  357. package/dist/assets/pixi-transform-channels-VjdohT11.js +1 -0
  358. package/dist/assets/play-mode-BFU2PCkG.js +22 -0
  359. package/dist/assets/play.command-BpqqLqkq.js +2 -0
  360. package/dist/assets/playtest-BXIL1JEF.js +1 -0
  361. package/dist/assets/pose-guard-6Osb2cFu.js +1 -0
  362. package/dist/assets/presentation-BPP5pXeQ.js +1 -0
  363. package/dist/assets/product-DFhyARJj.js +1 -0
  364. package/dist/assets/profiler.action-CaXJDp3t.js +1 -0
  365. package/dist/assets/profiler.menu-BIMF6Bi4.js +1 -0
  366. package/dist/assets/profiler.utility-BExw9wBO.js +1 -0
  367. package/dist/assets/project-authoring-session-Bnt6icLr.js +2 -0
  368. package/dist/assets/project-provenance-BoP3nrle.js +1 -0
  369. package/dist/assets/prompt-labels-DSMdM2_B.js +1 -0
  370. package/dist/assets/properties-bone-constraints.inspector-ByT6p7S-.js +1 -0
  371. package/dist/assets/properties-bone.inspector-z4qJwKO5.js +1 -0
  372. package/dist/assets/properties-collection.inspector-D0_3ijWU.js +1 -0
  373. package/dist/assets/properties-constraints.inspector-CESzjuls.js +1 -0
  374. package/dist/assets/properties-data.inspector-hG8Wgyzb.js +1 -0
  375. package/dist/assets/properties-material.inspector-CzY0JCQ6.js +1 -0
  376. package/dist/assets/properties-modifiers.inspector-3dDhwf7g.js +1 -0
  377. package/dist/assets/properties-object.inspector-CiarfxkT.js +1 -0
  378. package/dist/assets/properties-output.inspector-DKJxmKSD.js +1 -0
  379. package/dist/assets/properties-particles.inspector-CCEdYWGm.js +1 -0
  380. package/dist/assets/properties-physics.inspector-B2c0KUyA.js +1 -0
  381. package/dist/assets/properties-render.inspector-Bcm0HLRW.js +1 -0
  382. package/dist/assets/properties-scene.inspector-PIM_eTb_.js +1 -0
  383. package/dist/assets/properties-texture.inspector-CgFlnyr8.js +1 -0
  384. package/dist/assets/properties-view-layer.inspector-DGjF_Aqo.js +1 -0
  385. package/dist/assets/properties-world.inspector-CrMvaRvB.js +1 -0
  386. package/dist/assets/r3f-design-session-D-4yyDO9.js +2 -0
  387. package/dist/assets/r3f-physics-binding-BBo8oma9.js +1 -0
  388. package/dist/assets/r3f-root-factory-z9llD1OU.js +1 -0
  389. package/dist/assets/r3f-source-authoring-adapter-w6Bc60K-.js +13 -0
  390. package/dist/assets/rapier-physics-adapter-CaZqWLu0.js +1 -0
  391. package/dist/assets/rapier-physics-bridge-CMoeVo3Y.js +1 -0
  392. package/dist/assets/react-18-By2b4xR9.js +1 -0
  393. package/dist/assets/react-inspector.service-B_neRnSK.js +1 -0
  394. package/dist/assets/react-root-CEz5NTck.js +1 -0
  395. package/dist/assets/react-story-board-BDDwiE2H.js +1 -0
  396. package/dist/assets/react-three-fiber.esm-CycrbDlA.js +1 -0
  397. package/dist/assets/react-three-rapier.esm-CEfKpvxT.js +1 -0
  398. package/dist/assets/react-world-authoring-adapter-DmrwM3py.js +1 -0
  399. package/dist/assets/realm-services-CobQsq_X.js +1 -0
  400. package/dist/assets/rebind-controller-Dtq19Vb3.js +1 -0
  401. package/dist/assets/recast-navigation.wasm-compat-Dsoa_MD-.js +1 -0
  402. package/dist/assets/reflection-probe-Don-M3Fj.js +1 -0
  403. package/dist/assets/reflection-probe-capture.inspector-CmFUoJCx.js +1 -0
  404. package/dist/assets/register-render-vitals-BiZk29b2.js +1 -0
  405. package/dist/assets/registry-02YZjMNp.js +1 -0
  406. package/dist/assets/relative-path-guard-GiM7Lsz8.js +1 -0
  407. package/dist/assets/render-audio-control-vMRlePWb.js +1 -0
  408. package/dist/assets/render-batch-system-0vq7p0VC.js +1 -0
  409. package/dist/assets/render-census-BrQX_CXv.js +1 -0
  410. package/dist/assets/render-control-Df3yTiyr.js +1 -0
  411. package/dist/assets/render-env-D2IV2x5k.js +1 -0
  412. package/dist/assets/render-features-CPQ_e568.js +1 -0
  413. package/dist/assets/render-seed-DF4JHy7P.js +1 -0
  414. package/dist/assets/render-settings-Bw4W9SYF.js +1 -0
  415. package/dist/assets/render-vitals-BZ5HtvMi.js +1 -0
  416. package/dist/assets/renderer-config-BqG4O8i9.js +1 -0
  417. package/dist/assets/resolve-three-SZE_WWUM.js +702 -0
  418. package/dist/assets/root-seam-contract-Z0VWX3Bk.js +1 -0
  419. package/dist/assets/rrweb-Cd2ifIRP.js +142 -0
  420. package/dist/assets/run-ticks-settled-C4ksViyA.js +1 -0
  421. package/dist/assets/runtime-inspection-l2iFQSsg.js +1 -0
  422. package/dist/assets/scene-capture-BQKzU0NT.js +1 -0
  423. package/dist/assets/scene-capture-CGYF-Viw.js +1 -0
  424. package/dist/assets/scene-document.service-qkDjUrlP.js +2 -0
  425. package/dist/assets/scene-framing-Cat0GtyJ.js +1 -0
  426. package/dist/assets/scene-index-B6BZOHMk.js +1 -0
  427. package/dist/assets/scene-query-C7_N-TpI.js +1 -0
  428. package/dist/assets/schema-kl9-2B_J.js +1 -0
  429. package/dist/assets/sculpt.layout-zJF55yCR.js +1 -0
  430. package/dist/assets/seeded-random-i3mtgBKZ.js +1 -0
  431. package/dist/assets/session-CZ5JPg-z.js +4877 -0
  432. package/dist/assets/setup-audio-S8GQF91f.js +1 -0
  433. package/dist/assets/setup-particles-GCXlnkj_.js +1 -0
  434. package/dist/assets/setup-physics-BeZ7-LKD.js +1 -0
  435. package/dist/assets/setup-renderer-DVXaSGin.js +1587 -0
  436. package/dist/assets/shading.layout-DULYZV6M.js +1 -0
  437. package/dist/assets/sim-clock-CLflx7kg.js +1 -0
  438. package/dist/assets/sky-precompute-worker-ChN7J87v.js +1 -0
  439. package/dist/assets/soft-particle-depth-DGvfQDi1.js +1 -0
  440. package/dist/assets/source-object3d-authoring-adapter-B-L6Ha6f.js +1 -0
  441. package/dist/assets/source-persistence-backend-C-aR-B_Y.js +1 -0
  442. package/dist/assets/spark-renderer-lifecycle-ynWESJcv.js +1 -0
  443. package/dist/assets/spark.module-4pXQoz5d.js +12120 -0
  444. package/dist/assets/stage-invalidation-DBg3C3Ta.js +1 -0
  445. package/dist/assets/stage-keyboard-n-5kKH-m.js +1 -0
  446. package/dist/assets/stage-overlay-set-B9zp2sLB.js +1 -0
  447. package/dist/assets/stage-presence-markers-DiGI6A45.js +1 -0
  448. package/dist/assets/standard-viewport-dressing-CzjAe_0A.js +7 -0
  449. package/dist/assets/state-bridge-DLP1jLRW.js +1 -0
  450. package/dist/assets/state-watch.action-BOvQR2qt.js +1 -0
  451. package/dist/assets/state-watch.menu-CNLvDeeY.js +1 -0
  452. package/dist/assets/state-watch.utility-Bg1tTTQU.js +1 -0
  453. package/dist/assets/static-batch-advisor-B13QEH7d.js +1 -0
  454. package/dist/assets/stats.module-BL02l9NC.js +1 -0
  455. package/dist/assets/story-arg-descriptors-Ek86ExX7.js +1 -0
  456. package/dist/assets/story-capture-_gC8dXV-.js +1 -0
  457. package/dist/assets/story-documents--TDLaPeL.js +3 -0
  458. package/dist/assets/story-documents.service-BiS_YbNQ.js +1 -0
  459. package/dist/assets/story-documents.service-CxOPYJ2j.js +1 -0
  460. package/dist/assets/story-media-presence-BHzk2IV5.js +1 -0
  461. package/dist/assets/story-mount-turn-DFRTj5hi.js +1 -0
  462. package/dist/assets/story-pixi-preview-BUrOJZXS.js +1 -0
  463. package/dist/assets/story-presentation-j2AVN-mK.js +1 -0
  464. package/dist/assets/story-three-preview-BHEDZzcl.js +2 -0
  465. package/dist/assets/structural-ids-Dc-7rEwi.js +1 -0
  466. package/dist/assets/structural-signature-0w-i_ats.js +1 -0
  467. package/dist/assets/surface-content-Dg9Kkazf.js +1 -0
  468. package/dist/assets/surface-state-DaxyruCj.js +3 -0
  469. package/dist/assets/system-adapters-rIC8FSGP.js +1 -0
  470. package/dist/assets/system-runner-DkOjxEBt.js +1 -0
  471. package/dist/assets/system-slot-E2mEdiih.js +1 -0
  472. package/dist/assets/team-playtest.service-DqOinFVA.js +1 -0
  473. package/dist/assets/texture.layout-DASpHVht.js +1 -0
  474. package/dist/assets/three-CDSueJyJ.js +1 -0
  475. package/dist/assets/three-authoring-adapter-CmSQ3Vui.js +1 -0
  476. package/dist/assets/three-authoring.service-iuHLwtf1.js +2 -0
  477. package/dist/assets/three-ingest-runtime-QzDYk6tU.js +1 -0
  478. package/dist/assets/three-projection-core-BmKMZ-nf.js +1 -0
  479. package/dist/assets/three-viewport-presentation-QBQpSdMh.js +1 -0
  480. package/dist/assets/three.module-D396a9Mn.js +3840 -0
  481. package/dist/assets/three.quarks.esm-B1C61jGo.js +1039 -0
  482. package/dist/assets/tools-B_NJsk05.js +1 -0
  483. package/dist/assets/transform-writer-BhBBTx33.js +1 -0
  484. package/dist/assets/transport.header-B-6HQlU2.js +1 -0
  485. package/dist/assets/trigger-volume-BNK2XzPL.js +1 -0
  486. package/dist/assets/tuples-CIQ4Bn1U.js +1 -0
  487. package/dist/assets/tween.module-DciWpAG6.js +1 -0
  488. package/dist/assets/ui-board-document-Bwtt--xp.js +2 -0
  489. package/dist/assets/unexported-game-trap-Dm1JYKHy.js +2 -0
  490. package/dist/assets/unmanaged-root-detector-B8CpbkSN.js +2 -0
  491. package/dist/assets/upstream-pin-BdgRH6ID.js +1 -0
  492. package/dist/assets/use-data-Dzq-MytE.js +1 -0
  493. package/dist/assets/use-live-actor-state-DErbWQWF.js +1 -0
  494. package/dist/assets/use-selection-DbR73-xd.js +1 -0
  495. package/dist/assets/user-data-BB2Of6Ht.js +1 -0
  496. package/dist/assets/utility-view-state-BHypxA33.js +1 -0
  497. package/dist/assets/uv-editing.layout-BEKHxmHw.js +1 -0
  498. package/dist/assets/vgai-shared-fontawesome-CU65D4Ij.js +1 -0
  499. package/dist/assets/vgai-shared-jsx-dev-runtime-DFDKL7fx.js +1 -0
  500. package/dist/assets/vgai-shared-jsx-runtime-DIqBpTut.js +1 -0
  501. package/dist/assets/vgai-shared-react-BT7rMc2H.js +1 -0
  502. package/dist/assets/vgai-shared-react-dom-DFajMqMT.js +1 -0
  503. package/dist/assets/vgai-shared-react-dom-client-S0ozfl6_.js +1 -0
  504. package/dist/assets/vgai-shared-three-Bc5PvpLM.js +1 -0
  505. package/dist/assets/viewport-pick-context-DkawXbEi.js +1 -0
  506. package/dist/assets/viewport-root-presentation-CWsE56K6.js +1 -0
  507. package/dist/assets/viewport-shading-BuA88e_A.js +1 -0
  508. package/dist/assets/viewport-shading-boundary-B_-_gABg.js +82 -0
  509. package/dist/assets/viewport-surface-status-B3om4Kcf.js +1 -0
  510. package/dist/assets/vision_bundle-DX0dWqEa.js +15 -0
  511. package/dist/assets/voxel-surface-DtcsSWRL.js +1 -0
  512. package/dist/assets/wav-encode-D31zWF6O.js +1 -0
  513. package/dist/assets/webgl-frame-capture-FlF9zQmW.js +1 -0
  514. package/dist/assets/webgl-gpu-timer-D3YX7RaD.js +1 -0
  515. package/dist/assets/webworkerAll-CM2o_dnz.js +1 -0
  516. package/dist/assets/worker-UrMcrc5_.js +2 -0
  517. package/dist/assets/world-documents-147tiFZe.js +1 -0
  518. package/dist/assets/world-root-stage-binding-vwTrtBz6.js +1 -0
  519. package/dist/assets/world-state-BWG-IcOd.js +1 -0
  520. package/dist/assets/writer-B-KovzkA.js +5 -0
  521. package/dist/assets/xstate-animation-binding-Brd0NST6.js +1 -0
  522. package/dist/assets/xstate-animation-meta-Q3u9zh_m.js +1 -0
  523. package/dist/assets/xstate-behavior.action-B8UluFBK.js +1 -0
  524. package/dist/assets/xstate-behavior.document-CKAsE45I.js +1 -0
  525. package/dist/assets/xstate-behavior.inspector-vJJyuifc.js +1 -0
  526. package/dist/assets/xstate-behavior.menu-BXbPICIh.js +1 -0
  527. package/dist/assets/xstate-inspection-BsZv8LS9.js +1 -0
  528. package/dist/vgai-shared-react.json +10 -0
  529. package/dist/vgai-shared-three.json +3 -0
  530. package/dist-node/cli.js +9320 -0
  531. package/dist-node/create.js +3239 -0
  532. package/package.json +91 -0
  533. package/presets.mjs +2 -0
  534. package/src/contributions.d.ts +4 -0
  535. package/src/index.ts +38 -0
  536. package/starter/cube.blend +0 -0
  537. package/starter/cube.py +81 -0
  538. package/template/.agents/references/project-manual.md +341 -0
  539. package/template/.agents/skills/editor/SKILL.md +53 -0
  540. package/template/.agents/skills/editor/agents/openai.yaml +4 -0
  541. package/template/.agents/skills/editor/references/editor-control.md +363 -0
  542. package/template/.agents/skills/vgai-3d-models/SKILL.md +64 -0
  543. package/template/.agents/skills/vgai-ingest-existing-game/SKILL.md +112 -0
  544. package/template/.agents/skills/vgai-threejs-authoring/SKILL.md +347 -0
  545. package/template/.agents/skills/vgai-threejs-authoring/agents/openai.yaml +4 -0
  546. package/template/.agents/skills/vgai-threejs-authoring/references/helper-catalog.md +65 -0
  547. package/template/.claude/skills/editor/SKILL.md +53 -0
  548. package/template/.claude/skills/editor/agents/openai.yaml +4 -0
  549. package/template/.claude/skills/editor/references/editor-control.md +363 -0
  550. package/template/.claude/skills/vgai-3d-models/SKILL.md +64 -0
  551. package/template/.claude/skills/vgai-ingest-existing-game/SKILL.md +112 -0
  552. package/template/.claude/skills/vgai-threejs-authoring/SKILL.md +347 -0
  553. package/template/.claude/skills/vgai-threejs-authoring/agents/openai.yaml +4 -0
  554. package/template/.claude/skills/vgai-threejs-authoring/references/helper-catalog.md +65 -0
  555. package/template/.github/copilot-instructions.md +6 -0
  556. package/template/.github/skills/editor/SKILL.md +53 -0
  557. package/template/.github/skills/editor/agents/openai.yaml +4 -0
  558. package/template/.github/skills/editor/references/editor-control.md +363 -0
  559. package/template/.github/skills/vgai-3d-models/SKILL.md +64 -0
  560. package/template/.github/skills/vgai-ingest-existing-game/SKILL.md +112 -0
  561. package/template/.github/skills/vgai-threejs-authoring/SKILL.md +347 -0
  562. package/template/.github/skills/vgai-threejs-authoring/agents/openai.yaml +4 -0
  563. package/template/.github/skills/vgai-threejs-authoring/references/helper-catalog.md +65 -0
  564. package/template/.mcp.json +12 -0
  565. package/template/.vgai/assets.json +1 -0
  566. package/template/.vgai/provenance.json +4 -0
  567. package/template/.volter/tracker/validation/.preset.base.mts +178 -0
  568. package/template/.volter/tracker/validation/preset.mts +186 -0
  569. package/template/.volter/tracker/visualizer/.extension.base.tsx +14 -0
  570. package/template/.volter/tracker/visualizer/extension.tsx +14 -0
  571. package/template/.volter/tracker-config.json +17 -0
  572. package/template/AGENTS.md +176 -0
  573. package/template/CLAUDE.md +1 -0
  574. package/template/DEVLOG.md +20 -0
  575. package/template/IDIOMS.md +118 -0
  576. package/template/LICENSE +30 -0
  577. package/template/README.md +83 -0
  578. package/template/ROADMAP.md +20 -0
  579. package/template/asset-manifest.json +3 -0
  580. package/template/check-idioms.ts +1533 -0
  581. package/template/index.html +18 -0
  582. package/template/manifest-entry-modules-plugin.ts +53 -0
  583. package/template/package.json +62 -0
  584. package/template/public/jsm/libs/basis/basis_transcoder.js +19 -0
  585. package/template/public/jsm/libs/basis/basis_transcoder.wasm +0 -0
  586. package/template/public/jsm/libs/draco/gltf/draco_decoder.js +33 -0
  587. package/template/public/jsm/libs/draco/gltf/draco_decoder.wasm +0 -0
  588. package/template/public/jsm/libs/draco/gltf/draco_encoder.js +33 -0
  589. package/template/public/jsm/libs/draco/gltf/draco_wasm_wrapper.js +116 -0
  590. package/template/public/shaders/daylight-sky.frag.glsl +15 -0
  591. package/template/public/shaders/daylight-sky.vert.glsl +7 -0
  592. package/template/scripts/patch-drei-stats-gl.mjs +35 -0
  593. package/template/server/colyseus-setup.ts +111 -0
  594. package/template/server/loopback.ts +76 -0
  595. package/template/server/main.ts +78 -0
  596. package/template/server/rooms/arena-room.ts +488 -0
  597. package/template/server/rooms/game-room.ts +274 -0
  598. package/template/server/rooms.ts +15 -0
  599. package/template/server/tsconfig.json +19 -0
  600. package/template/src/bot/QaTester.tsx +35 -0
  601. package/template/src/bot/behaviors.ts +203 -0
  602. package/template/src/bot/bot-station.ts +192 -0
  603. package/template/src/bot/tester-run.ts +238 -0
  604. package/template/src/bot/tester-station.ts +193 -0
  605. package/template/src/components/environment/DaylightSky.tsx +54 -0
  606. package/template/src/components/environment/Ground.tsx +129 -0
  607. package/template/src/components/environment/SceneAtmosphere.tsx +14 -0
  608. package/template/src/components/environment/SoftGroundShadow.tsx +62 -0
  609. package/template/src/components/environment/SunShadowFit.tsx +141 -0
  610. package/template/src/contributions/README.md +98 -0
  611. package/template/src/contributions/analytics.analytics.tsx +26 -0
  612. package/template/src/contributions/data.document.tsx +35 -0
  613. package/template/src/contributions/pages.finder.ts +61 -0
  614. package/template/src/contributions/tester.inspector.tsx +64 -0
  615. package/template/src/contributions/use-game-modules.ts +80 -0
  616. package/template/src/data/README.md +17 -0
  617. package/template/src/input.ts +97 -0
  618. package/template/src/lib/audio/capability.json +4 -0
  619. package/template/src/lib/audio/sfx.ts +255 -0
  620. package/template/src/lib/react-root/capability.json +4 -0
  621. package/template/src/lib/react-root/index.ts +20 -0
  622. package/template/src/lib/react-root/react-root-adapter.tsx +57 -0
  623. package/template/src/lib/reflections/ReflectionProbe.tsx +201 -0
  624. package/template/src/lib/reflections/capability.json +4 -0
  625. package/template/src/lib/reflections/index.ts +19 -0
  626. package/template/src/lib/reflections/probe-controller.ts +75 -0
  627. package/template/src/lib/reflections/reflection-probe-registry.ts +402 -0
  628. package/template/src/lib/reflections/volume-reflection-material.ts +416 -0
  629. package/template/src/lib/static-batch/Frozen.tsx +91 -0
  630. package/template/src/lib/static-batch/capability.json +4 -0
  631. package/template/src/lib/static-batch/freeze.ts +579 -0
  632. package/template/src/lib/static-batch/index.ts +44 -0
  633. package/template/src/lib/static-batch/mutation-watch.ts +149 -0
  634. package/template/src/lib/static-batch/shadow-cache.ts +171 -0
  635. package/template/src/main.ts +63 -0
  636. package/template/src/manifest-entry-modules.d.ts +3 -0
  637. package/template/src/prefabs/HeroBox.stories.tsx +23 -0
  638. package/template/src/prefabs/HeroBox.tsx +35 -0
  639. package/template/src/scenes/MainScene.tsx +77 -0
  640. package/template/src/world.tsx +87 -0
  641. package/template/tsconfig.json +35 -0
  642. package/template/tsconfig.node.json +32 -0
  643. package/template/tsconfig.tools.json +22 -0
  644. package/template/validate-asset-content.ts +27 -0
  645. package/template/validate-assets.ts +60 -0
  646. package/template/validate-manifest.ts +55 -0
  647. package/template/vgai.adapter.ts +76 -0
  648. package/template/vgai.project.json +24 -0
  649. package/template/vite.config.ts +247 -0
  650. package/template-dotfiles/gitignore +63 -0
  651. package/workbench/src/media/game-cover.css +83 -0
  652. package/workbench/src/product.contribution.ts +188 -0
  653. package/workbench/src/vgaiGameSkew.ts +276 -0
@@ -0,0 +1,3239 @@
1
+ // node/create.ts
2
+ import { existsSync as existsSync5, readFileSync as readFileSync5 } from "node:fs";
3
+ import { dirname as dirname4, join as join6, resolve as resolve4 } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+
6
+ // node/scaffold/additions.ts
7
+ var SCAFFOLD_ADDITIONS = ["three", "ui", "server", "blender", "studio"];
8
+ var ADDITION_REQUIRES = {
9
+ studio: ["three"]
10
+ };
11
+ function closeAdditions(additions) {
12
+ const wanted = /* @__PURE__ */ new Set();
13
+ const visit2 = (addition) => {
14
+ if (wanted.has(addition)) return;
15
+ wanted.add(addition);
16
+ for (const required of ADDITION_REQUIRES[addition] ?? []) visit2(required);
17
+ };
18
+ for (const addition of additions) visit2(addition);
19
+ return SCAFFOLD_ADDITIONS.filter((addition) => wanted.has(addition));
20
+ }
21
+ var THREE_OWNED_PATHS = [
22
+ "src/lib/audio",
23
+ "src/world.tsx",
24
+ "src/scenes",
25
+ "src/prefabs",
26
+ "src/components",
27
+ "src/bot"
28
+ ];
29
+ var KIT_DECLARED_PACKAGES = [
30
+ "@volter/editor-blender",
31
+ "@volter/blender-engine",
32
+ "@volter/editor-core",
33
+ "@volter/editor-sdk",
34
+ "@volter/game-runtime",
35
+ "@volter/editor-live",
36
+ "@volter/game-live",
37
+ "@volter/editor-project",
38
+ "@volter/threejs-runtime"
39
+ ];
40
+ var STUDIO_OWNED_PATHS = [
41
+ "src/contributions/data.document.tsx",
42
+ "src/contributions/tester.inspector.tsx",
43
+ "src/contributions/analytics.analytics.tsx"
44
+ ];
45
+ var REACT_ONLY_REMOVED_PATHS = [
46
+ "src/runtime",
47
+ "src/scripts",
48
+ "src/prefabs",
49
+ "src/stage",
50
+ "src/world.tsx",
51
+ "src/lib/humanoid",
52
+ "src/lib/mesh",
53
+ "src/lib/native-three",
54
+ "src/components",
55
+ "public"
56
+ ];
57
+ var REACT_ONLY_PAGE_SOURCE = `export interface ReactGamePageProps {
58
+ readonly lastInput: string;
59
+ readonly title?: string;
60
+ }
61
+
62
+ /** Pure React-only game page. Runtime input ownership stays in game.tsx. */
63
+ export function ReactGamePage({ lastInput, title = 'My Game' }: ReactGamePageProps) {
64
+ return (
65
+ <main
66
+ data-testid="game-ui-root"
67
+ style={{
68
+ position: 'absolute',
69
+ inset: 0,
70
+ display: 'grid',
71
+ placeItems: 'center',
72
+ pointerEvents: 'auto',
73
+ color: '#f7f4ea',
74
+ background: 'radial-gradient(circle at 50% 30%, #26314b 0%, #111827 68%)',
75
+ fontFamily: 'system-ui, sans-serif',
76
+ }}
77
+ >
78
+ <section style={{ textAlign: 'center', padding: 32 }}>
79
+ <p style={{ margin: 0, color: '#93c5fd', fontWeight: 700, letterSpacing: 2 }}>
80
+ REACT ADAPTER ROOT
81
+ </p>
82
+ <h1 style={{ margin: '8px 0', fontSize: 'clamp(42px, 8vw, 86px)' }}>{title}</h1>
83
+ <p aria-live="polite" style={{ margin: 0, color: '#cbd5e1' }}>
84
+ Last input: {lastInput}
85
+ </p>
86
+ </section>
87
+ </main>
88
+ );
89
+ }
90
+ `;
91
+ var REACT_ONLY_GAME_SOURCE = `import { useEffect, useState } from 'react';
92
+ import { useDebugProvider } from '@volter/game-runtime/react/world-state';
93
+ import { ReactGamePage } from './game-page';
94
+
95
+ /** React-only live connector: DOM input is gameplay input; no canvas adapter is required. */
96
+ export default function GameUI() {
97
+ const [lastInput, setLastInput] = useState('Ready');
98
+
99
+ useEffect(() => {
100
+ const onKeyDown = (event: KeyboardEvent) => {
101
+ if (event.key.startsWith('Arrow')) setLastInput(event.key);
102
+ };
103
+ window.addEventListener('keydown', onKeyDown);
104
+ return () => window.removeEventListener('keydown', onKeyDown);
105
+ }, []);
106
+
107
+ useDebugProvider('react-starter', () => ({ lastInput }));
108
+
109
+ return <ReactGamePage lastInput={lastInput} />;
110
+ }
111
+ `;
112
+ var REACT_ONLY_STORY_SOURCE = `import type { Meta, StoryObj } from '@storybook/react';
113
+ import GameUI from './game';
114
+ import { ReactGamePage } from './game-page';
115
+
116
+ const meta = {
117
+ title: 'Game/React Root',
118
+ // \`component\` is what associates this CSF document with a root: the editor
119
+ // derives it from the component the stories are about, and \`GameUI\` is the
120
+ // \`ui\` root's manifest entry. It owns live input state, so the design-time
121
+ // states below render its presentational body with authored props.
122
+ component: GameUI,
123
+ render: (args) => <ReactGamePage {...args} />,
124
+ parameters: { vgai: { defaultStory: 'Ready' } },
125
+ args: { lastInput: 'Ready', title: 'My Game' },
126
+ } satisfies Meta<typeof ReactGamePage>;
127
+
128
+ export default meta;
129
+ type Story = StoryObj<typeof meta>;
130
+ export const Ready: Story = {};
131
+ export const ArrowUp: Story = { args: { lastInput: 'ArrowUp' } };
132
+ export const ArrowLeft: Story = { args: { lastInput: 'ArrowLeft' } };
133
+ export const LongTitle: Story = {
134
+ args: { title: 'The Long Way Home', lastInput: 'ArrowRight' },
135
+ };
136
+ `;
137
+ var REACT_ONLY_MAIN_SOURCE = `import { manifestEntryModules } from 'virtual:vgai-manifest-entries';
138
+ import { registerReactAdapter } from './lib/react-root';
139
+ import { mountGameFromManifest, type ManifestHost } from '@volter/game-runtime/runtime/mount-game';
140
+ import manifest from '../vgai.project.json';
141
+
142
+ registerReactAdapter();
143
+
144
+ async function main() {
145
+ document.title = manifest.name;
146
+ const container = document.getElementById('game-canvas') as HTMLElement;
147
+ const host: ManifestHost = {
148
+ container,
149
+ async loadEntryModule(path) {
150
+ const entryModule = manifestEntryModules[path];
151
+ if (!entryModule) {
152
+ throw new Error(
153
+ \`main.ts: entry module "\${path}" was not generated from vgai.project.json.\`,
154
+ );
155
+ }
156
+ return entryModule;
157
+ },
158
+ };
159
+ const session = await mountGameFromManifest(manifest, host);
160
+ const resize = () => session.resize(window.innerWidth, window.innerHeight);
161
+ resize();
162
+ window.addEventListener('resize', resize);
163
+ }
164
+
165
+ main().catch(console.error);
166
+ `;
167
+ var REACT_ONLY_FILES = {
168
+ "src/main.ts": REACT_ONLY_MAIN_SOURCE,
169
+ "src/ui/game-page.tsx": REACT_ONLY_PAGE_SOURCE,
170
+ "src/ui/game.tsx": REACT_ONLY_GAME_SOURCE,
171
+ "src/ui/game.stories.tsx": REACT_ONLY_STORY_SOURCE
172
+ };
173
+ function withEditorDeclaration(source, declaration2) {
174
+ if (!source.includes("defineAdapter({"))
175
+ throw new Error("Starter vgai.adapter.ts must call defineAdapter({ ... }).");
176
+ const look = [
177
+ declaration2.style ? `, style: ${declaration2.style.name}` : "",
178
+ declaration2.keymap ? `, keymap: ${declaration2.keymap.name}` : ""
179
+ ].join("");
180
+ const editor = ` editor: { Layout: ${declaration2.layout.name}${look}, inspector: '${declaration2.inspector}' },`;
181
+ const byModule = /* @__PURE__ */ new Map();
182
+ for (const value of [declaration2.layout, declaration2.style, declaration2.keymap]) {
183
+ if (!value) continue;
184
+ const names = byModule.get(value.from) ?? /* @__PURE__ */ new Set();
185
+ names.add(value.name);
186
+ byModule.set(value.from, names);
187
+ }
188
+ const imports = [...byModule].map(([from, names]) => `import { ${[...names].sort().join(", ")} } from '${from}';
189
+ `).join("");
190
+ return `${imports}${source.replace("defineAdapter({", `defineAdapter({
191
+ ${editor}`)}`;
192
+ }
193
+ var MODELS_AGENTS_CONTRACT = `# AGENTS.md \u2014 VGAI Models Project
194
+
195
+ A standalone modeling project built with VGAI \u2014 Blender itself, compiled to
196
+ WebAssembly and running headless in the editor tab's worker, over this
197
+ project's own \`.blend\` files. Work here, not in the engine repo. The editor
198
+ is the authoring and verification surface; nothing here plays.
199
+
200
+ ## Route the request first
201
+
202
+ | Intent | First action |
203
+ | --- | --- |
204
+ | Model, revise or add a model | \`src/models/<name>.blend\` \u2014 read \`src/models/cube.py\`'s docstring first |
205
+ | Open the editor, look, or verify | \`.agents/skills/editor/SKILL.md\` |
206
+ | Blender-style modeling craft | \`.agents/skills/vgai-3d-models/SKILL.md\` |
207
+
208
+ \`.agents/\` is canonical; \`.claude/skills/\` and \`.github/skills/\` are
209
+ generated projections (never edit); \`CLAUDE.md\` and
210
+ \`.github/copilot-instructions.md\` only point here.
211
+
212
+ ## What a model is
213
+
214
+ A model is a \`.blend\` under \`src/models/\` \u2014 Blender's own document, opened,
215
+ edited and saved by the Blender running in the editor tab. Beside it sits the
216
+ bpy script that authored it (\`cube.blend\` / \`cube.py\`): the script is the
217
+ asset's SOURCE and stays in the project, the \`.blend\` is what the editor
218
+ opens. The document does not run the script \u2014 you do, through the session's
219
+ Blender:
220
+
221
+ \`\`\`bash
222
+ npm run --silent vgai -- blender-mcp # the MCP transport onto the tab's Blender
223
+ \`\`\`
224
+
225
+ Every call is ordinary bpy against the open document, and the session saves it
226
+ about a second after your last call. The adapter's \`modelsFromBlendFiles\`
227
+ finder lists every \`.blend\` as a document. Coordinates are metres and Z is up
228
+ (Blender's); the glTF export converts to the game's Y-up.
229
+
230
+ ## The editor
231
+
232
+ Workspaces: \`model\`, \`sculpt\`, \`texture\`, \`animate\`, \`design\`, \`look\`
233
+ (\`npm run --silent vgai -- eval 'editor.workspace("sculpt")'\`; a wrong id
234
+ refuses and names the list). The look and keymap are Blender's
235
+ (\`@volter/editor-blender\` contributes them). There is no Game workspace and
236
+ \`vgai play\` refuses: this project declares no roots.
237
+
238
+ ## Verification contract \u2014 after every change
239
+
240
+ 1. \`npm run typecheck\` \u2014 the gate.
241
+ 2. Open the model's document and read the change through a door:
242
+ \`npm run --silent vgai -- eval 'editor.currentView()'\` names the open
243
+ document; \`npm run --silent vgai -- screenshot editor\` shows it; and
244
+ \`get_scene_info\` over \`blender-mcp\` is what the engine itself says is in
245
+ the file.
246
+ 3. \`npm run --silent vgai -- console\` silent \u2014 an unresolved entry is
247
+ remaining work, never noise.
248
+
249
+ ## Commands
250
+
251
+ \\\`\\\`\\\`bash
252
+ npm run dev # open/reuse this project's editor
253
+ npm run --silent vgai -- status # require connected: true
254
+ npm run --silent vgai -- screenshot # visible evidence
255
+ npm run --silent vgai -- eval '<js>' # THE door onto the editor
256
+ npm run typecheck # THE gate
257
+ \\\`\\\`\\\`
258
+
259
+ Always \`npm run --silent vgai -- <verb>\`, never a bare \`vgai\` (a global one may
260
+ belong to another checkout).
261
+ `;
262
+ function withAgentsContract(source, additions) {
263
+ const plays = additions.has("three") || additions.has("ui");
264
+ return additions.has("blender") && !plays ? MODELS_AGENTS_CONTRACT : source;
265
+ }
266
+ var PAGES_FINDER_SELECTION = "{ finder: 'pagesFromUiModules', include: ['src/ui/**/*page.tsx'] }";
267
+ var MODELS_FINDER_SELECTION = "{ finder: 'modelsFromBlendFiles', include: ['src/models/**/*.blend'] }";
268
+ var UI_REGION_INCLUDE = "ui: {\n include: ['src/ui/**/*.tsx'],\n },";
269
+ function joinAdditionFinders(adapterSource, additions) {
270
+ const joined = [];
271
+ if (additions.has("ui")) joined.push(PAGES_FINDER_SELECTION);
272
+ if (additions.has("blender")) joined.push(MODELS_FINDER_SELECTION);
273
+ if (joined.length === 0) return adapterSource;
274
+ const withRegion = additions.has("ui") ? adapterSource.replace("regionIncludes: {", `regionIncludes: {
275
+ ${UI_REGION_INCLUDE}`) : adapterSource;
276
+ return withRegion.replace(
277
+ "{ finder: 'prefabsFromStories' },",
278
+ `{ finder: 'prefabsFromStories' },${joined.map((f) => `
279
+ ${f},`).join("")}`
280
+ );
281
+ }
282
+ function adapterSourceFor(additions) {
283
+ const finders = [];
284
+ if (additions.has("ui")) {
285
+ finders.push(PAGES_FINDER_SELECTION);
286
+ }
287
+ if (additions.has("blender")) {
288
+ finders.push(MODELS_FINDER_SELECTION);
289
+ }
290
+ const regions = additions.has("ui") ? `
291
+ regionIncludes: {
292
+ ${UI_REGION_INCLUDE}
293
+ },` : "";
294
+ const documents = finders.length > 0 ? `
295
+ documents: {
296
+ find: [${finders.map((f) => `
297
+ ${f},`).join("")}
298
+ ],
299
+ },
300
+ ` : "";
301
+ return `import { defineAdapter } from '@volter/editor-project/adapter/adapter-module';
302
+
303
+ export default defineAdapter({${regions}${documents}});
304
+ `;
305
+ }
306
+
307
+ // node/scaffold/product.ts
308
+ function fail(source, message) {
309
+ throw new Error(`${source}: ${message}`);
310
+ }
311
+ function assertImportedValue(value, source, field) {
312
+ const record = value;
313
+ if (typeof record?.name !== "string" || record.name.length === 0)
314
+ fail(source, `${field}.name must be the exported binding to import, e.g. "GameLayout"`);
315
+ if (typeof record.from !== "string" || record.from.length === 0)
316
+ fail(
317
+ source,
318
+ `${field}.from must be the module it is imported from, e.g. "@volter/editor-blender/layouts"`
319
+ );
320
+ return { name: record.name, from: record.from };
321
+ }
322
+ function assertScaffoldComposition(value, source, product) {
323
+ const composition = value;
324
+ const packages = composition?.editorPackages;
325
+ if (!Array.isArray(packages) || packages.some((name) => typeof name !== "string" || !name))
326
+ fail(source, "compose() must return editorPackages: a list of package names");
327
+ if (!packages.includes(product))
328
+ fail(
329
+ source,
330
+ `compose() returned editorPackages ${JSON.stringify(packages)}, which omits ${product}. A scaffolded project declares the product it opens in \u2014 that declaration is how \`vgai edit\` finds the editor to run (ARCHITECTURE-CORE \xA7The target shape, rule 4).`
331
+ );
332
+ const editor = composition?.editor;
333
+ if (typeof editor?.inspector !== "string" || editor.inspector.length === 0)
334
+ fail(
335
+ source,
336
+ "compose() must return editor.inspector \u2014 which Inspector presentation this project opens with"
337
+ );
338
+ return {
339
+ editorPackages: [...packages],
340
+ editor: {
341
+ layout: assertImportedValue(editor.layout, source, "compose().editor.layout"),
342
+ ...editor.style === void 0 ? {} : { style: assertImportedValue(editor.style, source, "compose().editor.style") },
343
+ ...editor.keymap === void 0 ? {} : { keymap: assertImportedValue(editor.keymap, source, "compose().editor.keymap") },
344
+ inspector: editor.inspector
345
+ }
346
+ };
347
+ }
348
+
349
+ // node/scaffold/scaffold.ts
350
+ import { spawnSync } from "node:child_process";
351
+ import {
352
+ copyFileSync,
353
+ cpSync,
354
+ existsSync as existsSync3,
355
+ lstatSync,
356
+ mkdirSync as mkdirSync3,
357
+ readdirSync as readdirSync3,
358
+ readFileSync as readFileSync3,
359
+ rmSync as rmSync2,
360
+ statSync as statSync2,
361
+ writeFileSync as writeFileSync3
362
+ } from "node:fs";
363
+ import { basename, dirname as dirname2, join as join4, relative as relative3, resolve as resolve2 } from "node:path";
364
+
365
+ // ../../node_modules/jsonc-parser/lib/esm/impl/scanner.js
366
+ function createScanner(text, ignoreTrivia = false) {
367
+ const len = text.length;
368
+ let pos = 0, value = "", tokenOffset = 0, token = 16, lineNumber = 0, lineStartOffset = 0, tokenLineStartOffset = 0, prevTokenLineStartOffset = 0, scanError = 0;
369
+ function scanHexDigits(count, exact) {
370
+ let digits = 0;
371
+ let value2 = 0;
372
+ while (digits < count || !exact) {
373
+ let ch = text.charCodeAt(pos);
374
+ if (ch >= 48 && ch <= 57) {
375
+ value2 = value2 * 16 + ch - 48;
376
+ } else if (ch >= 65 && ch <= 70) {
377
+ value2 = value2 * 16 + ch - 65 + 10;
378
+ } else if (ch >= 97 && ch <= 102) {
379
+ value2 = value2 * 16 + ch - 97 + 10;
380
+ } else {
381
+ break;
382
+ }
383
+ pos++;
384
+ digits++;
385
+ }
386
+ if (digits < count) {
387
+ value2 = -1;
388
+ }
389
+ return value2;
390
+ }
391
+ function setPosition(newPosition) {
392
+ pos = newPosition;
393
+ value = "";
394
+ tokenOffset = 0;
395
+ token = 16;
396
+ scanError = 0;
397
+ }
398
+ function scanNumber() {
399
+ let start = pos;
400
+ if (text.charCodeAt(pos) === 48) {
401
+ pos++;
402
+ } else {
403
+ pos++;
404
+ while (pos < text.length && isDigit(text.charCodeAt(pos))) {
405
+ pos++;
406
+ }
407
+ }
408
+ if (pos < text.length && text.charCodeAt(pos) === 46) {
409
+ pos++;
410
+ if (pos < text.length && isDigit(text.charCodeAt(pos))) {
411
+ pos++;
412
+ while (pos < text.length && isDigit(text.charCodeAt(pos))) {
413
+ pos++;
414
+ }
415
+ } else {
416
+ scanError = 3;
417
+ return text.substring(start, pos);
418
+ }
419
+ }
420
+ let end = pos;
421
+ if (pos < text.length && (text.charCodeAt(pos) === 69 || text.charCodeAt(pos) === 101)) {
422
+ pos++;
423
+ if (pos < text.length && text.charCodeAt(pos) === 43 || text.charCodeAt(pos) === 45) {
424
+ pos++;
425
+ }
426
+ if (pos < text.length && isDigit(text.charCodeAt(pos))) {
427
+ pos++;
428
+ while (pos < text.length && isDigit(text.charCodeAt(pos))) {
429
+ pos++;
430
+ }
431
+ end = pos;
432
+ } else {
433
+ scanError = 3;
434
+ }
435
+ }
436
+ return text.substring(start, end);
437
+ }
438
+ function scanString() {
439
+ let result = "", start = pos;
440
+ while (true) {
441
+ if (pos >= len) {
442
+ result += text.substring(start, pos);
443
+ scanError = 2;
444
+ break;
445
+ }
446
+ const ch = text.charCodeAt(pos);
447
+ if (ch === 34) {
448
+ result += text.substring(start, pos);
449
+ pos++;
450
+ break;
451
+ }
452
+ if (ch === 92) {
453
+ result += text.substring(start, pos);
454
+ pos++;
455
+ if (pos >= len) {
456
+ scanError = 2;
457
+ break;
458
+ }
459
+ const ch2 = text.charCodeAt(pos++);
460
+ switch (ch2) {
461
+ case 34:
462
+ result += '"';
463
+ break;
464
+ case 92:
465
+ result += "\\";
466
+ break;
467
+ case 47:
468
+ result += "/";
469
+ break;
470
+ case 98:
471
+ result += "\b";
472
+ break;
473
+ case 102:
474
+ result += "\f";
475
+ break;
476
+ case 110:
477
+ result += "\n";
478
+ break;
479
+ case 114:
480
+ result += "\r";
481
+ break;
482
+ case 116:
483
+ result += " ";
484
+ break;
485
+ case 117:
486
+ const ch3 = scanHexDigits(4, true);
487
+ if (ch3 >= 0) {
488
+ result += String.fromCharCode(ch3);
489
+ } else {
490
+ scanError = 4;
491
+ }
492
+ break;
493
+ default:
494
+ scanError = 5;
495
+ }
496
+ start = pos;
497
+ continue;
498
+ }
499
+ if (ch >= 0 && ch <= 31) {
500
+ if (isLineBreak(ch)) {
501
+ result += text.substring(start, pos);
502
+ scanError = 2;
503
+ break;
504
+ } else {
505
+ scanError = 6;
506
+ }
507
+ }
508
+ pos++;
509
+ }
510
+ return result;
511
+ }
512
+ function scanNext() {
513
+ value = "";
514
+ scanError = 0;
515
+ tokenOffset = pos;
516
+ lineStartOffset = lineNumber;
517
+ prevTokenLineStartOffset = tokenLineStartOffset;
518
+ if (pos >= len) {
519
+ tokenOffset = len;
520
+ return token = 17;
521
+ }
522
+ let code = text.charCodeAt(pos);
523
+ if (isWhiteSpace(code)) {
524
+ do {
525
+ pos++;
526
+ value += String.fromCharCode(code);
527
+ code = text.charCodeAt(pos);
528
+ } while (isWhiteSpace(code));
529
+ return token = 15;
530
+ }
531
+ if (isLineBreak(code)) {
532
+ pos++;
533
+ value += String.fromCharCode(code);
534
+ if (code === 13 && text.charCodeAt(pos) === 10) {
535
+ pos++;
536
+ value += "\n";
537
+ }
538
+ lineNumber++;
539
+ tokenLineStartOffset = pos;
540
+ return token = 14;
541
+ }
542
+ switch (code) {
543
+ // tokens: []{}:,
544
+ case 123:
545
+ pos++;
546
+ return token = 1;
547
+ case 125:
548
+ pos++;
549
+ return token = 2;
550
+ case 91:
551
+ pos++;
552
+ return token = 3;
553
+ case 93:
554
+ pos++;
555
+ return token = 4;
556
+ case 58:
557
+ pos++;
558
+ return token = 6;
559
+ case 44:
560
+ pos++;
561
+ return token = 5;
562
+ // strings
563
+ case 34:
564
+ pos++;
565
+ value = scanString();
566
+ return token = 10;
567
+ // comments
568
+ case 47:
569
+ const start = pos - 1;
570
+ if (text.charCodeAt(pos + 1) === 47) {
571
+ pos += 2;
572
+ while (pos < len) {
573
+ if (isLineBreak(text.charCodeAt(pos))) {
574
+ break;
575
+ }
576
+ pos++;
577
+ }
578
+ value = text.substring(start, pos);
579
+ return token = 12;
580
+ }
581
+ if (text.charCodeAt(pos + 1) === 42) {
582
+ pos += 2;
583
+ const safeLength = len - 1;
584
+ let commentClosed = false;
585
+ while (pos < safeLength) {
586
+ const ch = text.charCodeAt(pos);
587
+ if (ch === 42 && text.charCodeAt(pos + 1) === 47) {
588
+ pos += 2;
589
+ commentClosed = true;
590
+ break;
591
+ }
592
+ pos++;
593
+ if (isLineBreak(ch)) {
594
+ if (ch === 13 && text.charCodeAt(pos) === 10) {
595
+ pos++;
596
+ }
597
+ lineNumber++;
598
+ tokenLineStartOffset = pos;
599
+ }
600
+ }
601
+ if (!commentClosed) {
602
+ pos++;
603
+ scanError = 1;
604
+ }
605
+ value = text.substring(start, pos);
606
+ return token = 13;
607
+ }
608
+ value += String.fromCharCode(code);
609
+ pos++;
610
+ return token = 16;
611
+ // numbers
612
+ case 45:
613
+ value += String.fromCharCode(code);
614
+ pos++;
615
+ if (pos === len || !isDigit(text.charCodeAt(pos))) {
616
+ return token = 16;
617
+ }
618
+ // found a minus, followed by a number so
619
+ // we fall through to proceed with scanning
620
+ // numbers
621
+ case 48:
622
+ case 49:
623
+ case 50:
624
+ case 51:
625
+ case 52:
626
+ case 53:
627
+ case 54:
628
+ case 55:
629
+ case 56:
630
+ case 57:
631
+ value += scanNumber();
632
+ return token = 11;
633
+ // literals and unknown symbols
634
+ default:
635
+ while (pos < len && isUnknownContentCharacter(code)) {
636
+ pos++;
637
+ code = text.charCodeAt(pos);
638
+ }
639
+ if (tokenOffset !== pos) {
640
+ value = text.substring(tokenOffset, pos);
641
+ switch (value) {
642
+ case "true":
643
+ return token = 8;
644
+ case "false":
645
+ return token = 9;
646
+ case "null":
647
+ return token = 7;
648
+ }
649
+ return token = 16;
650
+ }
651
+ value += String.fromCharCode(code);
652
+ pos++;
653
+ return token = 16;
654
+ }
655
+ }
656
+ function isUnknownContentCharacter(code) {
657
+ if (isWhiteSpace(code) || isLineBreak(code)) {
658
+ return false;
659
+ }
660
+ switch (code) {
661
+ case 125:
662
+ case 93:
663
+ case 123:
664
+ case 91:
665
+ case 34:
666
+ case 58:
667
+ case 44:
668
+ case 47:
669
+ return false;
670
+ }
671
+ return true;
672
+ }
673
+ function scanNextNonTrivia() {
674
+ let result;
675
+ do {
676
+ result = scanNext();
677
+ } while (result >= 12 && result <= 15);
678
+ return result;
679
+ }
680
+ return {
681
+ setPosition,
682
+ getPosition: () => pos,
683
+ scan: ignoreTrivia ? scanNextNonTrivia : scanNext,
684
+ getToken: () => token,
685
+ getTokenValue: () => value,
686
+ getTokenOffset: () => tokenOffset,
687
+ getTokenLength: () => pos - tokenOffset,
688
+ getTokenStartLine: () => lineStartOffset,
689
+ getTokenStartCharacter: () => tokenOffset - prevTokenLineStartOffset,
690
+ getTokenError: () => scanError
691
+ };
692
+ }
693
+ function isWhiteSpace(ch) {
694
+ return ch === 32 || ch === 9;
695
+ }
696
+ function isLineBreak(ch) {
697
+ return ch === 10 || ch === 13;
698
+ }
699
+ function isDigit(ch) {
700
+ return ch >= 48 && ch <= 57;
701
+ }
702
+ var CharacterCodes;
703
+ (function(CharacterCodes2) {
704
+ CharacterCodes2[CharacterCodes2["lineFeed"] = 10] = "lineFeed";
705
+ CharacterCodes2[CharacterCodes2["carriageReturn"] = 13] = "carriageReturn";
706
+ CharacterCodes2[CharacterCodes2["space"] = 32] = "space";
707
+ CharacterCodes2[CharacterCodes2["_0"] = 48] = "_0";
708
+ CharacterCodes2[CharacterCodes2["_1"] = 49] = "_1";
709
+ CharacterCodes2[CharacterCodes2["_2"] = 50] = "_2";
710
+ CharacterCodes2[CharacterCodes2["_3"] = 51] = "_3";
711
+ CharacterCodes2[CharacterCodes2["_4"] = 52] = "_4";
712
+ CharacterCodes2[CharacterCodes2["_5"] = 53] = "_5";
713
+ CharacterCodes2[CharacterCodes2["_6"] = 54] = "_6";
714
+ CharacterCodes2[CharacterCodes2["_7"] = 55] = "_7";
715
+ CharacterCodes2[CharacterCodes2["_8"] = 56] = "_8";
716
+ CharacterCodes2[CharacterCodes2["_9"] = 57] = "_9";
717
+ CharacterCodes2[CharacterCodes2["a"] = 97] = "a";
718
+ CharacterCodes2[CharacterCodes2["b"] = 98] = "b";
719
+ CharacterCodes2[CharacterCodes2["c"] = 99] = "c";
720
+ CharacterCodes2[CharacterCodes2["d"] = 100] = "d";
721
+ CharacterCodes2[CharacterCodes2["e"] = 101] = "e";
722
+ CharacterCodes2[CharacterCodes2["f"] = 102] = "f";
723
+ CharacterCodes2[CharacterCodes2["g"] = 103] = "g";
724
+ CharacterCodes2[CharacterCodes2["h"] = 104] = "h";
725
+ CharacterCodes2[CharacterCodes2["i"] = 105] = "i";
726
+ CharacterCodes2[CharacterCodes2["j"] = 106] = "j";
727
+ CharacterCodes2[CharacterCodes2["k"] = 107] = "k";
728
+ CharacterCodes2[CharacterCodes2["l"] = 108] = "l";
729
+ CharacterCodes2[CharacterCodes2["m"] = 109] = "m";
730
+ CharacterCodes2[CharacterCodes2["n"] = 110] = "n";
731
+ CharacterCodes2[CharacterCodes2["o"] = 111] = "o";
732
+ CharacterCodes2[CharacterCodes2["p"] = 112] = "p";
733
+ CharacterCodes2[CharacterCodes2["q"] = 113] = "q";
734
+ CharacterCodes2[CharacterCodes2["r"] = 114] = "r";
735
+ CharacterCodes2[CharacterCodes2["s"] = 115] = "s";
736
+ CharacterCodes2[CharacterCodes2["t"] = 116] = "t";
737
+ CharacterCodes2[CharacterCodes2["u"] = 117] = "u";
738
+ CharacterCodes2[CharacterCodes2["v"] = 118] = "v";
739
+ CharacterCodes2[CharacterCodes2["w"] = 119] = "w";
740
+ CharacterCodes2[CharacterCodes2["x"] = 120] = "x";
741
+ CharacterCodes2[CharacterCodes2["y"] = 121] = "y";
742
+ CharacterCodes2[CharacterCodes2["z"] = 122] = "z";
743
+ CharacterCodes2[CharacterCodes2["A"] = 65] = "A";
744
+ CharacterCodes2[CharacterCodes2["B"] = 66] = "B";
745
+ CharacterCodes2[CharacterCodes2["C"] = 67] = "C";
746
+ CharacterCodes2[CharacterCodes2["D"] = 68] = "D";
747
+ CharacterCodes2[CharacterCodes2["E"] = 69] = "E";
748
+ CharacterCodes2[CharacterCodes2["F"] = 70] = "F";
749
+ CharacterCodes2[CharacterCodes2["G"] = 71] = "G";
750
+ CharacterCodes2[CharacterCodes2["H"] = 72] = "H";
751
+ CharacterCodes2[CharacterCodes2["I"] = 73] = "I";
752
+ CharacterCodes2[CharacterCodes2["J"] = 74] = "J";
753
+ CharacterCodes2[CharacterCodes2["K"] = 75] = "K";
754
+ CharacterCodes2[CharacterCodes2["L"] = 76] = "L";
755
+ CharacterCodes2[CharacterCodes2["M"] = 77] = "M";
756
+ CharacterCodes2[CharacterCodes2["N"] = 78] = "N";
757
+ CharacterCodes2[CharacterCodes2["O"] = 79] = "O";
758
+ CharacterCodes2[CharacterCodes2["P"] = 80] = "P";
759
+ CharacterCodes2[CharacterCodes2["Q"] = 81] = "Q";
760
+ CharacterCodes2[CharacterCodes2["R"] = 82] = "R";
761
+ CharacterCodes2[CharacterCodes2["S"] = 83] = "S";
762
+ CharacterCodes2[CharacterCodes2["T"] = 84] = "T";
763
+ CharacterCodes2[CharacterCodes2["U"] = 85] = "U";
764
+ CharacterCodes2[CharacterCodes2["V"] = 86] = "V";
765
+ CharacterCodes2[CharacterCodes2["W"] = 87] = "W";
766
+ CharacterCodes2[CharacterCodes2["X"] = 88] = "X";
767
+ CharacterCodes2[CharacterCodes2["Y"] = 89] = "Y";
768
+ CharacterCodes2[CharacterCodes2["Z"] = 90] = "Z";
769
+ CharacterCodes2[CharacterCodes2["asterisk"] = 42] = "asterisk";
770
+ CharacterCodes2[CharacterCodes2["backslash"] = 92] = "backslash";
771
+ CharacterCodes2[CharacterCodes2["closeBrace"] = 125] = "closeBrace";
772
+ CharacterCodes2[CharacterCodes2["closeBracket"] = 93] = "closeBracket";
773
+ CharacterCodes2[CharacterCodes2["colon"] = 58] = "colon";
774
+ CharacterCodes2[CharacterCodes2["comma"] = 44] = "comma";
775
+ CharacterCodes2[CharacterCodes2["dot"] = 46] = "dot";
776
+ CharacterCodes2[CharacterCodes2["doubleQuote"] = 34] = "doubleQuote";
777
+ CharacterCodes2[CharacterCodes2["minus"] = 45] = "minus";
778
+ CharacterCodes2[CharacterCodes2["openBrace"] = 123] = "openBrace";
779
+ CharacterCodes2[CharacterCodes2["openBracket"] = 91] = "openBracket";
780
+ CharacterCodes2[CharacterCodes2["plus"] = 43] = "plus";
781
+ CharacterCodes2[CharacterCodes2["slash"] = 47] = "slash";
782
+ CharacterCodes2[CharacterCodes2["formFeed"] = 12] = "formFeed";
783
+ CharacterCodes2[CharacterCodes2["tab"] = 9] = "tab";
784
+ })(CharacterCodes || (CharacterCodes = {}));
785
+
786
+ // ../../node_modules/jsonc-parser/lib/esm/impl/string-intern.js
787
+ var cachedSpaces = new Array(20).fill(0).map((_, index) => {
788
+ return " ".repeat(index);
789
+ });
790
+ var maxCachedValues = 200;
791
+ var cachedBreakLinesWithSpaces = {
792
+ " ": {
793
+ "\n": new Array(maxCachedValues).fill(0).map((_, index) => {
794
+ return "\n" + " ".repeat(index);
795
+ }),
796
+ "\r": new Array(maxCachedValues).fill(0).map((_, index) => {
797
+ return "\r" + " ".repeat(index);
798
+ }),
799
+ "\r\n": new Array(maxCachedValues).fill(0).map((_, index) => {
800
+ return "\r\n" + " ".repeat(index);
801
+ })
802
+ },
803
+ " ": {
804
+ "\n": new Array(maxCachedValues).fill(0).map((_, index) => {
805
+ return "\n" + " ".repeat(index);
806
+ }),
807
+ "\r": new Array(maxCachedValues).fill(0).map((_, index) => {
808
+ return "\r" + " ".repeat(index);
809
+ }),
810
+ "\r\n": new Array(maxCachedValues).fill(0).map((_, index) => {
811
+ return "\r\n" + " ".repeat(index);
812
+ })
813
+ }
814
+ };
815
+
816
+ // ../../node_modules/jsonc-parser/lib/esm/impl/parser.js
817
+ var ParseOptions;
818
+ (function(ParseOptions2) {
819
+ ParseOptions2.DEFAULT = {
820
+ allowTrailingComma: false
821
+ };
822
+ })(ParseOptions || (ParseOptions = {}));
823
+ function parse(text, errors = [], options = ParseOptions.DEFAULT) {
824
+ let currentProperty = null;
825
+ let currentParent = [];
826
+ const previousParents = [];
827
+ function onValue(value) {
828
+ if (Array.isArray(currentParent)) {
829
+ currentParent.push(value);
830
+ } else if (currentProperty !== null) {
831
+ currentParent[currentProperty] = value;
832
+ }
833
+ }
834
+ const visitor = {
835
+ onObjectBegin: () => {
836
+ const object = {};
837
+ onValue(object);
838
+ previousParents.push(currentParent);
839
+ currentParent = object;
840
+ currentProperty = null;
841
+ },
842
+ onObjectProperty: (name) => {
843
+ currentProperty = name;
844
+ },
845
+ onObjectEnd: () => {
846
+ currentParent = previousParents.pop();
847
+ },
848
+ onArrayBegin: () => {
849
+ const array = [];
850
+ onValue(array);
851
+ previousParents.push(currentParent);
852
+ currentParent = array;
853
+ currentProperty = null;
854
+ },
855
+ onArrayEnd: () => {
856
+ currentParent = previousParents.pop();
857
+ },
858
+ onLiteralValue: onValue,
859
+ onError: (error, offset, length) => {
860
+ errors.push({ error, offset, length });
861
+ }
862
+ };
863
+ visit(text, visitor, options);
864
+ return currentParent[0];
865
+ }
866
+ function visit(text, visitor, options = ParseOptions.DEFAULT) {
867
+ const _scanner = createScanner(text, false);
868
+ const _jsonPath = [];
869
+ let suppressedCallbacks = 0;
870
+ function toNoArgVisit(visitFunction) {
871
+ return visitFunction ? () => suppressedCallbacks === 0 && visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter()) : () => true;
872
+ }
873
+ function toOneArgVisit(visitFunction) {
874
+ return visitFunction ? (arg) => suppressedCallbacks === 0 && visitFunction(arg, _scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter()) : () => true;
875
+ }
876
+ function toOneArgVisitWithPath(visitFunction) {
877
+ return visitFunction ? (arg) => suppressedCallbacks === 0 && visitFunction(arg, _scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter(), () => _jsonPath.slice()) : () => true;
878
+ }
879
+ function toBeginVisit(visitFunction) {
880
+ return visitFunction ? () => {
881
+ if (suppressedCallbacks > 0) {
882
+ suppressedCallbacks++;
883
+ } else {
884
+ let cbReturn = visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter(), () => _jsonPath.slice());
885
+ if (cbReturn === false) {
886
+ suppressedCallbacks = 1;
887
+ }
888
+ }
889
+ } : () => true;
890
+ }
891
+ function toEndVisit(visitFunction) {
892
+ return visitFunction ? () => {
893
+ if (suppressedCallbacks > 0) {
894
+ suppressedCallbacks--;
895
+ }
896
+ if (suppressedCallbacks === 0) {
897
+ visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter());
898
+ }
899
+ } : () => true;
900
+ }
901
+ const onObjectBegin = toBeginVisit(visitor.onObjectBegin), onObjectProperty = toOneArgVisitWithPath(visitor.onObjectProperty), onObjectEnd = toEndVisit(visitor.onObjectEnd), onArrayBegin = toBeginVisit(visitor.onArrayBegin), onArrayEnd = toEndVisit(visitor.onArrayEnd), onLiteralValue = toOneArgVisitWithPath(visitor.onLiteralValue), onSeparator = toOneArgVisit(visitor.onSeparator), onComment = toNoArgVisit(visitor.onComment), onError = toOneArgVisit(visitor.onError);
902
+ const disallowComments = options && options.disallowComments;
903
+ const allowTrailingComma = options && options.allowTrailingComma;
904
+ function scanNext() {
905
+ while (true) {
906
+ const token = _scanner.scan();
907
+ switch (_scanner.getTokenError()) {
908
+ case 4:
909
+ handleError(
910
+ 14
911
+ /* ParseErrorCode.InvalidUnicode */
912
+ );
913
+ break;
914
+ case 5:
915
+ handleError(
916
+ 15
917
+ /* ParseErrorCode.InvalidEscapeCharacter */
918
+ );
919
+ break;
920
+ case 3:
921
+ handleError(
922
+ 13
923
+ /* ParseErrorCode.UnexpectedEndOfNumber */
924
+ );
925
+ break;
926
+ case 1:
927
+ if (!disallowComments) {
928
+ handleError(
929
+ 11
930
+ /* ParseErrorCode.UnexpectedEndOfComment */
931
+ );
932
+ }
933
+ break;
934
+ case 2:
935
+ handleError(
936
+ 12
937
+ /* ParseErrorCode.UnexpectedEndOfString */
938
+ );
939
+ break;
940
+ case 6:
941
+ handleError(
942
+ 16
943
+ /* ParseErrorCode.InvalidCharacter */
944
+ );
945
+ break;
946
+ }
947
+ switch (token) {
948
+ case 12:
949
+ case 13:
950
+ if (disallowComments) {
951
+ handleError(
952
+ 10
953
+ /* ParseErrorCode.InvalidCommentToken */
954
+ );
955
+ } else {
956
+ onComment();
957
+ }
958
+ break;
959
+ case 16:
960
+ handleError(
961
+ 1
962
+ /* ParseErrorCode.InvalidSymbol */
963
+ );
964
+ break;
965
+ case 15:
966
+ case 14:
967
+ break;
968
+ default:
969
+ return token;
970
+ }
971
+ }
972
+ }
973
+ function handleError(error, skipUntilAfter = [], skipUntil = []) {
974
+ onError(error);
975
+ if (skipUntilAfter.length + skipUntil.length > 0) {
976
+ let token = _scanner.getToken();
977
+ while (token !== 17) {
978
+ if (skipUntilAfter.indexOf(token) !== -1) {
979
+ scanNext();
980
+ break;
981
+ } else if (skipUntil.indexOf(token) !== -1) {
982
+ break;
983
+ }
984
+ token = scanNext();
985
+ }
986
+ }
987
+ }
988
+ function parseString(isValue) {
989
+ const value = _scanner.getTokenValue();
990
+ if (isValue) {
991
+ onLiteralValue(value);
992
+ } else {
993
+ onObjectProperty(value);
994
+ _jsonPath.push(value);
995
+ }
996
+ scanNext();
997
+ return true;
998
+ }
999
+ function parseLiteral() {
1000
+ switch (_scanner.getToken()) {
1001
+ case 11:
1002
+ const tokenValue = _scanner.getTokenValue();
1003
+ let value = Number(tokenValue);
1004
+ if (isNaN(value)) {
1005
+ handleError(
1006
+ 2
1007
+ /* ParseErrorCode.InvalidNumberFormat */
1008
+ );
1009
+ value = 0;
1010
+ }
1011
+ onLiteralValue(value);
1012
+ break;
1013
+ case 7:
1014
+ onLiteralValue(null);
1015
+ break;
1016
+ case 8:
1017
+ onLiteralValue(true);
1018
+ break;
1019
+ case 9:
1020
+ onLiteralValue(false);
1021
+ break;
1022
+ default:
1023
+ return false;
1024
+ }
1025
+ scanNext();
1026
+ return true;
1027
+ }
1028
+ function parseProperty() {
1029
+ if (_scanner.getToken() !== 10) {
1030
+ handleError(3, [], [
1031
+ 2,
1032
+ 5
1033
+ /* SyntaxKind.CommaToken */
1034
+ ]);
1035
+ return false;
1036
+ }
1037
+ parseString(false);
1038
+ if (_scanner.getToken() === 6) {
1039
+ onSeparator(":");
1040
+ scanNext();
1041
+ if (!parseValue()) {
1042
+ handleError(4, [], [
1043
+ 2,
1044
+ 5
1045
+ /* SyntaxKind.CommaToken */
1046
+ ]);
1047
+ }
1048
+ } else {
1049
+ handleError(5, [], [
1050
+ 2,
1051
+ 5
1052
+ /* SyntaxKind.CommaToken */
1053
+ ]);
1054
+ }
1055
+ _jsonPath.pop();
1056
+ return true;
1057
+ }
1058
+ function parseObject() {
1059
+ onObjectBegin();
1060
+ scanNext();
1061
+ let needsComma = false;
1062
+ while (_scanner.getToken() !== 2 && _scanner.getToken() !== 17) {
1063
+ if (_scanner.getToken() === 5) {
1064
+ if (!needsComma) {
1065
+ handleError(4, [], []);
1066
+ }
1067
+ onSeparator(",");
1068
+ scanNext();
1069
+ if (_scanner.getToken() === 2 && allowTrailingComma) {
1070
+ break;
1071
+ }
1072
+ } else if (needsComma) {
1073
+ handleError(6, [], []);
1074
+ }
1075
+ if (!parseProperty()) {
1076
+ handleError(4, [], [
1077
+ 2,
1078
+ 5
1079
+ /* SyntaxKind.CommaToken */
1080
+ ]);
1081
+ }
1082
+ needsComma = true;
1083
+ }
1084
+ onObjectEnd();
1085
+ if (_scanner.getToken() !== 2) {
1086
+ handleError(7, [
1087
+ 2
1088
+ /* SyntaxKind.CloseBraceToken */
1089
+ ], []);
1090
+ } else {
1091
+ scanNext();
1092
+ }
1093
+ return true;
1094
+ }
1095
+ function parseArray() {
1096
+ onArrayBegin();
1097
+ scanNext();
1098
+ let isFirstElement = true;
1099
+ let needsComma = false;
1100
+ while (_scanner.getToken() !== 4 && _scanner.getToken() !== 17) {
1101
+ if (_scanner.getToken() === 5) {
1102
+ if (!needsComma) {
1103
+ handleError(4, [], []);
1104
+ }
1105
+ onSeparator(",");
1106
+ scanNext();
1107
+ if (_scanner.getToken() === 4 && allowTrailingComma) {
1108
+ break;
1109
+ }
1110
+ } else if (needsComma) {
1111
+ handleError(6, [], []);
1112
+ }
1113
+ if (isFirstElement) {
1114
+ _jsonPath.push(0);
1115
+ isFirstElement = false;
1116
+ } else {
1117
+ _jsonPath[_jsonPath.length - 1]++;
1118
+ }
1119
+ if (!parseValue()) {
1120
+ handleError(4, [], [
1121
+ 4,
1122
+ 5
1123
+ /* SyntaxKind.CommaToken */
1124
+ ]);
1125
+ }
1126
+ needsComma = true;
1127
+ }
1128
+ onArrayEnd();
1129
+ if (!isFirstElement) {
1130
+ _jsonPath.pop();
1131
+ }
1132
+ if (_scanner.getToken() !== 4) {
1133
+ handleError(8, [
1134
+ 4
1135
+ /* SyntaxKind.CloseBracketToken */
1136
+ ], []);
1137
+ } else {
1138
+ scanNext();
1139
+ }
1140
+ return true;
1141
+ }
1142
+ function parseValue() {
1143
+ switch (_scanner.getToken()) {
1144
+ case 3:
1145
+ return parseArray();
1146
+ case 1:
1147
+ return parseObject();
1148
+ case 10:
1149
+ return parseString(true);
1150
+ default:
1151
+ return parseLiteral();
1152
+ }
1153
+ }
1154
+ scanNext();
1155
+ if (_scanner.getToken() === 17) {
1156
+ if (options.allowEmptyContent) {
1157
+ return true;
1158
+ }
1159
+ handleError(4, [], []);
1160
+ return false;
1161
+ }
1162
+ if (!parseValue()) {
1163
+ handleError(4, [], []);
1164
+ return false;
1165
+ }
1166
+ if (_scanner.getToken() !== 17) {
1167
+ handleError(9, [], []);
1168
+ }
1169
+ return true;
1170
+ }
1171
+
1172
+ // ../../node_modules/jsonc-parser/lib/esm/main.js
1173
+ var ScanError;
1174
+ (function(ScanError2) {
1175
+ ScanError2[ScanError2["None"] = 0] = "None";
1176
+ ScanError2[ScanError2["UnexpectedEndOfComment"] = 1] = "UnexpectedEndOfComment";
1177
+ ScanError2[ScanError2["UnexpectedEndOfString"] = 2] = "UnexpectedEndOfString";
1178
+ ScanError2[ScanError2["UnexpectedEndOfNumber"] = 3] = "UnexpectedEndOfNumber";
1179
+ ScanError2[ScanError2["InvalidUnicode"] = 4] = "InvalidUnicode";
1180
+ ScanError2[ScanError2["InvalidEscapeCharacter"] = 5] = "InvalidEscapeCharacter";
1181
+ ScanError2[ScanError2["InvalidCharacter"] = 6] = "InvalidCharacter";
1182
+ })(ScanError || (ScanError = {}));
1183
+ var SyntaxKind;
1184
+ (function(SyntaxKind2) {
1185
+ SyntaxKind2[SyntaxKind2["OpenBraceToken"] = 1] = "OpenBraceToken";
1186
+ SyntaxKind2[SyntaxKind2["CloseBraceToken"] = 2] = "CloseBraceToken";
1187
+ SyntaxKind2[SyntaxKind2["OpenBracketToken"] = 3] = "OpenBracketToken";
1188
+ SyntaxKind2[SyntaxKind2["CloseBracketToken"] = 4] = "CloseBracketToken";
1189
+ SyntaxKind2[SyntaxKind2["CommaToken"] = 5] = "CommaToken";
1190
+ SyntaxKind2[SyntaxKind2["ColonToken"] = 6] = "ColonToken";
1191
+ SyntaxKind2[SyntaxKind2["NullKeyword"] = 7] = "NullKeyword";
1192
+ SyntaxKind2[SyntaxKind2["TrueKeyword"] = 8] = "TrueKeyword";
1193
+ SyntaxKind2[SyntaxKind2["FalseKeyword"] = 9] = "FalseKeyword";
1194
+ SyntaxKind2[SyntaxKind2["StringLiteral"] = 10] = "StringLiteral";
1195
+ SyntaxKind2[SyntaxKind2["NumericLiteral"] = 11] = "NumericLiteral";
1196
+ SyntaxKind2[SyntaxKind2["LineCommentTrivia"] = 12] = "LineCommentTrivia";
1197
+ SyntaxKind2[SyntaxKind2["BlockCommentTrivia"] = 13] = "BlockCommentTrivia";
1198
+ SyntaxKind2[SyntaxKind2["LineBreakTrivia"] = 14] = "LineBreakTrivia";
1199
+ SyntaxKind2[SyntaxKind2["Trivia"] = 15] = "Trivia";
1200
+ SyntaxKind2[SyntaxKind2["Unknown"] = 16] = "Unknown";
1201
+ SyntaxKind2[SyntaxKind2["EOF"] = 17] = "EOF";
1202
+ })(SyntaxKind || (SyntaxKind = {}));
1203
+ var parse2 = parse;
1204
+ var ParseErrorCode;
1205
+ (function(ParseErrorCode2) {
1206
+ ParseErrorCode2[ParseErrorCode2["InvalidSymbol"] = 1] = "InvalidSymbol";
1207
+ ParseErrorCode2[ParseErrorCode2["InvalidNumberFormat"] = 2] = "InvalidNumberFormat";
1208
+ ParseErrorCode2[ParseErrorCode2["PropertyNameExpected"] = 3] = "PropertyNameExpected";
1209
+ ParseErrorCode2[ParseErrorCode2["ValueExpected"] = 4] = "ValueExpected";
1210
+ ParseErrorCode2[ParseErrorCode2["ColonExpected"] = 5] = "ColonExpected";
1211
+ ParseErrorCode2[ParseErrorCode2["CommaExpected"] = 6] = "CommaExpected";
1212
+ ParseErrorCode2[ParseErrorCode2["CloseBraceExpected"] = 7] = "CloseBraceExpected";
1213
+ ParseErrorCode2[ParseErrorCode2["CloseBracketExpected"] = 8] = "CloseBracketExpected";
1214
+ ParseErrorCode2[ParseErrorCode2["EndOfFileExpected"] = 9] = "EndOfFileExpected";
1215
+ ParseErrorCode2[ParseErrorCode2["InvalidCommentToken"] = 10] = "InvalidCommentToken";
1216
+ ParseErrorCode2[ParseErrorCode2["UnexpectedEndOfComment"] = 11] = "UnexpectedEndOfComment";
1217
+ ParseErrorCode2[ParseErrorCode2["UnexpectedEndOfString"] = 12] = "UnexpectedEndOfString";
1218
+ ParseErrorCode2[ParseErrorCode2["UnexpectedEndOfNumber"] = 13] = "UnexpectedEndOfNumber";
1219
+ ParseErrorCode2[ParseErrorCode2["InvalidUnicode"] = 14] = "InvalidUnicode";
1220
+ ParseErrorCode2[ParseErrorCode2["InvalidEscapeCharacter"] = 15] = "InvalidEscapeCharacter";
1221
+ ParseErrorCode2[ParseErrorCode2["InvalidCharacter"] = 16] = "InvalidCharacter";
1222
+ })(ParseErrorCode || (ParseErrorCode = {}));
1223
+ function printParseErrorCode(code) {
1224
+ switch (code) {
1225
+ case 1:
1226
+ return "InvalidSymbol";
1227
+ case 2:
1228
+ return "InvalidNumberFormat";
1229
+ case 3:
1230
+ return "PropertyNameExpected";
1231
+ case 4:
1232
+ return "ValueExpected";
1233
+ case 5:
1234
+ return "ColonExpected";
1235
+ case 6:
1236
+ return "CommaExpected";
1237
+ case 7:
1238
+ return "CloseBraceExpected";
1239
+ case 8:
1240
+ return "CloseBracketExpected";
1241
+ case 9:
1242
+ return "EndOfFileExpected";
1243
+ case 10:
1244
+ return "InvalidCommentToken";
1245
+ case 11:
1246
+ return "UnexpectedEndOfComment";
1247
+ case 12:
1248
+ return "UnexpectedEndOfString";
1249
+ case 13:
1250
+ return "UnexpectedEndOfNumber";
1251
+ case 14:
1252
+ return "InvalidUnicode";
1253
+ case 15:
1254
+ return "InvalidEscapeCharacter";
1255
+ case 16:
1256
+ return "InvalidCharacter";
1257
+ }
1258
+ return "<unknown ParseErrorCode>";
1259
+ }
1260
+
1261
+ // ../editor-project/src/manifest/locate.ts
1262
+ import { existsSync } from "node:fs";
1263
+ import { join } from "node:path";
1264
+
1265
+ // ../editor-project/src/manifest/filename.ts
1266
+ var MANIFEST_FILENAME = "vgai.project.json";
1267
+ var REMOVED_MANIFEST_FILENAME = "vgai.game.json";
1268
+ function removedManifestFilenameMessage(where) {
1269
+ return `${where}: found \`${REMOVED_MANIFEST_FILENAME}\` and no \`${MANIFEST_FILENAME}\`. \`${REMOVED_MANIFEST_FILENAME}\` was REMOVED (the legacy-removal doctrine, docs/ARCHITECTURE-CORE.md \xA7Vocabulary) \u2014 nothing reads it any more, and it is deliberately NOT read as a fallback, because a second accepted name is the defect.
1270
+ Fix: rename it \u2014 \`git mv ${REMOVED_MANIFEST_FILENAME} ${MANIFEST_FILENAME}\`. The contents are unchanged; only the filename moved.`;
1271
+ }
1272
+
1273
+ // ../editor-project/src/manifest/locate.ts
1274
+ function assertNoRemovedManifestFilename(dir) {
1275
+ if (existsSync(join(dir, MANIFEST_FILENAME))) return;
1276
+ if (!existsSync(join(dir, REMOVED_MANIFEST_FILENAME))) return;
1277
+ throw new Error(removedManifestFilenameMessage(join(dir, REMOVED_MANIFEST_FILENAME)));
1278
+ }
1279
+ function resolveManifestPath(dir) {
1280
+ assertNoRemovedManifestFilename(dir);
1281
+ return join(dir, MANIFEST_FILENAME);
1282
+ }
1283
+ function hasManifest(dir) {
1284
+ assertNoRemovedManifestFilename(dir);
1285
+ return existsSync(join(dir, MANIFEST_FILENAME));
1286
+ }
1287
+
1288
+ // node/scaffold/baseline.ts
1289
+ import { execFileSync } from "node:child_process";
1290
+ import { createHash } from "node:crypto";
1291
+ import { mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
1292
+ import { join as join2, relative, sep } from "node:path";
1293
+ var SCAFFOLD_BASELINE_RELATIVE_PATH = ".vgai/scaffold-baseline.json";
1294
+ function readEngineSourceState(engineDir) {
1295
+ try {
1296
+ const sha = execFileSync("git", ["-C", engineDir, "rev-parse", "HEAD"], {
1297
+ encoding: "utf-8",
1298
+ stdio: ["ignore", "pipe", "ignore"]
1299
+ }).trim();
1300
+ const status = execFileSync("git", ["-C", engineDir, "status", "--porcelain", "--", "."], {
1301
+ encoding: "utf-8",
1302
+ stdio: ["ignore", "pipe", "ignore"]
1303
+ });
1304
+ return { sha, dirty: status.trim().length > 0 };
1305
+ } catch {
1306
+ return void 0;
1307
+ }
1308
+ }
1309
+ function hashFile(absPath) {
1310
+ return createHash("sha256").update(readFileSync(absPath)).digest("hex");
1311
+ }
1312
+ function listFilesRecursive(dir, base = dir) {
1313
+ const out = [];
1314
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
1315
+ const full = join2(dir, entry.name);
1316
+ if (entry.isDirectory()) {
1317
+ out.push(...listFilesRecursive(full, base));
1318
+ } else if (entry.isFile()) {
1319
+ out.push(relative(base, full).split(sep).join("/"));
1320
+ }
1321
+ }
1322
+ return out;
1323
+ }
1324
+ function buildScaffoldBaseline(targetDir, engineVersion, engineDir) {
1325
+ const relPaths = listFilesRecursive(targetDir).filter((p) => p !== SCAFFOLD_BASELINE_RELATIVE_PATH).sort();
1326
+ const files = {};
1327
+ for (const relPath of relPaths) {
1328
+ files[relPath] = hashFile(join2(targetDir, relPath));
1329
+ }
1330
+ const engineSource = engineDir ? readEngineSourceState(engineDir) : void 0;
1331
+ return { engineVersion, ...engineSource ? { engineSource } : {}, files };
1332
+ }
1333
+ function writeScaffoldBaseline(targetDir, engineVersion, engineDir) {
1334
+ const baseline = buildScaffoldBaseline(targetDir, engineVersion, engineDir);
1335
+ mkdirSync(join2(targetDir, ".vgai"), { recursive: true });
1336
+ writeFileSync(
1337
+ join2(targetDir, SCAFFOLD_BASELINE_RELATIVE_PATH),
1338
+ `${JSON.stringify(baseline, null, 2)}
1339
+ `,
1340
+ "utf-8"
1341
+ );
1342
+ return baseline;
1343
+ }
1344
+
1345
+ // node/scaffold/catalog.ts
1346
+ import {
1347
+ existsSync as existsSync2,
1348
+ mkdirSync as mkdirSync2,
1349
+ readdirSync as readdirSync2,
1350
+ readFileSync as readFileSync2,
1351
+ rmSync,
1352
+ statSync,
1353
+ writeFileSync as writeFileSync2
1354
+ } from "node:fs";
1355
+ import { dirname, isAbsolute, join as join3, relative as relative2, resolve, sep as sep2 } from "node:path";
1356
+
1357
+ // node/scaffold/adapter-region-merge.ts
1358
+ import ts from "typescript";
1359
+ function quoteLike(source, sample) {
1360
+ const double = sample !== void 0 && source[sample.getStart()] === '"';
1361
+ return (value) => double || value.includes("'") ? JSON.stringify(value) : `'${value}'`;
1362
+ }
1363
+ function stringLiteralOf(node) {
1364
+ return node && ts.isStringLiteralLike(node) ? node.text : void 0;
1365
+ }
1366
+ function propertyOf(object, name) {
1367
+ for (const member of object.properties) {
1368
+ if (!ts.isPropertyAssignment(member)) continue;
1369
+ const key = ts.isIdentifier(member.name) ? member.name.text : stringLiteralOf(member.name);
1370
+ if (key === name) return member;
1371
+ }
1372
+ return void 0;
1373
+ }
1374
+ function definitionObject(source) {
1375
+ for (const statement of source.statements) {
1376
+ if (!ts.isExportAssignment(statement) || statement.isExportEquals) continue;
1377
+ const call = statement.expression;
1378
+ if (!ts.isCallExpression(call)) {
1379
+ return { reason: "its default export is not a direct `defineAdapter({\u2026})` call" };
1380
+ }
1381
+ const arg = call.arguments[0];
1382
+ if (arg === void 0) {
1383
+ return { reason: "its default export takes no argument object to declare into" };
1384
+ }
1385
+ if (!ts.isObjectLiteralExpression(arg)) {
1386
+ return { reason: "its default export is not called with an object literal" };
1387
+ }
1388
+ return { object: arg };
1389
+ }
1390
+ return { reason: "it has no default export" };
1391
+ }
1392
+ function indentAt(text, position) {
1393
+ const lineStart = text.lastIndexOf("\n", position - 1) + 1;
1394
+ const match = /^[ \t]*/.exec(text.slice(lineStart, position));
1395
+ return match?.[0] ?? "";
1396
+ }
1397
+ function appendToArray(text, array, globs) {
1398
+ const last = array.elements[array.elements.length - 1];
1399
+ const closing = array.getEnd() - 1;
1400
+ const inner = last ? indentAt(text, last.getStart()) : `${indentAt(text, array.getStart())} `;
1401
+ const quote = quoteLike(text, last);
1402
+ const body = globs.map((glob) => `${inner}${quote(glob)},`).join("\n");
1403
+ const start = text.slice(0, closing).replace(/\s+$/, "").length;
1404
+ const needsComma = last !== void 0 && text[start - 1] !== ",";
1405
+ return {
1406
+ start,
1407
+ end: closing,
1408
+ text: `${needsComma ? "," : ""}
1409
+ ${body}
1410
+ ${indentAt(text, array.getStart())}`
1411
+ };
1412
+ }
1413
+ function appendProperty(text, object, property) {
1414
+ const last = object.properties[object.properties.length - 1];
1415
+ const closing = object.getEnd() - 1;
1416
+ const outer = indentAt(text, object.getStart());
1417
+ const inner = last ? indentAt(text, last.getStart()) : `${outer} `;
1418
+ const start = text.slice(0, closing).replace(/\s+$/, "").length;
1419
+ const needsComma = last !== void 0 && text[start - 1] !== ",";
1420
+ return { start, end: closing, text: `${needsComma ? "," : ""}
1421
+ ${property(inner)}
1422
+ ${outer}` };
1423
+ }
1424
+ function regionEntryText(indent, addition, quote) {
1425
+ const globs = addition.globs.map((glob) => `${indent} ${quote(glob)},`).join("\n");
1426
+ const key = /^[A-Za-z_$][\w$]*$/.test(addition.rootId) ? addition.rootId : quote(addition.rootId);
1427
+ return `${indent}${key}: {
1428
+ ${indent} include: [
1429
+ ${globs}
1430
+ ${indent} ],
1431
+ ${indent}},`;
1432
+ }
1433
+ function mergeAdapterRegionIncludes(source, additions) {
1434
+ if (additions.length === 0) return { kind: "unchanged" };
1435
+ const parsed = ts.createSourceFile("vgai.adapter.ts", source, ts.ScriptTarget.Latest, true);
1436
+ const definition = definitionObject(parsed);
1437
+ if ("reason" in definition) return { kind: "unreadable", reason: definition.reason };
1438
+ const listed = propertyOf(definition.object, "regions");
1439
+ if (listed && !ts.isStringLiteralLike(listed.initializer)) {
1440
+ return {
1441
+ kind: "unreadable",
1442
+ reason: "it states an explicit `regions` list, whose entries carry their own `include`"
1443
+ };
1444
+ }
1445
+ const splices = [];
1446
+ const added = [];
1447
+ const overlay = propertyOf(definition.object, "regionIncludes");
1448
+ const quote = quoteLike(source, void 0);
1449
+ if (!overlay) {
1450
+ for (const addition of additions) added.push(...addition.globs);
1451
+ splices.push(
1452
+ appendProperty(source, definition.object, (indent) => {
1453
+ const entries = additions.map((addition) => regionEntryText(`${indent} `, addition, quote)).join("\n");
1454
+ return `${indent}regionIncludes: {
1455
+ ${entries}
1456
+ ${indent}},`;
1457
+ })
1458
+ );
1459
+ } else {
1460
+ if (!ts.isObjectLiteralExpression(overlay.initializer)) {
1461
+ return { kind: "unreadable", reason: "`regionIncludes` is not an object literal" };
1462
+ }
1463
+ const table = overlay.initializer;
1464
+ for (const addition of additions) {
1465
+ const entry = propertyOf(table, addition.rootId);
1466
+ if (!entry) {
1467
+ added.push(...addition.globs);
1468
+ splices.push(
1469
+ appendProperty(source, table, (indent) => regionEntryText(indent, addition, quote))
1470
+ );
1471
+ continue;
1472
+ }
1473
+ if (!ts.isObjectLiteralExpression(entry.initializer)) {
1474
+ return {
1475
+ kind: "unreadable",
1476
+ reason: `\`regionIncludes.${addition.rootId}\` is not an object literal`
1477
+ };
1478
+ }
1479
+ const include = propertyOf(entry.initializer, "include");
1480
+ if (!include) {
1481
+ added.push(...addition.globs);
1482
+ splices.push(
1483
+ appendProperty(source, entry.initializer, (indent) => {
1484
+ const globs = addition.globs.map((glob) => `${indent} ${quote(glob)},`).join("\n");
1485
+ return `${indent}include: [
1486
+ ${globs}
1487
+ ${indent}],`;
1488
+ })
1489
+ );
1490
+ continue;
1491
+ }
1492
+ if (!ts.isArrayLiteralExpression(include.initializer)) {
1493
+ return {
1494
+ kind: "unreadable",
1495
+ reason: `\`regionIncludes.${addition.rootId}.include\` is not an array literal`
1496
+ };
1497
+ }
1498
+ const declared = new Set(
1499
+ include.initializer.elements.map((element) => stringLiteralOf(element))
1500
+ );
1501
+ if (declared.has(void 0)) {
1502
+ return {
1503
+ kind: "unreadable",
1504
+ reason: `\`regionIncludes.${addition.rootId}.include\` holds something other than string literals`
1505
+ };
1506
+ }
1507
+ const missing = addition.globs.filter((glob) => !declared.has(glob));
1508
+ if (missing.length === 0) continue;
1509
+ added.push(...missing);
1510
+ splices.push(appendToArray(source, include.initializer, missing));
1511
+ }
1512
+ }
1513
+ if (splices.length === 0) return { kind: "unchanged" };
1514
+ let text = source;
1515
+ for (const splice of [...splices].sort((a, b) => b.start - a.start)) {
1516
+ text = text.slice(0, splice.start) + splice.text + text.slice(splice.end);
1517
+ }
1518
+ return { kind: "merged", text, added };
1519
+ }
1520
+
1521
+ // node/scaffold/catalog.ts
1522
+ var PROJECT_CATALOG_DIR = join3(".vgai", "catalog");
1523
+ var DEFAULT_REACT_CAPABILITIES = ["react-root"];
1524
+ var CATALOG_SURFACES = ["three", "canvas", "dom"];
1525
+ var CAPABILITY_STAMP_FILENAME = "capability.json";
1526
+ function capabilityStampPath(entry) {
1527
+ const libDir = entry.files.filter((file) => file.startsWith(`src/lib/${entry.id}/`)).map((file) => file.split("/").slice(0, 3).join("/"))[0];
1528
+ return libDir ? `${libDir}/${CAPABILITY_STAMP_FILENAME}` : `src/tools/${entry.id}.${CAPABILITY_STAMP_FILENAME}`;
1529
+ }
1530
+ function isRecord(value) {
1531
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1532
+ }
1533
+ function stringArray(value, field, manifestPath) {
1534
+ if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string")) {
1535
+ throw new Error(`${manifestPath}: ${field} must be an array of strings`);
1536
+ }
1537
+ return value;
1538
+ }
1539
+ var RENAMED_CAPABILITY_IDS = /* @__PURE__ */ new Map([["mesh", "blender"]]);
1540
+ function renamedCapabilityIdMessage(where, oldId, newId) {
1541
+ return `${where}: capability id \`${oldId}\` was RENAMED to \`${newId}\` (2026-09-19). Nothing reads \`${oldId}\` any more, and it is deliberately NOT mapped onto \`${newId}\`, because a second accepted name is the defect.
1542
+ Fix: in this project, rename the file \u2014 \`git mv .vgai/catalog/${oldId}.json .vgai/catalog/${newId}.json\` \u2014 and change its \`"id"\` to \`"${newId}"\`. If a stamp file names the old id, rename that too (\`src/tools/${oldId}.*\` -> \`src/tools/${newId}.*\`). Then \`vgai outdated\` will report against the current entry. Nothing else about the capability changed.`;
1543
+ }
1544
+ function readCatalogEntry(path) {
1545
+ const parsed = JSON.parse(readFileSync2(path, "utf8"));
1546
+ if (!isRecord(parsed)) throw new Error(`${path}: capability manifest must be an object`);
1547
+ for (const field of ["description", "id", "title"]) {
1548
+ if (typeof parsed[field] !== "string" || parsed[field].length === 0) {
1549
+ throw new Error(`${path}: ${field} must be a non-empty string`);
1550
+ }
1551
+ }
1552
+ const renamedTo = RENAMED_CAPABILITY_IDS.get(parsed["id"]);
1553
+ if (renamedTo !== void 0) {
1554
+ throw new Error(renamedCapabilityIdMessage(path, parsed["id"], renamedTo));
1555
+ }
1556
+ if (typeof parsed["version"] !== "string" || !/^\d+\.\d+\.\d+$/.test(parsed["version"])) {
1557
+ throw new Error(`${path}: version must be a semver string like "0.1.0"`);
1558
+ }
1559
+ const manifest = {
1560
+ description: parsed["description"],
1561
+ files: stringArray(parsed["files"], "files", path),
1562
+ id: parsed["id"],
1563
+ requires: stringArray(parsed["requires"], "requires", path),
1564
+ skills: stringArray(parsed["skills"], "skills", path),
1565
+ title: parsed["title"],
1566
+ version: parsed["version"]
1567
+ };
1568
+ if (parsed["packageJson"] !== void 0) {
1569
+ if (!isRecord(parsed["packageJson"])) {
1570
+ throw new Error(`${path}: packageJson must be an object`);
1571
+ }
1572
+ const packageJson = parsed["packageJson"];
1573
+ const dependencies = readStringRecord(packageJson["dependencies"], "dependencies", path);
1574
+ const devDependencies = readStringRecord(
1575
+ packageJson["devDependencies"],
1576
+ "devDependencies",
1577
+ path
1578
+ );
1579
+ const scripts = readStringRecord(packageJson["scripts"], "scripts", path);
1580
+ const vgaiTools = packageJson["vgaiTools"];
1581
+ if (vgaiTools !== void 0 && (!Array.isArray(vgaiTools) || vgaiTools.some((entry) => typeof entry !== "string" && !isRecord(entry)))) {
1582
+ throw new Error(`${path}: packageJson.vgaiTools must be an array of module paths`);
1583
+ }
1584
+ manifest.packageJson = {
1585
+ ...dependencies ? { dependencies } : {},
1586
+ ...devDependencies ? { devDependencies } : {},
1587
+ ...scripts ? { scripts } : {},
1588
+ ...vgaiTools ? { vgaiTools } : {}
1589
+ };
1590
+ }
1591
+ const assetPacks = readAssetPacks(parsed["assetPacks"], path);
1592
+ if (assetPacks) manifest.assetPacks = assetPacks;
1593
+ const regions = readRegions(parsed["regions"], path);
1594
+ if (regions) manifest.regions = regions;
1595
+ assertJsxSurfacesDeclared(manifest, path);
1596
+ return manifest;
1597
+ }
1598
+ function readRegions(value, manifestPath) {
1599
+ if (value === void 0) return void 0;
1600
+ if (!isRecord(value)) throw new Error(`${manifestPath}: regions must be an object`);
1601
+ const regions = {};
1602
+ for (const [surface, globs] of Object.entries(value)) {
1603
+ if (!CATALOG_SURFACES.includes(surface)) {
1604
+ throw new Error(
1605
+ `${manifestPath}: regions key must be one of ${CATALOG_SURFACES.join(", ")} \u2014 got ${surface}`
1606
+ );
1607
+ }
1608
+ const list = stringArray(globs, `regions.${surface}`, manifestPath);
1609
+ if (list.length === 0) {
1610
+ throw new Error(`${manifestPath}: regions.${surface} must name at least one glob`);
1611
+ }
1612
+ for (const glob of list) assertRelativeProjectPath(glob);
1613
+ regions[surface] = list;
1614
+ }
1615
+ return regions;
1616
+ }
1617
+ function globToRegExp(glob) {
1618
+ let out = "";
1619
+ let i = 0;
1620
+ while (i < glob.length) {
1621
+ const ch = glob[i];
1622
+ if (ch === "*") {
1623
+ if (glob[i + 1] === "*") {
1624
+ out += glob[i + 2] === "/" ? "(?:.*/)?" : ".*";
1625
+ i += glob[i + 2] === "/" ? 3 : 2;
1626
+ continue;
1627
+ }
1628
+ out += "[^/]*";
1629
+ i += 1;
1630
+ continue;
1631
+ }
1632
+ if (ch === "?") {
1633
+ out += "[^/]";
1634
+ i += 1;
1635
+ continue;
1636
+ }
1637
+ out += ch.replace(/[.+^${}()|[\]\\]/g, "\\$&");
1638
+ i += 1;
1639
+ }
1640
+ return new RegExp(`^${out}$`);
1641
+ }
1642
+ function assertJsxSurfacesDeclared(manifest, manifestPath) {
1643
+ const globs = Object.values(manifest.regions ?? {}).flat().map(globToRegExp);
1644
+ const undeclared = manifest.files.filter(
1645
+ (file) => file.endsWith(".tsx") && !file.startsWith("src/tools/") && !file.startsWith("src/contributions/") && !globs.some((pattern) => pattern.test(file))
1646
+ );
1647
+ if (undeclared.length > 0) {
1648
+ throw new Error(
1649
+ `${manifestPath}: these .tsx files name no surface in \`regions\` \u2014 ${undeclared.join(", ")}. The editor stamps one source-id attribute per file and the default (\`data-oid\`) is correct only for React DOM; an R3F component that takes it breaks the running game (fiber pierces the dash and throws on the second apply). Declare each file under the surface it renders on \u2014 \`three\`, \`canvas\`, or \`dom\`.`
1650
+ );
1651
+ }
1652
+ }
1653
+ function readAssetPacks(value, manifestPath) {
1654
+ if (value === void 0) return void 0;
1655
+ if (!isRecord(value)) throw new Error(`${manifestPath}: assetPacks must be an object`);
1656
+ const packs = {};
1657
+ for (const [pack, entries] of Object.entries(value)) {
1658
+ if (pack.length === 0) throw new Error(`${manifestPath}: an assetPacks name must be non-empty`);
1659
+ if (!Array.isArray(entries)) {
1660
+ throw new Error(`${manifestPath}: assetPacks.${pack} must be an array`);
1661
+ }
1662
+ packs[pack] = entries.map((entry) => {
1663
+ if (!isRecord(entry))
1664
+ throw new Error(`${manifestPath}: assetPacks.${pack} entries must be objects`);
1665
+ const { key, dest, sha256 } = entry;
1666
+ if (typeof key !== "string" || !/^[^:]+:.+$/.test(key)) {
1667
+ throw new Error(`${manifestPath}: assetPacks.${pack} entry key must be "source:id"`);
1668
+ }
1669
+ if (typeof dest !== "string" || dest.length === 0) {
1670
+ throw new Error(`${manifestPath}: assetPacks.${pack} entry dest must be a non-empty path`);
1671
+ }
1672
+ assertRelativeProjectPath(dest);
1673
+ if (typeof sha256 !== "string" || !/^[a-f0-9]{64}$/.test(sha256)) {
1674
+ throw new Error(
1675
+ `${manifestPath}: assetPacks.${pack} entry sha256 must be 64 lowercase hex digits`
1676
+ );
1677
+ }
1678
+ return { key, dest, sha256 };
1679
+ });
1680
+ }
1681
+ return packs;
1682
+ }
1683
+ function readStringRecord(value, field, manifestPath) {
1684
+ if (value === void 0) return void 0;
1685
+ if (!isRecord(value) || Object.values(value).some((entry) => typeof entry !== "string")) {
1686
+ throw new Error(`${manifestPath}: packageJson.${field} must map strings to strings`);
1687
+ }
1688
+ return value;
1689
+ }
1690
+ function listManifestPaths(catalogDir) {
1691
+ if (!existsSync2(catalogDir)) throw new Error(`Catalog entries not found: ${catalogDir}`);
1692
+ return readdirSync2(catalogDir).filter((name) => name.endsWith(".json")).sort().map((name) => join3(catalogDir, name));
1693
+ }
1694
+ function readCatalog(catalogDir) {
1695
+ const manifests = listManifestPaths(join3(catalogDir, "entries")).map(readCatalogEntry);
1696
+ const ids = /* @__PURE__ */ new Set();
1697
+ for (const manifest of manifests) {
1698
+ if (ids.has(manifest.id)) throw new Error(`Duplicate capability id: ${manifest.id}`);
1699
+ ids.add(manifest.id);
1700
+ }
1701
+ for (const manifest of manifests) {
1702
+ for (const required of manifest.requires) {
1703
+ if (!ids.has(required)) {
1704
+ throw new Error(`Capability ${manifest.id} requires unknown capability ${required}`);
1705
+ }
1706
+ }
1707
+ }
1708
+ return manifests;
1709
+ }
1710
+ function initializeProjectCatalog(projectDir, catalogDir) {
1711
+ const targetDir = join3(projectDir, PROJECT_CATALOG_DIR);
1712
+ mkdirSync2(targetDir, { recursive: true });
1713
+ for (const manifestPath of listManifestPaths(join3(catalogDir, "entries"))) {
1714
+ const targetPath = join3(targetDir, manifestPath.slice(manifestPath.lastIndexOf(sep2) + 1));
1715
+ writeFileSync2(targetPath, readFileSync2(manifestPath));
1716
+ }
1717
+ }
1718
+ function presentCapabilityIds(projectDir, catalogDir) {
1719
+ const resolvedProject = resolve(projectDir);
1720
+ const resolvedCatalog = resolve(catalogDir);
1721
+ let catalog;
1722
+ try {
1723
+ catalog = readCatalog(resolvedCatalog);
1724
+ } catch {
1725
+ return [];
1726
+ }
1727
+ return catalog.filter((manifest) => {
1728
+ if (existsSync2(join3(resolvedProject, capabilityStampPath(manifest)))) return true;
1729
+ const files = entryFiles(manifest, resolvedCatalog);
1730
+ if (files.length === 0) return false;
1731
+ const matching = files.filter((file) => {
1732
+ const target = join3(resolvedProject, file.relativePath);
1733
+ return existsSync2(target) && readFileSync2(target).equals(file.bytes);
1734
+ }).length;
1735
+ return matching * 2 > files.length;
1736
+ }).map((manifest) => manifest.id).sort();
1737
+ }
1738
+ function assertRelativeProjectPath(path) {
1739
+ if (path.length === 0 || isAbsolute(path) || path.split(/[\\/]/).includes("..")) {
1740
+ throw new Error(`Capability file must be project-relative: ${path}`);
1741
+ }
1742
+ }
1743
+ function collectFiles(root) {
1744
+ const files = [];
1745
+ const visit2 = (dir) => {
1746
+ for (const entry of readdirSync2(dir, { withFileTypes: true })) {
1747
+ const path = join3(dir, entry.name);
1748
+ if (entry.isDirectory()) visit2(path);
1749
+ else if (entry.isFile()) files.push(path);
1750
+ }
1751
+ };
1752
+ visit2(root);
1753
+ return files.sort();
1754
+ }
1755
+ var PROJECT_SKILL_ROOTS = [
1756
+ join3(".agents", "skills"),
1757
+ join3(".claude", "skills"),
1758
+ join3(".github", "skills")
1759
+ ];
1760
+ function entryFiles(manifest, catalogDir) {
1761
+ const files = [];
1762
+ for (const relativePath of manifest.files) {
1763
+ assertRelativeProjectPath(relativePath);
1764
+ const source = join3(catalogDir, "project-source", relativePath);
1765
+ if (!existsSync2(source) || !statSync(source).isFile()) {
1766
+ throw new Error(`Capability ${manifest.id} source file is missing: ${source}`);
1767
+ }
1768
+ files.push({ bytes: readFileSync2(source), owner: manifest.id, relativePath });
1769
+ }
1770
+ for (const skill of manifest.skills) {
1771
+ if (!/^[a-z0-9-]+$/.test(skill)) throw new Error(`Invalid skill name: ${skill}`);
1772
+ const skillRoot = join3(dirname(catalogDir), "template", ".agents", "skills", skill);
1773
+ if (!existsSync2(skillRoot) || !statSync(skillRoot).isDirectory()) {
1774
+ throw new Error(`Capability ${manifest.id} skill is missing: ${skillRoot}`);
1775
+ }
1776
+ for (const source of collectFiles(skillRoot)) {
1777
+ for (const projectSkillRoot of PROJECT_SKILL_ROOTS) {
1778
+ files.push({
1779
+ bytes: readFileSync2(source),
1780
+ owner: manifest.id,
1781
+ relativePath: join3(projectSkillRoot, skill, relative2(skillRoot, source))
1782
+ });
1783
+ }
1784
+ }
1785
+ }
1786
+ return files;
1787
+ }
1788
+ function dependencyOrder(ids, byId) {
1789
+ const ordered = [];
1790
+ const visiting = /* @__PURE__ */ new Set();
1791
+ const visited = /* @__PURE__ */ new Set();
1792
+ const visit2 = (id) => {
1793
+ if (visited.has(id)) return;
1794
+ if (visiting.has(id)) throw new Error(`Capability dependency cycle includes ${id}`);
1795
+ const manifest = byId.get(id);
1796
+ if (!manifest) {
1797
+ const renamedTo = RENAMED_CAPABILITY_IDS.get(id);
1798
+ if (renamedTo !== void 0) {
1799
+ throw new Error(
1800
+ `Capability id \`${id}\` was RENAMED to \`${renamedTo}\` (2026-09-19). Nothing accepts \`${id}\` any more, and it is deliberately NOT mapped onto \`${renamedTo}\`, because a second accepted name is the defect.
1801
+ Fix: use the current name \u2014 \`${renamedTo}\`. Nothing else changed.`
1802
+ );
1803
+ }
1804
+ throw new Error(
1805
+ `Unknown capability: ${id}
1806
+ Available: ${[...byId.keys()].sort().join(", ")}`
1807
+ );
1808
+ }
1809
+ visiting.add(id);
1810
+ for (const required of manifest.requires) visit2(required);
1811
+ visiting.delete(id);
1812
+ visited.add(id);
1813
+ ordered.push(manifest);
1814
+ };
1815
+ for (const id of ids) visit2(id);
1816
+ return ordered;
1817
+ }
1818
+ function specParts(spec) {
1819
+ const m = /^\s*([\^~]?)=?v?(\d+\.\d+\.\d+(?:-[\w.]+)?)\s*$/.exec(spec);
1820
+ return m ? { prefix: m[1] ?? "", core: m[2] } : null;
1821
+ }
1822
+ var SPEC_WIDTH = { "^": 2, "~": 1, "": 0 };
1823
+ function widerSpec(a, b) {
1824
+ if (a === b) return a;
1825
+ const pa = specParts(a);
1826
+ const pb = specParts(b);
1827
+ if (!pa || !pb || pa.core !== pb.core) return null;
1828
+ return (SPEC_WIDTH[pa.prefix] ?? 0) >= (SPEC_WIDTH[pb.prefix] ?? 0) ? a : b;
1829
+ }
1830
+ function mergeStringDependencies(target, field, incoming, owner, origins, resolveSpec) {
1831
+ if (!incoming) return;
1832
+ const current = target[field];
1833
+ if (current !== void 0 && !isRecord(current)) {
1834
+ throw new Error(`package.json ${field} must be an object`);
1835
+ }
1836
+ const merged = { ...current ?? {} };
1837
+ for (const [name, declared] of Object.entries(incoming)) {
1838
+ const spec = field === "scripts" ? declared : resolveSpec?.(name, declared) ?? declared;
1839
+ const existing = merged[name];
1840
+ const key = `${field}.${name}`;
1841
+ if (existing !== void 0) {
1842
+ const projectOwned = !origins.has(key);
1843
+ const winner = typeof existing !== "string" ? null : field === "scripts" ? existing === spec ? existing : null : projectOwned ? widerSpec(existing, spec) === null ? null : existing : widerSpec(existing, spec);
1844
+ if (winner === null) {
1845
+ const from = origins.get(key) ?? "the project package.json";
1846
+ throw new Error(
1847
+ `Capability ${owner} requires ${key}=${spec}, but ${from} already set ${key}=${String(existing)}`
1848
+ );
1849
+ }
1850
+ merged[name] = winner;
1851
+ if (winner !== existing) origins.set(key, `capability ${owner}`);
1852
+ continue;
1853
+ }
1854
+ merged[name] = spec;
1855
+ origins.set(key, `capability ${owner}`);
1856
+ }
1857
+ target[field] = Object.fromEntries(Object.entries(merged).sort(([a], [b]) => a.localeCompare(b)));
1858
+ }
1859
+ function toolIdentity(tool) {
1860
+ if (typeof tool === "string") return tool;
1861
+ const identity = tool["entry"] ?? tool["id"];
1862
+ if (typeof identity !== "string" || identity.length === 0) {
1863
+ throw new Error("Capability tool requires an entry or id");
1864
+ }
1865
+ return identity;
1866
+ }
1867
+ function planCapabilityPackageJson(originalBytes, manifests, label = "package.json", resolveSpec) {
1868
+ const original = Buffer.from(originalBytes);
1869
+ const parsed = JSON.parse(original.toString("utf8"));
1870
+ if (!isRecord(parsed)) throw new Error(`${label}: package.json must be an object`);
1871
+ const origins = /* @__PURE__ */ new Map();
1872
+ for (const manifest of manifests) {
1873
+ const patch = manifest.packageJson;
1874
+ if (!patch) continue;
1875
+ mergeStringDependencies(
1876
+ parsed,
1877
+ "dependencies",
1878
+ patch.dependencies,
1879
+ manifest.id,
1880
+ origins,
1881
+ resolveSpec
1882
+ );
1883
+ mergeStringDependencies(
1884
+ parsed,
1885
+ "devDependencies",
1886
+ patch.devDependencies,
1887
+ manifest.id,
1888
+ origins,
1889
+ resolveSpec
1890
+ );
1891
+ mergeStringDependencies(parsed, "scripts", patch.scripts, manifest.id, origins);
1892
+ if (patch.vgaiTools) {
1893
+ const vgai = parsed["vgai"] === void 0 ? {} : parsed["vgai"];
1894
+ if (!isRecord(vgai)) throw new Error(`${label}: vgai must be an object`);
1895
+ const currentTools = vgai["tools"] === void 0 ? [] : vgai["tools"];
1896
+ if (!Array.isArray(currentTools) || currentTools.some((tool) => typeof tool !== "string" && !isRecord(tool))) {
1897
+ throw new Error(`${label}: vgai.tools must be an array of strings or objects`);
1898
+ }
1899
+ const tools = currentTools.map(
1900
+ (tool) => typeof tool === "string" ? tool : { ...tool }
1901
+ );
1902
+ for (const tool of patch.vgaiTools) {
1903
+ const id = toolIdentity(tool);
1904
+ const existing = tools.find((candidate) => toolIdentity(candidate) === id);
1905
+ if (existing && JSON.stringify(existing) !== JSON.stringify(tool)) {
1906
+ throw new Error(
1907
+ `Capability ${manifest.id} conflicts with existing vgai.tools entry ${id}`
1908
+ );
1909
+ }
1910
+ if (!existing) tools.push(tool);
1911
+ }
1912
+ tools.sort((a, b) => toolIdentity(a).localeCompare(toolIdentity(b)));
1913
+ vgai["tools"] = tools;
1914
+ parsed["vgai"] = vgai;
1915
+ }
1916
+ }
1917
+ return Buffer.from(`${JSON.stringify(parsed, null, 2)}
1918
+ `);
1919
+ }
1920
+ function mergedPackageJson(projectDir, manifests, resolveSpec) {
1921
+ const path = join3(projectDir, "package.json");
1922
+ const needsMerge = manifests.some((manifest) => manifest.packageJson !== void 0);
1923
+ if (!needsMerge) return void 0;
1924
+ if (!existsSync2(path))
1925
+ throw new Error(`Cannot install capability package changes: ${path} is missing`);
1926
+ const original = readFileSync2(path);
1927
+ const bytes = Buffer.from(planCapabilityPackageJson(original, manifests, path, resolveSpec));
1928
+ return { bytes, changed: !original.equals(bytes) };
1929
+ }
1930
+ var ASSET_MANIFEST_FILE = "asset-manifest.json";
1931
+ function mergedAssetManifest(projectDir, manifests) {
1932
+ const declared = [];
1933
+ for (const manifest of manifests) {
1934
+ for (const [pack, entries] of Object.entries(manifest.assetPacks ?? {})) {
1935
+ for (const entry of entries) declared.push({ ...entry, pack });
1936
+ }
1937
+ }
1938
+ if (declared.length === 0) return void 0;
1939
+ const file = join3(projectDir, ASSET_MANIFEST_FILE);
1940
+ const original = existsSync2(file) ? readFileSync2(file) : Buffer.alloc(0);
1941
+ const parsed = original.length > 0 ? JSON.parse(original.toString("utf8")) : {};
1942
+ if (parsed.packs !== void 0 && !isRecord(parsed.packs)) {
1943
+ throw new Error(`${ASSET_MANIFEST_FILE}: packs must be an object`);
1944
+ }
1945
+ const packs = parsed.packs ?? {};
1946
+ const claimed = new Set(
1947
+ Object.values(packs).flatMap((entries) => entries.map((entry) => entry.dest))
1948
+ );
1949
+ for (const entry of declared) {
1950
+ if (claimed.has(entry.dest)) continue;
1951
+ const existing = packs[entry.pack] ?? [];
1952
+ existing.push({ key: entry.key, dest: entry.dest, sha256: entry.sha256 });
1953
+ packs[entry.pack] = existing;
1954
+ claimed.add(entry.dest);
1955
+ }
1956
+ parsed.packs = packs;
1957
+ const bytes = Buffer.from(`${JSON.stringify(parsed, null, 2)}
1958
+ `);
1959
+ const byDest = /* @__PURE__ */ new Map();
1960
+ for (const [pack, entries] of Object.entries(packs)) {
1961
+ for (const entry of entries) {
1962
+ byDest.set(entry.dest, { key: entry.key, dest: entry.dest, sha256: entry.sha256, pack });
1963
+ }
1964
+ }
1965
+ const merged = [...new Set(declared.map((entry) => entry.dest))].map(
1966
+ (dest) => byDest.get(dest)
1967
+ );
1968
+ return { bytes, changed: !original.equals(bytes), declared: merged };
1969
+ }
1970
+ var ADAPTER_MODULE_FILE = "vgai.adapter.ts";
1971
+ function rootSurfaces(projectDir) {
1972
+ const surfaces = /* @__PURE__ */ new Map();
1973
+ let manifest;
1974
+ try {
1975
+ manifest = JSON.parse(readFileSync2(resolveManifestPath(projectDir), "utf8"));
1976
+ } catch {
1977
+ return surfaces;
1978
+ }
1979
+ if (!isRecord(manifest) || !Array.isArray(manifest["roots"])) return surfaces;
1980
+ for (const root of manifest["roots"]) {
1981
+ if (!isRecord(root) || typeof root["id"] !== "string") continue;
1982
+ const adapter = root["adapter"];
1983
+ const surface = typeof adapter === "string" ? adapter : isRecord(adapter) && typeof adapter["surface"] === "string" ? adapter["surface"] : void 0;
1984
+ if (surface && CATALOG_SURFACES.includes(surface)) {
1985
+ surfaces.set(root["id"], surface);
1986
+ }
1987
+ }
1988
+ return surfaces;
1989
+ }
1990
+ function mergedAdapterModule(projectDir, manifests) {
1991
+ const declaring = manifests.filter((manifest) => manifest.regions !== void 0);
1992
+ if (declaring.length === 0) return void 0;
1993
+ const surfaces = rootSurfaces(projectDir);
1994
+ const unplaced = [];
1995
+ const byRootId = /* @__PURE__ */ new Map();
1996
+ for (const manifest of declaring) {
1997
+ for (const surface of CATALOG_SURFACES) {
1998
+ const globs = manifest.regions?.[surface];
1999
+ if (globs === void 0) continue;
2000
+ const roots = [...surfaces].filter(([, value]) => value === surface).map(([id]) => id);
2001
+ if (roots.length !== 1) {
2002
+ if (surface === "dom" && roots.length === 0) continue;
2003
+ unplaced.push({
2004
+ capability: manifest.id,
2005
+ globs,
2006
+ reason: roots.length === 0 ? `${projectDir} declares no \`${surface}\` root to own them` : `${projectDir} declares ${roots.length} \`${surface}\` roots (${roots.join(", ")}) \u2014 only the game can say which owns them`,
2007
+ surface
2008
+ });
2009
+ continue;
2010
+ }
2011
+ const rootId = roots[0];
2012
+ byRootId.set(rootId, [...byRootId.get(rootId) ?? [], ...globs]);
2013
+ }
2014
+ }
2015
+ const path = join3(projectDir, ADAPTER_MODULE_FILE);
2016
+ if (byRootId.size === 0 || !existsSync2(path)) {
2017
+ for (const [rootId, globs] of byRootId) {
2018
+ unplaced.push({
2019
+ capability: declaring.map((manifest) => manifest.id).join(", "),
2020
+ globs,
2021
+ reason: `${path} does not exist \u2014 add \`regionIncludes: { ${rootId}: { include: [...] } }\` to one`,
2022
+ surface: surfaces.get(rootId)
2023
+ });
2024
+ }
2025
+ return { bytes: Buffer.alloc(0), changed: false, unplaced };
2026
+ }
2027
+ const additions = [...byRootId].map(([rootId, globs]) => ({ rootId, globs: [...new Set(globs)].sort() })).sort((a, b) => a.rootId.localeCompare(b.rootId));
2028
+ const original = readFileSync2(path);
2029
+ const merge = mergeAdapterRegionIncludes(original.toString("utf8"), additions);
2030
+ if (merge.kind === "unreadable") {
2031
+ for (const addition of additions) {
2032
+ unplaced.push({
2033
+ capability: declaring.map((manifest) => manifest.id).join(", "),
2034
+ globs: [...addition.globs],
2035
+ reason: `${path} could not be edited automatically \u2014 ${merge.reason}. Declare them on the \`${addition.rootId}\` region by hand`,
2036
+ surface: surfaces.get(addition.rootId)
2037
+ });
2038
+ }
2039
+ return { bytes: original, changed: false, unplaced };
2040
+ }
2041
+ if (merge.kind === "unchanged") return { bytes: original, changed: false, unplaced };
2042
+ return { bytes: Buffer.from(merge.text), changed: true, unplaced };
2043
+ }
2044
+ function addCapabilities(options) {
2045
+ const projectDir = resolve(options.projectDir);
2046
+ const catalogDir = resolve(options.catalogDir);
2047
+ const catalog = readCatalog(catalogDir);
2048
+ const byId = new Map(catalog.map((manifest) => [manifest.id, manifest]));
2049
+ const ordered = dependencyOrder(options.ids, byId);
2050
+ const plannedFiles = ordered.flatMap((manifest) => entryFiles(manifest, catalogDir));
2051
+ const targets = /* @__PURE__ */ new Map();
2052
+ for (const file of plannedFiles) {
2053
+ const prior = targets.get(file.relativePath);
2054
+ if (prior && !prior.bytes.equals(file.bytes)) {
2055
+ throw new Error(
2056
+ `Capabilities ${prior.owner} and ${file.owner} provide different contents for ${file.relativePath}`
2057
+ );
2058
+ }
2059
+ targets.set(file.relativePath, file);
2060
+ }
2061
+ const present = new Set(presentCapabilityIds(projectDir, catalogDir));
2062
+ const alreadyInstalled = ordered.filter((m) => present.has(m.id)).map((m) => m.id);
2063
+ const newManifests = ordered.filter((manifest) => !present.has(manifest.id));
2064
+ const toWrite = [];
2065
+ const kept = [];
2066
+ for (const file of targets.values()) {
2067
+ const target = join3(projectDir, file.relativePath);
2068
+ if (!existsSync2(target)) {
2069
+ toWrite.push(file);
2070
+ continue;
2071
+ }
2072
+ if (!readFileSync2(target).equals(file.bytes) && !present.has(file.owner)) {
2073
+ throw new Error(
2074
+ `Capability ${file.owner} would overwrite existing file: ${file.relativePath}`
2075
+ );
2076
+ }
2077
+ kept.push(file.relativePath);
2078
+ }
2079
+ const packageMerge = mergedPackageJson(projectDir, ordered, options.resolveDependencySpec);
2080
+ const assetMerge = mergedAssetManifest(projectDir, ordered);
2081
+ const adapterMerge = mergedAdapterModule(projectDir, ordered);
2082
+ const writtenFiles = toWrite.map((file) => file.relativePath);
2083
+ if (packageMerge?.changed) writtenFiles.push("package.json");
2084
+ if (assetMerge?.changed) writtenFiles.push(ASSET_MANIFEST_FILE);
2085
+ if (adapterMerge?.changed) writtenFiles.push(ADAPTER_MODULE_FILE);
2086
+ const stamps = newManifests.map((manifest) => ({
2087
+ bytes: Buffer.from(
2088
+ `${JSON.stringify({ id: manifest.id, version: manifest.version }, null, 2)}
2089
+ `
2090
+ ),
2091
+ relativePath: capabilityStampPath(manifest)
2092
+ }));
2093
+ for (const stamp of stamps) writtenFiles.push(stamp.relativePath);
2094
+ const dependencyNames = packageMerge?.changed ? [
2095
+ ...new Set(
2096
+ ordered.flatMap((manifest) => [
2097
+ ...Object.keys(manifest.packageJson?.dependencies ?? {}),
2098
+ ...Object.keys(manifest.packageJson?.devDependencies ?? {})
2099
+ ])
2100
+ )
2101
+ ].sort() : [];
2102
+ if (!options.dryRun) {
2103
+ if (options.installDependencies && dependencyNames.length > 0 && packageMerge) {
2104
+ const packagePath = join3(projectDir, "package.json");
2105
+ const original = readFileSync2(packagePath);
2106
+ const prepared = JSON.parse(original.toString("utf8"));
2107
+ const merged = JSON.parse(packageMerge.bytes.toString("utf8"));
2108
+ for (const section of ["dependencies", "devDependencies"]) {
2109
+ if (merged[section]) prepared[section] = merged[section];
2110
+ }
2111
+ const preparedBytes = Buffer.from(`${JSON.stringify(prepared, null, 2)}
2112
+ `);
2113
+ writeFileSync2(packagePath, preparedBytes);
2114
+ try {
2115
+ options.installDependencies(dependencyNames);
2116
+ } catch (error) {
2117
+ if (existsSync2(packagePath) && readFileSync2(packagePath).equals(preparedBytes)) {
2118
+ writeFileSync2(packagePath, original);
2119
+ }
2120
+ throw error;
2121
+ }
2122
+ if (!existsSync2(packagePath) || !readFileSync2(packagePath).equals(preparedBytes)) {
2123
+ throw new Error(
2124
+ "package.json changed during dependency installation; edits were preserved. Retry the capability addition."
2125
+ );
2126
+ }
2127
+ const { installDependencies: _installer, ...publishOptions } = options;
2128
+ const published = addCapabilities(publishOptions);
2129
+ return {
2130
+ ...published,
2131
+ dependencyNames,
2132
+ writtenFiles: [.../* @__PURE__ */ new Set([...published.writtenFiles, "package.json"])].sort()
2133
+ };
2134
+ }
2135
+ const isContribution = (file) => file.relativePath.replaceAll("\\", "/").startsWith("src/contributions/");
2136
+ const write = (file) => {
2137
+ const target = join3(projectDir, file.relativePath);
2138
+ mkdirSync2(dirname(target), { recursive: true });
2139
+ writeFileSync2(target, file.bytes);
2140
+ };
2141
+ for (const file of toWrite.filter((file2) => !isContribution(file2))) write(file);
2142
+ if (assetMerge?.changed) {
2143
+ writeFileSync2(join3(projectDir, ASSET_MANIFEST_FILE), assetMerge.bytes);
2144
+ }
2145
+ if (adapterMerge?.changed) {
2146
+ writeFileSync2(join3(projectDir, ADAPTER_MODULE_FILE), adapterMerge.bytes);
2147
+ }
2148
+ if (packageMerge?.changed) writeFileSync2(join3(projectDir, "package.json"), packageMerge.bytes);
2149
+ for (const file of toWrite.filter(isContribution)) write(file);
2150
+ for (const stamp of stamps) write(stamp);
2151
+ }
2152
+ return {
2153
+ alreadyInstalled,
2154
+ declaredAssets: assetMerge?.declared ?? [],
2155
+ unplacedRegions: adapterMerge?.unplaced ?? [],
2156
+ dependencyNames,
2157
+ dryRun: options.dryRun ?? false,
2158
+ installed: newManifests.map((manifest) => manifest.id),
2159
+ kept: kept.sort(),
2160
+ planned: ordered.map((manifest) => manifest.id),
2161
+ projectDir,
2162
+ writtenFiles: writtenFiles.sort()
2163
+ };
2164
+ }
2165
+
2166
+ // node/scaffold/engine-version.ts
2167
+ var SEMVER_RE = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z-.]+))?(?:\+([0-9A-Za-z-.]+))?$/;
2168
+ function parseSemver(version) {
2169
+ const match = SEMVER_RE.exec(version);
2170
+ if (!match) return null;
2171
+ return [Number(match[1]), Number(match[2]), Number(match[3])];
2172
+ }
2173
+ function compareTuples(a, b) {
2174
+ for (let i = 0; i < 3; i++) {
2175
+ if (a[i] < b[i]) return -1;
2176
+ if (a[i] > b[i]) return 1;
2177
+ }
2178
+ return 0;
2179
+ }
2180
+ function satisfiesRange(version, range) {
2181
+ const versionTuple = parseSemver(version);
2182
+ if (!versionTuple) return false;
2183
+ if (range.startsWith("^")) {
2184
+ const base = parseSemver(range.slice(1));
2185
+ return base ? satisfiesCaret(versionTuple, base) : true;
2186
+ }
2187
+ if (range.startsWith("~")) {
2188
+ const base = parseSemver(range.slice(1));
2189
+ return base ? satisfiesTilde(versionTuple, base) : true;
2190
+ }
2191
+ const exact = parseSemver(range);
2192
+ return exact ? compareTuples(versionTuple, exact) === 0 : true;
2193
+ }
2194
+ function satisfiesCaret(version, base) {
2195
+ if (compareTuples(version, base) < 0) return false;
2196
+ const [vMaj, vMin, vPat] = version;
2197
+ const [bMaj, bMin, bPat] = base;
2198
+ if (bMaj > 0) return vMaj === bMaj;
2199
+ if (bMin > 0) return vMaj === 0 && vMin === bMin;
2200
+ return vMaj === 0 && vMin === 0 && vPat === bPat;
2201
+ }
2202
+ function satisfiesTilde(version, base) {
2203
+ if (compareTuples(version, base) < 0) return false;
2204
+ return version[0] === base[0] && version[1] === base[1];
2205
+ }
2206
+
2207
+ // node/scaffold/templates.json
2208
+ var templates_default = {
2209
+ $comment: 'The empty project and the named presets of additions. NO EXAMPLES SHIP IN THE FIRST LAUNCH (2026-09-19, docs/WORK.md \xA7The examples are ARCHIVED): the three promoted `source: "example:<id>"` rows went with them to the tag archive/examples-2026-09-19. The `example:` source form is still parsed and scaffoldable \u2014 restoring the tag restores the rows without a code change.',
2210
+ registryVersion: 1,
2211
+ templates: [
2212
+ {
2213
+ id: "empty",
2214
+ title: "Empty project",
2215
+ description: "A project that declares nothing yet \u2014 add a 3D world, a UI, a server or models from here.",
2216
+ source: "template:empty",
2217
+ whatsInside: [
2218
+ "No roots, no configurations",
2219
+ "The four settings layers",
2220
+ "Add what the project needs"
2221
+ ]
2222
+ },
2223
+ {
2224
+ id: "prototype",
2225
+ title: "Game prototype",
2226
+ description: "A 3D world with modeling tools for a playable prototype, without required Data, Game Inspector or Analytics panels.",
2227
+ source: "template:prototype",
2228
+ whatsInside: [
2229
+ "Three.js world root",
2230
+ "Blender modeling tools",
2231
+ "Neutral daylight scene + focal cube prefab",
2232
+ "No required development panels",
2233
+ "No preselected genre"
2234
+ ]
2235
+ },
2236
+ {
2237
+ id: "game",
2238
+ title: "Game development",
2239
+ description: "A 3D world with modeling tools and multiplayer configuration. Nothing preselected errors; add the Data / Game Inspector / Analytics panels with --with studio when the game wants them.",
2240
+ source: "template:game",
2241
+ whatsInside: [
2242
+ "Three.js world root",
2243
+ "Blender modeling tools",
2244
+ "Neutral daylight scene + focal cube prefab",
2245
+ "server + multiplayer configurations",
2246
+ "No required development panels",
2247
+ "No preselected genre"
2248
+ ]
2249
+ },
2250
+ {
2251
+ id: "website",
2252
+ title: "Website / UI",
2253
+ description: "A React root mounted as a DOM layer \u2014 JSX as the authored truth.",
2254
+ source: "template:website",
2255
+ whatsInside: [
2256
+ "React DOM root",
2257
+ "Styled shell page",
2258
+ "react-root capability"
2259
+ ]
2260
+ },
2261
+ {
2262
+ id: "models",
2263
+ title: "Models",
2264
+ description: "The blender capability alone: Blender in the tab \u2014 .blend models under src/models/ with the bpy that authored them, the Model document and the model finder. No world to run.",
2265
+ source: "template:models",
2266
+ whatsInside: [
2267
+ "blender capability (@volter/editor-blender + @volter/blender-engine)",
2268
+ "src/models/ + the model finder",
2269
+ "Opens in the Model workspace"
2270
+ ]
2271
+ },
2272
+ {
2273
+ id: "full",
2274
+ title: "Everything",
2275
+ description: "Every addition in one project \u2014 a 3D world, a UI root, a multiplayer server, development panels and models. The composition acceptance: nothing here special-cases the presence of anything else.",
2276
+ source: "template:full",
2277
+ whatsInside: [
2278
+ "Three.js world + React DOM root",
2279
+ "server + multiplayer configurations",
2280
+ "Data, Game Inspector and Analytics stubs",
2281
+ "blender capability",
2282
+ "Game, Model and every other workspace"
2283
+ ]
2284
+ }
2285
+ ]
2286
+ };
2287
+
2288
+ // node/scaffold/templates.ts
2289
+ var SCAFFOLD_PRESENTATIONS = ["blank"];
2290
+ function parseTemplateSource(source) {
2291
+ const exampleId = source.startsWith("example:") ? source.slice("example:".length) : void 0;
2292
+ if (exampleId !== void 0) {
2293
+ if (exampleId.length === 0) throw new Error("Template registry: empty example id in source");
2294
+ return { type: "example", exampleId };
2295
+ }
2296
+ const template = source.startsWith("template:") ? source.slice("template:".length) : void 0;
2297
+ if (template !== void 0) {
2298
+ if (template.length === 0) throw new Error("Template registry: empty preset name in source");
2299
+ return { type: "template", template };
2300
+ }
2301
+ throw new Error(
2302
+ `Template registry: unparseable source "${source}" (expected "template:<id>" or "example:<id>")`
2303
+ );
2304
+ }
2305
+ function assertEntry(value, index) {
2306
+ if (typeof value !== "object" || value === null) {
2307
+ throw new Error(`Template registry: entry ${index} is not an object`);
2308
+ }
2309
+ const entry = value;
2310
+ for (const field of ["id", "title", "description", "source"]) {
2311
+ if (typeof entry[field] !== "string" || entry[field].length === 0) {
2312
+ throw new Error(`Template registry: entry ${index} is missing a non-empty "${field}"`);
2313
+ }
2314
+ }
2315
+ if (entry["thumbnail"] !== void 0 && typeof entry["thumbnail"] !== "string") {
2316
+ throw new Error(`Template registry: entry ${index} has a non-string "thumbnail"`);
2317
+ }
2318
+ if (entry["whatsInside"] !== void 0) {
2319
+ const bullets = entry["whatsInside"];
2320
+ if (!Array.isArray(bullets) || bullets.length === 0 || bullets.some((item) => typeof item !== "string" || item.length === 0)) {
2321
+ throw new Error(
2322
+ `Template registry: entry ${index} has an invalid "whatsInside" (non-empty string array expected)`
2323
+ );
2324
+ }
2325
+ }
2326
+ if (entry["presentation"] !== void 0) {
2327
+ const presentation = entry["presentation"];
2328
+ if (typeof presentation !== "string" || !SCAFFOLD_PRESENTATIONS.includes(presentation)) {
2329
+ throw new Error(
2330
+ `Template registry: entry ${index} declares presentation "${String(presentation)}" (expected one of ${SCAFFOLD_PRESENTATIONS.join(", ")})`
2331
+ );
2332
+ }
2333
+ }
2334
+ parseTemplateSource(entry["source"]);
2335
+ return entry;
2336
+ }
2337
+ function loadTemplateRegistry() {
2338
+ const raw = templates_default;
2339
+ if (typeof raw !== "object" || raw === null) {
2340
+ throw new Error("Template registry: templates.json is not an object");
2341
+ }
2342
+ const doc = raw;
2343
+ if (doc["registryVersion"] !== 1) {
2344
+ throw new Error(
2345
+ `Template registry: unsupported registryVersion ${String(doc["registryVersion"])}`
2346
+ );
2347
+ }
2348
+ if (!Array.isArray(doc["templates"]) || doc["templates"].length === 0) {
2349
+ throw new Error('Template registry: "templates" must be a non-empty array');
2350
+ }
2351
+ const templates = doc["templates"].map((entry, index) => assertEntry(entry, index));
2352
+ const seen = /* @__PURE__ */ new Set();
2353
+ for (const entry of templates) {
2354
+ if (seen.has(entry.id)) throw new Error(`Template registry: duplicate id "${entry.id}"`);
2355
+ seen.add(entry.id);
2356
+ }
2357
+ return { registryVersion: 1, templates };
2358
+ }
2359
+
2360
+ // node/scaffold/scaffold.ts
2361
+ var RUNTIME_PACKAGES = [
2362
+ { name: "@volter/editor-project", dir: "editor-project" },
2363
+ { name: "@volter/threejs-runtime", dir: "threejs-runtime" },
2364
+ { name: "@volter/game-runtime", dir: "game-runtime" }
2365
+ ];
2366
+ function resolveScaffoldPackageDir(monoRoot, checkoutRelativePath, packageName) {
2367
+ const checkoutDir = join4(monoRoot, checkoutRelativePath);
2368
+ if (existsSync3(checkoutDir)) return checkoutDir;
2369
+ const installedDir = join4(monoRoot, "node_modules", packageName);
2370
+ if (existsSync3(installedDir)) return installedDir;
2371
+ return checkoutDir;
2372
+ }
2373
+ function resolveScaffoldExamplesDir(monoRoot, productDir) {
2374
+ const checkoutExamples = join4(monoRoot, "examples");
2375
+ if (existsSync3(checkoutExamples)) return checkoutExamples;
2376
+ return join4(productDir, "examples");
2377
+ }
2378
+ var STARTER_MODEL_FILES = ["cube.blend", "cube.py"];
2379
+ function resolveScaffoldStarterDir(productDir) {
2380
+ return join4(productDir, "starter");
2381
+ }
2382
+ function slugify(name) {
2383
+ return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
2384
+ }
2385
+ function writeJson(path, data) {
2386
+ writeFileSync3(path, `${JSON.stringify(data, null, 2)}
2387
+ `, "utf-8");
2388
+ }
2389
+ function rewriteEngineRelativeFilePath(original, _engineRelPath) {
2390
+ for (const pkg of RUNTIME_PACKAGES) {
2391
+ const marker = `${pkg.dir}/src/`;
2392
+ const idx = original.indexOf(marker);
2393
+ if (idx === -1) continue;
2394
+ return `node_modules/${pkg.name}/src/${original.slice(idx + marker.length)}`;
2395
+ }
2396
+ return original;
2397
+ }
2398
+ function pinSharedDependencyVersions(pkg, engineDir, monoRoot, fallbackDir) {
2399
+ const engineDeps = resolveEngineDependencyNames(engineDir, fallbackDir);
2400
+ if (!engineDeps) return;
2401
+ for (const field of ["dependencies", "devDependencies"]) {
2402
+ const deps = pkg[field];
2403
+ if (!deps) continue;
2404
+ for (const name of Object.keys(deps)) {
2405
+ if (!engineDeps.has(name) || name.startsWith("@volter/")) continue;
2406
+ const installedVersion = readInstalledVersionWithFallback(monoRoot, fallbackDir, name);
2407
+ if (!installedVersion) continue;
2408
+ if (satisfiesRange(installedVersion, deps[name])) {
2409
+ deps[name] = installedVersion;
2410
+ }
2411
+ }
2412
+ }
2413
+ }
2414
+ var STANDALONE_PINNED_DEPENDENCIES = ["@playwright/test", "ztrack"];
2415
+ function pinStandaloneDependencyVersions(pkg, monoRoot) {
2416
+ const deps = pkg.devDependencies;
2417
+ if (!deps) return;
2418
+ for (const name of STANDALONE_PINNED_DEPENDENCIES) {
2419
+ const declaredRange = deps[name];
2420
+ if (!declaredRange) continue;
2421
+ const installedVersion = readInstalledVersion(monoRoot, name);
2422
+ if (!installedVersion) continue;
2423
+ if (satisfiesRange(installedVersion, declaredRange)) {
2424
+ deps[name] = installedVersion;
2425
+ }
2426
+ }
2427
+ }
2428
+ var PROJECT_ROADMAP_RELATIVE_PATH = "ROADMAP.md";
2429
+ var PROJECT_DEVELOPMENT_LOG_RELATIVE_PATH = "DEVLOG.md";
2430
+ function rewriteRoadmap(targetDir, name) {
2431
+ const path = join4(targetDir, PROJECT_ROADMAP_RELATIVE_PATH);
2432
+ if (!existsSync3(path)) return;
2433
+ const body = readFileSync3(path, "utf-8").replace(/^# .*$/m, `# Roadmap \u2014 ${name}`);
2434
+ writeFileSync3(path, body, "utf-8");
2435
+ }
2436
+ function resolveEngineDependencyNames(engineDir, fallbackDir) {
2437
+ const primary = readEngineDependencyNames(engineDir);
2438
+ if (primary) return primary;
2439
+ if (!fallbackDir) return void 0;
2440
+ return readEngineDependencyNames(join4(fallbackDir, "node_modules", "@volter", "game-runtime"));
2441
+ }
2442
+ function readInstalledVersionWithFallback(monoRoot, fallbackDir, name) {
2443
+ const primary = readInstalledVersion(monoRoot, name);
2444
+ if (primary) return primary;
2445
+ if (!fallbackDir) return void 0;
2446
+ return readInstalledVersion(fallbackDir, name);
2447
+ }
2448
+ function readEngineDependencyNames(engineDir) {
2449
+ try {
2450
+ const enginePkg = JSON.parse(readFileSync3(join4(engineDir, "package.json"), "utf-8"));
2451
+ return new Set(Object.keys(enginePkg.dependencies ?? {}));
2452
+ } catch {
2453
+ return void 0;
2454
+ }
2455
+ }
2456
+ function readInstalledVersion(monoRoot, packageName) {
2457
+ try {
2458
+ const installed = JSON.parse(
2459
+ readFileSync3(join4(monoRoot, "node_modules", packageName, "package.json"), "utf-8")
2460
+ );
2461
+ return installed.version;
2462
+ } catch {
2463
+ return void 0;
2464
+ }
2465
+ }
2466
+ function materializeTemplate(templateDir, targetDir, examplesDir, exampleId) {
2467
+ if (exampleId === void 0) {
2468
+ mkdirSync3(targetDir, { recursive: true });
2469
+ cpSync(templateDir, targetDir, {
2470
+ recursive: true,
2471
+ filter: (src) => shouldCopyStarterPath(templateDir, src)
2472
+ });
2473
+ return;
2474
+ }
2475
+ {
2476
+ const examplesSrcDir = join4(examplesDir, exampleId);
2477
+ if (!existsSync3(examplesSrcDir) || !hasManifest(examplesSrcDir)) {
2478
+ if (!existsSync3(examplesDir) || readdirSync3(examplesDir).length === 0) {
2479
+ throw new Error(
2480
+ `Cannot scaffold from example "${exampleId}": NO EXAMPLES SHIP IN THIS RELEASE.
2481
+ They are archived whole at the git tag \`archive/examples-2026-09-19\` and are restored from it when their turn comes (docs/WORK.md \xA7The examples are ARCHIVED).
2482
+ Fix: create the project without --example, which scaffolds from the starter template your product composes.`
2483
+ );
2484
+ }
2485
+ throw new Error(
2486
+ `Unknown example id "${exampleId}": no vgai.project.json found at ${examplesSrcDir}`
2487
+ );
2488
+ }
2489
+ mkdirSync3(targetDir, { recursive: true });
2490
+ if (!copyTrackedExampleFiles(examplesSrcDir, targetDir)) {
2491
+ cpSync(examplesSrcDir, targetDir, {
2492
+ recursive: true,
2493
+ filter: (src) => shouldCopyExamplePath(examplesSrcDir, src)
2494
+ });
2495
+ }
2496
+ return;
2497
+ }
2498
+ }
2499
+ function restorePackagedTemplateDotfiles(productDir, targetDir) {
2500
+ for (const filename of [".gitignore"]) {
2501
+ const destination = join4(targetDir, filename);
2502
+ if (existsSync3(destination)) continue;
2503
+ const source = join4(productDir, "template-dotfiles", filename.slice(1));
2504
+ if (!existsSync3(source)) {
2505
+ throw new Error(
2506
+ `Editor distribution omitted ${filename} and its template-dotfiles/${filename.slice(1)} fallback`
2507
+ );
2508
+ }
2509
+ copyFileSync(source, destination);
2510
+ }
2511
+ }
2512
+ var EXAMPLE_PROJECT_SUPPORT_PATHS = [
2513
+ ".agents",
2514
+ ".claude",
2515
+ ".github",
2516
+ ".mcp.json",
2517
+ ".npmrc",
2518
+ "AGENTS.md",
2519
+ "CLAUDE.md",
2520
+ PROJECT_DEVELOPMENT_LOG_RELATIVE_PATH
2521
+ ];
2522
+ function installExampleProjectSupport(templateDir, targetDir) {
2523
+ for (const relativePath of EXAMPLE_PROJECT_SUPPORT_PATHS) {
2524
+ const source = join4(templateDir, relativePath);
2525
+ const destination = join4(targetDir, relativePath);
2526
+ if (!existsSync3(source)) continue;
2527
+ copyMissingProjectSupport(templateDir, source, destination);
2528
+ }
2529
+ }
2530
+ function assertDevelopmentLog(targetDir) {
2531
+ const path = join4(targetDir, PROJECT_DEVELOPMENT_LOG_RELATIVE_PATH);
2532
+ if (!existsSync3(path)) {
2533
+ throw new Error(
2534
+ `Scaffolded project is missing ${PROJECT_DEVELOPMENT_LOG_RELATIVE_PATH}; restore it from the VGAI starter template`
2535
+ );
2536
+ }
2537
+ }
2538
+ function copyMissingProjectSupport(templateDir, source, destination) {
2539
+ if (!shouldCopyStarterPath(templateDir, source)) return;
2540
+ const sourceStat = lstatSync(source);
2541
+ if (sourceStat.isDirectory()) {
2542
+ if (existsSync3(destination) && !lstatSync(destination).isDirectory()) return;
2543
+ mkdirSync3(destination, { recursive: true });
2544
+ for (const entry of readdirSync3(source)) {
2545
+ copyMissingProjectSupport(templateDir, join4(source, entry), join4(destination, entry));
2546
+ }
2547
+ return;
2548
+ }
2549
+ if (!sourceStat.isFile() || existsSync3(destination)) return;
2550
+ mkdirSync3(dirname2(destination), { recursive: true });
2551
+ copyFileSync(source, destination);
2552
+ }
2553
+ function trackedExampleFiles(exampleDir) {
2554
+ const result = spawnSync("git", ["-C", exampleDir, "ls-files", "--cached", "-z", "--", "."], {
2555
+ stdio: ["ignore", "pipe", "ignore"]
2556
+ });
2557
+ if (result.status !== 0 || !result.stdout) return null;
2558
+ const paths = result.stdout.toString("utf8").split("\0").filter(Boolean);
2559
+ return paths.includes("vgai.project.json") ? paths : null;
2560
+ }
2561
+ function copyTrackedExampleFiles(exampleDir, targetDir) {
2562
+ const paths = trackedExampleFiles(exampleDir);
2563
+ if (!paths) return false;
2564
+ for (const relativePath of paths) {
2565
+ const source = join4(exampleDir, relativePath);
2566
+ if (!shouldCopyExamplePath(exampleDir, source)) continue;
2567
+ if (!existsSync3(source)) continue;
2568
+ const sourceStat = lstatSync(source);
2569
+ if (!sourceStat.isFile()) {
2570
+ throw new Error(`Example remixes only accept regular tracked files: ${source}`);
2571
+ }
2572
+ const destination = join4(targetDir, relativePath);
2573
+ mkdirSync3(dirname2(destination), { recursive: true });
2574
+ copyFileSync(source, destination);
2575
+ }
2576
+ return true;
2577
+ }
2578
+ function applyPresentation(_targetDir, presentation) {
2579
+ switch (presentation) {
2580
+ case "blank":
2581
+ return;
2582
+ }
2583
+ }
2584
+ function writeExampleReadme(targetDir, projectName, exampleId) {
2585
+ const path = join4(targetDir, "README.md");
2586
+ if (existsSync3(path)) return;
2587
+ writeFileSync3(
2588
+ path,
2589
+ `# ${projectName}
2590
+
2591
+ An editable standalone VGAI project scaffolded from the \`${exampleId ?? "example"}\` reference. Its gameplay source and assets were copied unchanged; this folder is now your project.
2592
+
2593
+ \`\`\`bash
2594
+ npm run dev # open/reuse the visual editor
2595
+ npm run vgai -- play # verify Play mode
2596
+ npm run typecheck
2597
+ npm run validate-manifest
2598
+ npm run validate-assets
2599
+ \`\`\`
2600
+
2601
+ Coding agents start with \`AGENTS.md\`; MCP-compatible hosts discover the project-scoped server through \`.mcp.json\`.
2602
+ `,
2603
+ "utf-8"
2604
+ );
2605
+ }
2606
+ function shouldCopyExamplePath(exampleDir, sourcePath) {
2607
+ const relativePath = relative3(exampleDir, sourcePath).replaceAll("\\", "/");
2608
+ const topLevel = relativePath.split("/")[0] ?? "";
2609
+ const segments = relativePath.split("/");
2610
+ return !["node_modules", "dist", "logs", ".vgai", ".git", "package-lock.json"].includes(topLevel) && !segments.some((segment) => segment === ".env" || segment.startsWith(".env."));
2611
+ }
2612
+ function shouldCopyStarterPath(templateDir, sourcePath) {
2613
+ const relativePath = relative3(templateDir, sourcePath).replaceAll("\\", "/");
2614
+ const topLevel = relativePath.split("/")[0] ?? "";
2615
+ return !["node_modules", "dist", "logs", ".vgai"].includes(topLevel);
2616
+ }
2617
+ function rewritePackageJson(targetDir, slug, engineDir, monoRoot) {
2618
+ const pkgPath = join4(targetDir, "package.json");
2619
+ if (!existsSync3(pkgPath)) return;
2620
+ const pkg = JSON.parse(readFileSync3(pkgPath, "utf-8"));
2621
+ pkg.name = slug;
2622
+ pkg.dependencies = pkg.dependencies ?? {};
2623
+ for (const runtime of RUNTIME_PACKAGES)
2624
+ pkg.dependencies[runtime.name] = engineDependencySpec(monoRoot, runtime.name);
2625
+ for (const name of ["@volter/editor-live", "@volter/game-live", "@volter/editor-sdk"]) {
2626
+ if (pkg.devDependencies?.[name] !== void 0) {
2627
+ pkg.devDependencies[name] = engineDependencySpec(monoRoot, name);
2628
+ }
2629
+ }
2630
+ for (const section of ["dependencies", "devDependencies"]) {
2631
+ const deps = pkg[section];
2632
+ if (!deps) continue;
2633
+ for (const [name, spec] of Object.entries(deps)) {
2634
+ if (!name.startsWith("@volter/") || !spec.startsWith("file:")) continue;
2635
+ deps[name] = engineDependencySpec(monoRoot, name, spec.slice("file:".length));
2636
+ }
2637
+ }
2638
+ pkg.scripts ??= {};
2639
+ for (const [name, script] of Object.entries(pkg.scripts)) {
2640
+ if (name !== "vgai" && script.startsWith("vgai ")) {
2641
+ pkg.scripts[name] = `npm run vgai -- ${script.slice("vgai ".length)}`;
2642
+ }
2643
+ }
2644
+ pkg.devDependencies = pkg.devDependencies ?? {};
2645
+ pkg.devDependencies["@volter/editor-core"] = engineDependencySpec(monoRoot, "@volter/editor-core");
2646
+ pinSharedDependencyVersions(pkg, engineDir, monoRoot);
2647
+ pinStandaloneDependencyVersions(pkg, monoRoot);
2648
+ writeJson(pkgPath, pkg);
2649
+ }
2650
+ function resolvePackageRoots() {
2651
+ return {
2652
+ engineRelPath: "node_modules/@volter/game-runtime",
2653
+ editorRelPath: "node_modules/@volter/editor-core",
2654
+ liveRelPath: "node_modules/@volter/editor-live",
2655
+ editorSdkRelPath: "node_modules/@volter/editor-sdk"
2656
+ };
2657
+ }
2658
+ function versionFromCheckout(monoRoot, relPath) {
2659
+ const cleaned = relPath.replace(/^(\.\.\/)+/, "");
2660
+ const candidate = resolve2(monoRoot, cleaned, "package.json");
2661
+ if (!existsSync3(candidate)) return void 0;
2662
+ try {
2663
+ const parsed = JSON.parse(readFileSync3(candidate, "utf8"));
2664
+ return typeof parsed.version === "string" ? parsed.version : void 0;
2665
+ } catch {
2666
+ return void 0;
2667
+ }
2668
+ }
2669
+ function engineDependencySpec(monoRoot, packageName, checkoutRelPath = "") {
2670
+ const version = readInstalledVersion(monoRoot, packageName) ?? versionFromCheckout(monoRoot, checkoutRelPath);
2671
+ if (!version) {
2672
+ throw new Error(`Cannot scaffold: ${packageName} has no resolvable version in ${monoRoot}.`);
2673
+ }
2674
+ return `^${version}`;
2675
+ }
2676
+ function rewriteGameManifest(targetDir, name, slug, additions, monoRoot) {
2677
+ const manifestPath = join4(targetDir, "vgai.project.json");
2678
+ const engineVersion = readInstalledVersion(monoRoot, "@volter/editor-project");
2679
+ let manifest;
2680
+ if (existsSync3(manifestPath)) {
2681
+ manifest = JSON.parse(readFileSync3(manifestPath, "utf-8"));
2682
+ } else {
2683
+ manifest = {
2684
+ manifestVersion: 2,
2685
+ name,
2686
+ version: "0.1.0",
2687
+ engine: { version: engineVersion ?? "0.0.0" },
2688
+ // A three root's document IS its TSX entry. (This branch only fires when
2689
+ // the template shipped NO manifest, which it always does.)
2690
+ roots: [{ id: "world", adapter: "three", entry: "src/world.tsx" }],
2691
+ resolution: { width: 1280, height: 720 }
2692
+ };
2693
+ }
2694
+ manifest["name"] = name;
2695
+ manifest["manifestVersion"] = 2;
2696
+ manifest["$schema"] = "./node_modules/@volter/editor-project/schemas/vgai-project.schema.json";
2697
+ manifest["appId"] = `com.example.${slug.replace(/[^a-zA-Z0-9]/g, "")}`;
2698
+ if (additions) {
2699
+ const roots = [];
2700
+ if (additions.has("three"))
2701
+ roots.push({ id: "world", adapter: "three", entry: "src/world.tsx" });
2702
+ if (additions.has("ui"))
2703
+ roots.push({ id: "ui", adapter: "dom", entry: "src/ui/game.tsx", zOrder: 0 });
2704
+ manifest["roots"] = roots;
2705
+ const configurations = manifest["configurations"] ?? [];
2706
+ manifest["configurations"] = configurations.filter((configuration) => {
2707
+ const kind = configuration["kind"];
2708
+ if (kind === "process" || kind === "compound") return additions.has("server");
2709
+ return true;
2710
+ });
2711
+ }
2712
+ if (engineVersion) {
2713
+ manifest["engine"] = {
2714
+ ...manifest["engine"],
2715
+ version: engineVersion
2716
+ };
2717
+ }
2718
+ writeJson(manifestPath, manifest);
2719
+ return manifest;
2720
+ }
2721
+ function repinEngineAfterInstall(targetDir) {
2722
+ const installed = readInstalledVersion(targetDir, "@volter/editor-project");
2723
+ if (!installed) return null;
2724
+ const manifestPath = resolveManifestPath(targetDir);
2725
+ let manifest;
2726
+ try {
2727
+ manifest = JSON.parse(readFileSync3(manifestPath, "utf-8"));
2728
+ } catch {
2729
+ return null;
2730
+ }
2731
+ const engine = manifest["engine"] ?? {};
2732
+ const from = typeof engine["version"] === "string" ? engine["version"] : "";
2733
+ if (from === installed) return null;
2734
+ manifest["engine"] = { ...engine, version: installed };
2735
+ writeJson(manifestPath, manifest);
2736
+ const baselinePath = join4(targetDir, SCAFFOLD_BASELINE_RELATIVE_PATH);
2737
+ try {
2738
+ const baseline = JSON.parse(readFileSync3(baselinePath, "utf-8"));
2739
+ baseline.engineVersion = installed;
2740
+ baseline.files["vgai.project.json"] = hashFile(manifestPath);
2741
+ writeFileSync3(baselinePath, `${JSON.stringify(baseline, null, 2)}
2742
+ `, "utf-8");
2743
+ } catch {
2744
+ }
2745
+ return { from, to: installed };
2746
+ }
2747
+ function checkoutVgaiPackageDirs(monoRoot) {
2748
+ const found = /* @__PURE__ */ new Map();
2749
+ const packagesDir = join4(monoRoot, "packages");
2750
+ let entries;
2751
+ try {
2752
+ entries = readdirSync3(packagesDir);
2753
+ } catch {
2754
+ return found;
2755
+ }
2756
+ for (const entry of entries) {
2757
+ const dir = join4(packagesDir, entry);
2758
+ try {
2759
+ if (!statSync2(dir).isDirectory()) continue;
2760
+ } catch {
2761
+ continue;
2762
+ }
2763
+ let name;
2764
+ try {
2765
+ name = JSON.parse(readFileSync3(join4(dir, "package.json"), "utf-8")).name;
2766
+ } catch {
2767
+ continue;
2768
+ }
2769
+ if (typeof name === "string" && name.startsWith("@volter/")) found.set(name, dir);
2770
+ }
2771
+ return found;
2772
+ }
2773
+ function pointUnpublishedPackagesAtCheckout(projectDir, monoRoot) {
2774
+ const pkgPath = join4(projectDir, "package.json");
2775
+ let pkg;
2776
+ try {
2777
+ pkg = JSON.parse(readFileSync3(pkgPath, "utf-8"));
2778
+ } catch {
2779
+ return [];
2780
+ }
2781
+ const rewritten = [];
2782
+ for (const section of ["dependencies", "devDependencies"]) {
2783
+ const deps = pkg[section];
2784
+ if (!deps) continue;
2785
+ for (const name of Object.keys(deps)) {
2786
+ const spec = checkoutPackageSpec(name, monoRoot);
2787
+ if (spec === null || deps[name] === spec) continue;
2788
+ deps[name] = spec;
2789
+ rewritten.push(name);
2790
+ }
2791
+ }
2792
+ if (rewritten.length > 0) writeJson(pkgPath, pkg);
2793
+ return rewritten;
2794
+ }
2795
+ function checkoutPackageSpec(name, monoRoot) {
2796
+ const dir = checkoutVgaiPackageDirs(monoRoot).get(name);
2797
+ return dir === void 0 ? null : `file:${dir}`;
2798
+ }
2799
+ function writeEditorPackages(targetDir, wanted) {
2800
+ const pkgPath = join4(targetDir, "package.json");
2801
+ const pkg = JSON.parse(readFileSync3(pkgPath, "utf-8"));
2802
+ const kit = new Set(KIT_DECLARED_PACKAGES);
2803
+ const replaced = Object.keys(pkg.devDependencies ?? {}).filter(
2804
+ (name) => name.startsWith("@volter/") && !kit.has(name)
2805
+ );
2806
+ const spec = pkg.devDependencies?.["@volter/editor-core"] ?? replaced.map((name) => pkg.devDependencies?.[name]).find((value) => value !== void 0) ?? "*";
2807
+ for (const name of [...replaced, ...wanted]) {
2808
+ delete pkg.dependencies?.[name];
2809
+ delete pkg.devDependencies?.[name];
2810
+ }
2811
+ pkg.devDependencies ??= {};
2812
+ for (const name of wanted) pkg.devDependencies[name] = spec;
2813
+ pkg.devDependencies = Object.fromEntries(
2814
+ Object.entries(pkg.devDependencies).sort(([a], [b]) => a.localeCompare(b))
2815
+ );
2816
+ writeJson(pkgPath, pkg);
2817
+ }
2818
+ function rewriteTemplateVariantFiles(targetDir, composition, additions, starterDir) {
2819
+ if (!additions.has("three") || !additions.has("studio")) {
2820
+ for (const relative4 of STUDIO_OWNED_PATHS) {
2821
+ rmSync2(join4(targetDir, relative4), { force: true });
2822
+ }
2823
+ }
2824
+ writeEditorPackages(targetDir, composition.editorPackages);
2825
+ if (!additions.has("three")) {
2826
+ for (const relative4 of THREE_OWNED_PATHS) {
2827
+ rmSync2(join4(targetDir, relative4), { recursive: true, force: true });
2828
+ }
2829
+ writeFileSync3(join4(targetDir, "vgai.adapter.ts"), adapterSourceFor(additions), "utf-8");
2830
+ } else {
2831
+ const adapterPath = join4(targetDir, "vgai.adapter.ts");
2832
+ const source = joinAdditionFinders(readFileSync3(adapterPath, "utf-8"), additions);
2833
+ writeFileSync3(adapterPath, source, "utf-8");
2834
+ }
2835
+ if (additions.has("blender")) {
2836
+ mkdirSync3(join4(targetDir, "src", "models"), { recursive: true });
2837
+ for (const file of STARTER_MODEL_FILES) {
2838
+ const source = join4(starterDir, file);
2839
+ if (!existsSync3(source))
2840
+ throw new Error(
2841
+ `Cannot scaffold a models project: the starter model ${file} is missing from ${starterDir}. It is a real Blender document, not a string this scaffolder can write, so there is nothing to fall back to.`
2842
+ );
2843
+ writeFileSync3(join4(targetDir, "src", "models", file), readFileSync3(source));
2844
+ }
2845
+ }
2846
+ if (!additions.has("ui")) return;
2847
+ if (additions.has("three")) {
2848
+ for (const [relative4, source] of Object.entries(REACT_ONLY_FILES)) {
2849
+ if (relative4 === "src/main.ts") continue;
2850
+ mkdirSync3(dirname2(join4(targetDir, relative4)), { recursive: true });
2851
+ writeFileSync3(join4(targetDir, relative4), source, "utf-8");
2852
+ }
2853
+ return;
2854
+ }
2855
+ for (const relative4 of REACT_ONLY_REMOVED_PATHS) {
2856
+ rmSync2(join4(targetDir, relative4), { recursive: true, force: true });
2857
+ }
2858
+ mkdirSync3(join4(targetDir, "public"), { recursive: true });
2859
+ mkdirSync3(join4(targetDir, "src", "ui"), { recursive: true });
2860
+ for (const [relative4, source] of Object.entries(REACT_ONLY_FILES)) {
2861
+ writeFileSync3(join4(targetDir, relative4), source, "utf-8");
2862
+ }
2863
+ }
2864
+ function rewriteTsconfig(targetDir, engineRelPath, editorRelPath) {
2865
+ const tsconfigPath = join4(targetDir, "tsconfig.json");
2866
+ if (!existsSync3(tsconfigPath)) return;
2867
+ const parseErrors = [];
2868
+ const tsconfig = parse2(readFileSync3(tsconfigPath, "utf-8"), parseErrors, {
2869
+ allowTrailingComma: true
2870
+ });
2871
+ if (parseErrors.length > 0) {
2872
+ const details = parseErrors.map((error) => `${printParseErrorCode(error.error)} at offset ${error.offset}`).join(", ");
2873
+ throw new Error(`Invalid TypeScript config ${tsconfigPath}: ${details}`);
2874
+ }
2875
+ tsconfig.compilerOptions = tsconfig.compilerOptions ?? {};
2876
+ tsconfig.compilerOptions.paths = {
2877
+ ...Object.fromEntries(
2878
+ RUNTIME_PACKAGES.map((runtime) => [
2879
+ `${runtime.name}/*`,
2880
+ [`node_modules/${runtime.name}/src/*`]
2881
+ ])
2882
+ ),
2883
+ // `@volter/editor-blender`'s two VALUE exports — the look and the layout a models
2884
+ // project's `vgai.adapter.ts` imports. Spelled entry by entry rather than
2885
+ // as a wildcard because the package's `exports` names them individually;
2886
+ // both entries are inert for a project that never declares the package.
2887
+ "@volter/editor-blender/looks": ["node_modules/@volter/editor-blender/src/looks.ts"],
2888
+ "@volter/editor-blender/layouts": ["node_modules/@volter/editor-blender/src/layouts.tsx"]
2889
+ };
2890
+ if (editorRelPath) {
2891
+ tsconfig.compilerOptions.paths["@editor/*"] = [`${editorRelPath}/src/*`];
2892
+ }
2893
+ if (Array.isArray(tsconfig.files)) {
2894
+ tsconfig.files = tsconfig.files.map((f) => rewriteEngineRelativeFilePath(f, engineRelPath));
2895
+ }
2896
+ writeJson(tsconfigPath, tsconfig);
2897
+ }
2898
+ function rewriteViteConfig(targetDir) {
2899
+ const vitePath = join4(targetDir, "vite.config.ts");
2900
+ if (!existsSync3(vitePath)) return;
2901
+ writeFileSync3(vitePath, rewriteViteConfigContent(readFileSync3(vitePath, "utf-8")), "utf-8");
2902
+ }
2903
+ function rewriteViteConfigContent(content) {
2904
+ return ensureReactDedupe(content);
2905
+ }
2906
+ function ensureReactDedupe(content) {
2907
+ const REQUIRED = ["react", "react-dom"];
2908
+ const dedupeMatch = content.match(/dedupe:\s*\[([^\]]*)\]/);
2909
+ if (dedupeMatch) {
2910
+ const inner = dedupeMatch[1] ?? "";
2911
+ const missing = REQUIRED.filter((name) => !new RegExp(`['"]${name}['"]`).test(inner));
2912
+ if (missing.length === 0) return content;
2913
+ const trimmed = inner.trim();
2914
+ const additions = missing.map((name) => `'${name}'`).join(", ");
2915
+ const newInner = trimmed.length === 0 ? additions : `${inner.replace(/,\s*$/, "")}, ${additions}`;
2916
+ return content.replace(dedupeMatch[0], `dedupe: [${newInner}]`);
2917
+ }
2918
+ if (!/resolve:\s*{/.test(content)) return content;
2919
+ return content.replace(
2920
+ /resolve:\s*{/,
2921
+ "resolve: {\n // react/react-dom dedupe (GH #123): see packages/editor/template/vite.config.ts's\n // matching comment for the dual-React-instance root cause this avoids.\n dedupe: ['react', 'react-dom'],"
2922
+ );
2923
+ }
2924
+ function rewriteIndexHtml(targetDir, name) {
2925
+ const htmlPath = join4(targetDir, "index.html");
2926
+ if (!existsSync3(htmlPath)) return;
2927
+ const html = readFileSync3(htmlPath, "utf-8").replace(
2928
+ /<title>.*<\/title>/,
2929
+ `<title>${name}</title>`
2930
+ );
2931
+ writeFileSync3(htmlPath, html, "utf-8");
2932
+ }
2933
+ function scaffoldProject(opts) {
2934
+ const { name, targetDir, monoRoot, exampleId } = opts;
2935
+ const composed = exampleId === void 0;
2936
+ const additions = composed ? new Set(closeAdditions(opts.additions ?? [])) : null;
2937
+ if (composed && !opts.composition) {
2938
+ throw new Error(
2939
+ "scaffoldProject: a composed project needs `composition` \u2014 the editor-side packages and editor declaration its PRODUCT declares (./product.ts). Only an `exampleId` scaffold goes without one."
2940
+ );
2941
+ }
2942
+ const composition = opts.composition;
2943
+ const slug = slugify(name) || slugify(basename(targetDir));
2944
+ if (!slug) throw new Error("Invalid project name");
2945
+ if (existsSync3(targetDir)) {
2946
+ throw new Error(`Directory already exists: ${targetDir}`);
2947
+ }
2948
+ const { productDir } = opts;
2949
+ const templateDir = join4(productDir, "template");
2950
+ const examplesDir = resolveScaffoldExamplesDir(monoRoot, productDir);
2951
+ const catalogDir = join4(productDir, "catalog");
2952
+ const engineDir = resolveScaffoldPackageDir(
2953
+ monoRoot,
2954
+ join4("packages", "game-runtime"),
2955
+ "@volter/game-runtime"
2956
+ );
2957
+ if (!existsSync3(templateDir)) {
2958
+ throw new Error(`Template not found at ${templateDir}. Is this product installed intact?`);
2959
+ }
2960
+ const hasCapabilityDistribution = existsSync3(catalogDir);
2961
+ materializeTemplate(templateDir, targetDir, examplesDir, exampleId);
2962
+ restorePackagedTemplateDotfiles(productDir, targetDir);
2963
+ if (exampleId !== void 0) {
2964
+ installExampleProjectSupport(templateDir, targetDir);
2965
+ writeExampleReadme(targetDir, name, exampleId);
2966
+ }
2967
+ assertDevelopmentLog(targetDir);
2968
+ if (opts.presentation) applyPresentation(targetDir, opts.presentation);
2969
+ const { engineRelPath, editorRelPath } = resolvePackageRoots();
2970
+ rewritePackageJson(targetDir, slug, engineDir, monoRoot);
2971
+ const manifest = rewriteGameManifest(targetDir, name, slug, additions, monoRoot);
2972
+ if (additions && composition) {
2973
+ rewriteTemplateVariantFiles(
2974
+ targetDir,
2975
+ composition,
2976
+ additions,
2977
+ resolveScaffoldStarterDir(productDir)
2978
+ );
2979
+ const adapterPath = join4(targetDir, "vgai.adapter.ts");
2980
+ writeFileSync3(
2981
+ adapterPath,
2982
+ withEditorDeclaration(readFileSync3(adapterPath, "utf-8"), composition.editor),
2983
+ "utf-8"
2984
+ );
2985
+ const agentsPath = join4(targetDir, "AGENTS.md");
2986
+ writeFileSync3(
2987
+ agentsPath,
2988
+ withAgentsContract(readFileSync3(agentsPath, "utf-8"), additions),
2989
+ "utf-8"
2990
+ );
2991
+ }
2992
+ rewriteTsconfig(targetDir, engineRelPath, editorRelPath);
2993
+ rewriteViteConfig(targetDir);
2994
+ rewriteIndexHtml(targetDir, name);
2995
+ rewriteRoadmap(targetDir, name);
2996
+ if (hasCapabilityDistribution) initializeProjectCatalog(targetDir, catalogDir);
2997
+ if (hasCapabilityDistribution && additions) {
2998
+ const ids = [
2999
+ ...additions.has("ui") ? DEFAULT_REACT_CAPABILITIES : [],
3000
+ ...additions.has("blender") ? ["blender"] : []
3001
+ ];
3002
+ if (ids.length > 0)
3003
+ addCapabilities({
3004
+ catalogDir,
3005
+ ids: [...ids],
3006
+ projectDir: targetDir,
3007
+ resolveDependencySpec: (name2, spec) => checkoutPackageSpec(name2, monoRoot) ?? spec
3008
+ });
3009
+ }
3010
+ pointUnpublishedPackagesAtCheckout(targetDir, monoRoot);
3011
+ const engineVersion = readInstalledVersion(monoRoot, "@volter/editor-project") ?? "0.0.0";
3012
+ writeScaffoldBaseline(targetDir, engineVersion, engineDir);
3013
+ return { targetDir, slug, manifest };
3014
+ }
3015
+
3016
+ // node/runtime-image.ts
3017
+ import { spawn } from "node:child_process";
3018
+ import { existsSync as existsSync4, lstatSync as lstatSync2, mkdirSync as mkdirSync4, readFileSync as readFileSync4, readlinkSync, symlinkSync, writeFileSync as writeFileSync4 } from "node:fs";
3019
+ import { homedir } from "node:os";
3020
+ import { dirname as dirname3, join as join5, resolve as resolve3 } from "node:path";
3021
+ var PRODUCT = "@volter/game-editor";
3022
+ function installRootOf(productRoot2) {
3023
+ for (let dir = productRoot2; ; dir = dirname3(dir)) {
3024
+ if (existsSync4(join5(dir, "node_modules", "@volter", "editor-project", "package.json"))) return dir;
3025
+ if (dirname3(dir) === dir) throw new Error(`@volter/editor-project is not installed above ${productRoot2}.`);
3026
+ }
3027
+ }
3028
+ function isCheckout(root) {
3029
+ return existsSync4(join5(root, "packages", "game-editor", "package.json"));
3030
+ }
3031
+ function imageDirFor(version) {
3032
+ const home = process.env["VOLTER_HOME"] ?? join5(homedir(), ".volter");
3033
+ return join5(home, "images", `game-editor-${version}`);
3034
+ }
3035
+ function imageVersion(nodeModules) {
3036
+ try {
3037
+ return JSON.parse(readFileSync4(join5(nodeModules, "@volter", "game-editor", "package.json"), "utf8")).version ?? null;
3038
+ } catch {
3039
+ return null;
3040
+ }
3041
+ }
3042
+ async function ensureRuntimeImage(productRoot2, version) {
3043
+ const root = installRootOf(productRoot2);
3044
+ if (isCheckout(root)) return join5(root, "node_modules");
3045
+ const dir = imageDirFor(version);
3046
+ const nodeModules = join5(dir, "node_modules");
3047
+ if (imageVersion(nodeModules) === version) return nodeModules;
3048
+ mkdirSync4(dir, { recursive: true });
3049
+ writeFileSync4(
3050
+ join5(dir, "package.json"),
3051
+ `${JSON.stringify({ name: `game-editor-image-${version}`, private: true, dependencies: { [PRODUCT]: version } }, null, 2)}
3052
+ `
3053
+ );
3054
+ console.error(`Installing the Volter Game Editor ${version} runtime image (once per version) into ${dir}`);
3055
+ await new Promise((done, fail2) => {
3056
+ const child = spawn(process.platform === "win32" ? "npm.cmd" : "npm", ["install", "--no-audit", "--no-fund"], {
3057
+ cwd: dir,
3058
+ stdio: "inherit"
3059
+ });
3060
+ child.once("error", fail2);
3061
+ child.once("exit", (code) => code === 0 ? done() : fail2(new Error(`The runtime image did not install (${code}); retry creating the project.`)));
3062
+ });
3063
+ if (imageVersion(nodeModules) !== version) throw new Error(`The runtime image at ${dir} does not carry ${PRODUCT}@${version}.`);
3064
+ return nodeModules;
3065
+ }
3066
+ function linkRuntimeImage(projectDir, imageNodeModules) {
3067
+ const link = join5(projectDir, "node_modules");
3068
+ if (existsSync4(link) || isDanglingLink(link)) {
3069
+ if (!lstatSync2(link).isSymbolicLink())
3070
+ throw new Error(`${link} is a real directory: this game installs its own dependencies, so it is not linked to the runtime image.`);
3071
+ if (resolve3(projectDir, readlinkSync(link)) === resolve3(imageNodeModules)) return;
3072
+ throw new Error(`${link} already links ${readlinkSync(link)}; remove it to link the runtime image.`);
3073
+ }
3074
+ symlinkSync(imageNodeModules, link, "dir");
3075
+ }
3076
+ function isDanglingLink(path) {
3077
+ try {
3078
+ return lstatSync2(path).isSymbolicLink();
3079
+ } catch {
3080
+ return false;
3081
+ }
3082
+ }
3083
+
3084
+ // node/scaffold/git-init.ts
3085
+ import { spawnSync as spawnSync2 } from "node:child_process";
3086
+ function runGit(cwd, args) {
3087
+ const result = spawnSync2("git", args, { cwd, encoding: "utf-8" });
3088
+ if (result.error) {
3089
+ const code = result.error.code;
3090
+ return { status: null, stdout: "", stderr: "", unavailable: code === "ENOENT" };
3091
+ }
3092
+ return {
3093
+ status: result.status,
3094
+ stdout: (result.stdout ?? "").trim(),
3095
+ stderr: (result.stderr ?? "").trim(),
3096
+ unavailable: false
3097
+ };
3098
+ }
3099
+ function hasCommitterIdentity(cwd) {
3100
+ const name = runGit(cwd, ["config", "--get", "user.name"]);
3101
+ const email = runGit(cwd, ["config", "--get", "user.email"]);
3102
+ return name.status === 0 && name.stdout !== "" && email.status === 0 && email.stdout !== "";
3103
+ }
3104
+ function initGitRepo(targetDir, projectName) {
3105
+ const insideWorkTree = runGit(targetDir, ["rev-parse", "--is-inside-work-tree"]);
3106
+ if (insideWorkTree.unavailable) {
3107
+ return {
3108
+ status: "skipped",
3109
+ reason: "git-unavailable",
3110
+ notice: "Skipped git init \u2014 git is not on PATH."
3111
+ };
3112
+ }
3113
+ if (insideWorkTree.status === 0 && insideWorkTree.stdout === "true") {
3114
+ return {
3115
+ status: "skipped",
3116
+ reason: "already-in-repo",
3117
+ notice: "Skipped git init \u2014 the project is already inside a git work tree."
3118
+ };
3119
+ }
3120
+ const authorFallback = hasCommitterIdentity(targetDir) ? [] : ["-c", "user.name=vgai", "-c", "user.email=scaffold@vgai"];
3121
+ const steps = [
3122
+ { label: "git init", args: ["init", "--quiet"] },
3123
+ { label: "git add", args: ["add", "-A"] },
3124
+ {
3125
+ label: "git commit",
3126
+ args: [...authorFallback, "commit", "--quiet", "-m", `scaffold ${projectName}`]
3127
+ }
3128
+ ];
3129
+ for (const step of steps) {
3130
+ const run = runGit(targetDir, step.args);
3131
+ if (run.status !== 0) {
3132
+ const detail = run.stderr !== "" ? run.stderr.split("\n")[0] : `exit ${run.status ?? "null"}`;
3133
+ return {
3134
+ status: "failed",
3135
+ reason: "git-command-failed",
3136
+ notice: `Skipped git init \u2014 ${step.label} failed: ${detail}`
3137
+ };
3138
+ }
3139
+ }
3140
+ return {
3141
+ status: "initialized",
3142
+ notice: `Initialized a git repository \u2014 one commit: "scaffold ${projectName}".`
3143
+ };
3144
+ }
3145
+
3146
+ // node/create.ts
3147
+ var productRoot = resolve4(dirname4(fileURLToPath(import.meta.url)), "..");
3148
+ var PRODUCT2 = "@volter/game-editor";
3149
+ var presets = {
3150
+ product: PRODUCT2,
3151
+ // Listed most-wanted first: this order IS the `--template` line in
3152
+ // `volter-game-editor --help`.
3153
+ templates: {
3154
+ // NOTHING PRESELECTED MAY ERROR. `studio` brings three stub contributions
3155
+ // that THROW on render, so a fresh `game` scaffold could never reach the
3156
+ // silent console the agent contract requires; they are an author's TODO
3157
+ // from the moment the author ASKS for those panels (`--with studio`, or
3158
+ // `--template full`).
3159
+ game: { additions: ["three", "server", "blender"] },
3160
+ /** A 3D world and its models: the smallest thing that plays. */
3161
+ prototype: { additions: ["three", "blender"] },
3162
+ // EVERY addition in one project — the composition acceptance made
3163
+ // permanent. Check it against `SCAFFOLD_ADDITIONS` (./scaffold/additions.ts)
3164
+ // when the scaffolder grows one.
3165
+ full: { additions: ["three", "ui", "server", "blender", "studio"] },
3166
+ /** The design skew: a React root and no 3D world. */
3167
+ website: { additions: ["ui"] },
3168
+ /** Nothing but the project — the shape an author adds to. */
3169
+ empty: { additions: [] }
3170
+ },
3171
+ // A bare `create` makes a game that plays; `empty` is asked for by name.
3172
+ defaultTemplate: "game",
3173
+ examples: true,
3174
+ compose(additions) {
3175
+ const three = additions.has("three");
3176
+ const studio = additions.has("studio");
3177
+ const layouts = "@volter/editor-sdk/layouts";
3178
+ const design = additions.has("ui") && !three;
3179
+ return {
3180
+ // THE PRODUCT THIS PROJECT OPENS IN, and the 3D lane beside it:
3181
+ // `@volter/editor-game` is the 3D world's lane, and a project with no 3D
3182
+ // root has nothing for Play, the Game workspace or the instruments over
3183
+ // a running game to run.
3184
+ editorPackages: [PRODUCT2, ...three ? ["@volter/editor-game"] : []],
3185
+ editor: {
3186
+ layout: { name: design ? "DesignLayout" : studio ? "StudioLayout" : "GameLayout", from: layouts },
3187
+ inspector: studio ? "column" : "card"
3188
+ }
3189
+ };
3190
+ }
3191
+ };
3192
+ function installRoot() {
3193
+ for (let dir = productRoot; ; dir = dirname4(dir)) {
3194
+ if (existsSync5(join6(dir, "node_modules", "@volter", "editor-project", "package.json"))) return dir;
3195
+ if (dirname4(dir) === dir) throw new Error(`Cannot scaffold: @volter/editor-project is not installed above ${productRoot}.`);
3196
+ }
3197
+ }
3198
+ function writeProject({ name, targetDir, template, additions = [] }) {
3199
+ if (!name.trim()) throw new Error("A project name is required.");
3200
+ const id = template ?? presets.defaultTemplate;
3201
+ const preset = presets.templates[id];
3202
+ if (!preset) throw new Error(`--template must be one of: ${Object.keys(presets.templates).join(", ")}`);
3203
+ const closed = new Set(closeAdditions([...preset.additions, ...additions]));
3204
+ const composition = assertScaffoldComposition(presets.compose(closed), "node/create.ts", PRODUCT2);
3205
+ return scaffoldProject({
3206
+ name,
3207
+ targetDir: resolve4(targetDir),
3208
+ monoRoot: installRoot(),
3209
+ productDir: productRoot,
3210
+ additions: [...closed],
3211
+ composition
3212
+ });
3213
+ }
3214
+ async function createGameProject(request) {
3215
+ const result = writeProject(request);
3216
+ const version = JSON.parse(readFileSync5(join6(productRoot, "package.json"), "utf8")).version;
3217
+ linkRuntimeImage(result.targetDir, await ensureRuntimeImage(productRoot, version));
3218
+ repinEngineAfterInstall(result.targetDir);
3219
+ console.error(initGitRepo(result.targetDir, request.name).notice);
3220
+ return { targetDir: result.targetDir, manifest: result.manifest };
3221
+ }
3222
+ var registry = new Map(loadTemplateRegistry().templates.map((entry) => [entry.id, entry]));
3223
+ var declaration = {
3224
+ product: PRODUCT2,
3225
+ templates: Object.keys(presets.templates).map((id) => {
3226
+ const entry = registry.get(id);
3227
+ if (!entry) throw new Error(`templates.json has no entry for preset "${id}".`);
3228
+ return { id, name: entry.title, description: entry.description };
3229
+ }),
3230
+ create: (request) => createGameProject(request)
3231
+ };
3232
+ export {
3233
+ createGameProject,
3234
+ declaration,
3235
+ installRoot,
3236
+ presets,
3237
+ productRoot,
3238
+ writeProject
3239
+ };