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,254 @@
1
+ ---
2
+ name: in-game-purchases
3
+ description: "Sell items for Sparks and let short players buy Sparks in game via the Summer purchase sheet: checkout, Sparks purchase, results, testing, store policy."
4
+ license: MIT
5
+ compatibility: [Cursor, Claude Code, Windsurf, Codex]
6
+ category: gameplay
7
+ allowed-tools: Read Grep Write summer_get_script_errors summer_get_scene_tree
8
+ paths: ["**/*.gd"]
9
+ ---
10
+
11
+ # In-game purchases with Sparks
12
+
13
+ Sparks are Summer's currency. A game never takes money, never holds a
14
+ balance and never approves a payment. It asks Summer, Summer shows its own
15
+ purchase sheet over the game, and the game reacts to the authoritative
16
+ result. There are two calls and they follow the same shape:
17
+
18
+ | The player wants to | Call | Validated by |
19
+ | --- | --- | --- |
20
+ | buy an item with Sparks they have | `Summer.client.store.request_checkout(lines)` | the Summer ledger (debit) |
21
+ | buy Sparks because they are short | `Summer.client.store.request_sparks_purchase(minimum_sparks)` | the payment provider (Stripe or Apple), then the ledger credit |
22
+
23
+ ## When to sell with Sparks
24
+
25
+ - Sell anything that persists across sessions or devices (cosmetics, unlocks,
26
+ passes) as a Summer item with a Sparks price. *Why:* the platform owns the
27
+ item, so ownership survives reinstalls and cannot be forged by editing the
28
+ game.
29
+ - Do not invent your own currency that is bought with money. *Why:* Summer
30
+ can only refund, protect and pay you out for Sparks purchases.
31
+ - Offer "Get Sparks" only when a purchase failed for lack of Sparks, or on an
32
+ explicit shop button. *Why:* the Summer sheet interrupts play; surprise
33
+ payment prompts read as pressure and get games reported.
34
+
35
+ ## Rules and the reason for each
36
+
37
+ 1. **Never grant an item from a button press or a receipt.** Unlock only when
38
+ `Summer.client.items` shows the player owns it. *Why:* the receipt proves
39
+ the debit; the inventory projection is what the platform guarantees the
40
+ player owns, including after a crash or on another device.
41
+ 2. **Never send prices, amounts or providers.** The game passes an offer ID
42
+ and a quantity, or a Sparks hint. *Why:* the platform prices everything; a
43
+ client-supplied price is exactly what a cheater edits.
44
+ 3. **One call is one purchase.** Every call creates a new identity. Never
45
+ call again to "retry" an unknown outcome. *Why:* the first request may
46
+ already be charged; the SDK and the Summer app recover it and deliver the
47
+ result on the signal.
48
+ 4. **Handle results only in the status signals, and deduplicate by
49
+ `request_id` plus `version`.** Connect normally (not deferred) before
50
+ requesting. *Why:* results can arrive after a restart or twice after a
51
+ crash; a synchronous handler is how the SDK knows the result was delivered.
52
+ 5. **Treat `manual_review` and pending as not done.** *Why:* the platform
53
+ has not decided yet; showing success or failure would be a guess.
54
+ 6. **Check readiness and hide what is unavailable.**
55
+ `check_checkout_readiness()` and `check_sparks_purchase_readiness()` return
56
+ a `SummerResult`. *Why:* editor play, guest sessions and older Summer apps
57
+ do not offer purchases; a dead button is worse than no button.
58
+
59
+ ## Result states
60
+
61
+ Both signals deliver a status with `state`:
62
+
63
+ | State | Meaning | What the game does |
64
+ | --- | --- | --- |
65
+ | `awaiting_approval` | the Summer sheet is open | nothing; optionally dim the shop |
66
+ | `pending` | payment or debit in progress | show "processing" |
67
+ | `purchased` | done; Sparks debited (checkout) or credited (Sparks) | checkout: refresh items and unlock from inventory. Sparks: say "Sparks added", let the player buy again |
68
+ | `declined` | the player closed the sheet | return to the shop quietly |
69
+ | `expired` | the sheet or payment timed out | same as declined |
70
+ | `rejected` | refused; read `error_code` | checkout with `insufficient_funds`: offer "Get Sparks". Sparks: `provider_rejected`, say the payment did not go through |
71
+ | `manual_review` | platform is checking it | "We are confirming this purchase" |
72
+ | `refunded` | Sparks only: a credited purchase was refunded or charged back (`full_refund`, `dispute_lost`) | nothing to undo; Summer already took the Sparks back. Refresh any balance display |
73
+
74
+ A Sparks request can also fail to start with `purchase_limit` (the player
75
+ reached the daily in-game Sparks limit) or `age_required` / `adult_required`
76
+ (only adults with a saved age can buy Sparks). Show a short message and no
77
+ retry button. *Why:* both limits are platform policy; retrying changes nothing.
78
+
79
+ The operation returned by each call also completes (`completed` signal) on
80
+ `purchased` (ok) or a terminal failure with codes such as `checkout_declined`
81
+ or `sparks_purchase_declined`. The status signal is the one to build UI on.
82
+
83
+ ## Minimal complete example
84
+
85
+ ```gdscript
86
+ extends Node
87
+ ## A one-item shop. Buys `offer_id`; if the player is short, lets them buy
88
+ ## Sparks through the Summer sheet, then they press Buy again.
89
+
90
+ @export var offer_id := "offer_sword"
91
+ @export var definition_id := "item_sword"
92
+ @export var price_sparks := 250 # display only; the platform charges its own price
93
+
94
+ signal message(text: String)
95
+ var _seen := {}
96
+
97
+ func _ready() -> void:
98
+ var store := Summer.client.store
99
+ store.checkout_status_changed.connect(_on_checkout)
100
+ store.sparks_purchase_status_changed.connect(_on_sparks)
101
+ Summer.client.items.refreshed.connect(_sync_owned)
102
+ _sync_owned()
103
+
104
+ func buy() -> void:
105
+ if not Summer.client.store.check_checkout_readiness().ok:
106
+ message.emit("The shop is not available here.")
107
+ return
108
+ var lines: Array[SummerCheckoutLine] = [SummerCheckoutLine.create(offer_id, 1)]
109
+ Summer.client.store.request_checkout(lines) # result arrives in _on_checkout
110
+
111
+ func get_sparks() -> void:
112
+ if not Summer.client.store.check_sparks_purchase_readiness().ok:
113
+ message.emit("Get Sparks from the Summer app.")
114
+ return
115
+ Summer.client.store.request_sparks_purchase(price_sparks) # hint only
116
+
117
+ func _first_time(status) -> bool:
118
+ var key := "%s:%d" % [status.request_id, status.version]
119
+ if _seen.has(key):
120
+ return false
121
+ _seen[key] = true
122
+ return true
123
+
124
+ func _on_checkout(status: SummerCheckoutStatus) -> void:
125
+ if not _first_time(status):
126
+ return
127
+ match status.state:
128
+ &"purchased":
129
+ Summer.client.items.refresh() # ownership comes from inventory
130
+ &"rejected":
131
+ if status.error_code == &"insufficient_funds":
132
+ message.emit("Not enough Sparks.") # show a Get Sparks button -> get_sparks()
133
+ else:
134
+ message.emit("The purchase was not completed.")
135
+ &"manual_review":
136
+ message.emit("We are confirming this purchase.")
137
+ &"declined", &"expired":
138
+ pass
139
+
140
+ func _on_sparks(status: SummerSparksPurchaseStatus) -> void:
141
+ if not _first_time(status):
142
+ return
143
+ match status.state:
144
+ &"purchased":
145
+ message.emit("%d Sparks added." % status.receipt.sparks_credited)
146
+ &"rejected":
147
+ message.emit("The payment did not go through.")
148
+ &"manual_review":
149
+ message.emit("We are confirming your payment.")
150
+
151
+ func _sync_owned() -> void:
152
+ if Summer.client.items.has_owned_definition(definition_id):
153
+ message.emit("Sword unlocked.") # the only place the item is granted
154
+ ```
155
+
156
+ After Sparks are added the player presses Buy again. That is a new checkout
157
+ and Summer shows it again. *Why:* the player confirms each spend separately.
158
+
159
+ ## Multiplayer: granting an effect on a dedicated authority
160
+
161
+ Buying Sparks only adds Sparks to the wallet. Anything the Sparks buy
162
+ ("Grow now", "Summon rain") is a separate checkout, and on a server the
163
+ authority must never grant it because a client says it paid. *Why:* a client
164
+ message is the one thing a cheater controls.
165
+
166
+ Model the effect as a consumable catalog item with instance ownership (each
167
+ purchase is a separate item, not a stack). *Why:* a stackable (quantity) item
168
+ shares one owned item ID across purchases, so the ID could not tell two
169
+ purchases apart. The client checks out; the receipt's `owned_item_ids` are item instances in
170
+ the player's Summer inventory. The client sends the authority only that owned
171
+ item ID. The authority consumes it with
172
+ `Summer.authority.items.consume(session, owned_item_id, idempotency_key)` and
173
+ applies the effect only after a successful receipt. *Why:* the platform ledger
174
+ consumes an instance item once, so the same item cannot be redeemed twice, in
175
+ this world or any other.
176
+
177
+ ```gdscript
178
+ # On the dedicated authority. `redeemed` is saved with the world.
179
+ func redeem(session: SummerSession, owned_item_id: String) -> void:
180
+ if redeemed.has(owned_item_id):
181
+ return # a repeated message grants once
182
+ var key := "redeem_" + owned_item_id.sha256_text().substr(0, 40)
183
+ var op := Summer.authority.items.consume(session, owned_item_id, key)
184
+ var result: SummerResult = await op.get_result_or_completed_signal()
185
+ if not result.ok:
186
+ # item_not_found: not owned or already used, never grant.
187
+ # unavailable: retry later with the same key.
188
+ return
189
+ redeemed[owned_item_id] = op.command_id # record, apply, then save the world
190
+ apply_grow_now(session)
191
+ ```
192
+
193
+ - Derive the key from the owned item ID. *Why:* the same key returns the same
194
+ receipt (`op.replayed` is true), so a retry after a timeout never consumes
195
+ twice, and a different item with that key fails with `idempotency_conflict`.
196
+ - Apply the effect when the receipt arrives even if `op.replayed` is true, as
197
+ long as `redeemed` does not have the item. *Why:* a replay means the item was
198
+ consumed earlier but your world may have crashed before saving the effect.
199
+ - Save the world right after applying. *Why:* the receipt replay is tied to
200
+ the authority process; after a restart as a different process the same key
201
+ is a new consumption and the already-consumed item returns `item_not_found`.
202
+
203
+ ## Idempotency
204
+
205
+ The SDK generates the request ID and replays it across transport failures and
206
+ app restarts; the platform credits a Sparks purchase once per provider
207
+ transaction and debits a checkout once per request. Your only job is the
208
+ `request_id:version` dedupe above, so a replayed signal does not show a
209
+ message or play an effect twice.
210
+
211
+ ## Per-surface behaviour
212
+
213
+ - **Summer Games app on iOS:** a native Summer sheet over the game. Sparks are
214
+ bought with Apple In-App Purchase only.
215
+ - **Summer desktop app:** an overlay sheet; Sparks are paid with Stripe in the
216
+ browser, and the result returns to the game on the signal.
217
+ - **Web:** the same sheet in the page, paid with Stripe.
218
+ - **Editor play and local runs:** readiness is `unavailable`. Build the
219
+ unavailable path first.
220
+
221
+ The game code is identical on every surface.
222
+
223
+ ## Testing
224
+
225
+ - Test against Summer staging, which runs payments in sandbox mode: Stripe
226
+ sandbox cards on web and desktop, an Apple Sandbox tester account on iOS test
227
+ builds. *Why:* no real money moves and results are identical to production.
228
+ - Walk every state: decline the sheet, let it expire, buy with too few
229
+ Sparks, buy Sparks, then buy the item. Kill the game while a payment is
230
+ pending and relaunch; the result must still arrive once.
231
+ - Verify the unlock comes from `items.refreshed`, not from the checkout
232
+ signal.
233
+
234
+ ## Store policy notes
235
+
236
+ - Apple requires In-App Purchase for digital goods and currency sold inside
237
+ iOS apps. Summer's iOS sheet handles this; never add your own payment links,
238
+ web prices or "cheaper on the web" text inside the game. *Why:* it can get
239
+ the Summer app removed from the App Store for every game.
240
+ - Randomized paid rewards must disclose their odds before purchase (Apple and
241
+ most regions require it).
242
+ - Say what a purchase gives in plain words next to the price.
243
+
244
+ ## Availability
245
+
246
+ `request_checkout` ships today. `request_sparks_purchase` needs a Summer
247
+ Engine and Summer app release that advertise `player.store.sparks_purchase@1`;
248
+ until then `check_sparks_purchase_readiness()` reports `unavailable` and the
249
+ example above falls back to "Get Sparks from the Summer app".
250
+
251
+ ## See also
252
+
253
+ - multiplayer-state
254
+ - ui-basics
@@ -0,0 +1,29 @@
1
+ id: skill/in-game-purchases
2
+ kind: skill
3
+ version: 1.0.0
4
+ summary: "Sell items for Sparks and let short players buy Sparks in game via the Summer purchase sheet: checkout, Sparks purchase, results, testing, store policy."
5
+ use_when:
6
+ - "adding a shop, buy button or paid item to a Summer game and wiring request_checkout"
7
+ - "a checkout was rejected with insufficient_funds and the player should be able to buy Sparks without leaving the game"
8
+ - "deciding whether an item should be sold for Sparks, or handling pending, declined, expired, rejected or manual_review purchase results"
9
+ do_not_use_when:
10
+ - "designing multiplayer state ownership unrelated to purchases (use multiplayer-state)"
11
+ facets:
12
+ lifecycle:
13
+ - build
14
+ domains:
15
+ - gameplay
16
+ - scripting
17
+ - game-design
18
+ modalities:
19
+ - scripts
20
+ compatibility:
21
+ engine: ">=4.6"
22
+ related:
23
+ skills:
24
+ - skill/multiplayer-state
25
+ - skill/ui-basics
26
+ source: official
27
+ license: MIT
28
+ status: preview
29
+ recommended: false
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: instantiate-asset-pack
3
- description: Use when the user wants to import or spawn an entire asset pack (the multi-slice ArtAsset produced by `create-asset-sheet`) into the current scene — not a single slice, the whole pack. Reads the pack's per-slice metadata (zOrder, isComposite, parentSliceIndex, widget, bbox), groups composites, sorts children by paint order, and emits the Sprite2D / Node2D / NinePatchRect ops to lay it out correctly. Trigger on "import the X pack", "spawn the UI from pack Y", "bring in that asset sheet", "add the panel from the pack".
3
+ description: "Import a whole create-asset-sheet pack into the scene: groups composites, sorts paint order, emits Sprite2D/Node2D/NinePatchRect ops to lay it out."
4
4
  license: MIT
