@vgai/editor 0.2.0 → 0.4.0-canary.20260715.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (430) hide show
  1. package/README.md +24 -0
  2. package/dist/assets/axe-C7YBtOuM.js +30 -0
  3. package/dist/assets/browserAll-DDtGGE48.js +1 -0
  4. package/dist/assets/create-runtime-DbTlBlKG.js +1 -0
  5. package/dist/assets/{game-BI111o5f.js → game-BE0r7DMI.js} +3 -3
  6. package/dist/assets/game-BdTHR2_X.js +1 -0
  7. package/dist/assets/{game-pt_1lQLv.js → game-C3iQGSqo.js} +1 -1
  8. package/dist/assets/game-CcHfYxjP.js +1 -0
  9. package/dist/assets/game-Cqzj_lpD.js +1 -0
  10. package/dist/assets/game-DSZdeCHu.js +1 -0
  11. package/dist/assets/game-Dch9sAPc.js +1 -0
  12. package/dist/assets/{game-xsOho_wg.js → game-SAFn90pA.js} +3 -3
  13. package/dist/assets/game-loop-DMIgSMV-.js +1 -0
  14. package/dist/assets/{game-source-CvidN7AB.js → game-source-Dk83w26t.js} +1 -1
  15. package/dist/assets/{index-Bp5cecD6.js → index-4idIsHHJ.js} +2 -2
  16. package/dist/assets/{index-DL7RcQ0n.js → index-C-LhOTBN.js} +1 -1
  17. package/dist/assets/{index-Cs8xwv3e.js → index-CDkxceqE.js} +1 -1
  18. package/dist/assets/index-CQEfi217.js +15412 -0
  19. package/dist/assets/index-Dvi-V0NE.css +1 -0
  20. package/dist/assets/ingest-siblings-s0P5I1Ub.js +1 -0
  21. package/dist/assets/mount-manifest-DXMOlF79.js +1 -0
  22. package/dist/assets/react-18-C9eHn8x1.js +1 -0
  23. package/dist/assets/webworkerAll-Fn0e-ouF.js +1 -0
  24. package/dist/assets/world-documents-GM0a9Kv7.js +1 -0
  25. package/dist/index.html +15 -13
  26. package/dist/ingest/racing-game/vgai.game.json +5 -4
  27. package/dist/ingest/simcity/vgai.game.json +5 -4
  28. package/dist/ingest/tanks/vgai.game.json +5 -4
  29. package/dist/project-scripts.bundle.js +3917 -0
  30. package/dist/scenes/untitled.vscn.json +2 -0
  31. package/dist-server/packaged.mjs +7697 -3435
  32. package/package.json +31 -4
  33. package/scripts/probe-reporter.ts +349 -0
  34. package/scripts/run-probe.ts +2260 -0
  35. package/server/asset-catalog-audit.ts +268 -0
  36. package/server/asset-catalog-v2.ts +146 -0
  37. package/server/asset-library-routes.ts +276 -58
  38. package/server/canonical-path.ts +1 -1
  39. package/server/dev.ts +148 -44
  40. package/server/editor-server.ts +888 -61
  41. package/server/editor-sse.ts +115 -4
  42. package/server/harness-chat-service.ts +796 -0
  43. package/server/local-asset-catalog.ts +157 -22
  44. package/server/packaged.ts +51 -21
  45. package/server/process-shutdown.ts +136 -0
  46. package/server/prod.ts +9 -6
  47. package/server/project-hmr-files.ts +41 -0
  48. package/server/project-operations.ts +343 -0
  49. package/server/project-optimize-deps-entries.ts +4 -4
  50. package/server/project-output-writer.ts +156 -0
  51. package/server/project-validation.ts +140 -0
  52. package/server/project-view.ts +8 -50
  53. package/server/server-utils.ts +75 -10
  54. package/server/session-registry.ts +12 -0
  55. package/src/EditorContext.tsx +107 -3
  56. package/src/action-registry.ts +115 -17
  57. package/src/adapter-resolver.ts +213 -478
  58. package/src/asset-events.ts +64 -1
  59. package/src/asset-preview.ts +906 -0
  60. package/src/asset-selection.ts +121 -0
  61. package/src/asset-workflow/asset-capabilities.ts +259 -0
  62. package/src/asset-workflow/asset-editor-errors.ts +46 -0
  63. package/src/asset-workflow/asset-import-pipeline.ts +176 -0
  64. package/src/asset-workflow/asset-library-query.ts +107 -0
  65. package/src/asset-workflow/asset-types.ts +192 -0
  66. package/src/asset-workflow/asset-workflow-quality.ts +65 -0
  67. package/src/asset-workflow/import-contract.ts +113 -0
  68. package/src/asset-workflow/model-conversion.ts +126 -0
  69. package/src/asset-workflow/model-inspection.ts +185 -0
  70. package/src/asset-workflow/project-asset-commands.ts +23 -0
  71. package/src/asset-workflow/project-asset-health.ts +153 -0
  72. package/src/asset-workflow/project-asset-operations.ts +119 -0
  73. package/src/asset-workflow/thumbnail-system.ts +172 -0
  74. package/src/authoring/active-systems.ts +15 -0
  75. package/src/authoring/boundary-authoring-adapter.ts +16 -5
  76. package/src/authoring/composite-authoring-adapter.ts +305 -124
  77. package/src/authoring/design-time-layers.ts +300 -117
  78. package/src/authoring/edit-mode-authoring.ts +278 -293
  79. package/src/authoring/embed-only-adapter.ts +4 -2
  80. package/src/authoring/first-party-hierarchy-menu.ts +7 -2
  81. package/src/authoring/first-party-inspector/AddSectionMenu.tsx +5 -12
  82. package/src/authoring/first-party-inspector/EnvironmentSection.tsx +53 -126
  83. package/src/authoring/first-party-inspector/HeaderSection.tsx +54 -65
  84. package/src/authoring/first-party-inspector/is-first-party-selection.ts +30 -11
  85. package/src/authoring/first-party-inspector/register.tsx +13 -2
  86. package/src/authoring/ingest-authoring-adapter.ts +142 -45
  87. package/src/authoring/mount-failure-report.ts +5 -5
  88. package/src/authoring/provenance.ts +41 -0
  89. package/src/authoring/react-dom-authoring-adapter.ts +92 -92
  90. package/src/authoring/react-inspector-section.tsx +489 -51
  91. package/src/authoring/react-world-authoring-adapter.ts +541 -306
  92. package/src/authoring/story-overlay.ts +1 -1
  93. package/src/authoring/story-types.ts +11 -0
  94. package/src/authoring/vgai-scene-authoring-adapter.ts +54 -25
  95. package/src/authoring/viewport-tool-context.ts +78 -0
  96. package/src/authoring/world-canvas-viewport-state.ts +35 -0
  97. package/src/authoring/world-hidden-viewport.ts +186 -0
  98. package/src/authoring/world-pan-state.ts +33 -17
  99. package/src/authoring/world-session-state.ts +1 -1
  100. package/src/authoring/world2d-authoring-adapter.ts +109 -52
  101. package/src/availability-tick.ts +56 -0
  102. package/src/browser-play-entry.ts +5 -5
  103. package/src/browser-project-scripts.ts +1 -0
  104. package/src/build-identity.ts +15 -0
  105. package/src/command-listener.ts +893 -19
  106. package/src/components/AlignToolbar.tsx +74 -63
  107. package/src/components/AppRoot.tsx +193 -26
  108. package/src/components/ApplicationMenus.tsx +272 -0
  109. package/src/components/AssetBrowser.tsx +1450 -293
  110. package/src/components/AssetEditorShell.tsx +141 -0
  111. package/src/components/AssetImportDetails.tsx +218 -0
  112. package/src/components/AssetLibraryPanel.tsx +14 -0
  113. package/src/components/CameraInfo.tsx +11 -20
  114. package/src/components/CenterDocuments.tsx +585 -0
  115. package/src/components/CommandPalette.tsx +75 -30
  116. package/src/components/ConsolePanel.css +55 -0
  117. package/src/components/ConsolePanel.tsx +57 -112
  118. package/src/components/DebugConsolePanel.tsx +461 -0
  119. package/src/components/DebuggerPanel.tsx +165 -0
  120. package/src/components/DefaultEditorLayout.tsx +167 -231
  121. package/src/components/GameHierarchy.tsx +873 -290
  122. package/src/components/GamePerformanceOverlay.tsx +46 -0
  123. package/src/components/HarnessChatPanel.tsx +2352 -0
  124. package/src/components/HistoryPanel.tsx +226 -0
  125. package/src/components/Inspector.tsx +153 -99
  126. package/src/components/InspectorToolSection.tsx +6 -4
  127. package/src/components/MountFailureBanner.tsx +31 -48
  128. package/src/components/NetworkSection.tsx +25 -14
  129. package/src/components/OnlineAssetBrowser.tsx +794 -343
  130. package/src/components/OverlayReportBanner.tsx +38 -64
  131. package/src/components/PerformancePanel.tsx +206 -0
  132. package/src/components/PlayBar.tsx +93 -263
  133. package/src/components/PrefabSaveDialog.tsx +55 -127
  134. package/src/components/ProjectHeader.css +60 -0
  135. package/src/components/ProjectHeader.tsx +170 -105
  136. package/src/components/ProjectScreen.tsx +246 -184
  137. package/src/components/ReactCanvasControls.tsx +185 -0
  138. package/src/components/ResolutionPicker.tsx +85 -0
  139. package/src/components/RootActivateDialog.tsx +39 -68
  140. package/src/components/SaveDialog.tsx +55 -127
  141. package/src/components/SaveStatus.tsx +11 -29
  142. package/src/components/StartupLoadingScreen.tsx +96 -0
  143. package/src/components/StateWatchPanel.tsx +302 -0
  144. package/src/components/StatsOverlay.tsx +12 -5
  145. package/src/components/StatusBar.tsx +64 -0
  146. package/src/components/ThemeManagerDialog.css +89 -0
  147. package/src/components/ThemeManagerDialog.tsx +371 -0
  148. package/src/components/ToolHost.tsx +26 -15
  149. package/src/components/Toolbar.tsx +117 -214
  150. package/src/components/VgaiVoxelLogo.tsx +89 -0
  151. package/src/components/ViewportOverlay.tsx +97 -172
  152. package/src/components/ViewportPanel.tsx +130 -31
  153. package/src/components/WorkspaceDock.tsx +891 -0
  154. package/src/components/WorldSelectionOverlay.tsx +51 -63
  155. package/src/components/WorldTextEditor.tsx +9 -5
  156. package/src/components/asset-documents.tsx +390 -0
  157. package/src/components/asset-editor-persistence.ts +44 -0
  158. package/src/components/asset-selection-section.tsx +338 -0
  159. package/src/components/asset-viewers/AudioViewer.tsx +73 -21
  160. package/src/components/asset-viewers/GenericJsonViewer.tsx +26 -11
  161. package/src/components/asset-viewers/ImageViewer.tsx +43 -11
  162. package/src/components/asset-viewers/InputMapViewer.tsx +512 -134
  163. package/src/components/asset-viewers/MaterialAssetEditor.tsx +540 -0
  164. package/src/components/asset-viewers/ModelViewer.tsx +805 -121
  165. package/src/components/asset-viewers/OnlineAssetDetail.tsx +177 -60
  166. package/src/components/asset-viewers/SourceAssetViewer.tsx +121 -0
  167. package/src/components/asset-workflow.css +506 -0
  168. package/src/components/build-documents.tsx +696 -0
  169. package/src/components/core-utilities.tsx +75 -0
  170. package/src/components/data-documents.tsx +364 -0
  171. package/src/components/{DataPanel.tsx → data-editor.tsx} +138 -288
  172. package/src/components/debugger-panel-state.ts +57 -0
  173. package/src/components/inspector-widgets/AlignmentGrid.tsx +8 -14
  174. package/src/components/inspector-widgets/BorderEditor.tsx +41 -33
  175. package/src/components/inspector-widgets/ColorPicker.tsx +39 -39
  176. package/src/components/inspector-widgets/FontPicker.tsx +13 -21
  177. package/src/components/inspector-widgets/GradientEditor.tsx +11 -19
  178. package/src/components/inspector-widgets/ScrubbableInput.tsx +6 -3
  179. package/src/components/inspector-widgets/ShadowEditor.tsx +20 -33
  180. package/src/components/inspector-widgets/shared.tsx +90 -49
  181. package/src/components/inspectors/AnimationSection.tsx +39 -40
  182. package/src/components/inspectors/AudioSection.tsx +28 -39
  183. package/src/components/inspectors/BoneAttachmentSection.tsx +19 -24
  184. package/src/components/inspectors/CameraSection.tsx +14 -23
  185. package/src/components/inspectors/ComponentsSection.tsx +39 -43
  186. package/src/components/inspectors/JointsSection.tsx +34 -43
  187. package/src/components/inspectors/LightSection.tsx +90 -35
  188. package/src/components/inspectors/MaterialSection.tsx +137 -174
  189. package/src/components/inspectors/MeshSection.tsx +9 -17
  190. package/src/components/inspectors/NavigationSection.tsx +8 -15
  191. package/src/components/inspectors/ParticleSection.tsx +91 -76
  192. package/src/components/inspectors/PhysicsSection.tsx +42 -46
  193. package/src/components/inspectors/PostProcessingSection.tsx +28 -36
  194. package/src/components/inspectors/RenderingSection.tsx +12 -20
  195. package/src/components/inspectors/ShadowSection.tsx +7 -8
  196. package/src/components/inspectors/SplineSection.tsx +31 -42
  197. package/src/components/inspectors/TransformSection.tsx +14 -22
  198. package/src/components/patterns/Dialog.tsx +95 -0
  199. package/src/components/patterns/Fields.tsx +44 -0
  200. package/src/components/patterns/List.tsx +25 -0
  201. package/src/components/patterns/StateSurface.tsx +40 -0
  202. package/src/components/patterns/Surfaces.tsx +115 -0
  203. package/src/components/patterns/Tabs.tsx +80 -0
  204. package/src/components/patterns/Toolbar.tsx +51 -0
  205. package/src/components/patterns/Tree.tsx +72 -0
  206. package/src/components/primitives/Button.tsx +46 -0
  207. package/src/components/primitives/ColorInput.tsx +11 -47
  208. package/src/components/primitives/EditorIcon.tsx +99 -0
  209. package/src/components/primitives/FormControls.tsx +71 -0
  210. package/src/components/primitives/JsonInput.tsx +15 -2
  211. package/src/components/primitives/Layout.tsx +100 -0
  212. package/src/components/primitives/Menu.tsx +105 -0
  213. package/src/components/primitives/NumberInput.tsx +8 -35
  214. package/src/components/primitives/Panel.tsx +49 -44
  215. package/src/components/primitives/SectionHeader.tsx +10 -28
  216. package/src/components/primitives/Text.tsx +46 -0
  217. package/src/components/primitives/Tooltip.tsx +20 -12
  218. package/src/components/primitives/Vec3Input.tsx +3 -0
  219. package/src/components/primitives/banner-tones.ts +33 -0
  220. package/src/components/primitives/editor-icons.ts +102 -0
  221. package/src/components/primitives/panel-header-styles.ts +30 -0
  222. package/src/components/project-operation-documents.tsx +226 -0
  223. package/src/components/status-contributions.tsx +175 -0
  224. package/src/components/story-documents-register.ts +15 -0
  225. package/src/components/story-documents.tsx +1185 -0
  226. package/src/components/tool-documents.tsx +110 -0
  227. package/src/components/workspace-dock.css +293 -0
  228. package/src/components/workspace-history.ts +33 -0
  229. package/src/components/world-documents.tsx +145 -0
  230. package/src/components/xstate-documents.tsx +209 -0
  231. package/src/composite-screenshot.ts +248 -0
  232. package/src/design-system/index.ts +70 -0
  233. package/src/design-system-stories/Foundation.stories.tsx +183 -0
  234. package/src/design-system-stories/Patterns.stories.tsx +251 -0
  235. package/src/design-system-stories/Workspace.stories.tsx +538 -0
  236. package/src/doctor/report.ts +57 -13
  237. package/src/editor-api.ts +295 -31
  238. package/src/editor-compatibility.ts +200 -0
  239. package/src/editor-console.ts +35 -17
  240. package/src/editor-hotkeys.ts +85 -33
  241. package/src/editor-store.ts +538 -233
  242. package/src/editor-viewport.ts +160 -34
  243. package/src/entity-factory.ts +14 -3
  244. package/src/gizmo-registry.ts +21 -5
  245. package/src/harness-chat-editor-context.ts +37 -0
  246. package/src/harness-chat-indicator.ts +68 -0
  247. package/src/harness-chat-layout.ts +53 -0
  248. package/src/harness-chat-lifecycle.ts +170 -0
  249. package/src/harness-chat-reconnect.ts +85 -0
  250. package/src/harness-chat-types.ts +409 -0
  251. package/src/hierarchy-drop.ts +50 -0
  252. package/src/hierarchy-expansion-state.ts +100 -0
  253. package/src/hierarchy-menu-registry.ts +1 -1
  254. package/src/hierarchy-projection.ts +76 -0
  255. package/src/history/editor-session.ts +21 -0
  256. package/src/history/history-commands.ts +147 -0
  257. package/src/history/history-service.ts +904 -0
  258. package/src/history/json-history-resource.ts +165 -0
  259. package/src/history/persistence-coordinator.ts +35 -0
  260. package/src/history/project-file-history.ts +266 -0
  261. package/src/history/project-root-history-backends.ts +53 -0
  262. package/src/history/resource-registry.ts +209 -0
  263. package/src/history/snapshot-store.ts +108 -0
  264. package/src/history/source-history-backend.ts +374 -0
  265. package/src/history/types.ts +100 -0
  266. package/src/hmr-registration-group.ts +67 -0
  267. package/src/hmr-stable-react-context.ts +23 -0
  268. package/src/hosted-example.ts +12 -2
  269. package/src/hotkeys.ts +89 -18
  270. package/src/ingest/discovery-react.ts +9 -10
  271. package/src/ingest/discovery.ts +4 -4
  272. package/src/ingest/discovery2d.ts +5 -5
  273. package/src/ingest/games/bloom-composer/vgai.game.json +3 -3
  274. package/src/ingest/games/embed-bundle/vgai.game.json +3 -3
  275. package/src/ingest/games/games-fps/vgai.game.json +3 -3
  276. package/src/ingest/games/iframe-reachable/vgai.game.json +3 -3
  277. package/src/ingest/games/interactive-cubes/vgai.game.json +3 -3
  278. package/src/ingest/games/mismatched-three/vgai.game.json +3 -3
  279. package/src/ingest/games/own-three-bundled/vgai.game.json +3 -3
  280. package/src/ingest/games/pointerlock-maze/vgai.game.json +7 -4
  281. package/src/ingest/games-2d/bubbo-bubbo/vgai.game.json +3 -3
  282. package/src/ingest/games-2d/bunnymark/vgai.game.json +3 -3
  283. package/src/ingest/games-2d/flappy/vgai.game.json +3 -3
  284. package/src/ingest/games-2d/flappy-pixi/vgai.game.json +3 -3
  285. package/src/ingest/games-2d/puzzling-potions/vgai.game.json +3 -3
  286. package/src/ingest/games-2d/tilemap-camera/vgai.game.json +3 -3
  287. package/src/ingest/games-react/react-rpg/vgai.game.json +3 -3
  288. package/src/ingest/types.ts +1 -1
  289. package/src/ingest-mode.ts +47 -52
  290. package/src/ingest-siblings.ts +23 -33
  291. package/src/initial-scene.ts +1 -2
  292. package/src/main.tsx +16 -8
  293. package/src/manifest-project.ts +10 -12
  294. package/src/model-thumbnail.ts +261 -26
  295. package/src/module-mode.ts +44 -50
  296. package/src/play-log-events.ts +26 -0
  297. package/src/play-mode.ts +495 -401
  298. package/src/play-scene-adoption.ts +23 -0
  299. package/src/playground/main.ts +68 -24
  300. package/src/playwright-shim.ts +473 -0
  301. package/src/project-manager.ts +90 -10
  302. package/src/project-operations.ts +112 -0
  303. package/src/project-story-discovery.ts +25 -0
  304. package/src/project-tool-discovery.ts +43 -0
  305. package/src/scene-serializer.ts +0 -6
  306. package/src/scene-sync.ts +7 -2
  307. package/src/script-loader.ts +3 -3
  308. package/src/skeleton-helper.ts +57 -0
  309. package/src/storage/seed.ts +68 -8
  310. package/src/stories/StoryPreviewMount.tsx +265 -0
  311. package/src/stories/action-stories.fixture.tsx +44 -0
  312. package/src/stories/button-stories.fixture.tsx +50 -0
  313. package/src/stories/compose-project-stories.ts +182 -0
  314. package/src/stories/loader-stories.fixture.tsx +53 -0
  315. package/src/stories/story-discovery.ts +130 -0
  316. package/src/stories/story-registry.ts +146 -0
  317. package/src/theme-css.ts +1049 -0
  318. package/src/theme-library.ts +238 -0
  319. package/src/theme-preference.ts +130 -0
  320. package/src/theme.ts +527 -0
  321. package/src/tool-loader.ts +80 -24
  322. package/src/ui-source/inspect.ts +27 -4
  323. package/src/ui-source/source-write-backend.ts +83 -22
  324. package/src/widgets/index.ts +9 -18
  325. package/src/workspace-aux-commands.ts +11 -0
  326. package/src/workspace-dock-controller.ts +64 -0
  327. package/src/workspace-document-ids.ts +5 -0
  328. package/src/workspace-document-registry.ts +367 -0
  329. package/src/workspace-state-persistence.ts +455 -0
  330. package/src/workspace-status-registry.ts +110 -0
  331. package/src/workspace-utility-commands.ts +49 -0
  332. package/src/workspace-utility-registry.ts +161 -0
  333. package/src/world-document-routing.ts +16 -0
  334. package/src/xstate-inspect/XStateMachineInspector.tsx +544 -0
  335. package/src/xstate-inspect/character-animation-machine.fixture.ts +74 -0
  336. package/src/xstate-inspect/use-live-actor-state.ts +39 -0
  337. package/src/xstate-inspect/xstate-graph.ts +265 -0
  338. package/src/xstate-inspect/xstate-layout.ts +76 -0
  339. package/src/z-index.ts +26 -0
  340. package/template/.claude/skills/editor/SKILL.md +129 -90
  341. package/template/AGENTS.md +1110 -0
  342. package/template/CLAUDE.md +1 -512
  343. package/template/IDIOMS.md +50 -0
  344. package/template/check-idioms.ts +706 -0
  345. package/template/manifest-entry-modules-plugin.ts +53 -0
  346. package/template/package.json +13 -4
  347. package/template/public/scenes/default.scn2d.json +6 -0
  348. package/template/public/scenes/default.vscn.json +7 -1
  349. package/template/public/scenes/untitled.vscn.json +10 -0
  350. package/template/scripts/playtest.ts +40 -0
  351. package/template/server/loopback.ts +75 -0
  352. package/template/server/rooms/arena-room.ts +69 -1
  353. package/template/server/rooms/game-room.ts +68 -1
  354. package/template/src/data/README.md +9 -4
  355. package/template/src/data/data-ref.ts +35 -0
  356. package/template/src/data/tuning.schema.ts +1 -1
  357. package/template/src/main.ts +41 -62
  358. package/template/src/manifest-entry-modules.d.ts +3 -0
  359. package/template/src/operations/README.md +88 -0
  360. package/template/src/runtime/pixi-adapter.ts +24 -0
  361. package/template/src/scripts/components/data-spinner.ts +43 -2
  362. package/template/src/scripts/components/spin-lap-math.ts +27 -0
  363. package/template/src/tools/README.md +5 -3
  364. package/template/src/tools/example.tool.tsx +13 -7
  365. package/template/src/ui/Button.stories.tsx +66 -0
  366. package/template/src/ui/RebindPanel.tsx +2 -6
  367. package/template/src/ui/game.tsx +17 -0
  368. package/template/tests/acceptance/example.spec.ts +64 -0
  369. package/template/tests/logic/example.test.ts +31 -0
  370. package/template/tests/logic/room.test.ts +100 -0
  371. package/template/tests/tsconfig.json +30 -0
  372. package/template/validate-manifest.ts +5 -5
  373. package/template/validate-scenes.ts +50 -18
  374. package/template/vgai.game.json +20 -13
  375. package/template/vite.config.ts +77 -16
  376. package/vite-plugin-ui-oid.ts +261 -17
  377. package/dist/assets/CCDIKSolver-Dz-ysxZF.js +0 -1
  378. package/dist/assets/SelectionBox-BXsv_6aH.js +0 -1
  379. package/dist/assets/browser-project-scripts-DOru4L1x.js +0 -2
  380. package/dist/assets/browserAll-CEkWYlFk.js +0 -1
  381. package/dist/assets/create-runtime-DYIWr3va.js +0 -1
  382. package/dist/assets/data-asset-Bb9sIM7i.js +0 -5
  383. package/dist/assets/game-8SDZPPgH.js +0 -1
  384. package/dist/assets/game-CevorxyV.js +0 -1
  385. package/dist/assets/game-Di7XlywD.js +0 -1
  386. package/dist/assets/game-DjnCaw8R.js +0 -1
  387. package/dist/assets/game-Q9A0aXSV.js +0 -1
  388. package/dist/assets/index-CPVV6pjw.js +0 -1
  389. package/dist/assets/index-CpOnYyeD.js +0 -213
  390. package/dist/assets/index-Dr8H_6Rl.js +0 -1
  391. package/dist/assets/index-_bCaipUk.js +0 -13650
  392. package/dist/assets/ingest-siblings-Dz8eEqrV.js +0 -1
  393. package/dist/assets/mount-manifest-Bhk0ohsl.js +0 -1
  394. package/dist/assets/scene-query-BivAHhJu.js +0 -1
  395. package/dist/assets/webworkerAll-BLrH0F6F.js +0 -1
  396. package/dist/assets/xstate-animation-binding-1NGLmw6y.js +0 -1
  397. package/dist/assets/xstate.esm-BgUD33nl.js +0 -3
  398. package/src/authoring/scene-ui-layer.ts +0 -485
  399. package/src/authoring/ui-authoring-adapter.ts +0 -325
  400. package/src/authoring/ui-hierarchy-menu.ts +0 -40
  401. package/src/authoring/ui-inspector-sections.tsx +0 -156
  402. package/src/authoring/undo-timeline.ts +0 -145
  403. package/src/components/BottomPanel.tsx +0 -326
  404. package/src/components/BuildPanel.tsx +0 -455
  405. package/src/components/FolderTree.tsx +0 -179
  406. package/src/components/RightPanel.tsx +0 -166
  407. package/src/components/WorldContextMenu.tsx +0 -257
  408. package/src/components/asset-viewers/AssetViewer.tsx +0 -38
  409. package/src/ingest/games-react/react-rpg/src/ui/game-state.tsx +0 -129
  410. package/src/scene-ui-mode/active-scene-ui.ts +0 -58
  411. package/src/scene-ui-mode/scene-ui-palette-panel.tsx +0 -152
  412. package/src/scene-ui-mode/scene-ui-timeline-tab.tsx +0 -29
  413. package/src/scene-ui-mode/ui-prefab-dialog-host.tsx +0 -74
  414. package/src/scene-ui-mode/ui-prefab-hierarchy-menu.ts +0 -49
  415. package/src/scene-ui-mode/ui-prefab-io.ts +0 -76
  416. package/src/ui-editor/inspector.tsx +0 -563
  417. package/src/ui-editor/node-ops.ts +0 -266
  418. package/src/ui-editor/overlay.tsx +0 -380
  419. package/src/ui-editor/palette.tsx +0 -114
  420. package/src/ui-editor/react-store.ts +0 -78
  421. package/src/ui-editor/timeline-panel.tsx +0 -443
  422. package/src/ui-editor/ui-edit-store.ts +0 -552
  423. package/src/ui-editor/ui-prefab.ts +0 -95
  424. package/template/project.json +0 -9
  425. package/template/src/scripts/main.ts +0 -94
  426. package/template/src/ui/DefaultHud.tsx +0 -40
  427. package/template/src/ui/game-state.tsx +0 -37
  428. package/template/src/ui/mount-default-hud.tsx +0 -19
  429. package/template/src/ui/mount-ui.ts +0 -15
  430. package/vite-plugin-react-world-provider.ts +0 -81
