summer-engine 3.1.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (366) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +27 -5
  3. package/.codex-plugin/plugin.json +28 -6
  4. package/.cursor-plugin/plugin.json +27 -5
  5. package/.factory-plugin/plugin.json +27 -5
  6. package/.opencode/plugins/summer.js +1 -1
  7. package/CHANGELOG.md +102 -0
  8. package/README.md +18 -3
  9. package/assets/audit/scene_audit.gd +4136 -0
  10. package/assets/seeing/seeing_probe.gd +1873 -0
  11. package/dist/cli/commands/skills.js +20 -2
  12. package/dist/core/api-client.d.ts +9 -1
  13. package/dist/core/api-client.js +21 -4
  14. package/dist/core/capabilities/agent-playbook.js +46 -0
  15. package/dist/core/capabilities/audit/accept.d.ts +55 -0
  16. package/dist/core/capabilities/audit/accept.js +147 -0
  17. package/dist/core/capabilities/audit/args.d.ts +95 -0
  18. package/dist/core/capabilities/audit/args.js +89 -0
  19. package/dist/core/capabilities/audit/audit.d.ts +56 -0
  20. package/dist/core/capabilities/audit/audit.js +287 -0
  21. package/dist/core/capabilities/audit/frame.d.ts +14 -0
  22. package/dist/core/capabilities/audit/frame.js +35 -0
  23. package/dist/core/capabilities/audit/gaps.d.ts +96 -0
  24. package/dist/core/capabilities/audit/gaps.js +257 -0
  25. package/dist/core/capabilities/audit/judge.d.ts +162 -0
  26. package/dist/core/capabilities/audit/judge.js +1134 -0
  27. package/dist/core/capabilities/audit/math.d.ts +110 -0
  28. package/dist/core/capabilities/audit/math.js +263 -0
  29. package/dist/core/capabilities/audit/summary.d.ts +74 -0
  30. package/dist/core/capabilities/audit/summary.js +212 -0
  31. package/dist/core/capabilities/board.d.ts +31 -0
  32. package/dist/core/capabilities/board.js +43 -0
  33. package/dist/core/capabilities/camera-view.d.ts +4 -2
  34. package/dist/core/capabilities/camera-view.js +6 -3
  35. package/dist/core/capabilities/connect-signal.d.ts +85 -0
  36. package/dist/core/capabilities/connect-signal.js +285 -0
  37. package/dist/core/capabilities/engine-fallbacks.d.ts +5 -0
  38. package/dist/core/capabilities/engine-fallbacks.js +5 -0
  39. package/dist/core/capabilities/engine-ops.d.ts +5 -1
  40. package/dist/core/capabilities/engine-ops.js +0 -3
  41. package/dist/core/capabilities/engine-receipt.d.ts +12 -0
  42. package/dist/core/capabilities/engine-receipt.js +26 -0
  43. package/dist/core/capabilities/file-read.d.ts +64 -0
  44. package/dist/core/capabilities/file-read.js +325 -0
  45. package/dist/core/capabilities/game-task-plan.js +4 -2
  46. package/dist/core/capabilities/grep.d.ts +60 -0
  47. package/dist/core/capabilities/grep.js +190 -0
  48. package/dist/core/capabilities/inspect-node.d.ts +56 -0
  49. package/dist/core/capabilities/inspect-node.js +225 -0
  50. package/dist/core/capabilities/inspect-resource.d.ts +61 -0
  51. package/dist/core/capabilities/inspect-resource.js +376 -0
  52. package/dist/core/capabilities/math3d.d.ts +28 -0
  53. package/dist/core/capabilities/math3d.js +88 -0
  54. package/dist/core/capabilities/motion-generation.d.ts +62 -0
  55. package/dist/core/capabilities/motion-generation.js +138 -0
  56. package/dist/core/capabilities/placement-batch.d.ts +102 -0
  57. package/dist/core/capabilities/placement-batch.js +483 -0
  58. package/dist/core/capabilities/placement-math.d.ts +70 -0
  59. package/dist/core/capabilities/placement-math.js +209 -0
  60. package/dist/core/capabilities/placement-script.d.ts +42 -0
  61. package/dist/core/capabilities/placement-script.js +1096 -0
  62. package/dist/core/capabilities/placement.d.ts +485 -0
  63. package/dist/core/capabilities/placement.js +1731 -0
  64. package/dist/core/capabilities/project-context.d.ts +33 -2
  65. package/dist/core/capabilities/project-context.js +87 -4
  66. package/dist/core/capabilities/replace-node.d.ts +91 -0
  67. package/dist/core/capabilities/replace-node.js +423 -0
  68. package/dist/core/capabilities/runtime-control.d.ts +18 -2
  69. package/dist/core/capabilities/runtime-control.js +67 -2
  70. package/dist/core/capabilities/scene-batch.d.ts +63 -0
  71. package/dist/core/capabilities/scene-batch.js +394 -0
  72. package/dist/core/capabilities/scene-readback.d.ts +36 -0
  73. package/dist/core/capabilities/scene-readback.js +54 -0
  74. package/dist/core/capabilities/seeing/args.d.ts +348 -0
  75. package/dist/core/capabilities/seeing/args.js +178 -0
  76. package/dist/core/capabilities/seeing/candidates.d.ts +127 -0
  77. package/dist/core/capabilities/seeing/candidates.js +282 -0
  78. package/dist/core/capabilities/seeing/math.d.ts +134 -0
  79. package/dist/core/capabilities/seeing/math.js +269 -0
  80. package/dist/core/capabilities/seeing/probe.d.ts +62 -0
  81. package/dist/core/capabilities/seeing/probe.js +188 -0
  82. package/dist/core/capabilities/seeing/scoring.d.ts +235 -0
  83. package/dist/core/capabilities/seeing/scoring.js +639 -0
  84. package/dist/core/capabilities/seeing/seeing.d.ts +233 -0
  85. package/dist/core/capabilities/seeing/seeing.js +1341 -0
  86. package/dist/core/capabilities/seeing/shot-store.d.ts +52 -0
  87. package/dist/core/capabilities/seeing/shot-store.js +204 -0
  88. package/dist/core/capabilities/surface-snap-mesh.d.ts +88 -0
  89. package/dist/core/capabilities/surface-snap-mesh.js +425 -0
  90. package/dist/core/capabilities/surface-snap.d.ts +77 -0
  91. package/dist/core/capabilities/surface-snap.js +461 -0
  92. package/dist/core/capabilities/tool-dispatch.js +231 -72
  93. package/dist/core/capabilities/tscn.d.ts +85 -0
  94. package/dist/core/capabilities/tscn.js +391 -0
  95. package/dist/core/capabilities/world-snapshot.d.ts +58 -0
  96. package/dist/core/capabilities/world-snapshot.js +150 -0
  97. package/dist/core/capability-skew.d.ts +5 -5
  98. package/dist/core/capability-skew.js +14 -6
  99. package/dist/core/headless/worker-engine-client.d.ts +1 -1
  100. package/dist/core/headless/worker-engine-client.js +2 -2
  101. package/dist/core/library-read.d.ts +37 -5
  102. package/dist/core/library-read.js +264 -33
  103. package/dist/core/library-search.d.ts +2 -2
  104. package/dist/installer/agent-config.js +5 -3
  105. package/dist/installer/agent-table.d.ts +16 -0
  106. package/dist/installer/agent-table.js +52 -17
  107. package/dist/mcp/server.js +9 -3
  108. package/dist/mcp/tools/asset-tools.js +21 -3
  109. package/dist/mcp/tools/audit-tools.d.ts +23 -0
  110. package/dist/mcp/tools/audit-tools.js +60 -0
  111. package/dist/mcp/tools/debug-tools.js +3 -1
  112. package/dist/mcp/tools/file-tools.js +17 -4
  113. package/dist/mcp/tools/generate-tools.js +74 -66
  114. package/dist/mcp/tools/library-tools.js +2 -0
  115. package/dist/mcp/tools/perception-tools.js +6 -19
  116. package/dist/mcp/tools/placement-tools.d.ts +24 -0
  117. package/dist/mcp/tools/placement-tools.js +91 -0
  118. package/dist/mcp/tools/project-tools.js +18 -15
  119. package/dist/mcp/tools/scene-tools.js +71 -83
  120. package/dist/mcp/tools/seeing-tools.d.ts +24 -0
  121. package/dist/mcp/tools/seeing-tools.js +64 -0
  122. package/dist/mcp/tools/spatial-tools.js +17 -9
  123. package/dist/mcp/tools/visual-tools.js +59 -7
  124. package/gemini-extension.json +26 -4
  125. package/integrations/amp/README.md +1 -1
  126. package/integrations/crush/README.md +1 -1
  127. package/integrations/grok-build/README.md +1 -1
  128. package/integrations/hermes/README.md +1 -1
  129. package/integrations/kimi-code/README.md +1 -1
  130. package/integrations/mistral-vibe/README.md +1 -1
  131. package/integrations/opencode/README.md +1 -1
  132. package/integrations/rovo-dev/README.md +1 -1
  133. package/integrations/vscode-copilot/README.md +1 -1
  134. package/integrations/warp/README.md +1 -1
  135. package/integrations/windsurf/README.md +1 -1
  136. package/library/references/mcp-tools-reference/mcp-tools-reference.md +59 -15
  137. package/library/references/mcp-tools-reference/resource.yaml +1 -1
  138. package/library/references/summer-folder/resource.yaml +1 -1
  139. package/library/references/summer-folder/summer-folder.md +1 -1
  140. package/library/skills/3d-lighting/SKILL.md +1 -1
  141. package/library/skills/README.md +36 -14
  142. package/library/skills/adaptive-music/SKILL.md +1 -1
  143. package/library/skills/agent-playtesting/SKILL.md +1 -1
  144. package/library/skills/ai-characters-in-games/SKILL.md +220 -0
  145. package/library/skills/ai-characters-in-games/resource.yaml +30 -0
  146. package/library/skills/ambient-bed/SKILL.md +1 -1
  147. package/library/skills/animated-loop/SKILL.md +1 -1
  148. package/library/skills/animation-tree/SKILL.md +1 -1
  149. package/library/skills/art-direction/SKILL.md +1 -1
  150. package/library/skills/asset-strategy/SKILL.md +2 -1
  151. package/library/skills/asset-strategy/resource.yaml +2 -1
  152. package/library/skills/audio-direction/SKILL.md +1 -1
  153. package/library/skills/auto-fire-targeting/SKILL.md +1 -1
  154. package/library/skills/brainstorm-game/SKILL.md +1 -1
  155. package/library/skills/brainstorming/SKILL.md +1 -1
  156. package/library/skills/browse-templates/SKILL.md +3 -3
  157. package/library/skills/browse-templates/resource.yaml +1 -1
  158. package/library/skills/camera-rigs/SKILL.md +128 -0
  159. package/library/skills/camera-rigs/resource.yaml +29 -0
  160. package/library/skills/celeste-momentum-platforming/SKILL.md +1 -1
  161. package/library/skills/character-animation-wiring/SKILL.md +1 -1
  162. package/library/skills/character-model/SKILL.md +1 -1
  163. package/library/skills/character-movement/SKILL.md +326 -0
  164. package/library/skills/character-movement/references/default-third-person-controller.gd +201 -0
  165. package/library/skills/character-movement/references/default-third-person-verification-probe.gd +154 -0
  166. package/library/skills/character-movement/references/movement-3d.md +136 -0
  167. package/library/skills/character-movement/references/platformer-feel.md +83 -0
  168. package/library/skills/character-movement/resource.yaml +40 -0
  169. package/library/skills/character-portrait/SKILL.md +1 -1
  170. package/library/skills/cinematic-cutscene/SKILL.md +1 -1
  171. package/library/skills/combat-basics/SKILL.md +159 -0
  172. package/library/skills/combat-basics/references/projectiles-and-aoe.md +100 -0
  173. package/library/skills/combat-basics/resource.yaml +34 -0
  174. package/library/skills/concept-art/SKILL.md +1 -1
  175. package/library/skills/create-asset-sheet/SKILL.md +1 -1
  176. package/library/skills/debug/SKILL.md +1 -1
  177. package/library/skills/debugging-game-feel/SKILL.md +1 -1
  178. package/library/skills/design-level/SKILL.md +1 -1
  179. package/library/skills/design-mechanic/SKILL.md +1 -1
  180. package/library/skills/design-npc/SKILL.md +1 -1
  181. package/library/skills/diagnosing-perf-regressions/SKILL.md +1 -1
  182. package/library/skills/dispatching-parallel-agents/SKILL.md +1 -1
  183. package/library/skills/driving-the-editor-ui/SKILL.md +1 -1
  184. package/library/skills/environment-kit/SKILL.md +1 -1
  185. package/library/skills/export-and-ship/SKILL.md +1 -1
  186. package/library/skills/fabricating-assets/SKILL.md +1 -1
  187. package/library/skills/facial-and-lipsync/SKILL.md +1 -1
  188. package/library/skills/fps-controller/SKILL.md +9 -7
  189. package/library/skills/fps-controller/resource.yaml +4 -1
  190. package/library/skills/game-feel/SKILL.md +1 -1
  191. package/library/skills/gameskill/SKILL.md +1 -1
  192. package/library/skills/gdscript-patterns/SKILL.md +1 -1
  193. package/library/skills/generate-motion/SKILL.md +9 -9
  194. package/library/skills/generate-motion/resource.yaml +2 -1
  195. package/library/skills/godogen-visual-proof-game-generation/SKILL.md +1 -1
  196. package/library/skills/headless-scripting/SKILL.md +1 -1
  197. package/library/skills/in-game-purchases/SKILL.md +254 -0
  198. package/library/skills/in-game-purchases/resource.yaml +29 -0
  199. package/library/skills/instantiate-asset-pack/SKILL.md +1 -1
  200. package/library/skills/investigating-bugs/SKILL.md +1 -1
  201. package/library/skills/lumera-single-image-scene-reconstruction/SKILL.md +1 -1
  202. package/library/skills/make-game/SKILL.md +25 -3
  203. package/library/skills/make-game/references/2d-platformer-polish.md +93 -0
  204. package/library/skills/make-game/references/2d-platformer.md +117 -0
  205. package/library/skills/make-game/references/2d-rpg-content.md +234 -0
  206. package/library/skills/make-game/references/2d-rpg.md +241 -0
  207. package/library/skills/make-game/references/2d-survivors-progression.md +201 -0
  208. package/library/skills/make-game/references/2d-survivors.md +237 -0
  209. package/library/skills/make-game/references/3d-fps-systems.md +216 -0
  210. package/library/skills/make-game/references/3d-fps.md +177 -0
  211. package/library/skills/make-game/references/3d-horror-systems.md +186 -0
  212. package/library/skills/make-game/references/3d-horror.md +201 -0
  213. package/library/skills/make-game/references/3d-third-person-systems.md +220 -0
  214. package/library/skills/make-game/references/3d-third-person.md +215 -0
  215. package/library/skills/make-game/resource.yaml +6 -1
  216. package/library/skills/multiplayer/SKILL.md +150 -0
  217. package/library/skills/multiplayer/resource.yaml +33 -0
  218. package/library/skills/multiplayer-movement/SKILL.md +510 -0
  219. package/library/skills/multiplayer-movement/files.md +501 -0
  220. package/library/skills/multiplayer-movement/resource.yaml +30 -0
  221. package/library/skills/multiplayer-project/SKILL.md +521 -0
  222. package/library/skills/multiplayer-project/files.md +448 -0
  223. package/library/skills/multiplayer-project/resource.yaml +36 -0
  224. package/library/skills/multiplayer-publish/SKILL.md +229 -0
  225. package/library/skills/multiplayer-publish/export-errors.md +89 -0
  226. package/library/skills/multiplayer-publish/resource.yaml +28 -0
  227. package/library/skills/multiplayer-state/SKILL.md +438 -0
  228. package/library/skills/multiplayer-state/files.md +592 -0
  229. package/library/skills/multiplayer-state/resource.yaml +35 -0
  230. package/library/skills/multiplayer-testing/SKILL.md +236 -0
  231. package/library/skills/multiplayer-testing/resource.yaml +39 -0
  232. package/library/skills/music-track/SKILL.md +1 -1
  233. package/library/skills/navigate-summer/SKILL.md +1 -1
  234. package/library/skills/new-project/SKILL.md +1 -1
  235. package/library/skills/organic-model/SKILL.md +1 -1
  236. package/library/skills/pixel-art/SKILL.md +1 -1
  237. package/library/skills/play/SKILL.md +1 -1
  238. package/library/skills/playtesting-a-feature/SKILL.md +1 -1
  239. package/library/skills/procedural-animation/SKILL.md +2 -2
  240. package/library/skills/procedural-animation/resource.yaml +1 -1
  241. package/library/skills/prop-model/SKILL.md +1 -1
  242. package/library/skills/psx-retro-rendering/SKILL.md +1 -1
  243. package/library/skills/realtime-wet-surfaces/SKILL.md +2 -2
  244. package/library/skills/remote-deploy/SKILL.md +1 -1
  245. package/library/skills/retarget/SKILL.md +1 -1
  246. package/library/skills/running-in-the-cloud/SKILL.md +1 -1
  247. package/library/skills/save-load/SKILL.md +156 -0
  248. package/library/skills/save-load/resource.yaml +27 -0
  249. package/library/skills/scene-composition/SKILL.md +1 -1
  250. package/library/skills/scene-hierarchy-design/SKILL.md +1 -1
  251. package/library/skills/scene-scripting/SKILL.md +1 -1
  252. package/library/skills/scene-to-level/SKILL.md +1 -1
  253. package/library/skills/skill-create/SKILL.md +1 -1
  254. package/library/skills/skill-improve/SKILL.md +1 -1
  255. package/library/skills/skill-test/SKILL.md +1 -1
  256. package/library/skills/skintokens-auto-rigging/SKILL.md +1 -1
  257. package/library/skills/skybox-panorama/SKILL.md +1 -1
  258. package/library/skills/sound-effect/SKILL.md +1 -1
  259. package/library/skills/spatial-placement/SKILL.md +134 -3
  260. package/library/skills/spatial-placement/references/kit-placement-tools.md +364 -0
  261. package/library/skills/spatial-placement/resource.yaml +16 -2
  262. package/library/skills/sprite-sheet/SKILL.md +1 -1
  263. package/library/skills/summer-analytics/SKILL.md +147 -0
  264. package/library/skills/summer-analytics/resource.yaml +28 -0
  265. package/library/skills/summer-friends/SKILL.md +226 -0
  266. package/library/skills/summer-friends/resource.yaml +28 -0
  267. package/library/skills/summer-leaderboards/SKILL.md +231 -0
  268. package/library/skills/summer-leaderboards/resource.yaml +30 -0
  269. package/library/skills/summer-match-results/SKILL.md +286 -0
  270. package/library/skills/summer-match-results/resource.yaml +32 -0
  271. package/library/skills/summer-matchmaking/SKILL.md +301 -0
  272. package/library/skills/summer-matchmaking/resource.yaml +32 -0
  273. package/library/skills/summer-parties/SKILL.md +253 -0
  274. package/library/skills/summer-parties/resource.yaml +30 -0
  275. package/library/skills/summer-player-data/SKILL.md +322 -0
  276. package/library/skills/summer-player-data/resource.yaml +30 -0
  277. package/library/skills/summer-store/SKILL.md +271 -0
  278. package/library/skills/summer-store/resource.yaml +29 -0
  279. package/library/skills/summer-world-chat/SKILL.md +195 -0
  280. package/library/skills/summer-world-chat/resource.yaml +30 -0
  281. package/library/skills/summer-world-saves/SKILL.md +284 -0
  282. package/library/skills/summer-world-saves/resource.yaml +29 -0
  283. package/library/skills/text-to-motion/SKILL.md +99 -0
  284. package/library/skills/text-to-motion/prompts-and-controls.md +34 -0
  285. package/library/skills/text-to-motion/resource.yaml +41 -0
  286. package/library/skills/text-to-motion/rigging-for-text-motion.md +54 -0
  287. package/library/skills/tileable-texture/SKILL.md +1 -1
  288. package/library/skills/trailer-shot/SKILL.md +1 -1
  289. package/library/skills/tune-performance/SKILL.md +1 -1
  290. package/library/skills/ui-basics/SKILL.md +10 -1
  291. package/library/skills/ui-graphics/SKILL.md +1 -1
  292. package/library/skills/use-widget-asset/SKILL.md +1 -1
  293. package/library/skills/using-summer/SKILL.md +2 -2
  294. package/library/skills/using-summer/resource.yaml +2 -2
  295. package/library/skills/vehicle-model/SKILL.md +1 -1
  296. package/library/skills/verification-before-completion/SKILL.md +1 -1
  297. package/library/skills/verifying-scenes/SKILL.md +76 -2
  298. package/library/skills/verifying-scenes/resource.yaml +13 -2
  299. package/library/skills/vfx-dissolve/SKILL.md +1 -1
  300. package/library/skills/vfx-fire/SKILL.md +1 -1
  301. package/library/skills/vfx-hit-spark/SKILL.md +1 -1
  302. package/library/skills/vfx-lightning/SKILL.md +1 -1
  303. package/library/skills/vfx-magic-glow/SKILL.md +1 -1
  304. package/library/skills/vfx-muzzle-flash/SKILL.md +1 -1
  305. package/library/skills/vfx-smoke/SKILL.md +1 -1
  306. package/library/skills/vfx-water-ripple/SKILL.md +1 -1
  307. package/library/skills/voice-line/SKILL.md +1 -1
  308. package/library/skills/web-and-touch-input/SKILL.md +38 -0
  309. package/library/skills/web-and-touch-input/resource.yaml +28 -0
  310. package/library/skills/web-compatibility-look/SKILL.md +62 -0
  311. package/library/skills/web-compatibility-look/resource.yaml +30 -0
  312. package/library/skills/world-building-3d/SKILL.md +8 -1
  313. package/library/skills/world-building-3d/references/spatial-tools.md +1 -1
  314. package/library/skills/world-building-3d/resource.yaml +2 -1
  315. package/library/skills/writing-plans/SKILL.md +1 -1
  316. package/library/skills/writing-skills/SKILL.md +1 -1
  317. package/library/templates/3d-lan-multiplayer-starter/resource.yaml +2 -2
  318. package/library/tools/attach-to-surface/resource.yaml +142 -0
  319. package/library/tools/batch/resource.yaml +9 -3
  320. package/library/tools/connect-ports/resource.yaml +120 -0
  321. package/library/tools/connect-signal/resource.yaml +3 -2
  322. package/library/tools/debug-views/resource.yaml +94 -0
  323. package/library/tools/frame-nodes/resource.yaml +104 -0
  324. package/library/tools/frame-shot/resource.yaml +134 -0
  325. package/library/tools/generate-motion/resource.yaml +44 -9
  326. package/library/tools/get-board/resource.yaml +50 -0
  327. package/library/tools/get-project-context/resource.yaml +13 -2
  328. package/library/tools/grep/resource.yaml +77 -0
  329. package/library/tools/inspect-asset/resource.yaml +71 -0
  330. package/library/tools/inspect-node/resource.yaml +9 -2
  331. package/library/tools/inspect-resource/resource.yaml +16 -5
  332. package/library/tools/instantiate-scene/resource.yaml +27 -2
  333. package/library/tools/measure/resource.yaml +96 -0
  334. package/library/tools/place-adjacent/resource.yaml +113 -0
  335. package/library/tools/play/resource.yaml +15 -2
  336. package/library/tools/raycast/resource.yaml +101 -0
  337. package/library/tools/read-file/resource.yaml +36 -2
  338. package/library/tools/read-library/resource.yaml +2 -2
  339. package/library/tools/repeat-along/resource.yaml +129 -0
  340. package/library/tools/replace-node/resource.yaml +11 -5
  341. package/library/tools/scene-audit/resource.yaml +144 -0
  342. package/library/tools/screenshot/resource.yaml +13 -2
  343. package/library/tools/search-assets/resource.yaml +18 -0
  344. package/library/tools/shot-sheet/resource.yaml +110 -0
  345. package/library/tools/snap-to-surface/resource.yaml +4 -1
  346. package/library/tools/world-snapshot/resource.yaml +24 -3
  347. package/library/tools/zoom/resource.yaml +105 -0
  348. package/package.json +1 -1
  349. package/registry/generated/aliases.json +17 -3
  350. package/registry/generated/counts.json +3 -3
  351. package/registry/generated/gemini-extension.json +26 -4
  352. package/registry/generated/index.json +2154 -469
  353. package/registry/generated/marketplace.claude.json +2 -2
  354. package/registry/generated/plugin.claude.json +27 -5
  355. package/registry/generated/plugin.codex.json +28 -6
  356. package/registry/generated/plugin.cursor.json +27 -5
  357. package/registry/generated/plugin.factory.json +27 -5
  358. package/registry/generated/skills-index.md +36 -14
  359. package/registry/generated/skills-registry.json +421 -124
  360. package/registry/generated/templates-registry.json +2 -2
  361. package/library/skills/host-authoritative-state/SKILL.md +0 -332
  362. package/library/skills/host-authoritative-state/resource.yaml +0 -28
  363. package/library/skills/peer-to-peer-multiplayer/SKILL.md +0 -373
  364. package/library/skills/peer-to-peer-multiplayer/resource.yaml +0 -28
  365. package/library/skills/setup-multiplayer/SKILL.md +0 -336
  366. package/library/skills/setup-multiplayer/resource.yaml +0 -28