5
5
  compatibility: [Cursor, Claude Code, Windsurf, Codex]
6
6
  category: 2d-assets
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: investigating-bugs
3
- description: Use when encountering any bug, test failure, or unexpected behavior, before proposing fixes
3
+ description: "Systematic investigation of any bug, test failure, or unexpected behavior before proposing fixes."
4
4
  ---
5
5
 
6
6
  # Systematic Debugging
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: lumera-single-image-scene-reconstruction
3
- description: "Use when building a Lumera-style single-image → editable-engine-scene pipeline in SummerEngine: VLM-parsed object boxes and parametric lights, per-object meshes, HDR environment probe, engine-native assembly, and a bounded dual-agent refinement loop."
3
+ description: "Lumera-style single image to editable 3D scene — VLM-parsed object boxes and parametric lights, per-object meshes, HDR probe, .tscn assembly, refinement loop."
4
4
  license: MIT
5
5
  category: art-pipeline
6
6
  tags:
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: make-game
3
- description: "Use when the user says \"make me a game\", \"build me a game\", \"I want to make a [genre] game\", \"let's build something\" \u2014 the orchestration spine that runs the full game-dev pipeline: brainstorm \u2192 plan \u2192 scaffold \u2192 build core mechanics \u2192 art direction \u2192 audio \u2192 polish/VFX \u2192 verify \u2192 ship. Delegates to specialist skills with explicit checkpoints between phases. Trigger on \"make a game\", \"build me a game\", \"create a new game\", \"make me a game\", \"let's build a game\", \"I want to build [game shape]\"."
3
+ description: "Orchestration spine for 'make me a game': brainstorm, plan, scaffold, mechanics, art, audio, polish, verify, ship — delegates to specialist skills."
4
4
  license: MIT