@@ -0,0 +1,53 @@
1
+ import type { Plugin } from 'vite';
2
+
3
+ const MANIFEST_ENTRIES_ID = 'virtual:vgai-manifest-entries';
4
+ const RESOLVED_MANIFEST_ENTRIES_ID = `\0${MANIFEST_ENTRIES_ID}`;
5
+
6
+ function collectManifestEntries(manifest: unknown): string[] {
7
+ const rawWorlds =
8
+ manifest && typeof manifest === 'object'
9
+ ? (manifest as { roots?: unknown }).roots
10
+ : undefined;
11
+ const entries = [
12
+ ...new Set(
13
+ (Array.isArray(rawWorlds) ? rawWorlds : [])
14
+ .map((world) =>
15
+ world && typeof world === 'object' ? (world as { entry?: unknown }).entry : undefined,
16
+ )
17
+ .filter((entry): entry is string => typeof entry === 'string'),
18
+ ),
19
+ ];
20
+
21
+ for (const entry of entries) {
22
+ if (entry.startsWith('/') || entry.includes('\\') || entry.split('/').includes('..')) {
23
+ throw new Error(`vgai.game.json world entry must be project-relative: ${entry}`);
24
+ }
25
+ }
26
+
27
+ return entries;
28
+ }
29
+
30
+ /**
31
+ * Render imports for the manifest's exact `roots[].entry` declarations.
32
+ * The manifest—not a filename convention—is the only discovery source.
33
+ */
34
+ export function renderManifestEntryModule(manifest: unknown): string {
35
+ const entries = collectManifestEntries(manifest);
36
+ const imports = entries.map(
37
+ (entry, index) => `import * as entry${index} from ${JSON.stringify(`/${entry}`)};`,
38
+ );
39
+ const members = entries.map((entry, index) => `${JSON.stringify(entry)}: entry${index}`);
40
+ return `${imports.join('\n')}\nexport const manifestEntryModules = {${members.join(',')}};\n`;
41
+ }
42
+
43
+ export function manifestEntryModulesPlugin(manifest: unknown): Plugin {
44
+ return {
45
+ name: 'vgai:manifest-entry-modules',
46
+ resolveId(id) {
47
+ return id === MANIFEST_ENTRIES_ID ? RESOLVED_MANIFEST_ENTRIES_ID : undefined;
48
+ },
49
+ load(id) {
50
+ return id === RESOLVED_MANIFEST_ENTRIES_ID ? renderManifestEntryModule(manifest) : undefined;
51
+ },
52
+ };
53
+ }
@@ -11,15 +11,18 @@
11
11
  "dev": "vgai edit .",
