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,6 +1,6 @@
1
1
  ---
2
2
  name: sprite-sheet
3
- description: Use when generating animated 2D character sprites laid out as a sprite sheet (grid of frames) — walk cycle, attack frames, idle bob, death sequence. Wires into AnimatedSprite2D / SpriteFrames. Trigger on "sprite sheet", "walk cycle", "attack frames", "animated sprite", "frame-by-frame animation", "2D character animation".
3
+ description: "Generate animated 2D character sprites laid out as a sprite sheet — walk cycle, attack, idle, death — wired into AnimatedSprite2D / SpriteFrames."
4
4
  license: MIT
5
5
  compatibility: [Cursor, Claude Code, Windsurf, Codex]
6
6
  category: 2d-assets
@@ -0,0 +1,147 @@
1
+ ---
2
+ name: summer-analytics
3
+ description: "Send game events to Summer analytics from the authority or client: fire-and-forget, never blocking gameplay."
4
+ license: MIT
5
+ compatibility: [Cursor, Claude Code, Windsurf, Codex]
6
+ category: multiplayer-and-networking
7
+ user-invocable: true
8
+ allowed-tools: Read Grep Edit Write summer_get_script_errors summer_play summer_stop summer_get_diagnostics summer_open
9
+ paths: ["**/*.gd"]
10
+ ---
11
+
12
+ # /summer-analytics — game events you can chart later
13
+
14
+ ## Overview
15
+
16
+ Summer analytics stores named events, such as `level_completed` or
17
+ `coin_collected`, for the creator to query in Studio. There are two ways in:
18
+
19
+ | Captured from | Call | What it means |
20
+ |---|---|---|
21
+ | The player's client | `Summer.client.analytics.capture(name, properties)` | An **untrusted** observation from that player's device. Summer attaches the player, game and build; you never pass ids. |
22
+ | The authority | `Summer.authority.analytics.capture(name, properties)` | An observation about this World's runtime. It describes the server, not a player or a match. |
23
+
24
+ Analytics is for **looking at** your game, never for running it:
25
+
26
+ - Capture returns immediately.
27
+ - Gameplay never waits for capture and never depends on its result.
28
+ - **Capture is never retried.** An `unavailable` result may already have stored the event, and capturing again records a second event.
29
+
30
+ **Where it works:** hosted only. Under Local Play both calls complete with
31
+ `ok == false` and code `unavailable`, and nothing is stored. Also print each
32
+ event while testing, so you can check it in the logs.
33
+
34
+ ## Steps
35
+
36
+ ### 1. Choose a small set of events
37
+
38
+ Name events after things that happened, in the past tense:
39
+ `match_started`, `coin_collected`, `tutorial_step_completed`.
40
+
41
+ - **Names**:
42
+ - 1 to 64 characters, matching `^[A-Za-z][A-Za-z0-9_.:-]{0,63}$`.
43
+ - Case-sensitive, and never starting with `summer.`.
44
+ - **Never put changing values in names** (`coin_7_collected`). Put them in properties: `{"coin": 7}`.
45
+ - New event names are rate-limited per player and per game per day.
46
+ - Known names keep working after that limit.
47
+ - **Properties** are a JSON `Dictionary`:
48
+ - at most 64 scalar values;
49
+ - nesting at most 4 deep;
50
+ - property names up to 128 bytes;
51
+ - one event at most 16 KiB.
52
+ - **Never send personal data or secrets.** Names such as `email`, `password`, `phone`, `address`, `ip_address` and `*_token` are rejected at any depth, as is anything starting with `$summer_`.
53
+
54
+ Capture authoritative facts on the authority, where the game decided them.
55
+ Capture interface facts on the client: menu opened, tutorial step shown,
56
+ settings changed.
57
+
58
+ ### 2. Add a fire-and-forget helper
59
+
60
+ Authority, in `authority/main.gd`:
61
+
62
+ ```gdscript
63
+ ## Fire-and-forget: gameplay never waits on analytics, and a failure is
64
+ ## logged once, never retried (a retry would count the event twice).
65
+ var _analytics_warned := false
66
+
67
+ func _track(event: String, properties: Dictionary = {}) -> void:
68
+ print("ANALYTICS ", event, " ", JSON.stringify(properties))
69
+ var capture := Summer.authority.analytics.capture(event, properties)
70
+ var result: SummerResult = await capture.get_result_or_completed_signal()
71
+ if not result.ok and not _analytics_warned:
72
+ _analytics_warned = true
73
+ push_warning("analytics unavailable: %s" % result.code)
74
+ ```
75
+
76
+ Client, in `client/main.gd`, the same shape with the client facade:
77
+
78
+ ```gdscript
79
+ var _analytics_warned := false
80
+
81
+ func _track(event: String, properties: Dictionary = {}) -> void:
82
+ print("ANALYTICS ", event, " ", JSON.stringify(properties))
83
+ var capture := Summer.client.analytics.capture(event, properties)
84
+ var result: SummerResult = await capture.get_result_or_completed_signal()
85
+ if not result.ok and not _analytics_warned:
86
+ _analytics_warned = true
87
+ push_warning("analytics unavailable: %s" % result.code)
88
+ ```
89
+
90
+ ### 3. Call it without awaiting
91
+
92
+ Call `_track(...)` as a statement and do **not** `await` it, so the caller
93
+ continues immediately. For example, in the authority's `_collect`, after the
94
+ coin is applied:
95
+
96
+ ```gdscript
97
+ _track("coin_collected", {"coin": coin, "players": seat_of.size()})
98
+ ```
99
+
100
+ On the client, after a menu choice:
101
+
102
+ ```gdscript
103
+ _track("menu_opened", {"from": "pause"})
104
+ ```
105
+
106
+ ### 4. Read the results
107
+
108
+ Open the game's analytics in Studio: `summer_open` with target `game` and
109
+ params `gameId` (your game's id) and `section: "analytics"`. Events show up
110
+ there after a short delay.
111
+
112
+ ## Result codes
113
+
114
+ | Code | Meaning | What to do |
115
+ |---|---|---|
116
+ | `unavailable` | No analytics service here (Local Play, an old Host), or a lost answer | Nothing. Do not capture again. |
117
+ | `capacity_exceeded` | More than 32 captures are pending | Capture less often; batch counts into one event |
118
+ | `analytics_storage_limit_exceeded` | The game's analytics quota is used up | Stop capturing this event type; final for now |
119
+ | `not_configured` | An older Supervisor without authority analytics | Nothing |
120
+
121
+ Every failure is final: none of them asks you to capture again.
122
+
123
+ ## Checklist
124
+
125
+ - [ ] Every capture is a plain `_track(...)` call; no gameplay code awaits it.
126
+ - [ ] Event names are fixed strings; values live in properties.
127
+ - [ ] No personal data, tokens or free-typed player text in properties.
128
+ - [ ] Authority-decided facts (won, collected, bought) are captured on the authority.
129
+ - [ ] Under Local Play the game plays normally while captures report `unavailable`.
130
+
131
+ ## Common mistakes
132
+
133
+ | Don't | Do | Why |
134
+ |---|---|---|
135
+ | `await _track(...)` in gameplay code | Call it and move on | A slow or failing capture would stall the game |
136
+ | Capture again after `unavailable` | Log once and drop it | It may already be stored; a second capture double-counts |
137
+ | `coin_%d_collected` names | `coin_collected` with `{"coin": 7}` | New names are rate-limited; values belong in properties |
138
+ | Trust client events for rewards or rankings | Decide on the authority; capture there too | Client events are untrusted observations |
139
+ | Put emails, ids or tokens in properties | Summer attaches player and game identity itself | Blocked names are rejected; personal data must not be collected |
140
+ | Make gameplay depend on analytics working | Treat it as optional | It is unavailable locally and may be unavailable hosted |
141
+ | Start names with `summer.` | Your own names | That namespace is reserved |
142
+
143
+ ## See also
144
+
145
+ - `skill/multiplayer` — where the client and the authority run
146
+ - `skill/multiplayer-state` — the authority's Command handlers, where most events happen
147
+ - `skill/summer-match-results` — results and ratings, which Summer records itself
@@ -0,0 +1,28 @@
1
+ id: skill/summer-analytics
2
+ kind: skill
3
+ version: 1.0.0
4
+ summary: "Send game events to Summer analytics from the authority or client: fire-and-forget, never blocking gameplay."
5
+ use_when:
6
+ - "adding analytics, telemetry or event tracking to a Summer game: level completed, coin collected, tutorial funnel"
7
+ - "deciding what to track on the client versus the authority, and how to name analytics events and properties"
8
+ - "analytics capture fails with unavailable, capacity_exceeded or analytics_storage_limit_exceeded"
9
+ facets:
10
+ lifecycle:
11
+ - build
12
+ domains:
13
+ - multiplayer
14
+ - scripting
15
+ modalities:
16
+ - scripts
17
+ compatibility:
18
+ engine: ">=4.6"
19
+ related:
20
+ skills:
21
+ - skill/multiplayer
22
+ - skill/multiplayer-state
23
+ - skill/summer-match-results
24
+ - skill/summer-store
25
+ source: official
26
+ license: MIT
27
+ status: preview
28
+ recommended: false
@@ -0,0 +1,226 @@
1
+ ---
2
+ name: summer-friends
3
+ description: "Summer friends in a game: a consented friends list, profile and chat screens, direct messages. Hosted only."
4
+ license: MIT
5
+ compatibility: [Cursor, Claude Code, Windsurf, Codex]
6
+ category: multiplayer-and-networking
7
+ user-invocable: true
8
+ allowed-tools: Read Grep Edit Write summer_get_script_errors summer_project_setting summer_play summer_stop summer_get_diagnostics
9
+ paths: ["**/*.gd", "summer.build.json"]
10
+ ---
11
+
12
+ # /summer-friends — friends, profiles and direct messages
13
+
14
+ ## Overview
15
+
16
+ Friendships belong to the player's Summer account. The Summer app owns the
17
+ social graph itself:
18
+
19
+ - friend requests;
20
+ - blocking;
21
+ - the friends list screen;
22
+ - profiles;
23
+ - chat.
24
+
25
+ Your game gets two client-only facades.
26
+
27
+ **`Summer.client.friends`**
28
+ - Two screens need **no consent**: `show_friends()` and `show_chat(user_id)`. They ask the Summer app to show its own screen over the game.
29
+ - `show_profile(user_id)` is the same. The profile includes add friend, message, invite to party and report, so it is the social feature most games need.
30
+ - **With consent**, it reads the list: each friend's name, handle and whether they are `offline`, `online`, `in_this_game` or `in_other_game`. Another game is never named.
31
+
32
+ **`Summer.client.messages`**
33
+ - Reads and sends the player's direct messages, with a separate consent for each kind of access.
34
+ - Prefer `show_chat(user_id)` unless chat is central to your game.
35
+
36
+ Reading friends or messages needs two things:
37
+
38
+ 1. **The Build declares the permission** in `summer.build.json`.
39
+ 2. **The player grants it** in the Summer app's consent sheet, which your game asks for with `request_access`.
40
+
41
+ Declining never blocks play. A game must work without these permissions.
42
+
43
+ **Availability:**
44
+
45
+ - **Engine release.** This needs an engine that includes Summer Engine PR #508. On engines without it, `Summer.client.friends` does not exist and scripts that use it fail to parse. Check the class reference for `SummerClientFriends` before using this skill.
46
+ - **Hosted only.** `is_available()` is `false` in Local Play and editor runs, for guests, for accounts the platform keeps out of social features (`age_restricted`, under 13), and in Summer apps without `player.friends@1` (friends) or `player.messaging@1` (messages).
47
+ - **Overlays.** The screens need the Summer app to offer friends and parties; otherwise they fail with `capability_unavailable` or `ui_unavailable`.
48
+
49
+ ## Steps
50
+
51
+ ### 1. Declare the permissions you use
52
+
53
+ Add a top-level `permissions` array to `summer.build.json`, next to `schema`
54
+ and `gameId`. List only what the game uses; each entry is an upper bound on
55
+ what you may ask for.
56
+
57
+ ```json
58
+ "permissions": ["social.friends.read"],
59
+ ```
60
+
61
+ | Permission | Allows |
62
+ | --- | --- |
63
+ | `social.friends.read` | `get_friends()`, statuses, the `changed` signal |
64
+ | `social.messages.read` | `list_conversations`, `list_messages`, `list_messages_after` |
65
+ | `social.messages.send` | `send` |
66
+ | `social.messages.read_state.write` | `mark_read` |
67
+
68
+ Unknown or duplicate entries are rejected when you publish. Without a
69
+ declaration, `get_access()` reports `undeclared`, and `request_access()` fails
70
+ at once with `permission_undeclared`.
71
+
72
+ ### 2. The friends node
73
+
74
+ `client/friends.gd`, a child `Friends` of `Main`. In `client/main.gd`'s `_ready()`, call
75
+ `$Friends.start()` right after `Summer.initialize` succeeds:
76
+
77
+ ```gdscript
78
+ extends Node
79
+ ## The player's Summer friends, with their consent, and the Summer app's
80
+ ## friend screens over the game.
81
+
82
+ signal friends_changed(rows: Array) # [{user_id, name, status}]
83
+ signal status(text: String)
84
+
85
+ var friends: SummerClientFriends
86
+
87
+
88
+ ## Main calls this right after Summer.initialize succeeds: a child's _ready
89
+ ## runs before that, while Summer.client is still null.
90
+ func start() -> void:
91
+ friends = Summer.client.friends
92
+ friends.changed.connect(_render)
93
+ friends.access_changed.connect(func(_state: StringName) -> void: _render())
94
+ _render()
95
+
96
+
97
+ ## The Friends button: asks for consent once, then shows the list.
98
+ func open() -> void:
99
+ if not friends.is_available():
100
+ status.emit("Friends are not available here.")
101
+ return
102
+ if friends.get_access() != &"granted":
103
+ var decision: SummerResult = await friends.request_access().get_result_or_completed_signal()
104
+ if not decision.ok:
105
+ status.emit("Your friends list stays private.")
106
+ return
107
+ _render()
108
+
109
+
110
+ func _render() -> void:
111
+ var rows := []
112
+ for friend in friends.get_friends():
113
+ rows.append({"user_id": friend.user_id, "name": friend.display_name, "status": friend.status})
114
+ friends_changed.emit(rows)
115
+
116
+
117
+ ## The Summer app's profile for any other player this game knows. No consent needed.
118
+ func show_profile(user_id: String) -> void:
119
+ var shown: SummerResult = await friends.show_profile(user_id).get_result_or_completed_signal()
120
+ if not shown.ok:
121
+ status.emit("That screen is not available right now.")
122
+
123
+
124
+ ## The Summer app's direct-message thread with a friend, over the game.
125
+ func show_chat(user_id: String) -> void:
126
+ var shown: SummerResult = await friends.show_chat(user_id).get_result_or_completed_signal()
127
+ if not shown.ok:
128
+ status.emit("That screen is not available right now.")
129
+ ```
130
+
131
+ How it behaves:
132
+
133
+ - **When the list is read again.** With a handler on `changed`, the engine re-reads the list on every change hint, after a consent decision, on `refresh()`, and about every 60 seconds while the game is in front. Never poll yourself.
134
+ - **Statuses.** Show `in_this_game` friends first. `unknown` means presence couldn't be read; it is not `offline`.
135
+ - **Rows.** Key them by `user_id`; each read replaces the `SummerFriend` objects.
136
+ - **Profiles of other players.** For the people in the current match, use the user ids your authority publishes (the `players` map in `skill/summer-world-chat`, step 1) and call `show_profile(user_id)`. Your own id fails with `invalid_argument`.
137
+ - **Inviting a friend into a match.** Use the party invite sheet (`skill/summer-parties`).
138
+
139
+ ### 3. Direct messages (only if chat is central)
140
+
141
+ ```gdscript
142
+ ## Sends one direct message, asking for the send permission once.
143
+ func send_message(user_id: String, text: String) -> void:
144
+ var messages := Summer.client.messages
145
+ if not messages.is_available():
146
+ return
147
+ if messages.get_access(&"social.messages.send") != &"granted":
148
+ var decision: SummerResult = await messages.request_access(PackedStringArray(["social.messages.send"])).get_result_or_completed_signal()
149
+ if not decision.ok:
150
+ return
151
+ var sent := messages.send(user_id, text)
152
+ var result: SummerResult = await sent.get_result_or_completed_signal()
153
+ if result.ok:
154
+ print("sent #%d" % sent.message.sequence)
155
+ elif result.code == &"text_not_allowed":
156
+ status.emit("That message was not sent.")
157
+ elif result.code == &"target_unavailable":
158
+ status.emit("You can't message this player.")
159
+ ```
160
+
161
+ Reading a thread works the same way:
162
+
163
+ - **Read a page.** Ask for `social.messages.read`, then `messages.list_messages(user_id)`. Read `op.messages`, newest page first; pass `op.next_cursor` for older pages.
164
+ - **Catch up.** After `messages_changed`, call `list_messages_after(user_id, last_sequence)`. Today `messages_changed` fires only after a stream resync, so also reload when the chat screen opens.
165
+ - **Mark read.** `mark_read(user_id, sequence)` needs `social.messages.read_state.write`. It marks the thread read on every device.
166
+ - **Send rules.** `send` takes 1–4000 characters and no control characters except newline and tab. Each call is one message; the engine never sends it twice.
167
+
168
+ ### 4. Failure codes
169
+
170
+ | Code | Meaning | Show |
171
+ | --- | --- | --- |
172
+ | `permission_not_requested`, `permission_declined`, `permission_revoked` | The player hasn't granted it | A "Show friends" button that calls `request_access()` again later |
173
+ | `permission_undeclared` | `summer.build.json` lacks it | Fix the declaration (step 1) |
174
+ | `capability_unavailable` | Local Play, guest or older Summer app | Hide the feature |
175
+ | `age_restricted` | Under-13 account | Hide the feature |
176
+ | `ui_unavailable` | The app can't show a sheet now | "Try again" |
177
+ | `operation_in_progress` (retryable) | Another Summer sheet (party or friends) is open | Wait |
178
+ | `text_not_allowed` | Filtered; nothing stored | "Not sent" |
179
+ | `target_unavailable` | Not a friend, blocked, or gone | "You can't message this player" |
180
+ | `rate_limited`, `unavailable` (retryable) | Busy, or the Player Host is unreachable | Retry later, never in a loop |
181
+
182
+ ### 5. Test
183
+
184
+ Local Play has no accounts, so check the hidden path locally:
185
+
186
+ - `is_available()` is `false`;
187
+ - buttons are hidden;
188
+ - there are no script errors.
189
+
190
+ ```
191
+ summer_project_setting name="summer/local_play/players" value=2
192
+ summer_play
193
+ summer_get_diagnostics
194
+ summer_stop
195
+ ```
196
+
197
+ Then test on Summer staging with two accounts that are friends: grant, decline
198
+ and revoke access in the Summer app, and watch `access_changed`.
199
+
200
+ ## Checklist
201
+
202
+ - [ ] The engine's class reference lists `SummerClientFriends` (Summer Engine PR #508 or later).
203
+ - [ ] `summer.build.json` declares exactly the permissions the code asks for.
204
+ - [ ] Local Play: friends features are hidden, with no script errors.
205
+ - [ ] Declining consent leaves the game fully playable, and the button can ask again later.
206
+ - [ ] Hosted: a friend playing the game shows `in_this_game`; `show_profile` opens for another player in the match.
207
+ - [ ] No polling timer: updates come from `changed`.
208
+
209
+ ## Common mistakes
210
+
211
+ | Don't | Do | Why |
212
+ | --- | --- | --- |
213
+ | Ask for consent at startup | Ask when the player opens a friends feature | A consent sheet without context gets declined |
214
+ | Gate play on friends access | Treat it as optional | Declining must never block the game |
215
+ | Build friend requests, blocking or a profile screen | `show_friends()`, `show_profile()`, `show_chat()` | The Summer app owns them, with no consent needed |
216
+ | Treat `unknown` as `offline` | Show it as unknown | It means presence couldn't be read |
217
+ | Poll `refresh()` on a timer | Connect `changed` | The engine already re-reads while a handler is connected |
218
+ | Declare every permission "just in case" | Declare only what you use | The consent sheet lists each declared permission |
219
+ | Use friends to put players in one match | `skill/summer-parties` | Parties are how players play together |
220
+
221
+ ## See also
222
+
223
+ - `skill/summer-parties`: playing together, the invite sheet
224
+ - `skill/summer-world-chat`: chat inside a match
225
+ - `skill/multiplayer-publish`: `summer.build.json` and publishing a Build
226
+ - `skill/multiplayer-testing`: what Local Play can and can't test
@@ -0,0 +1,28 @@
1
+ id: skill/summer-friends
2
+ kind: skill
3
+ version: 1.0.0
4
+ summary: "Summer friends in a game: a consented friends list, profile and chat screens, direct messages. Hosted only."
5
+ use_when:
6
+ - "showing a friends list, who is online or which friends are playing this Summer game"
7
+ - "opening a player's Summer profile, friends list or chat screen from inside a game"
8
+ - "reading or writing a player's direct messages, or a friends call fails with permission_undeclared or permission_declined"
9
+ facets:
10
+ lifecycle:
11
+ - build
12
+ domains:
13
+ - multiplayer
14
+ - ui
15
+ modalities:
16
+ - scripts
17
+ compatibility:
18
+ engine: ">=4.6"
19
+ related:
20
+ skills:
21
+ - skill/multiplayer
22
+ - skill/multiplayer-testing
23
+ - skill/summer-parties
24
+ - skill/summer-world-chat
25
+ source: official
26
+ license: MIT
27
+ status: preview
28
+ recommended: false
@@ -0,0 +1,231 @@
1
+ ---
2
+ name: summer-leaderboards
3
+ description: "Leaderboards in a Summer game: queue ratings from matches, and Game rankings your authority scores."
4
+ license: MIT
5
+ compatibility: [Cursor, Claude Code, Windsurf, Codex]
6
+ category: multiplayer-and-networking
7
+ user-invocable: true
8
+ allowed-tools: Read Grep Edit Write summer_read_file summer_replace_text summer_write_file summer_get_script_errors summer_play summer_stop summer_get_diagnostics
9
+ paths: ["summer.build.json", "client/**/*.gd", "authority/**/*.gd"]
10
+ ---
11
+
12
+ # /summer-leaderboards — ratings, rankings and the top 50
13
+
14
+ ## Overview
15
+
16
+ Summer keeps two kinds of score board. Pick by where the number comes from:
17
+
18
+ | Board | The number is | Declared as | Written by | Read with |
19
+ |---|---|---|---|---|
20
+ | **Queue rating** | A skill rating (Elo, MMR) that moves with every match in a rated queue | A queue with `"policy": "rating"` | Summer, when the authority concludes a match | `Summer.client.ratings`, `Summer.authority.ratings` |
21
+ | **Game ranking** | Any score your game defines: total coins, best time, levels cleared | `runtime.rankings` | Your authority, with compare-and-set | `Summer.client.rankings`, `Summer.authority.rankings` |
22
+
23
+ Players only ever read their **own** rating and score, plus the public top 50,
24
+ which shows display names, never account ids. Nobody can write a score from a
25
+ client.
26
+
27
+ Where it works: leaderboards, standings and rankings are read through the
28
+ Summer app that hosts the player, so they work in **hosted** games only.
29
+ Under Local Play they fail with a typed code (step 5); the authority's
30
+ `ratings.load` returns a deterministic test value. Build the screens so they
31
+ degrade gracefully, and check the real numbers on a hosted staging build.
32
+
33
+ This skill extends the Courtyard game: its authority concludes matches as in
34
+ `skill/summer-match-results`.
35
+
36
+ ## Steps
37
+
38
+ ### 1. Declare the boards
39
+
40
+ In `summer.build.json`, a rated queue gets a rating, and `runtime.rankings`
41
+ declares Game rankings:
42
+
43
+ ```json
44
+ "queues": [
45
+ {
46
+ "name": "duel",
47
+ "minPlayers": 2,
48
+ "maxPlayers": 2,
49
+ "worldDefinition": "courtyard",
50
+ "policy": "rating",
51
+ "ratingSystemRef": "elo_v1",
52
+ "teams": { "count": 2, "size": 1 },
53
+ "transport": "enet"
54
+ }
55
+ ],
56
+ "rankings": [
57
+ { "name": "coins", "initialRating": 0 }
58
+ ]
59
+ ```
60
+
61
+ - `ratingSystemRef`: `elo_v1` lets Summer compute rating moves from win, loss
62
+ and draw. `authority_v1` makes your authority report each player's move
63
+ (step 4). Optional `initialRating` is a newcomer's rating (default 1200).
64
+ - A ranking `name` is lower-case letters and digits separated by single `.`,
65
+ `_` or `-`, at most 64 characters; at most 32 rankings. `initialRating`
66
+ defaults to 0.
67
+ - To make a rated queue and a ranking one board, give the queue
68
+ `"rankingRef": "<ranking name>"` and drop the queue's `initialRating`. A
69
+ queue and a ranking may not share a name without `rankingRef`.
70
+
71
+ ### 2. Show a queue's top 50 and the player's standing
72
+
73
+ On a client, after Summer is initialized (no match needed):
74
+
75
+ ```gdscript
76
+ ## Fills a leaderboard screen for a rated queue. Hosted games only.
77
+ func show_queue_board(queue: StringName) -> void:
78
+ var board := Summer.client.ratings.leaderboard(queue)
79
+ var read: SummerResult = await board.get_result_or_completed_signal()
80
+ if not read.ok:
81
+ show_board_unavailable(read)
82
+ return
83
+ for entry: SummerLeaderboardEntry in board.entries:
84
+ add_board_row(entry.rank, entry.display_name, entry.value, entry.you)
85
+ var standing := Summer.client.ratings.standing(queue)
86
+ if (await standing.get_result_or_completed_signal()).ok:
87
+ if standing.rank > 0:
88
+ show_place("#%d of %d" % [standing.rank, standing.players])
89
+ elif standing.rated:
90
+ show_place("Top %.1f%%" % (100.0 - standing.percentile))
91
+ else:
92
+ show_place("Play a rated match to get a rank")
93
+ ```
94
+
95
+ - `entries` holds up to 50 rows, best first; `you` marks the player's own row.
96
+ - `standing.rank` is set only inside the top 1000; otherwise show the
97
+ percentile. Before the first rated match `rated` is false and `value` is the
98
+ queue's `initialRating`.
99
+ - `Summer.client.ratings.get_current(queue)` returns the last known
100
+ `SummerRatingSnapshot` (`value`, `games`, `version`) without a network read,
101
+ or `null`. `refresh(queue)` reads it again; `rating_changed(queue)` fires
102
+ when it moves.
103
+ - One read of each kind is in flight at a time; calling again while one is
104
+ pending returns the same operation.
105
+
106
+ After a match, `Summer.client.ratings.rating_committed` delivers the
107
+ player's own before-and-after rating (see `skill/summer-match-results`).
108
+
109
+ ### 3. Write a Game ranking from the authority
110
+
111
+ Only the authority writes rankings, by the player's stable id, with
112
+ **compare-and-set**: read the score and its version, write the new absolute
113
+ value against that version, and read again if someone else wrote first. In
114
+ `authority/main.gd`, after the match concluded:
115
+
116
+ ```gdscript
117
+ ## Adds this match's coins to each player's Game ranking "coins".
118
+ ## Compare-and-set: read the version, write against it, re-read on conflict.
119
+ func _record_coins() -> void:
120
+ for session_id: String in wallets:
121
+ var player: SummerPlayer = sessions[session_id].player
122
+ await _add_score(&"coins", player.user_id, int(wallets[session_id]))
123
+
124
+
125
+ func _add_score(ranking: StringName, player_id: String, points: int) -> void:
126
+ for attempt in 3:
127
+ var before := Summer.authority.rankings.get_score(ranking, player_id)
128
+ var read: SummerResult = await before.get_result_or_completed_signal()
129
+ if not read.ok:
130
+ return # hosted only: Local Play has no ranking service
131
+ var write := Summer.authority.rankings.set_score(ranking, player_id, before.rating.version, before.rating.value + points, before.rating.games + 1)
132
+ var wrote: SummerResult = await write.get_result_or_completed_signal()
133
+ if wrote.ok or wrote.code != &"ranking_version_conflict":
134
+ return
135
+ # Someone else wrote first: read again and recompute.
136
+ ```
137
+
138
+ `sessions` maps each `session_id` to the `SummerSession` the authority keeps
139
+ in `_on_session_joined` (`skill/summer-match-results`, step 1). The engine never
140
+ retries a write. After a failure other than a conflict, read the score before
141
+ deciding to write again: the first write may have committed.
142
+
143
+ Clients read their own ranking with `Summer.client.rankings.get_score("coins")`,
144
+ `standing("coins")` (full rank and player count; rank 0 before the first
145
+ score) and `leaderboard("coins")` (top 50, zero-score players included). These
146
+ work in a standalone game too, before any match.
147
+
148
+ ### 4. Own a co-op queue's rating (`authority_v1`)
149
+
150
+ Elo rates two sides against each other. A co-op mode, where a group plays
151
+ against the content, declares `"ratingSystemRef": "authority_v1"` and reports
152
+ every player's move when the match concludes:
153
+
154
+ ```gdscript
155
+ ## A co-op run against content rated `content_rating`; `cleared` says whether
156
+ ## the group made it. Moves each player's rating like Elo against the content.
157
+ func conclude_run(players: Array[SummerSession], content_rating: int, cleared: bool) -> void:
158
+ var outcomes: Dictionary[SummerSession, SummerAuthorityMatch.MatchOutcome] = {}
159
+ var deltas: Dictionary[SummerSession, int] = {}
160
+ for session in players:
161
+ var read := Summer.authority.ratings.load(session)
162
+ if not (await read.get_result_or_completed_signal()).ok:
163
+ return # rating_unavailable: this queue keeps no rating
164
+ var expected := 1.0 / (1.0 + pow(10.0, (content_rating - read.rating.value) / 400.0))
165
+ deltas[session] = roundi(32 * ((1.0 if cleared else 0.0) - expected))
166
+ outcomes[session] = SummerAuthorityMatch.MATCH_OUTCOME_WIN if cleared else SummerAuthorityMatch.MATCH_OUTCOME_LOSS
167
+ var concluded: SummerResult = await Summer.authority.match.conclude(outcomes, "run_complete", deltas).get_result_or_completed_signal()
168
+ ```
169
+
170
+ - Each delta is an `int` within ±1000, one for **every** participant.
171
+ Deltas on a non-`authority_v1` queue, or a missing one, fail the
172
+ conclusion with `invalid_request` and commit nothing; conclude again with
173
+ corrected arguments.
174
+ - `Summer.authority.ratings.load(session)` is for the authority's own logic.
175
+ Never show one player's rating to other players; the leaderboard is the
176
+ public view.
177
+ - `Summer.authority.ratings.leaderboard("dungeon")` reads the same top 50,
178
+ unmarked, for an in-World trophy wall.
179
+
180
+ ### 5. Degrade gracefully where boards aren't available
181
+
182
+ ```gdscript
183
+ func show_board_unavailable(result: SummerResult) -> void:
184
+ match String(result.code):
185
+ "rating_unavailable":
186
+ show_place("This mode has no ranking")
187
+ _:
188
+ show_place("Leaderboard unavailable right now" if result.retryable else "Leaderboards appear in the Summer app")
189
+ ```
190
+
191
+ Under Local Play these calls fail without a Summer account behind them:
192
+
193
+ | Call | Under Local Play |
194
+ |---|---|
195
+ | `Summer.client.ratings.leaderboard`, `standing`, `refresh` | Fails with `unavailable` (retryable) |
196
+ | `Summer.client.ratings.get_current` | `null` |
197
+ | `Summer.client.rankings.get_score`, `standing`, `leaderboard` | Fails with `unavailable` (not retryable) |
198
+ | `Summer.authority.rankings.get_score`, `set_score` | Fails with `service_error` |
199
+ | `Summer.authority.ratings.load` | Works: a deterministic test rating (system `deterministic-v1`) |
200
+ | `Summer.authority.ratings.leaderboard` | Works: an empty list |
201
+ | `Summer.authority.match.conclude` | Works: a deterministic settlement with test rating changes |
202
+
203
+ Hide or grey out leaderboard buttons when a read fails; never block the game
204
+ on them.
205
+
206
+ ## Checklist
207
+
208
+ - [ ] Every board is declared: rated queues with `ratingSystemRef`, rankings under `runtime.rankings`.
209
+ - [ ] The leaderboard screen marks the player's own row and shows rank or percentile.
210
+ - [ ] Ranking writes happen only on the authority, by `player.user_id`, with compare-and-set and a conflict re-read.
211
+ - [ ] `authority_v1` queues conclude with a delta for every participant; other queues send none.
212
+ - [ ] Every read handles failure, and the game stays playable without boards.
213
+ - [ ] Real numbers checked on a hosted staging build.
214
+
215
+ ## Common mistakes
216
+
217
+ | Don't | Do | Why |
218
+ |---|---|---|
219
+ | Write scores from the client | `Summer.authority.rankings.set_score` | Clients can only read their own score; the authority is trusted |
220
+ | `set_score` without the version you read | Read with `get_score`, pass `before.rating.version` | It is compare-and-set; a stale version fails `ranking_version_conflict` |
221
+ | Blindly retry a failed write | Read again, then decide | The first write may have committed; the engine doesn't replay it |
222
+ | Send rating deltas on an `elo_v1` or `fifo` queue | Deltas only on `authority_v1`, one per participant | Otherwise the conclusion fails `invalid_request` |
223
+ | Show other players' ratings from `authority.ratings.load` | Show the leaderboard | Ratings are private to each player |
224
+ | Name a ranking like a queue without `rankingRef` | Distinct names, or `rankingRef` to share one board | Summer rejects the manifest |
225
+ | Treat a Local Play failure as a bug | Expect `unavailable` or `service_error` locally; test boards hosted | Boards are read through the hosting Summer app |
226
+
227
+ ## See also
228
+
229
+ - `skill/summer-match-results` — concluding matches, which moves ratings
230
+ - `skill/summer-matchmaking` — declaring rated queues and teams
231
+ - `skill/summer-player-data` — saving per-player progress that isn't a ranking