5
5
  compatibility: [Cursor, Claude Code, Codex, Windsurf, Gemini, OpenCode]
6
6
  category: scene-and-project
@@ -27,6 +27,28 @@ This is the skill that runs end-to-end when a user says "make me a game." It doe
27
27
  - User already has a working scaffold and wants to iterate → start at the relevant phase below, don't re-run the whole pipeline.
28
28
  - User says "I want to use a template" → run `browse-templates` first; come back here only if they decide they want a custom build instead.
29
29
 
30
+ ## Genre playbooks (`references/`)
31
+
32
+ Distilled blueprints for common genres live in this skill's `references/` folder: architecture, scene tree, collision layers, core-loop code, build order, traps. Each genre is two files — a core file and a systems/polish file. Read the core file during Phase 2 (Plan) so the build plan follows its architecture and build order; read the systems file only when Phase 4 reaches those mechanics. Never load more than the one genre you are building.
33
+
34
+ | Game | Core | Systems | Root / player / camera |
35
+ |---|---|---|---|
36
+ | Side-scrolling platformer | `references/2d-platformer.md` | `references/2d-platformer-polish.md` | Node2D / CharacterBody2D / Camera2D follow |
37
+ | Horde survivors / bullet heaven | `references/2d-survivors.md` | `references/2d-survivors-progression.md` | Node2D / CharacterBody2D / Camera2D on player |
38
+ | Top-down action RPG (also the base for puzzle, grid, tower defense) | `references/2d-rpg.md` | `references/2d-rpg-content.md` | Node2D / CharacterBody2D / Camera2D |
39
+ | First-person shooter | `references/3d-fps.md` | `references/3d-fps-systems.md` | Node3D / CharacterBody3D / Camera3D on Head |
40
+ | Third-person action / 3D platformer | `references/3d-third-person.md` | `references/3d-third-person-systems.md` | Node3D / CharacterBody3D / SpringArm3D |
41
+ | First-person horror | `references/3d-horror.md` | `references/3d-horror-systems.md` | Node3D / CharacterBody3D / Camera3D on Head |
42
+
43
+ No playbook (racing, sandbox, sim): build fresh through the phases below. The playbooks lean on these system skills — load one when its mechanic comes up: `character-movement`, `camera-rigs`, `combat-basics`, `save-load`, `ui-basics`, `setup-multiplayer`.
44
+
45
+ Two rules from the playbooks apply to every genre:
46
+
47
+ - **2D scales to the viewport.** Set `display/window/stretch/mode = canvas_items` and `stretch/aspect = expand`; UI uses Control anchors; code-positioned nodes compute from `get_viewport_rect().size`. Never hardcode 1920x1080.
48
+ - **Playable slice, not tech demo.** Name the core loop in one sentence; every input gets feedback (tween, sound, particle, flash, shake); progression is visible; a restart exists. The bar is "feels good for 30 seconds".
49
+ - **Fast first draft when someone is waiting.** The first playable version uses shapes, the palette and any template art, plus at most one or two generated assets the person specifically asked for; generation takes minutes, so it never blocks the first play. Say plainly that it is a first draft to get a feel for the game, that the art is not final, and ask if this is the direction they want. Generate the rest of the art in later passes.
50
+ - **Text the default font can show.** No emoji or symbols (▲ ◀ ★ ♥ ✓) in UI text: they render as boxes with hex codes. Use words or icons; see `ui-basics`.
51
+
30
52
  ## The Pipeline
