summer-engine 3.0.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 (413) 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 +120 -0
  8. package/README.md +22 -7
  9. package/assets/audit/scene_audit.gd +4136 -0
  10. package/assets/seeing/seeing_probe.gd +1873 -0
  11. package/dist/cli/commands/setup.js +6 -19
  12. package/dist/cli/commands/skills.js +57 -32
  13. package/dist/core/api-client.d.ts +9 -1
  14. package/dist/core/api-client.js +21 -4
  15. package/dist/core/capabilities/agent-playbook.js +46 -0
  16. package/dist/core/capabilities/audit/accept.d.ts +55 -0
  17. package/dist/core/capabilities/audit/accept.js +147 -0
  18. package/dist/core/capabilities/audit/args.d.ts +95 -0
  19. package/dist/core/capabilities/audit/args.js +89 -0
  20. package/dist/core/capabilities/audit/audit.d.ts +56 -0
  21. package/dist/core/capabilities/audit/audit.js +287 -0
  22. package/dist/core/capabilities/audit/frame.d.ts +14 -0
  23. package/dist/core/capabilities/audit/frame.js +35 -0
  24. package/dist/core/capabilities/audit/gaps.d.ts +96 -0
  25. package/dist/core/capabilities/audit/gaps.js +257 -0
  26. package/dist/core/capabilities/audit/judge.d.ts +162 -0
  27. package/dist/core/capabilities/audit/judge.js +1134 -0
  28. package/dist/core/capabilities/audit/math.d.ts +110 -0
  29. package/dist/core/capabilities/audit/math.js +263 -0
  30. package/dist/core/capabilities/audit/summary.d.ts +74 -0
  31. package/dist/core/capabilities/audit/summary.js +212 -0
  32. package/dist/core/capabilities/board.d.ts +31 -0
  33. package/dist/core/capabilities/board.js +43 -0
  34. package/dist/core/capabilities/camera-view.d.ts +4 -2
  35. package/dist/core/capabilities/camera-view.js +6 -3
  36. package/dist/core/capabilities/connect-signal.d.ts +85 -0
  37. package/dist/core/capabilities/connect-signal.js +285 -0
  38. package/dist/core/capabilities/engine-fallbacks.d.ts +5 -0
  39. package/dist/core/capabilities/engine-fallbacks.js +5 -0
  40. package/dist/core/capabilities/engine-ops.d.ts +5 -1
  41. package/dist/core/capabilities/engine-ops.js +0 -3
  42. package/dist/core/capabilities/engine-receipt.d.ts +12 -0
  43. package/dist/core/capabilities/engine-receipt.js +26 -0
  44. package/dist/core/capabilities/file-read.d.ts +64 -0
  45. package/dist/core/capabilities/file-read.js +325 -0
  46. package/dist/core/capabilities/game-task-plan.js +4 -2
  47. package/dist/core/capabilities/grep.d.ts +60 -0
  48. package/dist/core/capabilities/grep.js +190 -0
  49. package/dist/core/capabilities/inspect-node.d.ts +56 -0
  50. package/dist/core/capabilities/inspect-node.js +225 -0
  51. package/dist/core/capabilities/inspect-resource.d.ts +61 -0
  52. package/dist/core/capabilities/inspect-resource.js +376 -0
  53. package/dist/core/capabilities/math3d.d.ts +28 -0
  54. package/dist/core/capabilities/math3d.js +88 -0
  55. package/dist/core/capabilities/motion-generation.d.ts +62 -0
  56. package/dist/core/capabilities/motion-generation.js +138 -0
  57. package/dist/core/capabilities/placement-batch.d.ts +102 -0
  58. package/dist/core/capabilities/placement-batch.js +483 -0
  59. package/dist/core/capabilities/placement-math.d.ts +70 -0
  60. package/dist/core/capabilities/placement-math.js +209 -0
  61. package/dist/core/capabilities/placement-script.d.ts +42 -0
  62. package/dist/core/capabilities/placement-script.js +1096 -0
  63. package/dist/core/capabilities/placement.d.ts +485 -0
  64. package/dist/core/capabilities/placement.js +1731 -0
  65. package/dist/core/capabilities/project-context.d.ts +33 -2
  66. package/dist/core/capabilities/project-context.js +87 -4
  67. package/dist/core/capabilities/replace-node.d.ts +91 -0
  68. package/dist/core/capabilities/replace-node.js +423 -0
  69. package/dist/core/capabilities/runtime-control.d.ts +20 -4
  70. package/dist/core/capabilities/runtime-control.js +67 -2
  71. package/dist/core/capabilities/scene-batch.d.ts +63 -0
  72. package/dist/core/capabilities/scene-batch.js +394 -0
  73. package/dist/core/capabilities/scene-readback.d.ts +36 -0
  74. package/dist/core/capabilities/scene-readback.js +54 -0
  75. package/dist/core/capabilities/seeing/args.d.ts +348 -0
  76. package/dist/core/capabilities/seeing/args.js +178 -0
  77. package/dist/core/capabilities/seeing/candidates.d.ts +127 -0
  78. package/dist/core/capabilities/seeing/candidates.js +282 -0
  79. package/dist/core/capabilities/seeing/math.d.ts +134 -0
  80. package/dist/core/capabilities/seeing/math.js +269 -0
  81. package/dist/core/capabilities/seeing/probe.d.ts +62 -0
  82. package/dist/core/capabilities/seeing/probe.js +188 -0
  83. package/dist/core/capabilities/seeing/scoring.d.ts +235 -0
  84. package/dist/core/capabilities/seeing/scoring.js +639 -0
  85. package/dist/core/capabilities/seeing/seeing.d.ts +233 -0
  86. package/dist/core/capabilities/seeing/seeing.js +1341 -0
  87. package/dist/core/capabilities/seeing/shot-store.d.ts +52 -0
  88. package/dist/core/capabilities/seeing/shot-store.js +204 -0
  89. package/dist/core/capabilities/surface-snap-mesh.d.ts +88 -0
  90. package/dist/core/capabilities/surface-snap-mesh.js +425 -0
  91. package/dist/core/capabilities/surface-snap.d.ts +77 -0
  92. package/dist/core/capabilities/surface-snap.js +461 -0
  93. package/dist/core/capabilities/tool-dispatch.js +231 -72
  94. package/dist/core/capabilities/tscn.d.ts +85 -0
  95. package/dist/core/capabilities/tscn.js +391 -0
  96. package/dist/core/capabilities/world-snapshot.d.ts +58 -0
  97. package/dist/core/capabilities/world-snapshot.js +150 -0
  98. package/dist/core/capability-skew.d.ts +5 -5
  99. package/dist/core/capability-skew.js +14 -6
  100. package/dist/core/headless/worker-engine-client.d.ts +1 -1
  101. package/dist/core/headless/worker-engine-client.js +2 -2
  102. package/dist/core/library-read.d.ts +37 -5
  103. package/dist/core/library-read.js +264 -33
  104. package/dist/core/library-search.d.ts +2 -2
  105. package/dist/core/skills-registry.d.ts +9 -1
  106. package/dist/core/skills-registry.js +25 -2
  107. package/dist/installer/agent-config.d.ts +9 -4
  108. package/dist/installer/agent-config.js +194 -392
  109. package/dist/installer/agent-table.d.ts +119 -0
  110. package/dist/installer/agent-table.js +619 -0
  111. package/dist/installer/setup.js +4 -2
  112. package/dist/installer/skill-locations.d.ts +8 -17
  113. package/dist/installer/skill-locations.js +22 -101
  114. package/dist/installer/version-check.d.ts +5 -1
  115. package/dist/installer/version-check.js +38 -28
  116. package/dist/mcp/server.js +9 -3
  117. package/dist/mcp/tools/asset-tools.js +21 -3
  118. package/dist/mcp/tools/audit-tools.d.ts +23 -0
  119. package/dist/mcp/tools/audit-tools.js +60 -0
  120. package/dist/mcp/tools/debug-tools.js +3 -1
  121. package/dist/mcp/tools/file-tools.js +17 -4
  122. package/dist/mcp/tools/generate-tools.js +74 -66
  123. package/dist/mcp/tools/library-tools.js +2 -0
  124. package/dist/mcp/tools/perception-tools.js +6 -19
  125. package/dist/mcp/tools/placement-tools.d.ts +24 -0
  126. package/dist/mcp/tools/placement-tools.js +91 -0
  127. package/dist/mcp/tools/project-tools.js +18 -15
  128. package/dist/mcp/tools/scene-tools.js +71 -83
  129. package/dist/mcp/tools/seeing-tools.d.ts +24 -0
  130. package/dist/mcp/tools/seeing-tools.js +64 -0
  131. package/dist/mcp/tools/spatial-tools.js +17 -9
  132. package/dist/mcp/tools/visual-tools.js +59 -7
  133. package/gemini-extension.json +26 -4
  134. package/integrations/README.md +48 -19
  135. package/integrations/amp/README.md +12 -0
  136. package/integrations/amp/manifest-target.json +3 -0
  137. package/integrations/antigravity/README.md +12 -0
  138. package/integrations/antigravity/manifest-target.json +3 -0
  139. package/integrations/claude-desktop/README.md +12 -0
  140. package/integrations/claude-desktop/manifest-target.json +3 -0
  141. package/integrations/cline/README.md +8 -9
  142. package/integrations/cline-cli/README.md +12 -0
  143. package/integrations/cline-cli/manifest-target.json +3 -0
  144. package/integrations/copilot-jetbrains/README.md +12 -0
  145. package/integrations/copilot-jetbrains/manifest-target.json +3 -0
  146. package/integrations/crush/README.md +12 -0
  147. package/integrations/crush/manifest-target.json +3 -0
  148. package/integrations/github-copilot/README.md +8 -8
  149. package/integrations/goose/README.md +12 -0
  150. package/integrations/goose/manifest-target.json +3 -0
  151. package/integrations/grok-build/README.md +12 -0
  152. package/integrations/grok-build/manifest-target.json +3 -0
  153. package/integrations/hermes/README.md +12 -0
  154. package/integrations/hermes/manifest-target.json +3 -0
  155. package/integrations/junie/README.md +12 -0
  156. package/integrations/junie/manifest-target.json +3 -0
  157. package/integrations/kilo-code/README.md +6 -10
  158. package/integrations/kimi-code/README.md +12 -0
  159. package/integrations/kimi-code/manifest-target.json +3 -0
  160. package/integrations/kiro/README.md +12 -0
  161. package/integrations/kiro/manifest-target.json +3 -0
  162. package/integrations/lm-studio/README.md +8 -8
  163. package/integrations/mistral-vibe/README.md +12 -0
  164. package/integrations/mistral-vibe/manifest-target.json +3 -0
  165. package/integrations/opencode/README.md +9 -12
  166. package/integrations/qoder/README.md +12 -0
  167. package/integrations/qoder/manifest-target.json +3 -0
  168. package/integrations/qwen-code/README.md +12 -0
  169. package/integrations/qwen-code/manifest-target.json +3 -0
  170. package/integrations/roo-code/README.md +8 -7
  171. package/integrations/rovo-dev/README.md +12 -0
  172. package/integrations/rovo-dev/manifest-target.json +3 -0
  173. package/integrations/trae/README.md +12 -0
  174. package/integrations/trae/manifest-target.json +3 -0
  175. package/integrations/visual-studio/README.md +12 -0
  176. package/integrations/visual-studio/manifest-target.json +3 -0
  177. package/integrations/vscode-copilot/README.md +9 -9
  178. package/integrations/warp/README.md +12 -0
  179. package/integrations/warp/manifest-target.json +3 -0
  180. package/integrations/windsurf/README.md +8 -9
  181. package/integrations/zed/README.md +12 -0
  182. package/integrations/zed/manifest-target.json +3 -0
  183. package/library/references/mcp-tools-reference/mcp-tools-reference.md +59 -15
  184. package/library/references/mcp-tools-reference/resource.yaml +1 -1
  185. package/library/references/summer-folder/resource.yaml +1 -1
  186. package/library/references/summer-folder/summer-folder.md +1 -1
  187. package/library/skills/3d-lighting/SKILL.md +1 -1
  188. package/library/skills/README.md +264 -0
  189. package/library/skills/adaptive-music/SKILL.md +1 -1
  190. package/library/skills/agent-playtesting/SKILL.md +1 -1
  191. package/library/skills/ai-characters-in-games/SKILL.md +220 -0
  192. package/library/skills/ai-characters-in-games/resource.yaml +30 -0
  193. package/library/skills/ambient-bed/SKILL.md +1 -1
  194. package/library/skills/animated-loop/SKILL.md +1 -1
  195. package/library/skills/animation-tree/SKILL.md +1 -1
  196. package/library/skills/art-direction/SKILL.md +1 -1
  197. package/library/skills/asset-strategy/SKILL.md +2 -1
  198. package/library/skills/asset-strategy/resource.yaml +2 -1
  199. package/library/skills/audio-direction/SKILL.md +1 -1
  200. package/library/skills/auto-fire-targeting/SKILL.md +1 -1
  201. package/library/skills/brainstorm-game/SKILL.md +1 -1
  202. package/library/skills/brainstorming/SKILL.md +1 -1
  203. package/library/skills/browse-templates/SKILL.md +3 -3
  204. package/library/skills/browse-templates/resource.yaml +1 -1
  205. package/library/skills/camera-rigs/SKILL.md +128 -0
  206. package/library/skills/camera-rigs/resource.yaml +29 -0
  207. package/library/skills/celeste-momentum-platforming/SKILL.md +1 -1
  208. package/library/skills/character-animation-wiring/SKILL.md +1 -1
  209. package/library/skills/character-model/SKILL.md +1 -1
  210. package/library/skills/character-movement/SKILL.md +326 -0
  211. package/library/skills/character-movement/references/default-third-person-controller.gd +201 -0
  212. package/library/skills/character-movement/references/default-third-person-verification-probe.gd +154 -0
  213. package/library/skills/character-movement/references/movement-3d.md +136 -0
  214. package/library/skills/character-movement/references/platformer-feel.md +83 -0
  215. package/library/skills/character-movement/resource.yaml +40 -0
  216. package/library/skills/character-portrait/SKILL.md +1 -1
  217. package/library/skills/cinematic-cutscene/SKILL.md +1 -1
  218. package/library/skills/combat-basics/SKILL.md +159 -0
  219. package/library/skills/combat-basics/references/projectiles-and-aoe.md +100 -0
  220. package/library/skills/combat-basics/resource.yaml +34 -0
  221. package/library/skills/concept-art/SKILL.md +1 -1
  222. package/library/skills/create-asset-sheet/SKILL.md +1 -1
  223. package/library/skills/debug/SKILL.md +1 -1
  224. package/library/skills/debugging-game-feel/SKILL.md +1 -1
  225. package/library/skills/design-level/SKILL.md +1 -1
  226. package/library/skills/design-mechanic/SKILL.md +1 -1
  227. package/library/skills/design-npc/SKILL.md +1 -1
  228. package/library/skills/diagnosing-perf-regressions/SKILL.md +1 -1
  229. package/library/skills/dispatching-parallel-agents/SKILL.md +1 -1
  230. package/library/skills/driving-the-editor-ui/SKILL.md +1 -1
  231. package/library/skills/environment-kit/SKILL.md +1 -1
  232. package/library/skills/export-and-ship/SKILL.md +1 -1
  233. package/library/skills/fabricating-assets/SKILL.md +1 -1
  234. package/library/skills/facial-and-lipsync/SKILL.md +1 -1
  235. package/library/skills/fps-controller/SKILL.md +9 -7
  236. package/library/skills/fps-controller/resource.yaml +4 -1
  237. package/library/skills/game-feel/SKILL.md +1 -1
  238. package/library/skills/gameskill/SKILL.md +1 -1
  239. package/library/skills/gdscript-patterns/SKILL.md +1 -1
  240. package/library/skills/generate-motion/SKILL.md +9 -9
  241. package/library/skills/generate-motion/resource.yaml +2 -1
  242. package/library/skills/godogen-visual-proof-game-generation/SKILL.md +1 -1
  243. package/library/skills/headless-scripting/SKILL.md +1 -1
  244. package/library/skills/in-game-purchases/SKILL.md +254 -0
  245. package/library/skills/in-game-purchases/resource.yaml +29 -0
  246. package/library/skills/instantiate-asset-pack/SKILL.md +1 -1
  247. package/library/skills/investigating-bugs/SKILL.md +1 -1
  248. package/library/skills/lumera-single-image-scene-reconstruction/SKILL.md +1 -1
  249. package/library/skills/make-game/SKILL.md +25 -3
  250. package/library/skills/make-game/references/2d-platformer-polish.md +93 -0
  251. package/library/skills/make-game/references/2d-platformer.md +117 -0
  252. package/library/skills/make-game/references/2d-rpg-content.md +234 -0
  253. package/library/skills/make-game/references/2d-rpg.md +241 -0
  254. package/library/skills/make-game/references/2d-survivors-progression.md +201 -0
  255. package/library/skills/make-game/references/2d-survivors.md +237 -0
  256. package/library/skills/make-game/references/3d-fps-systems.md +216 -0
  257. package/library/skills/make-game/references/3d-fps.md +177 -0
  258. package/library/skills/make-game/references/3d-horror-systems.md +186 -0
  259. package/library/skills/make-game/references/3d-horror.md +201 -0
  260. package/library/skills/make-game/references/3d-third-person-systems.md +220 -0
  261. package/library/skills/make-game/references/3d-third-person.md +215 -0
  262. package/library/skills/make-game/resource.yaml +6 -1
  263. package/library/skills/multiplayer/SKILL.md +150 -0
  264. package/library/skills/multiplayer/resource.yaml +33 -0
  265. package/library/skills/multiplayer-movement/SKILL.md +510 -0
  266. package/library/skills/multiplayer-movement/files.md +501 -0
  267. package/library/skills/multiplayer-movement/resource.yaml +30 -0
  268. package/library/skills/multiplayer-project/SKILL.md +521 -0
  269. package/library/skills/multiplayer-project/files.md +448 -0
  270. package/library/skills/multiplayer-project/resource.yaml +36 -0
  271. package/library/skills/multiplayer-publish/SKILL.md +229 -0
  272. package/library/skills/multiplayer-publish/export-errors.md +89 -0
  273. package/library/skills/multiplayer-publish/resource.yaml +28 -0
  274. package/library/skills/multiplayer-state/SKILL.md +438 -0
  275. package/library/skills/multiplayer-state/files.md +592 -0
  276. package/library/skills/multiplayer-state/resource.yaml +35 -0
  277. package/library/skills/multiplayer-testing/SKILL.md +236 -0
  278. package/library/skills/multiplayer-testing/resource.yaml +39 -0
  279. package/library/skills/music-track/SKILL.md +1 -1
  280. package/library/skills/navigate-summer/SKILL.md +1 -1
  281. package/library/skills/new-project/SKILL.md +1 -1
  282. package/library/skills/organic-model/SKILL.md +1 -1
  283. package/library/skills/pixel-art/SKILL.md +1 -1
  284. package/library/skills/play/SKILL.md +1 -1
  285. package/library/skills/playtesting-a-feature/SKILL.md +1 -1
  286. package/library/skills/procedural-animation/SKILL.md +2 -2
  287. package/library/skills/procedural-animation/resource.yaml +1 -1
  288. package/library/skills/prop-model/SKILL.md +1 -1
  289. package/library/skills/psx-retro-rendering/SKILL.md +1 -1
  290. package/library/skills/realtime-wet-surfaces/SKILL.md +2 -2
  291. package/library/skills/remote-deploy/SKILL.md +1 -1
  292. package/library/skills/retarget/SKILL.md +1 -1
  293. package/library/skills/running-in-the-cloud/SKILL.md +1 -1
  294. package/library/skills/save-load/SKILL.md +156 -0
  295. package/library/skills/save-load/resource.yaml +27 -0
  296. package/library/skills/scene-composition/SKILL.md +1 -1
  297. package/library/skills/scene-hierarchy-design/SKILL.md +1 -1
  298. package/library/skills/scene-scripting/SKILL.md +1 -1
  299. package/library/skills/scene-to-level/SKILL.md +1 -1
  300. package/library/skills/skill-create/SKILL.md +1 -1
  301. package/library/skills/skill-improve/SKILL.md +1 -1
  302. package/library/skills/skill-test/SKILL.md +1 -1
  303. package/library/skills/skintokens-auto-rigging/SKILL.md +1 -1
  304. package/library/skills/skybox-panorama/SKILL.md +1 -1
  305. package/library/skills/sound-effect/SKILL.md +1 -1
  306. package/library/skills/spatial-placement/SKILL.md +134 -3
  307. package/library/skills/spatial-placement/references/kit-placement-tools.md +364 -0
  308. package/library/skills/spatial-placement/resource.yaml +16 -2
  309. package/library/skills/sprite-sheet/SKILL.md +1 -1
  310. package/library/skills/summer-analytics/SKILL.md +147 -0
  311. package/library/skills/summer-analytics/resource.yaml +28 -0
  312. package/library/skills/summer-friends/SKILL.md +226 -0
  313. package/library/skills/summer-friends/resource.yaml +28 -0
  314. package/library/skills/summer-leaderboards/SKILL.md +231 -0
  315. package/library/skills/summer-leaderboards/resource.yaml +30 -0
  316. package/library/skills/summer-match-results/SKILL.md +286 -0
  317. package/library/skills/summer-match-results/resource.yaml +32 -0
  318. package/library/skills/summer-matchmaking/SKILL.md +301 -0
  319. package/library/skills/summer-matchmaking/resource.yaml +32 -0
  320. package/library/skills/summer-parties/SKILL.md +253 -0
  321. package/library/skills/summer-parties/resource.yaml +30 -0
  322. package/library/skills/summer-player-data/SKILL.md +322 -0
  323. package/library/skills/summer-player-data/resource.yaml +30 -0
  324. package/library/skills/summer-store/SKILL.md +271 -0
  325. package/library/skills/summer-store/resource.yaml +29 -0
  326. package/library/skills/summer-world-chat/SKILL.md +195 -0
  327. package/library/skills/summer-world-chat/resource.yaml +30 -0
  328. package/library/skills/summer-world-saves/SKILL.md +284 -0
  329. package/library/skills/summer-world-saves/resource.yaml +29 -0
  330. package/library/skills/text-to-motion/SKILL.md +99 -0
  331. package/library/skills/text-to-motion/prompts-and-controls.md +34 -0
  332. package/library/skills/text-to-motion/resource.yaml +41 -0
  333. package/library/skills/text-to-motion/rigging-for-text-motion.md +54 -0
  334. package/library/skills/tileable-texture/SKILL.md +1 -1
  335. package/library/skills/trailer-shot/SKILL.md +1 -1
  336. package/library/skills/tune-performance/SKILL.md +1 -1
  337. package/library/skills/ui-basics/SKILL.md +10 -1
  338. package/library/skills/ui-graphics/SKILL.md +1 -1
  339. package/library/skills/use-widget-asset/SKILL.md +1 -1
  340. package/library/skills/using-summer/SKILL.md +2 -2
  341. package/library/skills/using-summer/resource.yaml +2 -2
  342. package/library/skills/vehicle-model/SKILL.md +1 -1
  343. package/library/skills/verification-before-completion/SKILL.md +1 -1
  344. package/library/skills/verifying-scenes/SKILL.md +76 -2
  345. package/library/skills/verifying-scenes/resource.yaml +13 -2
  346. package/library/skills/vfx-dissolve/SKILL.md +1 -1
  347. package/library/skills/vfx-fire/SKILL.md +1 -1
  348. package/library/skills/vfx-hit-spark/SKILL.md +1 -1
  349. package/library/skills/vfx-lightning/SKILL.md +1 -1
  350. package/library/skills/vfx-magic-glow/SKILL.md +1 -1
  351. package/library/skills/vfx-muzzle-flash/SKILL.md +1 -1
  352. package/library/skills/vfx-smoke/SKILL.md +1 -1
  353. package/library/skills/vfx-water-ripple/SKILL.md +1 -1
  354. package/library/skills/voice-line/SKILL.md +1 -1
  355. package/library/skills/web-and-touch-input/SKILL.md +38 -0
  356. package/library/skills/web-and-touch-input/resource.yaml +28 -0
  357. package/library/skills/web-compatibility-look/SKILL.md +62 -0
  358. package/library/skills/web-compatibility-look/resource.yaml +30 -0
  359. package/library/skills/world-building-3d/SKILL.md +8 -1
  360. package/library/skills/world-building-3d/references/spatial-tools.md +1 -1
  361. package/library/skills/world-building-3d/resource.yaml +2 -1
  362. package/library/skills/writing-plans/SKILL.md +1 -1
  363. package/library/skills/writing-skills/SKILL.md +1 -1
  364. package/library/templates/3d-lan-multiplayer-starter/resource.yaml +2 -2
  365. package/library/tools/attach-to-surface/resource.yaml +142 -0
  366. package/library/tools/batch/resource.yaml +9 -3
  367. package/library/tools/connect-ports/resource.yaml +120 -0
  368. package/library/tools/connect-signal/resource.yaml +3 -2
  369. package/library/tools/debug-views/resource.yaml +94 -0
  370. package/library/tools/frame-nodes/resource.yaml +104 -0
  371. package/library/tools/frame-shot/resource.yaml +134 -0
  372. package/library/tools/generate-motion/resource.yaml +44 -9
  373. package/library/tools/get-board/resource.yaml +50 -0
  374. package/library/tools/get-project-context/resource.yaml +13 -2
  375. package/library/tools/grep/resource.yaml +77 -0
  376. package/library/tools/inspect-asset/resource.yaml +71 -0
  377. package/library/tools/inspect-node/resource.yaml +9 -2
  378. package/library/tools/inspect-resource/resource.yaml +16 -5
  379. package/library/tools/instantiate-scene/resource.yaml +27 -2
  380. package/library/tools/measure/resource.yaml +96 -0
  381. package/library/tools/place-adjacent/resource.yaml +113 -0
  382. package/library/tools/play/resource.yaml +15 -2
  383. package/library/tools/raycast/resource.yaml +101 -0
  384. package/library/tools/read-file/resource.yaml +36 -2
  385. package/library/tools/read-library/resource.yaml +2 -2
  386. package/library/tools/repeat-along/resource.yaml +129 -0
  387. package/library/tools/replace-node/resource.yaml +11 -5
  388. package/library/tools/scene-audit/resource.yaml +144 -0
  389. package/library/tools/screenshot/resource.yaml +13 -2
  390. package/library/tools/search-assets/resource.yaml +18 -0
  391. package/library/tools/shot-sheet/resource.yaml +110 -0
  392. package/library/tools/snap-to-surface/resource.yaml +4 -1
  393. package/library/tools/world-snapshot/resource.yaml +24 -3
  394. package/library/tools/zoom/resource.yaml +105 -0
  395. package/package.json +3 -3
  396. package/registry/generated/aliases.json +17 -3
  397. package/registry/generated/counts.json +3 -3
  398. package/registry/generated/gemini-extension.json +26 -4
  399. package/registry/generated/index.json +2154 -469
  400. package/registry/generated/marketplace.claude.json +2 -2
  401. package/registry/generated/plugin.claude.json +27 -5
  402. package/registry/generated/plugin.codex.json +28 -6
  403. package/registry/generated/plugin.cursor.json +27 -5
  404. package/registry/generated/plugin.factory.json +27 -5
  405. package/registry/generated/skills-index.md +264 -0
  406. package/registry/generated/skills-registry.json +901 -206
  407. package/registry/generated/templates-registry.json +2 -2
  408. package/library/skills/host-authoritative-state/SKILL.md +0 -332
  409. package/library/skills/host-authoritative-state/resource.yaml +0 -28
  410. package/library/skills/peer-to-peer-multiplayer/SKILL.md +0 -373
  411. package/library/skills/peer-to-peer-multiplayer/resource.yaml +0 -28
  412. package/library/skills/setup-multiplayer/SKILL.md +0 -336
  413. package/library/skills/setup-multiplayer/resource.yaml +0 -28