12
12
  "game": "vite",
13
13
  "build": "tsc && vite build",
14
- "typecheck": "tsc --noEmit && tsc --noEmit -p server/tsconfig.json",
14
+ "typecheck": "tsc --noEmit && tsc --noEmit -p server/tsconfig.json && tsc --noEmit -p tests/tsconfig.json",
15
15
  "emit-schemas": "npx tsx emit-schemas.ts",
16
16
  "validate-scenes": "npx tsx validate-scenes.ts .",
17
17
  "validate-manifest": "npx tsx validate-manifest.ts vgai.game.json",
18
- "server": "npx tsx --tsconfig server/tsconfig.json server/main.ts"
18
+ "check-idioms": "npx tsx check-idioms.ts .",
19
+ "server": "npx tsx --tsconfig server/tsconfig.json server/main.ts",
20
+ "test": "vitest run tests/logic",
21
+ "test:acceptance": "vgai probe",
22
+ "playtest": "npx tsx scripts/playtest.ts"
19
23
  },
20
24
  "dependencies": {
21
25
  "@vgai/engine": "*",
22
- "@vgai/scene-ui": "*",
23
26
  "@colyseus/schema": "^4.0.14",
24
27
  "@colyseus/sdk": "^0.17.34",
25
28
  "@dimforge/rapier3d-compat": "^0.14.0",
@@ -42,12 +45,18 @@
42
45
  "@types/react": "^19.2.14",
43
46
  "@types/react-dom": "^19.2.3",
44
47
  "@types/three": "^0.170.0",
48
+ "@playwright/test": "^1.58.2",
49
+ "@vgai/probe": "*",
50
+ "@vgai/live": "*",
51
+ "@vgai/sdk": "*",
52
+ "@vgai/editor-sdk": "*",
45
53
  "@vitejs/plugin-react": "^5.1.4",
46
54
  "colyseus": "^0.17.8",
47
55
  "@colyseus/ws-transport": "^0.17.9",
48
56
  "storybook": "^9.1.20",
49
57
  "tsx": "^4.23.0",
50
58
  "typescript": "^5.6.0",
51
- "vite": "^6.0.0"
59
+ "vite": "^6.0.0",
60
+ "vitest": "^3.2.6"
52
61
  }