31
53
 
32
54
  ```
@@ -153,7 +175,7 @@ For each mechanic in the plan, **in order**:
153
175
 
154
176
  2. **Implement**:
155
177
  - Add the nodes via `summer_add_node` / `summer_set_prop`. Use `scene-composition` if the structure is non-trivial.
156
- - For movement-class mechanics, prefer the matching pre-built skill: `fps-controller`, `peer-to-peer-multiplayer`, etc.
178
+ - For movement-class mechanics, prefer the matching pre-built skill: `character-movement`, `fps-controller`, `multiplayer-movement`, etc. Follow the genre playbook's build order when one applies.
157
179
  - Write GDScript with `gdscript-patterns` open.
158
180
 
159
181
  3. **Verify**:
@@ -176,7 +198,7 @@ Repeat until every mechanic in the plan is implemented OR the user calls cut.
176
198
  Skill: art-direction
177
199
  ```
178
200
 
179
- That writes `.summer/art-bible.md` if it doesn't exist, then guides the lighting / material / palette pass. Use `3d-lighting` for the actual scene work.
201
+ That writes `.summer/art-bible.md` if it doesn't exist, then guides the lighting / material / palette pass. Use `3d-lighting` for the actual scene work. If the game plays in the browser or is exported for the web, it runs the Compatibility renderer only: follow `web-compatibility-look` instead of Forward+-only features (SDFGI, SSAO, SSR, volumetric fog), and keep `rendering/renderer/rendering_method` on `gl_compatibility`.
180
202
 