@@ -1,7 +1,12 @@
1
1
  import { z } from "zod";
2
2
  import { withEngine, ToolInputError } from "./with-engine.js";
3
- import { executeOpsChunked, executeSceneMutation } from "../../core/capabilities/engine-ops.js";
4
- import { annotateVariantTypes } from "../../core/capabilities/variant-types.js";
3
+ import { executeSceneMutation } from "../../core/capabilities/engine-ops.js";
4
+ import { instantiateScene, runBatch } from "../../core/capabilities/placement-batch.js";
5
+ import { renderPlacementResult } from "./placement-tools.js";
6
+ import { inspectNodeFields, inspectNodeInputShape } from "../../core/capabilities/inspect-node.js";
7
+ import { inspectResource, inspectResourceInputShape } from "../../core/capabilities/inspect-resource.js";
8
+ import { rawSceneReplaceRefusal, replaceNodeInputShape, replaceNodePersisted, } from "../../core/capabilities/replace-node.js";
9
+ import { connectSignalInputShape, connectSignalPersisted } from "../../core/capabilities/connect-signal.js";
5
10
  import { FALLBACK_SINGLE_ONLY_OPS, resolveSingleOnlyOps, } from "../../core/capability-skew.js";
6
11
  // Re-exported for tests and for callers that reason about dispatch classes.
