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
@@ -0,0 +1,501 @@
1
+ # multiplayer-movement: complete files after this step
2
+
3
+ Every file below ran as shown under Local Play. Compare against your project, or copy a file whole.
4
+
5
+ ## `authority/main.gd`
6
+
7
+ ```gdscript
8
+ extends Node
9
+ ## The match server. It runs headless and owns every rule.
10
+
11
+ const Game = preload("res://network/game.gd")
12
+ const PlayerArchetype = preload("res://authority/player_archetype.tres")
13
+ ## How far a player may move in one burst after a network stall, in metres.
14
+ const BURST := Game.MAX_SPEED * 0.5
15
+
16
+ var spawner: SummerNetworkSpawner
17
+ var world: SummerNetworkWorld
18
+ var seat_of := {} # session_id -> seat, held until the Session leaves
19
+ var allowance := {} # seat -> metres the player may still move
20
+ var refilled_at := {} # seat -> msec of the last allowance refill
21
+
22
+
23
+ func _ready() -> void:
24
+ spawner = Game.build_network(self, PlayerArchetype)
25
+ world = $World
26
+ spawner.entity_spawned.connect(_on_player_spawned)
27
+ spawner.command_received.connect(_on_command)
28
+ world.session_left.connect(_on_session_left)
29
+ var initialized: SummerResult = await Summer.initialize(Game.GAME_ID).get_result_or_completed_signal()
30
+ if not initialized.ok:
31
+ push_error(initialized.message)
32
+ return
33
+ if not world.is_ready():
34
+ await world.binding_ready
35
+ if not spawner.is_network_ready():
36
+ await spawner.network_ready
37
+ print("COURTYARD_AUTHORITY_READY")
38
+
39
+
40
+ ## A seat is a player's place in this World for their whole stay, across
41
+ ## reconnects. Returns -1 when the World is full.
42
+ func _seat(session: SummerSession) -> int:
43
+ if seat_of.has(session.session_id):
44
+ return seat_of[session.session_id]
45
+ var taken := seat_of.values()
46
+ for seat in Game.MAX_PLAYERS:
47
+ if seat not in taken:
48
+ seat_of[session.session_id] = seat
49
+ return seat
50
+ return -1
51
+
52
+
53
+ ## The Spawner spawns one player entity per joined player, once that player's
54
+ ## network is ready (and again after a reconnect). Its owner becomes the only
55
+ ## writer of the pose; the group ends with the entity.
56
+ func _on_player_spawned(entity: SummerNetworkEntity) -> void:
57
+ var seat := _seat(entity.session)
58
+ if seat < 0:
59
+ push_warning("no free seat")
60
+ return
61
+ allowance[seat] = BURST
62
+ refilled_at[seat] = Time.get_ticks_msec()
63
+ var group := spawner.create_state_group(Game.MOTION, Game.motion_key(seat), Game.spawn_pose(seat, entity.entity_id), entity.session, entity)
64
+ group.set_acceptance_policy(_accept_motion.bind(seat))
65
+ print("COURTYARD_PLAYER_SPAWNED seat=%d entity=%d" % [seat, entity.entity_id])
66
+
67
+
68
+ ## Runs on every pose an owner submits. True accepts it unchanged; false
69
+ ## refuses it, and the owner snaps back to the last accepted pose.
70
+ func _accept_motion(candidate: Dictionary, current: Dictionary, seat: int) -> bool:
71
+ if candidate.entity != current.entity:
72
+ return false # a player can move, never become someone else
73
+ var position: Vector3 = candidate.position
74
+ if not Game.in_bounds(position) or not is_finite(candidate.yaw):
75
+ return false
76
+ # A distance allowance refilled at MAX_SPEED: bursts after a stall pass,
77
+ # speed hacks and teleports do not.
78
+ var now := Time.get_ticks_msec()
79
+ var budget := minf(float(allowance[seat]) + Game.MAX_SPEED * (now - int(refilled_at[seat])) / 1000.0, BURST)
80
+ refilled_at[seat] = now
81
+ var distance := position.distance_to(current.position)
82
+ if distance > budget:
83
+ allowance[seat] = budget
84
+ return false
85
+ allowance[seat] = budget - distance
86
+ return true
87
+
88
+
89
+ ## Moves a player on purpose (respawn, portal). The owner snaps to it.
90
+ func teleport(seat: int, position: Vector3) -> void:
91
+ var group := spawner.get_state_group(Game.MOTION, Game.motion_key(seat))
92
+ if group != null and group.active:
93
+ var pose := group.get_state()
94
+ pose.position = position
95
+ allowance[seat] = BURST
96
+ group.reset(pose)
97
+
98
+
99
+ func _on_command(request: SummerNetworkCommandRequest) -> void:
100
+ var command := Game.unpack(request.payload)
101
+ match str(command.get("c", "")):
102
+ "join":
103
+ _join(request)
104
+ _:
105
+ request.refuse(&"unknown_command")
106
+
107
+
108
+ ## A client sends "join" once its network is ready.
109
+ func _join(request: SummerNetworkCommandRequest) -> void:
110
+ var seat := _seat(request.get_session())
111
+ if seat < 0:
112
+ request.refuse(&"match_full")
113
+ return
114
+ request.accept({}, Game.pack({"seat": seat}))
115
+ print("COURTYARD_PLAYER_JOINED seat=%d" % seat)
116
+
117
+
118
+ ## The Session ended for good: free the seat. (Its pose group already ended
119
+ ## with the player's entity.)
120
+ func _on_session_left(session: SummerSession, reason: String) -> void:
121
+ var seat: int = seat_of.get(session.session_id, -1)
122
+ seat_of.erase(session.session_id)
123
+ print("COURTYARD_PLAYER_LEFT seat=%d reason=%s" % [seat, reason])
124
+ ```
125
+
126
+ ## `client/main.gd`
127
+
128
+ ```gdscript
129
+ extends Node
130
+ ## What each player runs: joins the match and shows every player.
131
+
132
+ const Game = preload("res://network/game.gd")
133
+ const PlayerArchetype = preload("res://client/player_archetype.tres")
134
+
135
+ var spawner: SummerNetworkSpawner
136
+ var waiting := {} # entity id -> pose group that arrived before its entity
137
+
138
+
139
+ func _ready() -> void:
140
+ spawner = Game.build_network(self, PlayerArchetype)
141
+ # Connect before joining, or the first values arrive unseen.
142
+ spawner.state_group_created.connect(_on_group_created)
143
+ spawner.entity_spawned.connect(_on_entity_spawned)
144
+ var initialized: SummerResult = await Summer.initialize(Game.GAME_ID).get_result_or_completed_signal()
145
+ if not initialized.ok:
146
+ push_error(initialized.message)
147
+ return
148
+ var join := Summer.client.join(SummerJoinTarget.queue(Game.QUEUE))
149
+ # Hosted matchmaking may ask the player to accept a match.
150
+ join.acceptance_required.connect(func(proposal: SummerMatchmakingProposal) -> void: proposal.accept())
151
+ var joined: SummerResult = await join.get_result_or_completed_signal()
152
+ if not joined.ok:
153
+ push_error("join failed: %s %s" % [joined.code, joined.message])
154
+ return
155
+ if not spawner.is_network_ready():
156
+ await spawner.network_ready
157
+ var entered := await command({"c": "join"})
158
+ if not entered.ok:
159
+ push_error("could not enter the match: %s" % entered.error)
160
+ return
161
+ print("COURTYARD_CLIENT_JOINED")
162
+
163
+
164
+ ## Sends one Command and waits for the authority's answer.
165
+ func command(payload: Dictionary) -> Dictionary:
166
+ var admission := spawner.enqueue_command(Game.CMD, Game.pack(payload))
167
+ if not admission.is_enqueued():
168
+ return {"ok": false, "error": String(admission.get_code())}
169
+ var handle := admission.get_handle()
170
+ if not handle.is_terminal():
171
+ await handle.completed
172
+ if handle.get_outcome() == SummerNetworkCommandHandle.OUTCOME_ACCEPTED:
173
+ return {"ok": true, "error": "", "result": Game.unpack(handle.get_result())}
174
+ return {"ok": false, "error": String(handle.get_reason())}
175
+
176
+
177
+ func _on_group_created(group: SummerNetworkStateGroup) -> void:
178
+ if group.get_stream_id() == Game.MOTION:
179
+ _attach_pose(group, int(group.get_state().entity))
180
+
181
+
182
+ ## The pose group and the player's entity can arrive in either order.
183
+ func _attach_pose(group: SummerNetworkStateGroup, entity_id: int) -> void:
184
+ var entity := spawner.get_entity(entity_id)
185
+ if entity == null or entity.root == null:
186
+ waiting[entity_id] = group
187
+ return
188
+ entity.root.bind(group)
189
+
190
+
191
+ func _on_entity_spawned(entity: SummerNetworkEntity) -> void:
192
+ if waiting.has(entity.entity_id):
193
+ _attach_pose(waiting[entity.entity_id], entity.entity_id)
194
+ waiting.erase(entity.entity_id)
195
+ ```
196
+
197
+ ## `client/player_observer.gd`
198
+
199
+ ```gdscript
200
+ extends Node3D
201
+ ## Someone else's player. It glides between the poses its owner published,
202
+ ## drawn VIEW_DELAY in the past so there is always a newer pose to glide to.
203
+
204
+ const VIEW_DELAY := 0.1
205
+
206
+ var group: SummerNetworkStateGroup
207
+ var _samples: Array = [] # [time, position, yaw] per received pose
208
+ var _offsets: Array = [] # recent arrival minus authority acceptance, seconds
209
+
210
+
211
+ func bind(motion: SummerNetworkStateGroup) -> void:
212
+ group = motion
213
+ group.state_installed.connect(_on_installed)
214
+ _on_installed(group.get_state(), group.get_revision(), true)
215
+
216
+
217
+ func _on_installed(state: Dictionary, _revision: int, reset: bool) -> void:
218
+ if state.is_empty():
219
+ return
220
+ var now := Time.get_ticks_usec() / 1000000.0
221
+ if reset:
222
+ _samples.clear() # a spawn or teleport is a cut, not a slide
223
+ global_position = state.position
224
+ rotation.y = state.yaw
225
+ _samples.append([_pose_time(now), state.position, state.yaw])
226
+ if _samples.size() > 20:
227
+ _samples.pop_front()
228
+
229
+
230
+ func _process(_delta: float) -> void:
231
+ if _samples.is_empty():
232
+ return
233
+ var at := Time.get_ticks_usec() / 1000000.0 - VIEW_DELAY
234
+ var newest: Array = _samples[-1]
235
+ if at >= newest[0] or _samples.size() == 1:
236
+ global_position = newest[1]
237
+ rotation.y = newest[2]
238
+ return
239
+ for i in range(_samples.size() - 1, 0, -1):
240
+ var a: Array = _samples[i - 1]
241
+ var b: Array = _samples[i]
242
+ if at >= a[0]:
243
+ var t := clampf((at - a[0]) / maxf(b[0] - a[0], 0.0001), 0.0, 1.0)
244
+ global_position = (a[1] as Vector3).lerp(b[1], t)
245
+ rotation.y = lerp_angle(a[2], b[2], t)
246
+ return
247
+ global_position = _samples[0][1]
248
+
249
+
250
+ ## Places a pose on the local timeline by when the authority accepted it, so
251
+ ## poses that arrive bunched together still play back evenly.
252
+ func _pose_time(now: float) -> float:
253
+ var timing := group.get_timing()
254
+ if timing == null or timing.state_authority_usec < 0:
255
+ return now
256
+ var accepted := timing.state_authority_usec / 1000000.0
257
+ _offsets.append(now - accepted)
258
+ if _offsets.size() > 40:
259
+ _offsets.pop_front()
260
+ return minf(accepted + float(_offsets.min()), now)
261
+ ```
262
+
263
+ ## `client/player_observer.tscn`
264
+
265
+ ```ini
266
+ [gd_scene load_steps=3 format=3]
267
+
268
+ [ext_resource type="Script" path="res://client/player_observer.gd" id="1"]
269
+
270
+ [sub_resource type="CapsuleMesh" id="Mesh"]
271
+
272
+ [node name="PlayerObserver" type="Node3D"]
273
+ script = ExtResource("1")
274
+
275
+ [node name="Body" type="MeshInstance3D" parent="."]
276
+ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0)
277
+ mesh = SubResource("Mesh")
278
+ ```
279
+
280
+ ## `client/player_owner.gd`
281
+
282
+ ```gdscript
283
+ extends CharacterBody3D
284
+ ## Your own player. You move it locally and publish where it is; the
285
+ ## authority only snaps you somewhere on spawn, teleport or a refused pose.
286
+
287
+ const WALK_SPEED := 6.0
288
+ const JUMP_VELOCITY := 5.0
289
+ const SEND_INTERVAL := 1.0 / 20.0
290
+
291
+ var group: SummerNetworkStateGroup
292
+ var _pose := {} # the full pose; only position and yaw change
293
+ var _sent := {}
294
+ var _send_elapsed := 0.0
295
+
296
+
297
+ func bind(motion: SummerNetworkStateGroup) -> void:
298
+ group = motion
299
+ group.state_installed.connect(_on_installed)
300
+ _on_installed(group.get_state(), group.get_revision(), true)
301
+
302
+
303
+ func _on_installed(state: Dictionary, _revision: int, reset: bool) -> void:
304
+ # Accepted poses are not echoed back to you (skip_writer_echo). A reset is
305
+ # the authority moving you: spawn, teleport, or a pose it refused.
306
+ if not reset or state.is_empty():
307
+ return
308
+ _pose = state.duplicate()
309
+ _sent = state.duplicate()
310
+ global_position = state.position
311
+ rotation.y = state.yaw
312
+ velocity = Vector3.ZERO
313
+
314
+
315
+ func _physics_process(delta: float) -> void:
316
+ if group == null or not group.active:
317
+ return
318
+ if not is_on_floor():
319
+ velocity += get_gravity() * delta
320
+ if Input.is_action_just_pressed(&"ui_accept") and is_on_floor():
321
+ velocity.y = JUMP_VELOCITY
322
+ var input := Input.get_vector(&"ui_left", &"ui_right", &"ui_up", &"ui_down")
323
+ velocity.x = input.x * WALK_SPEED
324
+ velocity.z = input.y * WALK_SPEED
325
+ if input != Vector2.ZERO:
326
+ rotation.y = atan2(-input.x, -input.y)
327
+ move_and_slide()
328
+ _publish(delta)
329
+
330
+
331
+ ## Publishes the pose 20 times a second, and only when it changed.
332
+ func _publish(delta: float) -> void:
333
+ _send_elapsed += delta
334
+ if _send_elapsed < SEND_INTERVAL:
335
+ return
336
+ _send_elapsed = 0.0
337
+ _pose.position = global_position
338
+ _pose.yaw = rotation.y
339
+ if _pose == _sent:
340
+ return
341
+ group.submit(_pose)
342
+ _sent = _pose.duplicate()
343
+ ```
344
+
345
+ ## `client/player_owner.tscn`
346
+
347
+ ```ini
348
+ [gd_scene load_steps=5 format=3]
349
+
350
+ [ext_resource type="Script" path="res://client/player_owner.gd" id="1"]
351
+
352
+ [sub_resource type="CapsuleShape3D" id="Shape"]
353
+
354
+ [sub_resource type="CapsuleMesh" id="Mesh"]
355
+
356
+ [node name="PlayerOwner" type="CharacterBody3D"]
357
+ script = ExtResource("1")
358
+
359
+ [node name="Shape" type="CollisionShape3D" parent="."]
360
+ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0)
361
+ shape = SubResource("Shape")
362
+
363
+ [node name="Body" type="MeshInstance3D" parent="."]
364
+ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0)
365
+ mesh = SubResource("Mesh")
366
+
367
+ [node name="Camera3D" type="Camera3D" parent="."]
368
+ transform = Transform3D(1, 0, 0, 0, 0.8, 0.6, 0, -0.6, 0.8, 0, 6, 8)
369
+ current = true
370
+ ```
371
+
372
+ ## `network/composition.tres`
373
+
374
+ ```ini
375
+ [gd_resource type="SummerNetworkComposition" load_steps=12 format=3]
376
+
377
+ [sub_resource type="SummerNetworkField" id="MotionPosition"]
378
+ field_name = &"position"
379
+ type = 9
380
+
381
+ [sub_resource type="SummerNetworkField" id="MotionYaw"]
382
+ field_name = &"yaw"
383
+ type = 2
384
+
385
+ [sub_resource type="SummerNetworkField" id="MotionEntity"]
386
+ field_name = &"entity"
387
+ type = 1
388
+
389
+ [sub_resource type="SummerNetworkSchema" id="MotionSchema"]
390
+ schema_id = &"courtyard.motion.v1"
391
+ state_fields = Array[SummerNetworkField]([SubResource("MotionEntity"), SubResource("MotionPosition"), SubResource("MotionYaw")])
392
+
393
+ [sub_resource type="SummerWorldAudience" id="Everyone"]
394
+ max_expansion = 8
395
+
396
+ [sub_resource type="SummerNetworkStateStream" id="Motion"]
397
+ stream_id = &"courtyard.motion"
398
+ writer_policy = 1
399
+ skip_writer_echo = true
400
+ state_schema = SubResource("MotionSchema")
401
+ audience_policy = SubResource("Everyone")
402
+ max_audience_count = 8
403
+ max_keys = 8
404
+ max_state_bytes = 1024
405
+ max_total_bytes = 8192
406
+
407
+ [sub_resource type="SummerNetworkField" id="CommandBytes"]
408
+ field_name = &"b"
409
+ type = 20
410
+
411
+ [sub_resource type="SummerNetworkSchema" id="CommandSchema"]
412
+ schema_id = &"courtyard.cmd.v1"
413
+ state_fields = Array[SummerNetworkField]([SubResource("CommandBytes")])
414
+
415
+ [sub_resource type="SummerNetworkField" id="ResultBytes"]
416
+ field_name = &"b"
417
+ type = 20
418
+
419
+ [sub_resource type="SummerNetworkSchema" id="ResultSchema"]
420
+ schema_id = &"courtyard.cmd.result.v1"
421
+ state_fields = Array[SummerNetworkField]([SubResource("ResultBytes")])
422
+
423
+ [sub_resource type="SummerNetworkOccurrenceStream" id="Commands"]
424
+ stream_id = &"courtyard.cmd"
425
+ command_scope = 2
426
+ command_tick_dispatch = true
427
+ command_timeout_msec = 8000
428
+ payload_schema = SubResource("CommandSchema")
429
+ result_schema = SubResource("ResultSchema")
430
+
431
+ [resource]
432
+ network_version = "1.0.0"
433
+ state_streams = Array[SummerNetworkStateStream]([SubResource("Motion")])
434
+ occurrence_streams = Array[SummerNetworkOccurrenceStream]([SubResource("Commands")])
435
+ ```
436
+
437
+ ## `network/game.gd`
438
+
439
+ ```gdscript
440
+ extends RefCounted
441
+ ## Shared by the client and the authority: ids, streams and shared rules.
442
+
443
+ const GAME_ID := "game_courtyard"
444
+ const QUEUE := &"courtyard"
445
+ const MOTION := &"courtyard.motion"
446
+ const CMD := &"courtyard.cmd"
447
+ const MAX_PLAYERS := 8
448
+ const COMPOSITION := preload("res://network/composition.tres")
449
+
450
+ ## The authority's sanity bound on movement, in metres per second. Keep it
451
+ ## above the fastest legitimate speed (walking, jumping, falling).
452
+ const MAX_SPEED := 15.0
453
+ const ARENA_RADIUS := 40.0
454
+
455
+
456
+ ## Adds the World, an Entities root and the Spawner under `parent`. Both sides
457
+ ## pass their own player archetype; the composition is the same file.
458
+ static func build_network(parent: Node, player: SummerEntityArchetype) -> SummerNetworkSpawner:
459
+ var world := SummerNetworkWorld.new()
460
+ world.name = "World"
461
+ parent.add_child(world)
462
+ var entities := Node3D.new()
463
+ entities.name = "Entities"
464
+ parent.add_child(entities)
465
+ var spawner := SummerNetworkSpawner.new()
466
+ spawner.name = "Spawner"
467
+ spawner.network_world_path = NodePath("../World")
468
+ spawner.entities_root_path = NodePath("../Entities")
469
+ spawner.archetypes = [player]
470
+ spawner.player_archetype = &"player" # one entity per joined player
471
+ spawner.network_composition = COMPOSITION
472
+ parent.add_child(spawner)
473
+ return spawner
474
+
475
+
476
+ ## Pose groups are keyed by seat, so a stream needs at most MAX_PLAYERS keys.
477
+ static func motion_key(seat: int) -> StringName:
478
+ return StringName("p%d" % seat)
479
+
480
+
481
+ ## Seats spawn on a circle. `entity` ties the pose to the player's entity.
482
+ static func spawn_pose(seat: int, entity_id: int) -> Dictionary:
483
+ var angle := TAU * float(seat) / MAX_PLAYERS
484
+ return {"entity": entity_id, "position": Vector3(cos(angle) * 4.0, 1.0, sin(angle) * 4.0), "yaw": 0.0}
485
+
486
+
487
+ static func in_bounds(position: Vector3) -> bool:
488
+ return position.is_finite() and Vector2(position.x, position.z).length() <= ARENA_RADIUS \
489
+ and position.y > -10.0 and position.y < 30.0
490
+
491
+
492
+ ## Commands and results travel as JSON bytes: a network String holds at most
493
+ ## 256 bytes.
494
+ static func pack(document: Dictionary) -> Dictionary:
495
+ return {"b": JSON.stringify(document).to_utf8_buffer()}
496
+
497
+
498
+ static func unpack(fields: Dictionary) -> Dictionary:
499
+ var parsed: Variant = JSON.parse_string((fields.get("b", PackedByteArray()) as PackedByteArray).get_string_from_utf8())
500
+ return parsed if parsed is Dictionary else {}
501
+ ```
@@ -0,0 +1,30 @@
1
+ id: skill/multiplayer-movement
2
+ kind: skill
3
+ version: 1.0.0
4
+ summary: "Client-side movement in Summer multiplayer: owners move instantly, others glide, the authority checks each pose."
5
+ use_when:
6
+ - "moving players in a Summer multiplayer game: each player's own character, other players drawn smoothly"
7
+ - "remote players stutter, jitter, teleport or rubberband in a Summer multiplayer game"
8
+ - "stopping speed hacks and teleport cheats on player movement; respawning or teleporting a player on purpose"
9
+ facets:
10
+ lifecycle:
11
+ - build
12
+ domains:
13
+ - multiplayer
14
+ - character-controller
15
+ - scripting
16
+ modalities:
17
+ - scripts
18
+ - scenes
19
+ compatibility:
20
+ engine: ">=4.6"
21
+ related:
22
+ skills:
23
+ - skill/multiplayer
24
+ - skill/multiplayer-project
25
+ - skill/multiplayer-state
26
+ - skill/multiplayer-testing
27
+ source: official
28
+ license: MIT
29
+ status: stable
30
+ recommended: false