181
203
  ```
182
204
  Skill: audio-direction
@@ -0,0 +1,93 @@
1
+ # 2D Platformer - Enemies, Hazards, Juice, Progression
2
+
3
+ Add these only after the core loop (run/jump/goal/death) from `2d-platformer.md`
4
+ feels good. Combat mechanics reuse the `combat-basics` skill.
5
+
6
+ ## Patrol enemy
7
+
8
+ A `CharacterBody2D` that walks, turns at ledges/walls, and hurts on contact. Ledge
9
+ detection via a downward `RayCast2D` at the front foot.
10
+
11
+ ```gdscript
12
+ extends CharacterBody2D
13
+ @export var speed: float = 60.0
14
+ var dir: float = 1.0
15
+ var gravity: float = ProjectSettings.get_setting("physics/2d/default_gravity")
16
+ @onready var ledge: RayCast2D = $LedgeCheck # points down, ahead of feet
17
+
18
+ func _physics_process(delta: float) -> void:
19
+ if not is_on_floor():
20
+ velocity.y += gravity * delta
21
+ if is_on_wall() or (is_on_floor() and not ledge.is_colliding()):
22
+ dir *= -1.0
23
+ ledge.position.x *= -1.0
24
+ $Sprite2D.flip_h = dir < 0.0
25
+ velocity.x = dir * speed
26
+ move_and_slide()
27
+ ```
28
+
29
+ Give it a hurtbox (masks PlayerHurtbox) and a Health node from `combat-basics`.
30
+
31
+ ## Stomp-to-kill
32
+
33
+ The classic platformer verb. A separate Area2D under the player masking only the
34
+ Enemies layer; on overlap, kill the enemy and bounce the player.
35
+
36
+ ```gdscript
37
+ # in player, StompArea (Area2D) child
38
+ func _on_stomp_body_entered(enemy: Node) -> void:
39
+ if velocity.y > 0.0 and enemy.has_method("die"):
40
+ enemy.die()
41
+ velocity.y = jump_velocity * 0.7 # bounce
42
+ ```
43
+
44
+ Falling (`velocity.y > 0`) distinguishes a stomp from a side hit that should damage
45
+ the player instead.
46
+
47
+ ## Hazards
48
+
49
+ - Spikes/lava: an Area2D on the Triggers layer that calls `player.die()`.
50
+ - Bounce pad: Area2D that sets `player.velocity.y = -launch_force` on enter.
51
+ - Bottomless pit: one wide killzone under the level.
52
+
53
+ ## Juice (the difference between prototype and game)
54
+
55
+ Route through a small helper so every hit feels alive:
56
+
57
+ - Hit flash: `modulate` to white, tween back over 0.06s.
58
+ - Screen shake: offset the Camera2D by decaying random noise for ~0.2s.
59
+ - Hitstop: `Engine.time_scale = 0.05` for one frame on a kill, then back to 1.0.
60
+ - Floating text: spawn a Label that rises and fades on coin/hit.
61
+ - Squash/stretch: tween the sprite `scale` to (1.2, 0.8) on land, back over 0.1s.
62
+ - Dust particles on land and on turn.
63
+
64
+ A silent, still platformer fails the 30-second bar even if every system works.
65
+
66
+ ## Progression: coins, gems, and a level goal
67
+
68
+ - Coins increment `GameManager.score`; emit `score_changed` for the HUD.
69
+ - A `level_end` Area2D (flag/door) triggers the level-complete screen with time and
70
+ coin count, then advances to the next room `.tscn`.
71
+ - Save unlocked rooms + best times via the `save-load` skill.
72
+
73
+ ## Metroidvania gating (optional)
74
+
75
+ For an interconnected map with ability gates:
76
+
77
+ - `AbilityManager` autoload: `unlocked: Dictionary`, `has(name)`, `unlock(name)`.
78
+ - Ability pickup: Area2D that calls `AbilityManager.unlock("double_jump")`.
79
+ - Ability gate: a wall/door that only opens if `AbilityManager.has("dash")`, or a
80
+ ledge only reachable with double jump.
81
+ - The player controller checks `AbilityManager.has("double_jump")` before allowing
82
+ a second air jump, `has("dash")` before a dash, etc.
83
+
84
+ Keep gating data-driven: one place lists what each ability unlocks, so designers
85
+ tune it without touching the controller.
86
+
87
+ ## Traps
88
+
89
+ - Enemies as RigidBody2D fight the player physically; use CharacterBody2D or Area2D.
90
+ - Stomp check without a `velocity.y > 0` guard kills enemies on any touch.
91
+ - Ledge raycast that does not flip with direction walks enemies off cliffs.
92
+ - Piling on juice at once (shake + hitstop + flash on every coin) reads as noise;
93
+ reserve the big feedback for kills and damage, keep coins light.
@@ -0,0 +1,117 @@
1
+ # 2D Platformer - Core
2
+
3
+ Side-scrolling platformer blueprint: architecture, the level, and the core loop.
4
+ Movement itself lives in the `character-movement` skill (base controller) and its
5
+ `../../character-movement/references/platformer-feel.md` (coyote time, jump buffer, variable height) - do
6
+ not rewrite it here; wire it in. For Celeste-grade precision movement (dash, wall
7
+ jump, climb) use `celeste-momentum-platforming` instead.
8
+
9
+ ## Minimum playable base (build this first)
10
+
11
+ Scene first (the make-game Scaffold phase): `main.tscn` with a Node2D root, a ground `StaticBody2D`
12
+ with a `CollisionShape2D`, the player, and a `Camera2D` child of the player. Prove
13
+ run + jump + land before anything else. Placeholder art is a colored
14
+ `ColorRect`/`Sprite2D`.
15
+
16
+ ## Architecture (grows into a full game)
17
+
18
+ ```
19
+ res://
20
+ scenes/
21
+ player/player.tscn
22
+ rooms/room_01.tscn # one .tscn per room/level
23
+ enemies/patrol_enemy.tscn
24
+ ui/{hud,pause_menu,main_menu,game_over}.tscn
25
+ scripts/
26
+ autoloads/
27
+ event_bus.gd # global signals, decouples systems
28
+ game_manager.gd # score, lives, current room, checkpoint
29
+ audio_manager.gd # pooled SFX + music
30
+ save_manager.gd
31
+ player/player_controller.gd
32
+ systems/{coin,checkpoint,killzone,moving_platform,one_way_platform,
33
+ crumbling_platform,bounce_pad,door,level_end}.gd
34
+ ```
35
+
36
+ Add autoloads only once the base loop works. Register in Project Settings in
37
+ dependency order: EventBus first (others reference it), then GameManager, then the
38
+ rest. All autoloads `process_mode = ALWAYS` so they survive pause.
39
+
40
+ ## Collision layers (set names in Project Settings)
41
+
42
+ | Layer | Name | Used by |
43
+ |-------|------|---------|
44
+ | 1 | World | TileMap, static platforms |
45
+ | 2 | Player | Player body |
46
+ | 3 | Enemies | Enemy bodies |
47
+ | 4 | PlayerHitbox | Sword/stomp hit area |
48
+ | 5 | EnemyHitbox | Enemy hit area |
49
+ | 6 | PlayerHurtbox | Player hurt area |
50
+ | 7 | EnemyHurtbox | Enemy hurt area |
51
+ | 8 | Collectibles | Coins, gems |
52
+ | 9 | Triggers | Doors, killzones, checkpoints |
53
+
54
+ Hitboxes mask the OPPOSING hurtbox (see the `combat-basics` skill). The stomp detector is a
55
+ separate Area under the player masking only the Enemies layer.
56
+
57
+ ## Building the level with a TileMap
58
+
59
+ Use a `TileMapLayer` (Godot 4.3+) for the solid world. Create a `TileSet`, paint
60
+ the collision polygon on the solid tiles, put the layer on the World collision
61
+ layer. The player collides with it for free - no per-tile StaticBody.
62
+
63
+ - One `TileMapLayer` for collidable terrain, a second (no collision, lower
64
+ z-index) for background decoration.
65
+ - For large levels, split into room `.tscn`s and load the current room via a
66
+ RoomManager; connect doors to `change_scene_to_file` or swap room instances.
67
+ - Parallax background: `Parallax2D` (or ParallaxBackground) layers with
68
+ `motion_scale` < 1 so distant layers move slower.
69
+
70
+ ## Moving, one-way, and crumbling platforms
71
+
72
+ These three cover most platformer level tech.
73
+
74
+ ```gdscript
75
+ # moving_platform.gd - AnimatableBody2D so riders move with it
76
+ extends AnimatableBody2D
77
+ @export var offset: Vector2 = Vector2(200, 0)
78
+ @export var duration: float = 2.0
79
+ func _ready() -> void:
80
+ var t := create_tween().set_loops().set_trans(Tween.TRANS_SINE)
81
+ t.tween_property(self, "position", position + offset, duration)
82
+ t.tween_property(self, "position", position, duration)
83
+ ```
84
+
85
+ Use `AnimatableBody2D` (not StaticBody2D) for movers - it carries the player. For
86
+ one-way platforms, enable `one_way_collision` on the platform's CollisionShape2D
87
+ so the player jumps up through and lands on top. Crumbling platform: on
88
+ `body_entered`, start a short timer, shake, then disable collision and fade out;
89
+ re-enable after a respawn delay.
90
+
91
+ ## Checkpoints and death
92
+
93
+ ```gdscript
94
+ # checkpoint.gd
95
+ extends Area2D
96
+ func _ready() -> void:
97
+ body_entered.connect(func(b):
98
+ if b.is_in_group("player"):
99
+ GameManager.checkpoint = global_position)
100
+
101
+ # killzone.gd - fall/spike death
102
+ extends Area2D
103
+ func _ready() -> void:
104
+ body_entered.connect(func(b):
105
+ if b.is_in_group("player"):
106
+ b.die()) # player respawns at GameManager.checkpoint
107
+ ```
108
+
109
+ ## Core loop checklist (the 30-second bar)
110
+
111
+ - Run + jump feels good (tuned gravity/fall multiplier, coyote + buffer).
112
+ - Coins/goal give immediate feedback: sound + pop tween + counter tick.
113
+ - Death is instant and respawns at the last checkpoint, no long reload.
114
+ - A visible goal (flag/door) ends the level with a clear result.
115
+
116
+ Enemies, hazards, juice, and metroidvania progression are in
117
+ `2d-platformer-polish.md`.