@@ -0,0 +1,483 @@
1
+ /**
2
+ * Instantiate-with-transform and compact batch receipts, shared by
3
+ * summer_instantiate_scene, summer_batch, summer_repeat_along and their CLI
4
+ * twins.
5
+ *
6
+ * The engine's InstantiateScene accepts only parent / scene / name /
7
+ * target_size (scene_ops.cpp instantiate_scene) and must travel as its own
8
+ * request (single-only). A placed piece is therefore an InstantiateScene plus
9
+ * SetProps on the node path its receipt reports (meta.nodePath, which already
10
+ * carries any collision rename). The caller writes ONE op; this module expands
11
+ * it.
12
+ *
13
+ * Request cost: the SetProps of consecutive InstantiateScene ops are held back
14
+ * and sent together (up to TRANSFORM_OPS_PER_REQUEST per request) just before
15
+ * the next op that is not an InstantiateScene, riding along with it when it is
16
+ * batchable. N placed pieces followed by the SaveScene therefore cost N + 2
17
+ * requests, not 2N + 1. Every op that could depend on a piece's transform
18
+ * (SetProp, SnapToSurface, AlignDistribute3D, a raw query, the SaveScene) runs
19
+ * after the transforms land, and when an InstantiateScene fails the transforms
20
+ * of the pieces already created are still sent, so a failure never leaves an
21
+ * earlier piece sitting at the origin.
22
+ *
23
+ * With no placement fields and receipt "full", callers keep using the old
24
+ * executeSceneMutation path unchanged.
25
+ */
26
+ import { ToolInputError } from "../tool-errors.js";
27
+ import { asRecord } from "../util/json.js";
28
+ import { resolveSingleOnlyOps } from "../capability-skew.js";
29
+ import { extractOpError } from "./engine-receipt.js";
30
+ import { executeSceneBatch, rawConnectSignalRefusal } from "./scene-batch.js";
31
+ import { executeOpsChunked, executeSceneMutation, isSingleOnlyOp, sceneMutationOps, } from "./engine-ops.js";
32
+ import { isFiniteVec3, parseGodotTransform, parseGodotVector3, toGodotTransform, toGodotVector3, } from "./placement-math.js";
33
+ /** Fields an InstantiateScene op may carry that the engine op itself lacks. */
34
+ export const PLACEMENT_FIELDS = ["position", "rotation_degrees", "scale", "transform"];
35
+ /** Model-visible budget for compact receipts (the 5 KB tool-result contract). */
36
+ export const COMPACT_LIMIT_BYTES = 5 * 1024;
37
+ /** Held-back transform SetProps sent per request; the engine refuses requests
38
+ * over 256 ops (local_api_server.cpp). */
39
+ export const TRANSFORM_OPS_PER_REQUEST = 200;
40
+ const SUMMARY_TARGET_BYTES = 4600;
41
+ const ERROR_TEXT_LIMIT = 240;
42
+ function vectorField(value, label) {
43
+ if (isFiniteVec3(value))
44
+ return value;
45
+ if (typeof value === "string") {
46
+ const parsed = parseGodotVector3(value);
47
+ if (parsed)
48
+ return parsed;
49
+ }
50
+ throw new ToolInputError(`${label} must be [x, y, z] finite numbers or a "Vector3(x, y, z)" string.`);
51
+ }
52
+ /**
53
+ * Split one InstantiateScene op into the engine op (placement fields removed)
54
+ * and the SetProps that place it. Validates every field before anything is
55
+ * sent; `label` names the op in error messages (e.g. "ops[3]").
56
+ */
57
+ export function splitInstantiatePlacement(op, label) {
58
+ const present = PLACEMENT_FIELDS.filter((field) => op[field] !== undefined && op[field] !== null);
59
+ if (present.length === 0)
60
+ return { op, props: [] };
61
+ const stripped = { ...op };
62
+ for (const field of PLACEMENT_FIELDS)
63
+ delete stripped[field];
64
+ if (present.includes("transform") && present.length > 1) {
65
+ throw new ToolInputError(`${label}: pass either transform or position/rotation_degrees/scale, not both.`);
66
+ }
67
+ if (op.target_size !== undefined && (present.includes("scale") || present.includes("transform"))) {
68
+ throw new ToolInputError(`${label}: target_size sets the scale; do not combine it with scale or transform.`);
69
+ }
70
+ if (present.includes("transform")) {
71
+ const raw = op.transform;
72
+ const parsed = typeof raw === "string" ? parseGodotTransform(raw) : null;
73
+ if (!parsed) {
74
+ throw new ToolInputError(`${label}.transform must be a "Transform3D(xx, xy, xz, yx, yy, yz, zx, zy, zz, ox, oy, oz)" string.`);
75
+ }
76
+ return { op: stripped, props: [{ key: "transform", value: toGodotTransform(parsed) }] };
77
+ }
78
+ // Rotation and scale first, position last: independent local properties,
79
+ // but this order reads like the inspector.
80
+ const props = [];
81
+ for (const key of ["rotation_degrees", "scale", "position"]) {
82
+ if (op[key] === undefined || op[key] === null)
83
+ continue;
84
+ props.push({ key, value: toGodotVector3(vectorField(op[key], `${label}.${key}`)) });
85
+ }
86
+ return { op: stripped, props };
87
+ }
88
+ export function hasPlacementFields(op) {
89
+ return PLACEMENT_FIELDS.some((field) => op[field] !== undefined && op[field] !== null);
90
+ }
91
+ function readFailure(result) {
92
+ if (!result)
93
+ return {};
94
+ const error = typeof result.error === "string" ? result.error : undefined;
95
+ const failureReason = typeof result.failure_reason === "string"
96
+ ? result.failure_reason
97
+ : typeof result.failureReason === "string"
98
+ ? result.failureReason
99
+ : undefined;
100
+ return { error, failureReason };
101
+ }
102
+ /** The node path an InstantiateScene / AddNode receipt reports. */
103
+ export function receiptNodePath(result) {
104
+ const meta = asRecord(result?.meta);
105
+ const path = meta?.nodePath;
106
+ return typeof path === "string" && path.length > 0 ? path : undefined;
107
+ }
108
+ /**
109
+ * Run an op list (SaveScene already appended by the caller when it mutates a
110
+ * scene) honoring the single-op contract, expanding InstantiateScene placement
111
+ * fields into SetProps on the created node. The SetProps of a run of
112
+ * InstantiateScene ops are sent together before the next other op (see the
113
+ * module comment).
114
+ */
115
+ export async function executePlacementBatch(send, ops, singleOnly,
116
+ /** How many leading ops are the caller's; later ones (the appended
117
+ * SaveScene) are reported with index null. */
118
+ inputCount = ops.length) {
119
+ // Validate and plan everything before the first request. Placement fields
120
+ // are read on InstantiateScene only; every other op is forwarded verbatim.
121
+ const planned = ops.map((op, index) => {
122
+ const ownIndex = index < inputCount ? index : null;
123
+ if (String(op.op ?? "") === "InstantiateScene") {
124
+ const split = splitInstantiatePlacement(op, `ops[${index}]`);
125
+ return { op: split.op, index: ownIndex, props: split.props };
126
+ }
127
+ return { op, index: ownIndex, props: [] };
128
+ });
129
+ // Group consecutive batchable ops; single-only ops travel alone.
130
+ const chunks = [];
131
+ let current = [];
132
+ for (const item of planned) {
133
+ if (isSingleOnlyOp(String(item.op.op ?? ""), singleOnly)) {
134
+ if (current.length > 0)
135
+ chunks.push(current);
136
+ current = [];
137
+ chunks.push([item]);
138
+ }
139
+ else {
140
+ current.push(item);
141
+ }
142
+ }
143
+ if (current.length > 0)
144
+ chunks.push(current);
145
+ const trace = { entries: [], receipts: [], requests: 0, failed: false };
146
+ const entryFor = (item, derived, opKind) => ({
147
+ index: item.index,
148
+ op: opKind ?? String(item.op.op ?? ""),
149
+ ...(derived ? { derived } : {}),
150
+ sent: false,
151
+ });
152
+ const allEntries = chunks.map((chunk) => chunk.map((item) => entryFor(item)));
153
+ trace.entries = allEntries.flat();
154
+ const sendChunk = async (sent, entries) => {
155
+ trace.requests++;
156
+ const receipt = await send(sent);
157
+ trace.receipts.push(receipt);
158
+ const envelope = (asRecord(receipt) ?? {});
159
+ trace.last = envelope;
160
+ const results = Array.isArray(envelope.results) ? envelope.results : [];
161
+ const envelopeError = extractOpError(receipt);
162
+ entries.forEach((entry, i) => {
163
+ entry.sent = true;
164
+ const result = asRecord(results[i]) ?? undefined;
165
+ entry.result = result;
166
+ if (result && result.ok === false) {
167
+ entry.ok = false;
168
+ Object.assign(entry, readFailure(result));
169
+ }
170
+ else if (result && result.ok === true) {
171
+ entry.ok = true;
172
+ }
173
+ else if (envelopeError) {
174
+ entry.ok = false;
175
+ entry.error = typeof envelope.error === "string" ? envelope.error : envelopeError;
176
+ }
177
+ else {
178
+ entry.ok = true;
179
+ }
180
+ });
181
+ if (envelopeError) {
182
+ trace.failed = true;
183
+ trace.failedEnvelope = envelope;
184
+ return false;
185
+ }
186
+ return true;
187
+ };
188
+ // Transform SetProps held back from InstantiateScene ops, sent together.
189
+ const pending = [];
190
+ const flushPending = async () => {
191
+ while (pending.length > 0) {
192
+ const part = pending.splice(0, TRANSFORM_OPS_PER_REQUEST);
193
+ const ok = await sendChunk(part.map((item) => item.op), part.map((item) => item.entry));
194
+ if (!ok)
195
+ return false;
196
+ }
197
+ return true;
198
+ };
199
+ for (let c = 0; c < chunks.length; c++) {
200
+ const chunk = chunks[c];
201
+ const entries = allEntries[c];
202
+ const head = chunk[0];
203
+ const instantiate = chunk.length === 1 && String(head.op.op ?? "") === "InstantiateScene";
204
+ if (!instantiate && pending.length > 0) {
205
+ const batchable = !isSingleOnlyOp(String(head.op.op ?? ""), singleOnly);
206
+ if (batchable && pending.length + chunk.length <= TRANSFORM_OPS_PER_REQUEST) {
207
+ // The held-back transforms ride along, ahead of the ops that may read them.
208
+ const part = pending.splice(0);
209
+ const ok = await sendChunk([...part.map((item) => item.op), ...chunk.map((item) => item.op)], [...part.map((item) => item.entry), ...entries]);
210
+ if (!ok)
211
+ break;
212
+ continue;
213
+ }
214
+ if (!(await flushPending()))
215
+ break;
216
+ }
217
+ const ok = await sendChunk(chunk.map((item) => item.op), entries);
218
+ if (!ok) {
219
+ // The pieces created before the failure still get their transforms.
220
+ if (instantiate)
221
+ await flushPending();
222
+ break;
223
+ }
224
+ if (instantiate && head.props.length > 0) {
225
+ const nodePath = receiptNodePath(entries[0].result);
226
+ if (!nodePath) {
227
+ trace.failed = true;
228
+ entries[0].ok = false;
229
+ entries[0].failureReason = "instantiate_receipt_missing_node_path";
230
+ entries[0].error =
231
+ "InstantiateScene applied but its receipt carried no meta.nodePath, so the requested transform was NOT applied; the instance sits at its scene default. Set it with summer_set_prop.";
232
+ await flushPending();
233
+ break;
234
+ }
235
+ const propEntries = head.props.map(() => entryFor(head, "transform", "SetProp"));
236
+ // Keep trace order: the derived SetProps right after their InstantiateScene.
237
+ const at = trace.entries.indexOf(entries[0]);
238
+ trace.entries.splice(at + 1, 0, ...propEntries);
239
+ head.props.forEach((prop, i) => {
240
+ pending.push({ op: { op: "SetProp", path: nodePath, key: prop.key, value: prop.value }, entry: propEntries[i] });
241
+ });
242
+ }
243
+ }
244
+ // An op list without a trailing op (no SaveScene) still sends its transforms.
245
+ if (!trace.failed)
246
+ await flushPending();
247
+ if (trace.failed)
248
+ trace.error = honestError(trace);
249
+ return trace;
250
+ }
251
+ function honestError(trace) {
252
+ const failed = trace.entries.find((entry) => entry.ok === false);
253
+ const envelope = trace.failedEnvelope;
254
+ const base = (typeof envelope?.error === "string" && envelope.error) ||
255
+ failed?.error ||
256
+ `Engine request failed (${failed?.op ?? "batch"}).`;
257
+ const applied = trace.entries.filter((entry) => entry.sent && entry.ok === true).map((entry) => entry.op);
258
+ const notSent = trace.entries.filter((entry) => !entry.sent).map((entry) => entry.op);
259
+ if (applied.length === 0)
260
+ return base;
261
+ const savePending = notSent.includes("SaveScene");
262
+ return (`${base} NOTE: ${applied.length} earlier op(s) already applied` +
263
+ (savePending
264
+ ? " — the scene is modified in the editor but NOT saved to disk. Fix the problem, then call summer_save_scene."
265
+ : ".") +
266
+ (notSent.length > 0 ? ` Not sent: ${notSent.length} op(s).` : ""));
267
+ }
268
+ /** The merged envelope in the same shape executeOpsChunked returns. */
269
+ export function traceEnvelope(trace) {
270
+ const results = trace.entries.filter((entry) => entry.result).map((entry) => entry.result);
271
+ if (trace.failed) {
272
+ return {
273
+ ...(trace.failedEnvelope ?? trace.last ?? {}),
274
+ ok: false,
275
+ status: "error",
276
+ error: trace.error,
277
+ results,
278
+ receipts: trace.receipts,
279
+ };
280
+ }
281
+ if (trace.requests === 1)
282
+ return (asRecord(trace.receipts[0]) ?? {});
283
+ return { ...(trace.last ?? {}), results, requests: trace.requests, receipts: trace.receipts };
284
+ }
285
+ function clip(text) {
286
+ if (!text)
287
+ return text;
288
+ return text.length > ERROR_TEXT_LIMIT ? `${text.slice(0, ERROR_TEXT_LIMIT)}...` : text;
289
+ }
290
+ /**
291
+ * Compact receipt: counts, failures with their op index, created node paths.
292
+ * Lists are trimmed to stay under the 5 KB budget and the trim is declared.
293
+ */
294
+ export function summarizeTrace(trace, inputOps) {
295
+ const byIndex = new Map();
296
+ for (const entry of trace.entries) {
297
+ if (entry.index === null)
298
+ continue;
299
+ const list = byIndex.get(entry.index) ?? [];
300
+ list.push(entry);
301
+ byIndex.set(entry.index, list);
302
+ }
303
+ let applied = 0;
304
+ let notSent = 0;
305
+ const failures = [];
306
+ const created = [];
307
+ const renamed = [];
308
+ for (let index = 0; index < inputOps.length; index++) {
309
+ const entries = byIndex.get(index) ?? [];
310
+ if (entries.length === 0 || entries.every((entry) => !entry.sent)) {
311
+ notSent++;
312
+ continue;
313
+ }
314
+ const bad = entries.find((entry) => entry.ok === false);
315
+ if (bad) {
316
+ failures.push({
317
+ index,
318
+ op: String(inputOps[index].op ?? ""),
319
+ ...(bad.derived ? { step: "transform_setprop" } : {}),
320
+ ...(bad.failureReason ? { failure_reason: bad.failureReason } : {}),
321
+ error: clip(bad.error ?? "failed"),
322
+ });
323
+ }
324
+ else {
325
+ applied++;
326
+ }
327
+ const head = entries[0];
328
+ if ((head.op === "InstantiateScene" || head.op === "AddNode") && head.ok) {
329
+ const path = receiptNodePath(head.result);
330
+ if (path) {
331
+ created.push(path);
332
+ const requested = inputOps[index].name;
333
+ const actualName = path.split("/").pop();
334
+ if (typeof requested === "string" && requested.length > 0 && actualName !== requested) {
335
+ renamed.push({ index, requested, actual: path });
336
+ }
337
+ }
338
+ }
339
+ }
340
+ const save = trace.entries.find((entry) => entry.index === null && entry.op === "SaveScene");
341
+ const summary = {
342
+ ok: !trace.failed,
343
+ receipt: "summary",
344
+ ops: inputOps.length,
345
+ requests: trace.requests,
346
+ applied,
347
+ failed: failures.length,
348
+ not_sent: notSent,
349
+ ...(save ? { saved: save.sent && save.ok === true } : {}),
350
+ ...(trace.failed ? { error: clip(trace.error) } : {}),
351
+ failures,
352
+ created_total: created.length,
353
+ created,
354
+ renamed,
355
+ };
356
+ return fitSummary(summary);
357
+ }
358
+ function bytes(value) {
359
+ return Buffer.byteLength(JSON.stringify(value), "utf8");
360
+ }
361
+ /** Trim created / renamed / failures (in that order) until the summary fits. */
362
+ function fitSummary(summary) {
363
+ if (bytes(summary) <= SUMMARY_TARGET_BYTES)
364
+ return summary;
365
+ const out = { ...summary };
366
+ const truncated = {};
367
+ for (const key of ["created", "renamed", "failures"]) {
368
+ const list = [...(out[key] ?? [])];
369
+ const total = list.length;
370
+ while (list.length > 0 && bytes({ ...out, [key]: list, truncated }) > SUMMARY_TARGET_BYTES) {
371
+ list.pop();
372
+ }
373
+ if (list.length < total) {
374
+ out[key] = list;
375
+ truncated[key] = { shown: list.length, total };
376
+ }
377
+ if (bytes({ ...out, truncated }) <= SUMMARY_TARGET_BYTES)
378
+ break;
379
+ }
380
+ out.truncated = truncated;
381
+ out.truncation_note =
382
+ "Lists were cut to fit the 5 KB receipt. Unlisted created nodes are at parent/name as requested unless a rename was listed; split the batch to see every path.";
383
+ return out;
384
+ }
385
+ /** An older engine applies the op but drops target_size: its receipt then
386
+ * lacks scale_applied. Confess that instead of letting a 40-unit "chair"
387
+ * pass as normalized. */
388
+ function withTargetSizeNote(result, targetSize) {
389
+ if (targetSize === undefined || !result || typeof result !== "object")
390
+ return result;
391
+ const envelope = result;
392
+ const instanced = envelope.results?.find((entry) => entry.op === "InstantiateScene" && entry.ok === true);
393
+ if (instanced && !("scale_applied" in instanced)) {
394
+ return {
395
+ ...envelope,
396
+ target_size_note: `This Summer Engine build IGNORED target_size (no scale_applied in the receipt) — the instance is at the asset's raw scale, NOT normalized to ${targetSize}. ` +
397
+ "Scale it yourself (summer_set_prop scale, or ctx code in summer_run_script), verify with summer_world_snapshot/summer_screenshot, or update Summer Engine.",
398
+ };
399
+ }
400
+ return result;
401
+ }
402
+ export async function instantiateScene(client, args) {
403
+ const op = { op: "InstantiateScene", parent: args.parent, scene: args.scene };
404
+ if (args.name)
405
+ op.name = args.name;
406
+ if (args.target_size !== undefined)
407
+ op.target_size = args.target_size;
408
+ for (const field of PLACEMENT_FIELDS) {
409
+ if (args[field] !== undefined)
410
+ op[field] = args[field];
411
+ }
412
+ if (!hasPlacementFields(op)) {
413
+ return withTargetSizeNote(await executeSceneMutation(client, args.scenePath, [op]), args.target_size);
414
+ }
415
+ const trace = await executePlacementBatch((chunk) => client.executeIdentityBoundOps(chunk, { scenePath: args.scenePath }), sceneMutationOps([op]), resolveSingleOnlyOps(client), 1);
416
+ const envelope = traceEnvelope(trace);
417
+ // results[] already holds every op's receipt; the per-request copies are
418
+ // only kept when something failed (they carry the failing envelope).
419
+ if (!trace.failed)
420
+ delete envelope.receipts;
421
+ const head = trace.entries[0];
422
+ const nodePath = receiptNodePath(head?.result);
423
+ const derived = trace.entries.filter((entry) => entry.derived === "transform");
424
+ const applied = derived.length > 0 && derived.every((entry) => entry.ok === true);
425
+ return withTargetSizeNote({
426
+ ...envelope,
427
+ placement: {
428
+ ...(nodePath ? { nodePath } : {}),
429
+ applied,
430
+ fields: PLACEMENT_FIELDS.filter((field) => op[field] !== undefined),
431
+ space: "parent_local",
432
+ },
433
+ }, args.target_size);
434
+ }
435
+ /** Scene mutation kinds summer_batch recognizes (one SaveScene appended). */
436
+ export const SCENE_MUTATION_OPS = new Set([
437
+ "AddNode", "RemoveNode", "MoveNode", "ReparentNode", "ReplaceNode",
438
+ "SetProp", "SetResourceProperty", "ConnectSignal", "DisconnectSignal",
439
+ "InstantiateScene", "SaveScene", "SnapToSurface", "AlignDistribute3D", "Undo",
440
+ ]);
441
+ /** Read-only spatial queries: identity-bound to an exact scene, never saved. */
442
+ export const SCENE_QUERY_OPS = new Set([
443
+ "TestPlacement3D", "NavigationProbe3D", "Starcast3D",
444
+ ]);
445
+ /**
446
+ * summer_batch's engine path for both faces. Without placement fields and with
447
+ * receipt "full" this is exactly the previous behavior. Raw WriteFile /
448
+ * ReplaceText refusal stays in each face (their messages differ).
449
+ */
450
+ export async function runBatch(client, args) {
451
+ const { scenePath, ops } = args;
452
+ const containsMutation = ops.some((op) => SCENE_MUTATION_OPS.has(String(op.op ?? "")));
453
+ const needsScenePath = containsMutation || ops.some((op) => SCENE_QUERY_OPS.has(String(op.op ?? "")));
454
+ if (needsScenePath && !scenePath) {
455
+ throw new ToolInputError("summer_batch requires scenePath when ops targets a scene");
456
+ }
457
+ const options = { groupUndo: true, ...(scenePath ? { scenePath } : {}) };
458
+ // A raw ConnectSignal is saved without its connection (scene-batch.ts).
459
+ const connectRefusal = rawConnectSignalRefusal(ops);
460
+ if (connectRefusal)
461
+ throw new ToolInputError(connectRefusal);
462
+ const placement = ops.some((op) => String(op.op ?? "") === "InstantiateScene" && hasPlacementFields(op));
463
+ // ReparentNode drops the moved node's subtree on save; scene-batch.ts keeps
464
+ // and verifies it, with its own full receipt.
465
+ if (containsMutation && ops.some((op) => op.op === "ReparentNode")) {
466
+ if (placement || args.receipt === "summary") {
467
+ throw new ToolInputError("summer_batch sends ReparentNode through its keep-and-verify path, which does not expand InstantiateScene placement fields or build a summary receipt. " +
468
+ "Send the ReparentNode ops in their own summer_batch (receipt \"full\"). Nothing was sent.");
469
+ }
470
+ if (typeof client.readProjectFile !== "function" || typeof client.getSceneState !== "function") {
471
+ throw new ToolInputError("summer_batch with ReparentNode needs an engine client that can read the saved scene back. Nothing was sent.");
472
+ }
473
+ return executeSceneBatch(client, scenePath, ops, options);
474
+ }
475
+ if (!placement && args.receipt !== "summary") {
476
+ if (containsMutation)
477
+ return executeSceneMutation(client, scenePath, ops, options);
478
+ return executeOpsChunked((chunk) => (needsScenePath ? client.executeIdentityBoundOps(chunk, options) : client.executeOps(chunk, options)), ops, resolveSingleOnlyOps(client));
479
+ }
480
+ const send = (chunk) => needsScenePath ? client.executeIdentityBoundOps(chunk, options) : client.executeOps(chunk, options);
481
+ const trace = await executePlacementBatch(send, containsMutation ? sceneMutationOps(ops) : ops, resolveSingleOnlyOps(client), ops.length);
482
+ return args.receipt === "summary" ? summarizeTrace(trace, ops) : traceEnvelope(trace);
483
+ }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Small, dependency-free 3D math for the placement tools (tool/place-adjacent,
3
+ * tool/attach-to-surface, tool/connect-ports, tool/repeat-along) and the
4
+ * Godot variant-string formatting they send through SetProp.
5
+ *
6
+ * Conventions:
7
+ * - A basis is three COLUMN vectors [x, y, z] (Godot's Basis.x/.y/.z).
8
+ * - A transform is { basis, origin } and maps local -> parent space.
9
+ * - "Scene space" is the scene root's frame, the same space GetWorldSnapshot
10
+ * and the placement scripts report; in the editor it equals world space.
11
+ * - Godot's Transform3D(...) string lists the basis ROW-major, then the origin
12
+ * (core/variant/variant_parser.cpp), so toGodotTransform transposes.
13
+ */
14
+ export type Vec3 = [number, number, number];
15
+ export type Basis3 = [Vec3, Vec3, Vec3];
16
+ export interface Xform {
17
+ basis: Basis3;
18
+ origin: Vec3;
19
+ }
20
+ export declare const AXIS_NAMES: readonly ["+x", "-x", "+y", "-y", "+z", "-z"];
21
+ export type SignedAxis = (typeof AXIS_NAMES)[number];
22
+ export declare const WORLD_AXES: readonly ["x", "y", "z"];
23
+ export type WorldAxis = (typeof WORLD_AXES)[number];
24
+ export declare const add: (a: Vec3, b: Vec3) => Vec3;
25
+ export declare const sub: (a: Vec3, b: Vec3) => Vec3;
26
+ export declare const scale: (a: Vec3, s: number) => Vec3;
27
+ export declare const dot: (a: Vec3, b: Vec3) => number;
28
+ export declare const cross: (a: Vec3, b: Vec3) => Vec3;
29
+ export declare const length: (a: Vec3) => number;
30
+ export declare function normalize(a: Vec3): Vec3;
31
+ export declare function isFiniteVec3(value: unknown): value is Vec3;
32
+ export declare function axisIndex(axis: WorldAxis): 0 | 1 | 2;
33
+ /** Unit vector for a signed axis name such as "-z". */
34
+ export declare function signedAxisVector(axis: SignedAxis): Vec3;
35
+ export declare function sameAxisLine(a: SignedAxis, b: SignedAxis): boolean;
36
+ export declare const IDENTITY_BASIS: Basis3;
37
+ export declare function basisMulVec(b: Basis3, v: Vec3): Vec3;
38
+ export declare function basisMul(a: Basis3, b: Basis3): Basis3;
39
+ export declare function basisTranspose(b: Basis3): Basis3;
40
+ export declare function basisDeterminant(b: Basis3): number;
41
+ /** General 3x3 inverse (parents may carry non-uniform scale). */
42
+ export declare function basisInverse(b: Basis3): Basis3;
43
+ export declare function xformMulPoint(t: Xform, p: Vec3): Vec3;
44
+ export declare function xformCompose(a: Xform, b: Xform): Xform;
45
+ export declare function xformInverse(t: Xform): Xform;
46
+ /** 12 numbers, basis columns then origin (the placement scripts' wire form). */
47
+ export declare function xformFromArray(values: unknown): Xform;
48
+ /** Column lengths: the per-axis scale a basis applies. */
49
+ export declare function basisScale(b: Basis3): Vec3;
50
+ /** Rotation by `angle` radians about unit `axis` (Rodrigues). */
51
+ export declare function rotationAbout(axis: Vec3, angle: number): Basis3;
52
+ /** Shortest-arc rotation taking unit `from` onto unit `to`. For opposite
53
+ * vectors the half-turn axis is `fallbackAxis` made perpendicular to `from`. */
54
+ export declare function rotationBetween(from: Vec3, to: Vec3, fallbackAxis?: Vec3): Basis3;
55
+ /** The rotation mapping local frame (a, b, a x b) onto world frame (A, B, A x B).
56
+ * a/b and A/B must each be orthonormal pairs. */
57
+ export declare function rotationFromFrames(localA: Vec3, localB: Vec3, worldA: Vec3, worldB: Vec3): Basis3;
58
+ /** Angle in degrees between two directions. */
59
+ export declare function angleDegrees(a: Vec3, b: Vec3): number;
60
+ /** Round for model-visible output (millimetres by default). */
61
+ export declare function round(value: number, digits?: number): number;
62
+ export declare function roundVec(v: Vec3, digits?: number): Vec3;
63
+ /** A number in Godot variant-string form: fixed-point, never exponent notation. */
64
+ export declare function godotNumber(value: number): string;
65
+ export declare function toGodotVector3(v: Vec3): string;
66
+ export declare function toGodotTransform(t: Xform): string;
67
+ /** Parse "Vector3(x, y, z)" into numbers, or null when it is not one. */
68
+ export declare function parseGodotVector3(value: string): Vec3 | null;
69
+ /** Parse "Transform3D(<12 numbers>)" (Godot row-major basis, then origin). */
70
+ export declare function parseGodotTransform(value: string): Xform | null;