53
62
  }
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 1,
3
+ "surface": "world2d",
4
+ "background": "#10131c",
5
+ "entities": []
6
+ }
@@ -6,10 +6,12 @@
6
6
  },
7
7
  "entities": [
8
8
  {
9
+ "id": "d43d8032-0e0c-4936-b996-87924d458668",
9
10
  "name": "AmbientLight",
10
11
  "light": { "type": "hemisphere", "color": "#ffffff", "groundColor": "#444444", "intensity": 0.5 }
11
12
  },
12
13
  {
14
+ "id": "d3231678-2f7f-4839-994b-1edf2abcc73c",
13
15
  "name": "Sun",
14
16
  "light": { "type": "directional", "color": "#ffffff", "intensity": 1 },
15
17
  "transform": { "position": [5, 10, 5] },
@@ -20,6 +22,7 @@
20
22
  }
21
23
  },
22
24
  {
25
+ "id": "2efb889f-5ca2-4715-a614-a379fdcb195b",
23
26
  "name": "Ground",
24
27
  "mesh": { "type": "box", "args": [20, 0.2, 20] },
25
28
  "material": { "type": "standard", "color": "#888888" },
@@ -27,6 +30,7 @@
27
30
  "shadow": { "enabled": true }
28
31
  },
29
32
  {
33
+ "id": "50a15029-7b16-4bb4-b013-b222b3ae0ad3",
30
34
  "name": "Box",
31
35
  "mesh": { "type": "box", "args": [1, 1, 1] },
32
36
  "material": { "type": "standard", "color": "#4488ff" },
@@ -35,9 +39,11 @@
35
39
  "components": { "DataSpinner": { "spinScale": 1 } }
36
40
  },