7
12
  // executeSceneMutation is the ONE copy in core/capabilities/engine-ops.ts,
@@ -28,6 +33,8 @@ function requireSuccessfulOps(result, context) {
28
33
  function minimalSceneText(rootName, rootType) {
29
34
  return `[gd_scene format=3]\n\n[node name="${rootName}" type="${rootType}"]\n`;
30
35
  }
36
+ const finiteNumber = z.number().finite();
37
+ const finiteVector3 = z.tuple([finiteNumber, finiteNumber, finiteNumber]);
31
38
  // Node names reject . : @ / " %; the type must be a plain class name.
32
39
  // Both are interpolated into quoted .tscn fields, so validate before composing.
33
40
  const VALID_ROOT_NAME = /^[A-Za-z_][A-Za-z0-9_\- ]*$/;
@@ -194,7 +201,9 @@ Do not guess paths. Prefer:
194
201
 
195
202
  The scene must already exist in the project. Use summer_import_from_url first if importing from external sources.
196
203
 
197
- PASS target_size FOR IMPORTED MODELS. Downloaded/generated .glb assets arrive at arbitrary scale (a "chair" can be 40 units tall). target_size uniformly scales the instanced subtree so its largest world-AABB dimension equals that many units — commit to real-world size: chair 1.0, door 2.0, car 4.5, person 1.7, tree 6-10. The result then reports dimensions + scale_applied; verify placement afterwards (summer_world_snapshot AABBs, summer_screenshot). Older engine builds ignore target_size — when the result lacks scale_applied, this tool appends a note and you must scale the node yourself (summer_set_prop scale) and re-check.`, {
204
+ PASS target_size FOR IMPORTED MODELS. Downloaded/generated .glb assets arrive at arbitrary scale (a "chair" can be 40 units tall). target_size uniformly scales the instanced subtree so its largest world-AABB dimension equals that many units — commit to real-world size: chair 1.0, door 2.0, car 4.5, person 1.7, tree 6-10. The result then reports dimensions + scale_applied; verify placement afterwards (summer_world_snapshot AABBs, summer_screenshot). Older engine builds ignore target_size — when the result lacks scale_applied, this tool appends a note and you must scale the node yourself (summer_set_prop scale) and re-check.
205
+
206
+ PLACE IT IN THE SAME CALL: position, rotation_degrees and scale ([x, y, z], parent-local, like summer_set_prop), or transform (a "Transform3D(...)" string). The instance is created, then those properties are set on the exact node path the receipt reports (a name collision rename is followed), then the scene is saved: one call per piece, no window at the origin. The result adds placement {nodePath, applied, fields}. Do not combine transform with the others, or scale/transform with target_size. Measure a kit piece first with summer_inspect_asset.`, {
198
207
  scenePath: z.string().describe("Target scene to receive the instance, e.g. 'res://main.tscn'"),
199
208
  parent: z.string().describe("Parent node path, e.g. './World'"),
200
209
  scene: z.string().describe("Scene/model path, e.g. 'res://player.tscn' or 'res://models/tree.glb'"),
@@ -204,30 +213,18 @@ PASS target_size FOR IMPORTED MODELS. Downloaded/generated .glb assets arrive at
204
213
  .positive()
205
214
  .optional()
206
215
  .describe("Normalize the instance's physical size: uniformly scale it so its largest world-AABB dimension equals this many units (chair 1.0, car 4.5, person 1.7). Strongly recommended for imported .glb/.gltf models."),
207
- }, async ({ scenePath, parent, scene, name, target_size }) => withEngine(async (client) => {
208
- const op = { op: "InstantiateScene", parent, scene };
209
- if (name)
210
- op.name = name;
211
- if (target_size !== undefined)
212
- op.target_size = target_size;
213
- const result = await executeSceneMutation(client, scenePath, [op]);
214
- // An older engine applies the op but silently drops target_size — its
215
- // receipt then lacks scale_applied. Confess that instead of letting a
216
- // 40-unit "chair" pass as normalized.
217
- if (target_size !== undefined && result && typeof result === "object") {
218
- const envelope = result;
219
- const instanced = envelope.results?.find((entry) => entry.op === "InstantiateScene" && entry.ok === true);
220
- if (instanced && !("scale_applied" in instanced)) {
221
- return {
222
- ...envelope,
223
- 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 ${target_size}. ` +
224
- "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.",
225
- };
226
- }
227
- }
228
- return result;
229
- }));
230
- server.tool("summer_connect_signal", `Connect a signal between two nodes. Signals are Godot's event system — they notify when something happens.
216
+ position: finiteVector3.optional().describe("Parent-local position [x, y, z] set right after the instance is created."),
217
+ rotation_degrees: finiteVector3.optional().describe("Parent-local rotation in degrees [x, y, z] (Godot rotation_degrees)."),
218
+ scale: finiteVector3.optional().describe("Local scale [x, y, z]. Not with target_size."),
219
+ transform: z
220
+ .string()
221
+ .optional()
222
+ .describe('Full local transform as "Transform3D(xx, xy, xz, yx, yy, yz, zx, zy, zz, ox, oy, oz)" (Godot row-major basis, then origin). Not with position/rotation_degrees/scale/target_size.'),
223
+ }, async (args) =>
224
+ // E2E: an older engine applies the op but silently drops target_size —
225
+ // instantiateScene appends target_size_note when scale_applied is absent.
226
+ withEngine(async (client) => instantiateScene(client, args)));
227
+ server.tool("summer_connect_signal", `Connect a signal between two nodes so the connection is SAVED in the scene. Signals are Godot's event system — they notify when something happens.
231
228
 
232
229
  Common signals:
233
230
  - "body_entered" / "body_exited" — Area3D/Area2D detects physics bodies
@@ -236,15 +233,9 @@ Common signals:
236
233
  - "area_entered" — Area detects another area
237
234
  - "input_event" — CollisionObject received input
238
235
 
239
- The receiver node must have a script with the specified method.`, {
240
- scenePath: z.string().describe("Target scene path, e.g. 'res://main.tscn'"),
241
- emitter: z.string().describe("Node that fires the signal, e.g. './Player/HitArea'"),
242
- signal: z.string().describe("Signal name, e.g. 'body_entered'"),
243
- receiver: z.string().describe("Node with the handler script, e.g. './Player'"),
244
- method: z.string().describe("Method name in the receiver's script, e.g. '_on_hit_area_body_entered'"),
245
- }, async ({ scenePath, emitter, signal, receiver, method }) => withEngine(async (client) => executeSceneMutation(client, scenePath, [
246
- { op: "ConnectSignal", emitter, signal, receiver, method },
247
- ])));
236
+ The receiver should have the method (a script method, or a built-in such as queue_free); a missing one is saved anyway and reported in warnings. scenePath must be a .tscn.
237
+
238
+ PERSISTENCE IS VERIFIED: the engine's ConnectSignal op connects without CONNECT_PERSIST, so its connection never reached the file. This tool connects through a RunSceneScript probe with CONNECT_PERSIST (replacing a non-persistent connection of the same pair), saves, reads the saved .tscn back and returns persisted:true / verified:true only when the [connection] line is there; otherwise an error with failure_reason not_persisted. The probe runs in the active tab: a scene in a background tab is brought forward and the user's tab restored (tab_switched). One Ctrl+Z reverts it.`, connectSignalInputShape, async (args) => withEngine(async (client) => connectSignalPersisted(client, args)));
248
239
  server.tool("summer_select_node", "Select a node in the editor's scene tree and show it in the inspector panel. Useful for focusing the editor on a specific node.", {
249
240
  nodePath: z.string().describe("Node path to select"),
250
241
  scenePath: z.string().optional().describe("Open this scene first, then select the node"),
@@ -254,35 +245,29 @@ The receiver node must have a script with the specified method.`, {
254
245
  op.scenePath = scenePath;
255
246
  return client.executeOps([op]);
256
247
  }));
257
- server.tool("summer_replace_node", "Replace a node with a different type or scene, preserving its position in the tree and its children. Useful for changing a StaticBody3D to a RigidBody3D, or swapping a placeholder with a proper prefab.", {
258
- scenePath: z.string().describe("Target scene path, e.g. 'res://main.tscn'"),
259
- path: z.string().describe("Node path to replace"),
260
- type: z.string().optional().describe("New node type, e.g. 'RigidBody3D'"),
261
- scene: z.string().optional().describe("Scene to replace with, e.g. 'res://enemies/boss.tscn'"),
262
- }, async ({ scenePath, path, type, scene }) => withEngine(async (client) => {
263
- const op = { op: "ReplaceNode", path };
264
- if (type)
265
- op.type = type;
266
- if (scene)
267
- op.scene = scene;
268
- return executeSceneMutation(client, scenePath, [op]);
269
- }));
248
+ server.tool("summer_replace_node", `Replace a node with a different scene/model or node type, keeping its parent, sibling index, name, transform and property overrides, and the children the scene added under it. Use it to swap a kit piece for another (a wall host for a door host), a placeholder for a prefab, or a StaticBody3D for a RigidBody3D.
249
+
250
+ Give exactly one of scene or type. The scenePath must be a .tscn.
251
+
252
+ PERSISTENCE IS VERIFIED: the tool saves, reads the saved .tscn back and checks that the node at path now instances the new scene (or has the new type), under the same parent, with every child present. persisted:true is proven from the file; a mismatch is an error with failure_reason not_persisted — never report that as done.
253
+
254
+ How: a scene swap runs as InstantiateScene (temporary name) -> SetProp each property override -> ReparentNode the children -> MoveNode to the old index -> RemoveNode the old node -> rename -> SaveScene, because the engine's own ReplaceNode keeps the OLD scene reference in the saved file. A type change of a plain node uses the engine's ReplaceNode. State that cannot travel (groups, signal connections, scene-local sub_resource values, overrides of nodes inside the old scene) is listed in not_carried_over. Undo takes one Ctrl+Z per step.`, replaceNodeInputShape, async (args) => withEngine(async (client) => replaceNodePersisted(client, args)));
270
255
  server.tool("summer_inspect_node", `Get all editable properties of a node with their current values, types, and resource info.
271
256
 
272
257
  Call this before modifying a node to understand its current state. Returns every property the Godot inspector would show. Each prop carries the engine's raw Variant.Type integer as "type" plus its name as "type_name" (e.g. type 5 = TYPE_VECTOR2, 20 = TYPE_COLOR, 24 = TYPE_OBJECT); resource-valued props also carry resource_type / resource_path.
273
258
 
274
259
  Reads the currently OPEN scene — "path" is relative to its root (there is no scenePath argument; open the scene first if needed).
275
260
 
276
- Example: inspect a light to see its energy, color, shadow settings before changing them.`, {
277
- path: z.string().describe("Node path from scene tree, e.g. 'Player', 'World/Enemies/Boss', 'DirectionalLight3D'"),
278
- }, async ({ path }) =>
261
+ Example: inspect a light to see its energy, color, shadow settings before changing them.
262
+
263
+ The full read is about 5 KB. To read only what you need, pass fields: property names or globs ('position', 'surface_material_override/*'), plus derived fields: transform (local position / rotation_degrees / scale, and a Transform3D literal for 3D nodes), global_transform (world origin + Transform3D, composed from the world snapshot), scene_file_path (the scene this node instances), aabb (world bounds), warnings. Example: fields:['transform','global_transform','scene_file_path'] is a few hundred bytes. missing_fields and unavailable say what could not be read.`, inspectNodeInputShape, async (args) =>
279
264
  // E2E 2026-09-03 F-14: the engine returns Variant.Type as a bare int.
280
- withEngine(async (client) => annotateVariantTypes(await client.inspectNode(path))));
281
- server.tool("summer_inspect_resource", `Get all properties of a resource (material, mesh, shape, environment, etc).
265
+ withEngine(async (client) => inspectNodeFields(client, args)));
266
+ server.tool("summer_inspect_resource", `Read a resource: a material, mesh, shape, texture, environment, or a scene/model file.
282
267
 
283
- Use when you need the sub-properties of a resource attached to a node. For example, summer_inspect_node tells you a MeshInstance3D has a "StandardMaterial3D" material — this tool tells you that material's albedo_color, metallic, roughness, etc.`, {
284
- path: z.string().describe("Resource path, e.g. 'res://materials/ground.tres' or 'res://models/player.glb'"),
285
- }, async ({ path }) => withEngine(async (client) => client.inspectResource(path)));
268
+ Two forms, pass exactly one:
269
+ - path: a resource FILE ('res://materials/ground.tres', a mesh 'res://kit/meshes/wall_01.res', 'res://models/player.glb'), loaded read-only in the editor. A Mesh returns its AABB, surface_count and per surface the primitive, vertex and index counts, attributes, triangles and material (class, path or embedded, albedo for standard materials), plus the unique materials and blend shapes. A scene or model (.tscn/.glb/.gltf) returns its node count, the first 40 nodes with type, instanced scene and mesh, and its meshes; summer_inspect_asset measures it (AABB, planes, ports). Every other resource (and a mesh) returns its editor properties that differ from the class default (props), with props_at_default counting the rest.
270
+ - nodePath + property: a resource a node of the ACTIVE scene tab holds, e.g. nodePath 'Floor', property 'mesh'. For example, summer_inspect_node tells you a MeshInstance3D has a "StandardMaterial3D" material_override — this form returns its albedo_color, metallic, roughness, etc.`, inspectResourceInputShape, async (args) => withEngine(async (client) => inspectResource(client, args)));
286
271
  server.tool("summer_batch", `Execute multiple operations in a single call. Each op is forwarded to the engine VERBATIM, so this is also how you reach engine ops that have no dedicated tool.
287
272
 
288
273
  UNDO: when nothing in the list forces a split (see the single-op contract below), the whole batch is ONE undo step — the user undoes everything with a single Ctrl+Z. When single-only ops are present the list is split into sequential requests and EACH chunk is its own undo step (one Ctrl+Z per chunk; the receipt shows the chunks). Use this when building something that involves multiple nodes and properties — e.g., creating a player character with collision, camera, and properties.
@@ -297,6 +282,11 @@ RAW RUNTIME OPS (interactive verification — structured failure_reason passes t
297
282
  - RunVerification — spawn a hidden, disposable game instance that runs a GDScript probe and dies (never touches the editor): {"op": "RunVerification", "probe_source": "...", "max_seconds": 20}. Returns {ok, results, frames, out_dir}. Probe API: report(name, value) / save_frame(name) / press(action) / key(keycode) / finish(). save_frame REQUIRES a name argument — save_frame() with no args is a script error. Mount scenes deferred: get_tree().root.add_child.call_deferred(instance); await get_tree().process_frame; await settle() — a direct add_child in _ready can hit the parent-busy guard and capture a black frame.
298
283
  - SimulateInput — inject an action/key/mouse/axis into the RUNNING game (summer_play first): {"op": "SimulateInput", "type": "action", "action": "jump", "pressed": true}. It MUST be sent alone (single-op batch). failure_reason "not_running" = start the game first; "unsupported" = the running game build predates the handler — fall back to RunVerification or ask the user.
299
284
 
285
+ A raw ReplaceNode with scene is refused (it saves the old scene reference); use summer_replace_node.
286
+ A raw ConnectSignal is refused (the engine connects without CONNECT_PERSIST, so the file never holds it); use summer_connect_signal.
287
+
288
+ REPARENTNODE KEEPS ITS SUBTREE AND IS VERIFIED: the engine's ReparentNode re-owns only the moved node, so its children and grandchildren were dropped from the saved file. A batch with ReparentNode saves first, reads the saved .tscn, sends each ReparentNode in its own request with an in-place ReparentNode (same parent, same index) per scene-owned descendant to give it back to the scene, then reads the saved file again: persisted:true / verified:true only when every moved node and descendant is at its new path; otherwise an error with failure_reason not_persisted. A move onto a parent that already has a child of that name is refused (failure_reason name_collision). The scenePath must be a .tscn, and Undo cannot share the batch.
289
+
300
290
  Do not mix OpenScene with scene mutations in one batch. OpenScene is a UI action;
301
291
  send it separately. scenePath selects every mutation target. The tool appends one
302
292
  final SaveScene when the batch mutates a scene; if supplied explicitly, SaveScene
@@ -306,10 +296,21 @@ SaveScene, InstantiateScene, ReplaceNode, SimulateInput, the runtime reads
306
296
  ops to travel as their own request, so this tool automatically splits your op
307
297
  list into sequential requests around them — each split chunk is its own undo
308
298
  step (NOT one step for the whole batch), and if a later chunk fails the receipt
309
- reports exactly which earlier ops already applied.`, {
299
+ reports exactly which earlier ops already applied.
300
+
301
+ PLACED INSTANCES: an InstantiateScene op may also carry position, rotation_degrees, scale ([x, y, z] or "Vector3(...)") or transform ("Transform3D(...)"); the tool sets them on the created node. One op per piece. Other ops are forwarded verbatim. Cost: each InstantiateScene is its own engine request (the engine requires it); the transforms of a run of InstantiateScene ops are then sent together (up to 200 per request) before the next other op, so N placed pieces plus the save cost about N + 2 requests and N + 2 undo steps. Every later op (a SetProp, SnapToSurface, the save) sees the pieces already placed; if an InstantiateScene fails, the pieces created before it still get their transforms.
302
+
303
+ RECEIPTS: receipt "summary" returns only counts, failures [{index, op, error}] (index = position in your ops list), created node paths and renames, under 5 KB with any cut declared. Use it for any batch over a few ops; the full receipt of a large batch overflows the tool-output limit.
304
+
305
+ scenePersistence.saved means the SaveScene ran; it does not prove what the file
306
+ holds. verified:true is set only where the tool read the saved file back.`, {
310
307
  scenePath: z.string().optional().describe("Required when ops contains scene mutations; exact res:// target scene path"),
311
308
  ops: z.array(z.record(z.unknown())).describe("Array of operation objects, each with 'op' plus its parameters"),
312
- }, async ({ scenePath, ops }) => withEngine(async (client) => {
309
+ receipt: z
310
+ .enum(["full", "summary"])
311
+ .optional()
312
+ .describe("full (default): every engine receipt. summary: counts, failures with op index, created node paths only (under 5 KB)."),
313
+ }, async ({ scenePath, ops, receipt }) => withEngine(async (client) => {
313
314
  const rawFileMutation = ops.find((op) => {
314
315
  const kind = String(op.op ?? "");
315
316
  return kind === "WriteFile" || kind === "ReplaceText";
@@ -318,28 +319,15 @@ reports exactly which earlier ops already applied.`, {
318
319
  throw new ToolInputError(`summer_batch does not accept raw ${String(rawFileMutation.op)} operations. ` +
319
320
  "Use summer_write_file or summer_replace_text so project identity, content guards, and same-file ordering are enforced.");
320
321
  }
321
- const sceneMutations = new Set([
322
- "AddNode", "RemoveNode", "MoveNode", "ReparentNode", "ReplaceNode",
323
- "SetProp", "SetResourceProperty", "ConnectSignal", "DisconnectSignal",
324
- "InstantiateScene", "SaveScene", "SnapToSurface", "AlignDistribute3D", "Undo",
325
- ]);
326
- // Read-only spatial queries target an exact scene (identity-bound) but
327
- // never save — no SaveScene is appended for them.
328
- const sceneQueries = new Set([
329
- "TestPlacement3D", "NavigationProbe3D", "Starcast3D",
330
- ]);
331
- const containsMutation = ops.some((op) => sceneMutations.has(String(op.op ?? "")));
332
- const needsScenePath = containsMutation ||
333
- ops.some((op) => sceneQueries.has(String(op.op ?? "")));
334
- if (needsScenePath && !scenePath) {
335
- throw new ToolInputError("summer_batch requires scenePath when ops targets a scene");
336
- }
337
- const options = { groupUndo: true, ...(scenePath ? { scenePath } : {}) };
338
- if (containsMutation) {
339
- return executeSceneMutation(client, scenePath, ops, options);
340
- }
341
- return executeOpsChunked((chunk) => needsScenePath
342
- ? client.executeIdentityBoundOps(chunk, options)
343
- : client.executeOps(chunk, options), ops, resolveSingleOnlyOps(client));
344
- }));
322
+ const replaceRefusal = rawSceneReplaceRefusal(ops);
323
+ if (replaceRefusal)
324
+ throw new ToolInputError(replaceRefusal);
325
+ // Scene mutations get one final SaveScene; read-only spatial queries
326
+ // (TestPlacement3D, NavigationProbe3D, Starcast3D) are identity-bound
327
+ // to the scene but never saved (core/capabilities/placement-batch.ts).
328
+ const result = await runBatch(client, { scenePath, ops: ops, receipt });
329
+ return receipt === "summary" ? { summaryReceipt: result } : result;
330
+ }, receipt === "summary"
331
+ ? { onResult: (wrapped) => renderPlacementResult(wrapped.summaryReceipt) }
332
+ : undefined));
345
333
  }
@@ -0,0 +1,24 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { type SeeingResult } from "../../core/capabilities/seeing/seeing.js";
3
+ /**
4
+ * Seeing tools: look at a 3D environment the way a player and an artist do.
5
+ * Every image comes back INLINE as an MCP image block (one grid image for a
6
+ * sheet, never N images), with a compact text caption (labels, poses, scores,
7
+ * mark -> path). Renders use the scene's REAL WorldEnvironment and lights.
8
+ * Implementation and the in-engine kernel: src/core/capabilities/seeing/.
9
+ */
10
+ type ToolResultContent = {
11
+ type: "text";
12
+ text: string;
13
+ } | {
14
+ type: "image";
15
+ data: string;
16
+ mimeType: string;
17
+ };
18
+ type ToolResult = {
19
+ content: ToolResultContent[];
20
+ isError?: boolean;
21
+ };
22
+ export declare function seeingContent(result: SeeingResult): ToolResult;
23
+ export declare function registerSeeingTools(server: McpServer): void;
24
+ export {};
@@ -0,0 +1,64 @@
1
+ import { withEngine } from "./with-engine.js";
2
+ import { debugViews, frameNodes, frameShot, shotSheet, zoom, } from "../../core/capabilities/seeing/seeing.js";
3
+ import { debugViewsShape, frameNodesShape, frameShotShape, shotSheetShape, zoomShape, } from "../../core/capabilities/seeing/args.js";
4
+ function wrap(result) {
5
+ return result.ok ? { seeing: result } : { seeing: result, failure_reason: result.failure_reason };
6
+ }
7
+ export function seeingContent(result) {
8
+ if (!result.ok) {
9
+ return {
10
+ isError: true,
11
+ content: [
12
+ {
13
+ type: "text",
14
+ text: JSON.stringify({
15
+ error: result.error,
16
+ failure_reason: result.failure_reason,
17
+ ...(result.hint ? { hint: result.hint } : {}),
18
+ ...(result.detail ? { detail: result.detail } : {}),
19
+ }, null, 2),
20
+ },
21
+ ],
22
+ };
23
+ }
24
+ const content = [];
25
+ if (result.image)
26
+ content.push({ type: "image", data: result.image.base64, mimeType: result.image.mime || "image/jpeg" });
27
+ content.push({ type: "text", text: result.caption });
28
+ return { content };
29
+ }
30
+ function run(op) {
31
+ return async (args) => withEngine(async (client) => wrap(await op(client, args)), {
32
+ onResult: (wrapped) => seeingContent(wrapped.seeing),
33
+ });
34
+ }
35
+ const COMMON = `Read-only: the scene file, the open tab and the undo history are never touched (the render is an offscreen copy of the SAVED scene). The image arrives inline; the caption carries poses, labels and numbers. Failures are structured (failure_reason), never a silent fallback.`;
36
+ export function registerSeeingTools(server) {
37
+ server.tool("summer_frame_nodes", `Frame one or more nodes with a camera fitted to their WORLD bounds and render it with the scene's REAL WorldEnvironment, lights, fog and tonemap (unlike summer_screenshot nodePath, which only works with the flat preview environment).
38
+
39
+ Pick the side with direction (front/back/left/right/top/iso) or an explicit from vector; fill sets how much of the frame they span. bookmark_name also saves the fitted pose so every later render (summer_shot_sheet, summer_debug_views, summer_screenshot framing:"bookmark") lines up with it. marks:true adds numbered labels mapped to node paths.
40
+
41
+ An explicit from is checked in-engine before you trust the image: if walls block the nodes, or the camera stands behind or inside a one-sided surface (its back is not drawn, so the image would look THROUGH the wall), the caption opens with a WARNING and the nearest valid from (+ fov) to pass back. With marks:true every labelled node gets an occlusion test (centre + 4 bounds points); hidden ones are noted "(hidden behind <path>)".
42
+
43
+ Returns the image + caption: the pose as Vector3 literals, the bounds, the environment used, the view check, and the mark list. ${COMMON}`, frameNodesShape, run(frameNodes));
44
+ server.tool("summer_shot_sheet", `Render several bookmarks and/or explicit poses into ONE labelled grid image in a single call: same tile size, same view, real lighting. Use it after every change to see all hero views at once instead of N screenshots.
45
+
46
+ compare_previous:true turns each bookmark into a row of [previous | now | difference map] and reports the share of pixels that changed and where. Each bookmark keeps exactly one previous render (its compare baseline) at res://.summer/shots/<bookmark>.jpg (JPEG, <= 1024 px; the folder is capped at 20 MB, oldest first). Only compare_previous:true or update_previous:true replaces it; a plain sheet creates a missing baseline and never overwrites one. view renders every tile as lighting/unshaded/normals/overdraw/wireframe instead of beauty.
47
+
48
+ Returns the grid + caption (tile number -> label and pose, difference stats). ${COMMON}`, shotSheetShape, run(shotSheet));
49
+ server.tool("summer_debug_views", `One pose rendered as a grid of debug views next to the beauty pass: beauty, lighting (light only: direction, pools, dead-dark areas), unshaded (albedo: texture quality, value grouping), normals (world-space, x red y green z blue: seams, flipped or faceted normals), overdraw (stacked transparent layers), wireframe (triangle density, floating or duplicated pieces).
50
+
51
+ Use it on the weakest shot of a sheet to see WHY it reads badly. lighting/unshaded/overdraw/wireframe are the engine's Viewport debug draw modes; normals uses an unshaded override material on a private copy (normal maps and alpha cut-outs are not applied) and works on every renderer. The caption names the method per view.
52
+
53
+ Returns the grid + caption. ${COMMON}`, debugViewsShape, run(debugViews));
54
+ server.tool("summer_zoom", `High-resolution close look at part of a frame: region [x, y, w, h] (fractions of the frame) or mark N from a marks render of the same pose. The camera renders the EXACT sub-frustum of that region at full output resolution, so you see real texture detail, seams, gaps and floating pieces, not upscaled pixels. A region is honoured exactly (no pad by default, never widened to an aspect ratio: the image takes the region's own aspect, with dark bars only for extreme shapes); a mark gets pad 0.15.
55
+
56
+ Use after a sheet or debug view shows something suspicious. view picks beauty or a debug view. Returns the zoomed image + caption (the real zoom factor, the rendered region, widened_because when it is larger than asked, mark -> node path and a warning when that node is hidden). ${COMMON}`, zoomShape, run(zoom));
57
+ server.tool("summer_frame_shot", `Smart framing: find good camera poses for a shot type automatically, measured in-engine against the real geometry.
58
+
59
+ shot: establishing (wide), eye_level (from a spawn node at player eye height), low_angle (hero, near the ground looking up: the camera moves closer and widens its FOV instead of sinking into the ground), detail (close-up), corridor (down a lane or corridor found inside the subject by a free-space scan, preferring the view in from its open end, walls on both sides).
60
+
61
+ How: candidate poses on a ring/hemisphere (or along the corridor line) at the distance where the subject fills the shot's target share of the frame; each is checked with a THICK sphere sweep to points on the subject (thin rays miss corners), a near-lens sphere (camera inside or touching geometry is nudged forward or rejected), a ray grid through the frame, and a small beauty render per pose. Walls/terrain blocking the subject reject a pose, and so does a camera behind or inside a one-sided surface (a sight line or a quarter of the frame meeting a wall from behind: its back is not drawn, so the image would look through it). Foliage, fences, props and pipes in front are allowed (wanted, up to a limit) as framing; transparent materials (alpha, scissor, glass, foliage cards) are see-through cover at partial weight. Scored on rule-of-thirds placement, frame fill, level horizon, sky share, depth behind the subject (no flat wall right behind it), empty or featureless areas, near-wall clearance, near/far value contrast, foreground framing, surfaces seen from behind, the key light's direction (side or front-side beats a flat front-lit face) and the world edge (sky or void below the horizon).
62
+
63
+ Returns the top 3 with score breakdowns and poses — three different views (one per side of the subject while the score allows, at least 25 degrees apart) — saves the best as a bookmark (default <shot>_<subject>), and renders the 3 as one sheet with real lighting (render:"best" or "none" to save context). ${COMMON} Saving the bookmark writes res://.summer/camera_bookmarks.json.`, frameShotShape, run(frameShot));
64
+ }
@@ -1,6 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import { withEngine, missingEngineOpResult, ToolInputError, withOldEngineHint } from "./with-engine.js";
3
3
  import { executeSceneMutation } from "./scene-tools.js";
4
+ import { SNAP_LIFT_MARGIN, SNAP_MAX_AUTO_LIFT, snapToSurface } from "../../core/capabilities/surface-snap.js";
4
5
  // engine_lacks_op fallbacks: ONE copy for every face (E2E 2026-09-03 F-16).
5
6
  import { ALIGN_DISTRIBUTE_FALLBACK, NAVIGATION_PROBE_FALLBACK, SNAP_TO_SURFACE_FALLBACK, STARCAST_FALLBACK, TEST_PLACEMENT_FALLBACK, } from "../../core/capabilities/engine-fallbacks.js";
6
7
  /** Hard budget for one tool's model-visible result. These ops are designed to
@@ -244,9 +245,14 @@ Use the default downward direction to seat props on floors, ramps, tables, or sh
244
245
 
245
246
  EVIDENCE BOUNDARY:
246
247
  - physics means Godot swept the subject's enabled collider shapes against body colliders and refined the first-contact bracket.
247
- - visual_aabb is an explicit broad-phase fallback for mesh-only geometry; it does not prove triangle contact, and alignUp is not applied from that approximate normal.
248
+ - visual_aabb is the engine's broad-phase fallback for mesh-only geometry (no collider on the subject or the support): AABBs swept against AABBs. It does not prove triangle contact, and alignUp is not applied from that approximate normal.
249
+ - visual_mesh: whenever the engine answers with visual_aabb (overlap_recovery_exceeded, gap_exceeds_hit_travel, surface_not_found, or a seat), a read-only probe measures the move from visible triangles instead: the subject's vertices cast along the direction onto the triangles of the meshes below (a surface cutting through the subject counts as sunk), plus the support's vertices under it cast back. One SetProp places the subject, a second read verifies the gap (the move is undone if it disagrees by more than 5 mm), and the scene is saved. The receipt says evidence visual_mesh, the engine's own answer under engine, verify {final_gap, ok}, and evidenceDetails (samples, triangles, whether the subject and the support have colliders). Meshes whose shader writes POSITION (screen-space quads) are not surfaces. When the triangles find no support either, the engine's failure is returned with mesh_fallback saying why.
248
250
  - initiallyOverlapping and backoffDistance expose bounded pre-sweep recovery. The tool fails instead of teleporting when the subject cannot be cleared within maxDistance.
249
251
 
252
+ SUNK PROPS: when the subject starts inside its support (gap_exceeds_hit_travel with a start overlap), the tool lifts it against the cast direction by the overlap depth plus ${SNAP_LIFT_MARGIN} m (at most ${SNAP_MAX_AUTO_LIFT} m and the subject's own extent), snaps again from there, and keeps that only if it settles on a node it was sunk into; the receipt then carries recovery (lifted_by, original_local_position) and 'before' is the lifted pose. Otherwise the original position is restored.
253
+
254
+ FAILURES EXPLAIN THEMSELVES: after gap_exceeds_hit_travel or overlap_recovery_exceeded a read-only starcast at the current pose adds start_overlap, blocking (the nodes it touches or sits inside), below, and a concrete next_step.
255
+
250
256
  The normal result is bounded below 5 KB and returns before/after transforms, supportPath, finalGap with an error bound, slopeDeg, evidence, and warnings. scenePath and subjectPath are always required; there is no editor-selection fallback. On an engine build that predates SnapToSurface the result is a structured engine_lacks_op failure naming the fallback.`, {
251
257
  scenePath: exactScenePath.describe("Exact scene containing the subject, e.g. 'res://levels/market.tscn'"),
252
258
  subjectPath: exactNodePath.describe("Exact Node3D path relative to the scene root, e.g. './Props/Crate'"),
@@ -286,14 +292,16 @@ The normal result is bounded below 5 KB and returns before/after transforms, sup
286
292
  // Cross-field: a raw zod shape cannot express it, so it stays here.
287
293
  if (gap > maxDistance)
288
294
  throw new ToolInputError("gap must not exceed maxDistance.");
289
- const receipt = await executeSceneMutation(client, exactScene, [{
290
- op: "SnapToSurface",
291
- subject_path: exactSubject,
292
- direction,
293
- max_distance: maxDistance,
294
- gap,
295
- align_up: alignUp,
296
- }]);
295
+ // ONE implementation for both faces (core/capabilities/surface-snap.ts):
296
+ // the snap, a starcast diagnosis on failure, and the sunk-prop lift.
297
+ const receipt = await snapToSurface(client, {
298
+ scenePath: exactScene,
299
+ subjectPath: exactSubject,
300
+ direction: direction,
301
+ maxDistance,
302
+ gap,
303
+ alignUp,
304
+ });
297
305
  return withOldEngineHint(receipt, "SnapToSurface", SNAP_TO_SURFACE_FALLBACK);
298
306
  }, compactResult({
299
307
  op: "SnapToSurface",
@@ -1,9 +1,12 @@
1
1
  import { z } from "zod";
2
- import { withEngine, missingEngineOpResult, withOldEngineHint } from "./with-engine.js";
2
+ import { withEngine, missingEngineOpResult, withOldEngineHint, ToolInputError } from "./with-engine.js";
3
3
  import { withFailureReasonHint } from "./perception-tools.js";
4
4
  import { analyzedSnapshot, captureGame, captureScene, captureViewport, VIEWPORT_RECAPTURE_DELAY_MS, } from "../../core/capabilities/capture.js";
5
5
  import { describeFlatFrame } from "../../core/capabilities/frame-quality.js";
6
6
  import { CAMERA_BOOKMARK_ACTIONS, CAMERA_BOOKMARK_FALLBACK, SCREENSHOT_FRAMINGS, MAX_MARKS_CAP, buildCameraBookmarkOp, buildScenePreviewInput, formatSceneMarks, isFixedPoseFraming, readCameraPose, readSceneMarks, } from "../../core/capabilities/camera-view.js";
7
+ import { checkMarkOcclusion, formatMarksWithOcclusion, rememberBookmarkRender, shotSheet, slotPolicy, } from "../../core/capabilities/seeing/seeing.js";
8
+ import { parseVector3 } from "../../core/capabilities/seeing/math.js";
9
+ import { seeingContent } from "./seeing-tools.js";
7
10
  // The capture path (content check, single viewport recapture, scene-kind read
8
11
  // for the no-camera confession) is ONE copy in core/capabilities/capture.ts,
9
12
  // shared with the CLI face; re-exported so tests and callers keep this door.
@@ -170,7 +173,7 @@ Static frame only — one moment, not motion. For a SEQUENCE of frames over time
170
173
  marks: z
171
174
  .boolean()
172
175
  .optional()
173
- .describe('target:"scene" only, 3D scenes. Draw a Set-of-Mark overlay: numbered tags + box outlines over the largest visible VisualInstance3D nodes (lights excluded), ranked by projected screen area. The caption lists label -> node path (scene-root-relative) so you can name what you see. Works with every framing. 2D scenes return marks_unsupported. Default false.'),
176
+ .describe('target:"scene" only, 3D scenes. Draw a Set-of-Mark overlay: numbered tags + box outlines over the largest visible VisualInstance3D nodes (lights excluded), ranked by projected screen area. The caption lists label -> node path (scene-root-relative) so you can name what you see, and an occlusion test (centre + 4 bounds points from the rendered camera) notes "(hidden behind <path>)" on labels whose node is hidden: ignore those. Works with every framing. 2D scenes return marks_unsupported. Default false.'),
174
177
  max_marks: z
175
178
  .number()
176
179
  .int()
@@ -178,10 +181,36 @@ Static frame only — one moment, not motion. For a SEQUENCE of frames over time
178
181
  .max(MAX_MARKS_CAP)
179
182
  .optional()
180
183
  .describe(`marks:true only. Cap on numbered labels (engine default 32, at most ${MAX_MARKS_CAP}). The caption says when the cap truncated the list.`),
181
- }, async ({ target, scenePath, framing, bookmark_name, size, nodePath, camera_path, camera_position, camera_look_at, fov, marks, max_marks, }) => {
184
+ compare_previous: z
185
+ .boolean()
186
+ .optional()
187
+ .describe('framing:"bookmark" only. Return ONE image of [previous render | now | difference map] for the bookmark, with the share of changed pixels (summer_shot_sheet compare_previous with this one bookmark); this render then replaces the bookmark\'s previous image in res://.summer/shots/<bookmark>.jpg. A plain bookmark render (no marks, at most 1024 px) only creates that image when it is missing and never overwrites the compare baseline.'),
188
+ update_previous: z
189
+ .boolean()
190
+ .optional()
191
+ .describe('framing:"bookmark" only. Replace the bookmark\'s previous image (its compare baseline) with this clean render. Default false: an existing baseline is kept.'),
192
+ }, async ({ target, scenePath, framing, bookmark_name, size, nodePath, camera_path, camera_position, camera_look_at, fov, marks, max_marks, compare_previous, update_previous, }) => {
193
+ if (compare_previous) {
194
+ // Same implementation as summer_shot_sheet: one bookmark row of
195
+ // [previous | now | difference].
196
+ return withEngine(async (client) => {
197
+ if (target !== "scene" || !bookmark_name || (framing !== undefined && framing !== "bookmark")) {
198
+ throw new ToolInputError('compare_previous needs target:"scene" with framing:"bookmark" and bookmark_name. Nothing was sent.');
199
+ }
200
+ const result = await shotSheet(client, {
201
+ scenePath,
202
+ shots: [{ bookmark_name, ...(fov !== undefined ? { fov } : {}) }],
203
+ compare_previous: true,
204
+ max_size: 1536,
205
+ });
206
+ return { seeing: result, ...(result.ok ? {} : { failure_reason: result.failure_reason }) };
207
+ }, { onResult: (wrapped) => seeingContent(wrapped.seeing) });
208
+ }
182
209
  // Resolved inside the engine closure so a contradictory framing is a
183
210
  // classified invalid_input (nothing sent), never a transport failure.
184
211
  let preview;
212
+ let slotNotes = [];
213
+ let markOcclusion;
185
214
  return withEngine(async (client) => {
186
215
  if (target === "game")
187
216
  return captureGame(client);
@@ -199,7 +228,27 @@ Static frame only — one moment, not motion. For a SEQUENCE of frames over time
199
228
  marks,
200
229
  max_marks,
201
230
  });
202
- return teachPreviewFailure(await captureScene(client, preview));
231
+ const snap = teachPreviewFailure(await captureScene(client, preview));
232
+ // One before/after slot per bookmark: a clean render creates it
233
+ // when missing; only update_previous replaces an existing one.
234
+ const bookmark = preview.framing?.startsWith("bookmark:") ? preview.framing.slice("bookmark:".length) : undefined;
235
+ if (snap.ok && snap.base64 && bookmark && snap.framing === preview.framing) {
236
+ slotNotes = await rememberBookmarkRender(typeof client.getProjectRoot === "function" ? client.getProjectRoot() : undefined, bookmark, { base64: snap.base64, width: snap.width, height: snap.height }, preview.marks === true, slotPolicy({ updatePrevious: update_previous === true }));
237
+ }
238
+ // Labels on hidden nodes: test each labelled node from the
239
+ // rendered camera (centre + 4 bounds points).
240
+ const meta = snap.metadata;
241
+ const marked = snap.ok && preview.marks ? readSceneMarks(meta) : null;
242
+ const camera = readCameraPose(meta)?.position;
243
+ if (marked?.marks.length && camera) {
244
+ try {
245
+ markOcclusion = await checkMarkOcclusion(client, scenePath, parseVector3(camera, "camera_pose.position"), marked.marks);
246
+ }
247
+ catch (err) {
248
+ markOcclusion = { occlusion: new Map(), note: `NOTE: the mark occlusion check could not run (${err instanceof Error ? err.message : String(err)}).` };
249
+ }
250
+ }
251
+ return snap;
203
252
  }
204
253
  return captureViewport(client);
205
254
  }, {
@@ -367,11 +416,14 @@ Static frame only — one moment, not motion. For a SEQUENCE of frames over time
367
416
  details.push(`camera pose: ${parts.join(", ")}`);
368
417
  }
369
418
  const marksSummary = readSceneMarks(meta);
370
- if (marksSummary)
371
- marksBlock = formatSceneMarks(marksSummary);
419
+ if (marksSummary) {
420
+ marksBlock = markOcclusion ? formatMarksWithOcclusion(marksSummary, markOcclusion.occlusion) : formatSceneMarks(marksSummary);
421
+ if (markOcclusion?.note)
422
+ marksBlock.push(markOcclusion.note);
423
+ }
372
424
  }
373
425
  const detailNote = details.length ? `; ${details.join(", ")}` : "";
374
- const trailer = [...warnings, ...notes];
426
+ const trailer = [...warnings, ...notes, ...slotNotes];
375
427
  const caption = `${label} (${dims}${detailNote}). Saved to ${snap.localPath ?? "n/a"}.${frameCheck} Describe only what is visibly in the image above.` +
376
428
  (marksBlock.length ? `\n\n${marksBlock.join("\n")}` : "") +
377
429
  (trailer.length ? `\n\n${trailer.join("\n")}` : "");
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "_generated": "GENERATED from integrations/gemini — do not edit; npm run generate:registry",
3
3
  "name": "summer",
4
- "version": "3.0.0",
4
+ "version": "3.2.0",
5
5
  "description": "Agent tooling for Summer Engine: MCP bridge, context primer, and game-dev skills. Use with the npm CLI for skill files on disk.",
6
6
  "contextFileName": "GEMINI.md",
7
7
  "mcpServers": {
@@ -27,6 +27,7 @@
27
27
  "./library/skills/3d-lighting/",
28
28
  "./library/skills/adaptive-music/",
29
29
  "./library/skills/agent-playtesting/",
30
+ "./library/skills/ai-characters-in-games/",
30
31
  "./library/skills/ambient-bed/",
31
32
  "./library/skills/animated-loop/",
32
33
  "./library/skills/animation-tree/",
@@ -37,11 +38,14 @@
37
38
  "./library/skills/brainstorm-game/",
38
39
  "./library/skills/brainstorming/",
39
40
  "./library/skills/browse-templates/",
41
+ "./library/skills/camera-rigs/",
40
42
  "./library/skills/celeste-momentum-platforming/",
41
43
  "./library/skills/character-animation-wiring/",
42
44
  "./library/skills/character-model/",
45
+ "./library/skills/character-movement/",
43
46
  "./library/skills/character-portrait/",
44
47
  "./library/skills/cinematic-cutscene/",
48
+ "./library/skills/combat-basics/",
45
49
  "./library/skills/concept-art/",
46
50
  "./library/skills/create-asset-sheet/",
47
51
  "./library/skills/debug/",
@@ -63,16 +67,21 @@
63
67
  "./library/skills/generate-motion/",
64
68
  "./library/skills/godogen-visual-proof-game-generation/",
65
69
  "./library/skills/headless-scripting/",
66
- "./library/skills/host-authoritative-state/",
70
+ "./library/skills/in-game-purchases/",
67
71
  "./library/skills/instantiate-asset-pack/",
68
72
  "./library/skills/investigating-bugs/",
69
73
  "./library/skills/lumera-single-image-scene-reconstruction/",
70
74
  "./library/skills/make-game/",
75
+ "./library/skills/multiplayer/",
76
+ "./library/skills/multiplayer-movement/",
77
+ "./library/skills/multiplayer-project/",
78
+ "./library/skills/multiplayer-publish/",
79
+ "./library/skills/multiplayer-state/",
80
+ "./library/skills/multiplayer-testing/",
71
81
  "./library/skills/music-track/",
72
82
  "./library/skills/navigate-summer/",
73
83
  "./library/skills/new-project/",
74
84
  "./library/skills/organic-model/",
75
- "./library/skills/peer-to-peer-multiplayer/",
76
85
  "./library/skills/pixel-art/",
77
86
  "./library/skills/play/",
78
87
  "./library/skills/playtesting-a-feature/",
@@ -83,11 +92,11 @@
83
92
  "./library/skills/remote-deploy/",
84
93
  "./library/skills/retarget/",
85
94
  "./library/skills/running-in-the-cloud/",
95
+ "./library/skills/save-load/",
86
96
  "./library/skills/scene-composition/",
87
97
  "./library/skills/scene-hierarchy-design/",
88
98
  "./library/skills/scene-scripting/",
89
99
  "./library/skills/scene-to-level/",
90
- "./library/skills/setup-multiplayer/",
91
100
  "./library/skills/skill-create/",
92
101
  "./library/skills/skill-improve/",
93
102
  "./library/skills/skill-test/",
@@ -96,6 +105,17 @@
96
105
  "./library/skills/sound-effect/",
97
106
  "./library/skills/spatial-placement/",
98
107
  "./library/skills/sprite-sheet/",
108
+ "./library/skills/summer-analytics/",
109
+ "./library/skills/summer-friends/",
110
+ "./library/skills/summer-leaderboards/",
111
+ "./library/skills/summer-match-results/",
112
+ "./library/skills/summer-matchmaking/",
113
+ "./library/skills/summer-parties/",
114
+ "./library/skills/summer-player-data/",
115
+ "./library/skills/summer-store/",
116
+ "./library/skills/summer-world-chat/",
117
+ "./library/skills/summer-world-saves/",
118
+ "./library/skills/text-to-motion/",
99
119
  "./library/skills/tileable-texture/",
100
120
  "./library/skills/trailer-shot/",
101
121
  "./library/skills/tune-performance/",
@@ -115,6 +135,8 @@
115
135
  "./library/skills/vfx-smoke/",
116
136
  "./library/skills/vfx-water-ripple/",
117
137
  "./library/skills/voice-line/",
138
+ "./library/skills/web-and-touch-input/",
139
+ "./library/skills/web-compatibility-look/",
118
140
  "./library/skills/world-building-3d/",
119
141
  "./library/skills/writing-plans/",
120
142
  "./library/skills/writing-skills/"