37
41
  {
42
+ "id": "af6855d6-9bf9-47f3-bcb1-d5e6843c97bd",
38
43
  "name": "Camera",
39
44
  "transform": { "position": [3, 3, 3] },
40
- "camera": { "type": "perspective", "fov": 60, "near": 0.1, "far": 1000 }
45
+ "camera": { "type": "perspective", "fov": 60, "near": 0.1, "far": 1000 },
46
+ "components": { "SceneCamera": { "x": 3, "y": 3, "z": 3, "lookAtY": 0.5 } }
41
47
  }
42
48
  ]
43
49
  }
@@ -3,6 +3,7 @@
3
3
  "name": "Untitled",
4
4
  "entities": [
5
5
  {
6
+ "id": "cf60bb73-ace4-4078-a1a1-2a21af3b4cfb",
6
7
  "name": "Camera",
7
8
  "camera": {
8
9
  "type": "perspective"
@@ -13,9 +14,18 @@
13
14
  2,
14
15
  5
15
16
  ]
17
+ },
18
+ "components": {
19
+ "SceneCamera": {
20
+ "x": 0,
21
+ "y": 2,
22
+ "z": 5,
23
+ "lookAtY": 0
24
+ }
16
25
  }
17
26
  },
18
27
  {
28
+ "id": "49bbe8e0-0b0c-4780-88bb-d34790cce748",
19
29
  "name": "Box",
20
30
  "mesh": {
21
31
  "type": "box"
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Inner-loop autoplay (see AGENTS.md's "Autoplay bots" — Level 2). A plain
3
+ * `@vgai/live` script: no test runner, no Playwright config, no fixture, no
4
+ * second browser. It ATTACHES to the live `vgai edit` session/tab you
5
+ * already have open (run `vgai edit .` first if you don't) and drives it
6
+ * with the SAME `GameClient` vocabulary `tests/acceptance/example.spec.ts`
7
+ * uses — compare the two side by side; the difference in ceremony is the
8
+ * whole point.
9
+ *
10
+ * Run: `npm run playtest` (or `npx tsx scripts/playtest.ts`). Nothing here
11
+ * is committed evidence — it's scratch space for "does my game work right
12
+ * now". Once an interaction proves a feature, graduate it into a spec under
13
+ * `tests/acceptance/` (`vgai probe --init` scaffolds the first one).
14
+ *
15
+ * Drives the template's shipped example component, `DataSpinner`
16
+ * (`src/scripts/components/data-spinner.ts`) — replace this with your own
17
+ * provider/command/action names as your first real edit.
18
+ */
19
+
20
+ import { editor, game } from '@vgai/live';
21
+
22
+ await editor.play(); // enters play mode; the ack waits for the game's full async setup
23
+
24
+ // Fixture (declared cheat, D16) — jump to a known state. Never a substitute
25
+ // for the honest-input proof below.
26
+ await game.command('spinner.reset');
27
+
28
+ // Proof: the same honest input path a human's keys hit (see
29
+ // public/inputmaps/default.inputmap.json's 'attack' binding).
30
+ await game.input.hold('attack', { simSeconds: 4 });
31
+
32
+ await game.waitFor((s) => (s('spinner') as { lapsCompleted: number }).lapsCompleted >= 1, {
33
+ simSeconds: 10,
34
+ });
35
+
36
+ const spinner = (await game.state('spinner')) as { lapsCompleted: number };
37
+ console.log(`spinner lapsCompleted: ${spinner.lapsCompleted}`);
38
+
39
+ const shot = await game.screenshot('playtest-after-boosted-spin');
40
+ console.log(`screenshot: ${shot}`);
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Loopback Colyseus server harness for headless multiplayer tests — a
3
+ * near-verbatim copy of the engine repo's own
4
+ * `packages/editor/test/helpers/colyseus-loopback.ts` (Acceptance Driver
5
+ * build plan Task 4.4), shipped INTO every scaffolded project so a
6
+ * multiplayer game has a headless L1-equivalent (`docs/ACCEPTANCE-DRIVER-SPEC.md`
7
+ * §2.3's "Multiplayer lane") before `--players N` exists on `vgai probe`.
8
+ *
9
+ * Starts the REAL `startColyseus` bootstrap (`./colyseus-setup.js`) with the
10
+ * shipped room registry (`./rooms.js` — `ArenaRoom` + `GameRoom`) on an
11
+ * OS-assigned ephemeral port, in-process. No mocks: this is the exact same
12
+ * `Server` / `WebSocketTransport` a real `npm run server` would boot, just on
13
+ * `port: 0` so concurrent test runs never collide on `2567`.
14
+ *
15
+ * Usage:
16
+ * ```ts
17
+ * const server = await startLoopbackColyseus();
18
+ * try {
19
+ * const client = new Client(server.url);
20
+ * const room = await client.joinOrCreate('game_room', {}, undefined, undefined, {
21
+ * allowDebugCommands: true,
22
+ * });
23
+ * // ...
24
+ * } finally {
25
+ * server.stop();
26
+ * }
27
+ * ```
28
+ */
29
+
30
+ import { startColyseus } from './colyseus-setup.js';
31
+ import { rooms } from './rooms.js';
32
+
33
+ export interface LoopbackColyseus {
34
+ /** `ws://127.0.0.1:<port>` — the ephemeral port the server actually bound. */
35
+ url: string;
36
+ /** Tear down the server (closes the underlying HTTP/WS server). */
37
+ stop: () => void;
38
+ }
39
+
40
+ /**
41
+ * `@colyseus/core`'s matchmaker setup unconditionally `import("@pm2/io")`s and
42
+ * registers metrics, which makes `@pm2/io` probe `process.send` and start
43
+ * speaking the PM2 agent protocol (`axm:*` messages) over it. Under vitest's
44
+ * forked worker pool, `process.send` is real (the runner's own parent<->child
45
+ * channel), so those messages get relayed to the parent and crash its
46
+ * deserializer — nothing to do with this test's own logic. Patch `process.send`
47
+ * to drop only `axm:*` payloads for the harness's lifetime; everything else
48
+ * (vitest's own protocol) passes through untouched.
49
+ */
50
+ function suppressPm2IoIpcNoise(): () => void {
51
+ const original = process.send?.bind(process);
52
+ if (!original) return () => {};
53
+ const patched = (message: unknown, ...rest: unknown[]): boolean => {
54
+ const type = (message as { type?: unknown } | null)?.type;
55
+ if (typeof type === 'string' && type.startsWith('axm:')) return true;
56
+ return (original as (...a: unknown[]) => boolean)(message, ...rest);
57
+ };
58
+ process.send = patched as NonNullable<typeof process.send>;
59
+ return () => {
60
+ process.send = original;
61
+ };
62
+ }
63
+
64
+ /** Boot the real Colyseus server on an ephemeral loopback port. */
65
+ export async function startLoopbackColyseus(): Promise<LoopbackColyseus> {
66
+ const restorePm2IoIpc = suppressPm2IoIpcNoise();
67
+ const handle = await startColyseus({ rooms, port: 0 });
68
+ return {
69
+ url: `ws://127.0.0.1:${handle.port}`,
70
+ stop: () => {
71
+ handle.stop();
72
+ restorePm2IoIpc();
73
+ },
74
+ };
75
+ }
@@ -17,6 +17,11 @@
17
17
  * - Configurable bot count (0–6), spawned on create, stored in the same players MapSchema.
18
18
  * - Server picks behavior (idle/patrol/chase/flee) + target position.
19
19
  * - Client handles smooth navmesh pathfinding.
20
+ *
21
+ * Also handles `__vgai:debugCommand` { name, args, requestId } — a
22
+ * `locus: 'server'` debug command's client leg (`docs/SYNTHETIC-PLAYER-SPEC.md`
23
+ * §3.1's "Multiplayer locus" note, Acceptance Driver build plan Task 4.2);
24
+ * see `DEBUG_COMMANDS`/`onCreate` below.
20
25
  */
21
26
 
22
27
  import { Room, type Client } from 'colyseus';
@@ -111,6 +116,25 @@ function randomTagger(state: ArenaState): string {
111
116
  return ids[Math.floor(Math.random() * ids.length)]!;
112
117
  }
113
118
 
119
+ /**
120
+ * The `locus: 'server'` debug-command table (Acceptance Driver build plan
121
+ * Task 4.2) — mirrors `GameRoom`'s `DEBUG_COMMANDS` (`../game-room.ts`), one
122
+ * worked example per room. Mutates the AUTHORITATIVE (server) copy of state,
123
+ * never client prediction. Gated by `allowDebugCommands` — see `onCreate`.
124
+ */
125
+ const DEBUG_COMMANDS: Record<
126
+ string,
127
+ (room: ArenaRoom, client: Client, args: unknown[]) => unknown
128
+ > = {
129
+ 'give-score': (room, client, args) => {
130
+ const amount = typeof args[0] === 'number' ? args[0] : 1;
131
+ const player = room.state.players.get(client.sessionId);
132
+ if (!player) throw new Error(`give-score: no player for session "${client.sessionId}"`);
133
+ player.score += amount;
134
+ return { score: player.score };
135
+ },
136
+ };
137
+
114
138
  // --- Room ---
115
139
 
116
140
  export class ArenaRoom extends Room {
@@ -120,11 +144,55 @@ export class ArenaRoom extends Room {
120
144
  private colorIndex = 0;
121
145
  private npcBrains = new Map<string, NPCBrain>();
122
146
 
123
- onCreate(options?: { botCount?: number }) {
147
+ onCreate(options?: { botCount?: number; allowDebugCommands?: boolean }) {
124
148
  // Spawn NPC bots (count from room creator, default 2, max 6)
125
149
  const npcCount = Math.max(0, Math.min(MAX_NPCS, options?.botCount ?? 2));
126
150
  this.spawnNPCs(npcCount);
127
151
 
152
+ // Off by default (FROZEN DECISION: env-var OR room-option) — `vgai probe`/
153
+ // the loopback harness (`../loopback.ts`) opt in via the room option; a
154
+ // plain `npm run server` boot never accepts debug commands unless
155
+ // VGAI_ALLOW_DEBUG_COMMANDS is set in its environment.
156
+ const debugCommandsAllowed =
157
+ options?.allowDebugCommands === true || Boolean(process.env['VGAI_ALLOW_DEBUG_COMMANDS']);
158
+
159
+ this.onMessage(
160
+ '__vgai:debugCommand',
161
+ (client, message: { name: string; args?: unknown[]; requestId: string }) => {
162
+ if (!debugCommandsAllowed) {
163
+ client.send('__vgai:debugCommandResult', {
164
+ requestId: message.requestId,
165
+ ok: false,
166
+ error: 'debug commands disabled',
167
+ });
168
+ return;
169
+ }
170
+ const handler = DEBUG_COMMANDS[message.name];
171
+ if (!handler) {
172
+ client.send('__vgai:debugCommandResult', {
173
+ requestId: message.requestId,
174
+ ok: false,
175
+ error: `debug: no server command registered under "${message.name}"`,
176
+ });
177
+ return;
178
+ }
179
+ try {
180
+ const result = handler(this, client, message.args ?? []);
181
+ client.send('__vgai:debugCommandResult', {
182
+ requestId: message.requestId,
183
+ ok: true,
184
+ result,
185
+ });
186
+ } catch (err) {
187
+ client.send('__vgai:debugCommandResult', {
188
+ requestId: message.requestId,
189
+ ok: false,
190
+ error: err instanceof Error ? err.message : String(err),
191
+ });
192
+ }
193
+ },
194
+ );
195
+
128
196
  // Handle start_game from host
129
197
  this.onMessage('start_game', (client) => {
130
198
  if (client.sessionId !== this.state.hostId) return;
@@ -7,6 +7,10 @@
7
7
  *
8
8
  * Messages (client → server only):
9
9
  * position { x, y, z } — client movement input
10
+ * __vgai:debugCommand { name, args, requestId } — a `locus: 'server'`
11
+ * debug command's client leg (`docs/SYNTHETIC-PLAYER-SPEC.md` §3.1's
12
+ * "Multiplayer locus" note, Acceptance Driver build plan Task 4.2); see
13
+ * `DEBUG_COMMANDS`/`onCreate` below.
10
14
  *
11
15
  * Everything else (players, orbs, scores) is synchronized via Schema
12
16
  * state: new joiners receive the full state automatically, and ongoing
@@ -54,6 +58,25 @@ class GameState extends Schema {
54
58
 
55
59
  let nextOrbId = 0;
56
60
 
61
+ /**
62
+ * The `locus: 'server'` debug-command table (Task 4.2) — one worked example,
63
+ * `give-score`, mirroring the client-side `DataSpinner.spinner.reset` fixture
64
+ * (`src/scripts/components/data-spinner.ts`): mutates the AUTHORITATIVE
65
+ * (server) copy of state, never client prediction. Gated by
66
+ * `allowDebugCommands` — see `onCreate` — so a production `npm run server`
67
+ * boot never accepts these unless explicitly opted in.
68
+ */
69
+ const DEBUG_COMMANDS: Record<string, (room: GameRoom, client: Client, args: unknown[]) => unknown> =
70
+ {
71
+ 'give-score': (room, client, args) => {
72
+ const amount = typeof args[0] === 'number' ? args[0] : 1;
73
+ const player = room.state.players.get(client.sessionId);
74
+ if (!player) throw new Error(`give-score: no player for session "${client.sessionId}"`);
75
+ player.score += amount;
76
+ return { score: player.score };
77
+ },
78
+ };
79
+
57
80
  function randomSpawnPosition(): { x: number; y: number; z: number } {
58
81
  const angle = Math.random() * Math.PI * 2;
59
82
  return {
@@ -83,7 +106,14 @@ export class GameRoom extends Room {
83
106
  // from `setSimulationInterval` — it exists in both runtimes.
84
107
  private orbRespawnTicks: number[] = [];
85
108
 
86
- onCreate() {
109
+ onCreate(options?: { allowDebugCommands?: boolean }) {
110
+ // Off by default (FROZEN DECISION: env-var OR room-option) — `vgai probe`/
111
+ // the loopback harness (`../loopback.ts`) opt in via the room option; a
112
+ // plain `npm run server` boot never accepts debug commands unless
113
+ // VGAI_ALLOW_DEBUG_COMMANDS is set in its environment.
114
+ const debugCommandsAllowed =
115
+ options?.allowDebugCommands === true || Boolean(process.env['VGAI_ALLOW_DEBUG_COMMANDS']);
116
+
87
117
  // Handle client messages
88
118
  this.onMessage('position', (client, position: { x: number; y: number; z: number }) => {
89
119
  const player = this.state.players.get(client.sessionId);
@@ -94,6 +124,43 @@ export class GameRoom extends Room {
94
124
  }
95
125
  });
96
126
 
127
+ this.onMessage(
128
+ '__vgai:debugCommand',
129
+ (client, message: { name: string; args?: unknown[]; requestId: string }) => {
130
+ if (!debugCommandsAllowed) {
131
+ client.send('__vgai:debugCommandResult', {
132
+ requestId: message.requestId,
133
+ ok: false,
134
+ error: 'debug commands disabled',
135
+ });
136
+ return;
137
+ }
138
+ const handler = DEBUG_COMMANDS[message.name];
139
+ if (!handler) {
140
+ client.send('__vgai:debugCommandResult', {
141
+ requestId: message.requestId,
142
+ ok: false,
143
+ error: `debug: no server command registered under "${message.name}"`,
144
+ });
145
+ return;
146
+ }
147
+ try {
148
+ const result = handler(this, client, message.args ?? []);
149
+ client.send('__vgai:debugCommandResult', {
150
+ requestId: message.requestId,
151
+ ok: true,
152
+ result,
153
+ });
154
+ } catch (err) {
155
+ client.send('__vgai:debugCommandResult', {
156
+ requestId: message.requestId,
157
+ ok: false,
158
+ error: err instanceof Error ? err.message : String(err),
159
+ });
160
+ }
161
+ },
162
+ );
163
+
97
164
  // Spawn initial orbs
98
165
  for (let i = 0; i < MAX_ORBS; i++) {
99
166
  this.spawnOrb();
@@ -8,7 +8,7 @@ copy that trio for each new asset and register it in `assets.ts` (one list,
8
8
  feeding both `npm run emit-schemas` and the build-time check that fails
9
9
  `npm run build` loud on invalid data or a dangling `"file#key"` ref; `vgai
10
10
  doctor <folder>` runs the same checks). Never hardcode a tunable as a constant in
11
- game code — see "Tunable values → a data asset" in this project's CLAUDE.md,
11
+ game code — see "Tunable values → a data asset" in this project's AGENTS.md,
12
12
  and `docs/DATA-TOOLS-DESIGN.md` in the engine checkout for the design.
13
13
 
14
14
  Two blessed shapes, and only these (they're what the editor's DATA tab can
@@ -31,10 +31,15 @@ written; fix the sheet and re-import. `"$schema"` is never a CSV column —
31
31
  it's carried over from the file automatically.
32
32
 
33
33
  Cross-asset fields (one table's row pointing at another asset — an enemy's
34
- drop pointing at an item) should use `dataRef('<target-stem>')`
35
- (`@engine/data/data-ref`) in the schema instead of a bare `z.string()`: the
34
+ drop pointing at an item) should use `dataRef('<target-stem>')` —
35
+ `import { dataRef } from './data-ref'` (see `./data-ref.ts`; never
36
+ `@engine/data/data-ref` or `@vgai/engine/data/data-ref` directly — a schema
37
+ file is reached from `vite.config.ts` at Vite config-load time, which only
38
+ bundles relative imports, so `./data-ref` is the one import spelling that
39
+ resolves there too) — in the schema instead of a bare `z.string()`: the
36
40
  DATA tab then renders that field as a `stem#key` PICKER (listing the target
37
41
  file's own keys) instead of free text, and `vgai doctor`/`npm run build`
38
42
  catch it if the target file is ever renamed or deleted — not just if the key
39
43
  inside it goes missing. Read it back with `getRef(targetHandle, row.field)`
40
- (pass the target's own `defineData` handle, not a string) from game code.
44
+ (also from `./data-ref`; pass the target's own `defineData` handle, not a
45
+ string) from game code.
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Re-exports the engine's `dataRef`/`getRef` (docs/DATA-TOOLS-DESIGN.md §2.2)
3
+ * — the ONE place a `*.schema.ts` should import them from. Import via
4
+ * `from './data-ref'` (a plain, project-internal relative import — every
5
+ * `*.schema.ts` lives right next to this file in `src/data/`), never
6
+ * `@engine/data/data-ref` or `@vgai/engine/data/data-ref` directly.
7
+ *
8
+ * Why this file has to exist at all, ENGINE-RELATIVE (not a bare specifier),
9
+ * same reasoning as `vite.config.ts`'s `vgaiDataCheck` import: this project's
10
+ * data-asset schemas (`src/data/*.schema.ts`) are reached from
11
+ * `vite.config.ts` itself (via `./src/data/assets`) when Vite loads its OWN
12
+ * config, so `npm run build`'s dangling-ref gate can run the EXACT executable
13
+ * Zod schema (§9.1) — and that config-load step only BUNDLES relative
14
+ * imports. A bare specifier is externalized and handed to plain node, which
15
+ * cannot load the engine's shipped TypeScript source either way:
16
+ * `@engine/...` isn't even a real package outside Vite's app-build alias
17
+ * (which doesn't exist yet while Vite is still loading its own config), and
18
+ * `@vgai/engine/...` IS a real, installed package, but its `exports` map
19
+ * points at raw `.ts` — a file plain node's ESM loader cannot parse without a
20
+ * loader hook (the same `ERR_UNKNOWN_FILE_EXTENSION` `vite.config.ts`'s own
21
+ * comment describes for `vgaiDataCheck`).
22
+ *
23
+ * A relative import is the only thing that resolves in every context that
24
+ * touches a `dataRef` field: `tsc`, the app's Vite build, Vite's config-load
25
+ * (the one bare specifiers break), the editor (which aliases `@engine/*` for
26
+ * its OWN app build, but never for config-load either), and `tsx` (`npm run
27
+ * emit-schemas`, `vgai doctor`). Routing every schema file through this ONE
28
+ * module — instead of each one spelling out its own checkout-relative path —
29
+ * means only this file's import needs rewriting per project: the scaffolder
30
+ * does it automatically (`create-vgai-project/src/scaffold.ts`'s
31
+ * `rewriteDataRefModule`, mirroring `rewriteViteConfig`), the same way it
32
+ * already rewrites `vite.config.ts`'s engine-relative import. Never hand-edit
33
+ * the import below — `vgai upgrade` re-syncs it too.
34
+ */
35
+ export { dataRef, getRef, type DataRef } from '../../../../engine/src/data/data-ref';
@@ -15,7 +15,7 @@
15
15
  * annotations `GameComponent.static schema` uses. They document the file,
16
16
  * constrain edits, and (W2+) become editor widgets.
17
17
  *
18
- * Rule of thumb (project CLAUDE.md carries the doctrine): if a designer
18
+ * Rule of thumb (project AGENTS.md carries the doctrine): if a designer
19
19
  * should be able to change it, it belongs here — NOT as a constant in a
20
20
  * component. Per-entity placement config stays on component schemas.
21
21
  */