summer-engine 3.1.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (366) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +27 -5
  3. package/.codex-plugin/plugin.json +28 -6
  4. package/.cursor-plugin/plugin.json +27 -5
  5. package/.factory-plugin/plugin.json +27 -5
  6. package/.opencode/plugins/summer.js +1 -1
  7. package/CHANGELOG.md +102 -0
  8. package/README.md +18 -3
  9. package/assets/audit/scene_audit.gd +4136 -0
  10. package/assets/seeing/seeing_probe.gd +1873 -0
  11. package/dist/cli/commands/skills.js +20 -2
  12. package/dist/core/api-client.d.ts +9 -1
  13. package/dist/core/api-client.js +21 -4
  14. package/dist/core/capabilities/agent-playbook.js +46 -0
  15. package/dist/core/capabilities/audit/accept.d.ts +55 -0
  16. package/dist/core/capabilities/audit/accept.js +147 -0
  17. package/dist/core/capabilities/audit/args.d.ts +95 -0
  18. package/dist/core/capabilities/audit/args.js +89 -0
  19. package/dist/core/capabilities/audit/audit.d.ts +56 -0
  20. package/dist/core/capabilities/audit/audit.js +287 -0
  21. package/dist/core/capabilities/audit/frame.d.ts +14 -0
  22. package/dist/core/capabilities/audit/frame.js +35 -0
  23. package/dist/core/capabilities/audit/gaps.d.ts +96 -0
  24. package/dist/core/capabilities/audit/gaps.js +257 -0
  25. package/dist/core/capabilities/audit/judge.d.ts +162 -0
  26. package/dist/core/capabilities/audit/judge.js +1134 -0
  27. package/dist/core/capabilities/audit/math.d.ts +110 -0
  28. package/dist/core/capabilities/audit/math.js +263 -0
  29. package/dist/core/capabilities/audit/summary.d.ts +74 -0
  30. package/dist/core/capabilities/audit/summary.js +212 -0
  31. package/dist/core/capabilities/board.d.ts +31 -0
  32. package/dist/core/capabilities/board.js +43 -0
  33. package/dist/core/capabilities/camera-view.d.ts +4 -2
  34. package/dist/core/capabilities/camera-view.js +6 -3
  35. package/dist/core/capabilities/connect-signal.d.ts +85 -0
  36. package/dist/core/capabilities/connect-signal.js +285 -0
  37. package/dist/core/capabilities/engine-fallbacks.d.ts +5 -0
  38. package/dist/core/capabilities/engine-fallbacks.js +5 -0
  39. package/dist/core/capabilities/engine-ops.d.ts +5 -1
  40. package/dist/core/capabilities/engine-ops.js +0 -3
  41. package/dist/core/capabilities/engine-receipt.d.ts +12 -0
  42. package/dist/core/capabilities/engine-receipt.js +26 -0
  43. package/dist/core/capabilities/file-read.d.ts +64 -0
  44. package/dist/core/capabilities/file-read.js +325 -0
  45. package/dist/core/capabilities/game-task-plan.js +4 -2
  46. package/dist/core/capabilities/grep.d.ts +60 -0
  47. package/dist/core/capabilities/grep.js +190 -0
  48. package/dist/core/capabilities/inspect-node.d.ts +56 -0
  49. package/dist/core/capabilities/inspect-node.js +225 -0
  50. package/dist/core/capabilities/inspect-resource.d.ts +61 -0
  51. package/dist/core/capabilities/inspect-resource.js +376 -0
  52. package/dist/core/capabilities/math3d.d.ts +28 -0
  53. package/dist/core/capabilities/math3d.js +88 -0
  54. package/dist/core/capabilities/motion-generation.d.ts +62 -0
  55. package/dist/core/capabilities/motion-generation.js +138 -0
  56. package/dist/core/capabilities/placement-batch.d.ts +102 -0
  57. package/dist/core/capabilities/placement-batch.js +483 -0
  58. package/dist/core/capabilities/placement-math.d.ts +70 -0
  59. package/dist/core/capabilities/placement-math.js +209 -0
  60. package/dist/core/capabilities/placement-script.d.ts +42 -0
  61. package/dist/core/capabilities/placement-script.js +1096 -0
  62. package/dist/core/capabilities/placement.d.ts +485 -0
  63. package/dist/core/capabilities/placement.js +1731 -0
  64. package/dist/core/capabilities/project-context.d.ts +33 -2
  65. package/dist/core/capabilities/project-context.js +87 -4
  66. package/dist/core/capabilities/replace-node.d.ts +91 -0
  67. package/dist/core/capabilities/replace-node.js +423 -0
  68. package/dist/core/capabilities/runtime-control.d.ts +18 -2
  69. package/dist/core/capabilities/runtime-control.js +67 -2
  70. package/dist/core/capabilities/scene-batch.d.ts +63 -0
  71. package/dist/core/capabilities/scene-batch.js +394 -0
  72. package/dist/core/capabilities/scene-readback.d.ts +36 -0
  73. package/dist/core/capabilities/scene-readback.js +54 -0
  74. package/dist/core/capabilities/seeing/args.d.ts +348 -0
  75. package/dist/core/capabilities/seeing/args.js +178 -0
  76. package/dist/core/capabilities/seeing/candidates.d.ts +127 -0
  77. package/dist/core/capabilities/seeing/candidates.js +282 -0
  78. package/dist/core/capabilities/seeing/math.d.ts +134 -0
  79. package/dist/core/capabilities/seeing/math.js +269 -0
  80. package/dist/core/capabilities/seeing/probe.d.ts +62 -0
  81. package/dist/core/capabilities/seeing/probe.js +188 -0
  82. package/dist/core/capabilities/seeing/scoring.d.ts +235 -0
  83. package/dist/core/capabilities/seeing/scoring.js +639 -0
  84. package/dist/core/capabilities/seeing/seeing.d.ts +233 -0
  85. package/dist/core/capabilities/seeing/seeing.js +1341 -0
  86. package/dist/core/capabilities/seeing/shot-store.d.ts +52 -0
  87. package/dist/core/capabilities/seeing/shot-store.js +204 -0
  88. package/dist/core/capabilities/surface-snap-mesh.d.ts +88 -0
  89. package/dist/core/capabilities/surface-snap-mesh.js +425 -0
  90. package/dist/core/capabilities/surface-snap.d.ts +77 -0
  91. package/dist/core/capabilities/surface-snap.js +461 -0
  92. package/dist/core/capabilities/tool-dispatch.js +231 -72
  93. package/dist/core/capabilities/tscn.d.ts +85 -0
  94. package/dist/core/capabilities/tscn.js +391 -0
  95. package/dist/core/capabilities/world-snapshot.d.ts +58 -0
  96. package/dist/core/capabilities/world-snapshot.js +150 -0
  97. package/dist/core/capability-skew.d.ts +5 -5
  98. package/dist/core/capability-skew.js +14 -6
  99. package/dist/core/headless/worker-engine-client.d.ts +1 -1
  100. package/dist/core/headless/worker-engine-client.js +2 -2
  101. package/dist/core/library-read.d.ts +37 -5
  102. package/dist/core/library-read.js +264 -33
  103. package/dist/core/library-search.d.ts +2 -2
  104. package/dist/installer/agent-config.js +5 -3
  105. package/dist/installer/agent-table.d.ts +16 -0
  106. package/dist/installer/agent-table.js +52 -17
  107. package/dist/mcp/server.js +9 -3
  108. package/dist/mcp/tools/asset-tools.js +21 -3
  109. package/dist/mcp/tools/audit-tools.d.ts +23 -0
  110. package/dist/mcp/tools/audit-tools.js +60 -0
  111. package/dist/mcp/tools/debug-tools.js +3 -1
  112. package/dist/mcp/tools/file-tools.js +17 -4
  113. package/dist/mcp/tools/generate-tools.js +74 -66
  114. package/dist/mcp/tools/library-tools.js +2 -0
  115. package/dist/mcp/tools/perception-tools.js +6 -19
  116. package/dist/mcp/tools/placement-tools.d.ts +24 -0
  117. package/dist/mcp/tools/placement-tools.js +91 -0
  118. package/dist/mcp/tools/project-tools.js +18 -15
  119. package/dist/mcp/tools/scene-tools.js +71 -83
  120. package/dist/mcp/tools/seeing-tools.d.ts +24 -0
  121. package/dist/mcp/tools/seeing-tools.js +64 -0
  122. package/dist/mcp/tools/spatial-tools.js +17 -9
  123. package/dist/mcp/tools/visual-tools.js +59 -7
  124. package/gemini-extension.json +26 -4
  125. package/integrations/amp/README.md +1 -1
  126. package/integrations/crush/README.md +1 -1
  127. package/integrations/grok-build/README.md +1 -1
  128. package/integrations/hermes/README.md +1 -1
  129. package/integrations/kimi-code/README.md +1 -1
  130. package/integrations/mistral-vibe/README.md +1 -1
  131. package/integrations/opencode/README.md +1 -1
  132. package/integrations/rovo-dev/README.md +1 -1
  133. package/integrations/vscode-copilot/README.md +1 -1
  134. package/integrations/warp/README.md +1 -1
  135. package/integrations/windsurf/README.md +1 -1
  136. package/library/references/mcp-tools-reference/mcp-tools-reference.md +59 -15
  137. package/library/references/mcp-tools-reference/resource.yaml +1 -1
  138. package/library/references/summer-folder/resource.yaml +1 -1
  139. package/library/references/summer-folder/summer-folder.md +1 -1
  140. package/library/skills/3d-lighting/SKILL.md +1 -1
  141. package/library/skills/README.md +36 -14
  142. package/library/skills/adaptive-music/SKILL.md +1 -1
  143. package/library/skills/agent-playtesting/SKILL.md +1 -1
  144. package/library/skills/ai-characters-in-games/SKILL.md +220 -0
  145. package/library/skills/ai-characters-in-games/resource.yaml +30 -0
  146. package/library/skills/ambient-bed/SKILL.md +1 -1
  147. package/library/skills/animated-loop/SKILL.md +1 -1
  148. package/library/skills/animation-tree/SKILL.md +1 -1
  149. package/library/skills/art-direction/SKILL.md +1 -1
  150. package/library/skills/asset-strategy/SKILL.md +2 -1
  151. package/library/skills/asset-strategy/resource.yaml +2 -1
  152. package/library/skills/audio-direction/SKILL.md +1 -1
  153. package/library/skills/auto-fire-targeting/SKILL.md +1 -1
  154. package/library/skills/brainstorm-game/SKILL.md +1 -1
  155. package/library/skills/brainstorming/SKILL.md +1 -1
  156. package/library/skills/browse-templates/SKILL.md +3 -3
  157. package/library/skills/browse-templates/resource.yaml +1 -1
  158. package/library/skills/camera-rigs/SKILL.md +128 -0
  159. package/library/skills/camera-rigs/resource.yaml +29 -0
  160. package/library/skills/celeste-momentum-platforming/SKILL.md +1 -1
  161. package/library/skills/character-animation-wiring/SKILL.md +1 -1
  162. package/library/skills/character-model/SKILL.md +1 -1
  163. package/library/skills/character-movement/SKILL.md +326 -0
  164. package/library/skills/character-movement/references/default-third-person-controller.gd +201 -0
  165. package/library/skills/character-movement/references/default-third-person-verification-probe.gd +154 -0
  166. package/library/skills/character-movement/references/movement-3d.md +136 -0
  167. package/library/skills/character-movement/references/platformer-feel.md +83 -0
  168. package/library/skills/character-movement/resource.yaml +40 -0
  169. package/library/skills/character-portrait/SKILL.md +1 -1
  170. package/library/skills/cinematic-cutscene/SKILL.md +1 -1
  171. package/library/skills/combat-basics/SKILL.md +159 -0
  172. package/library/skills/combat-basics/references/projectiles-and-aoe.md +100 -0
  173. package/library/skills/combat-basics/resource.yaml +34 -0
  174. package/library/skills/concept-art/SKILL.md +1 -1
  175. package/library/skills/create-asset-sheet/SKILL.md +1 -1
  176. package/library/skills/debug/SKILL.md +1 -1
  177. package/library/skills/debugging-game-feel/SKILL.md +1 -1
  178. package/library/skills/design-level/SKILL.md +1 -1
  179. package/library/skills/design-mechanic/SKILL.md +1 -1
  180. package/library/skills/design-npc/SKILL.md +1 -1
  181. package/library/skills/diagnosing-perf-regressions/SKILL.md +1 -1
  182. package/library/skills/dispatching-parallel-agents/SKILL.md +1 -1
  183. package/library/skills/driving-the-editor-ui/SKILL.md +1 -1
  184. package/library/skills/environment-kit/SKILL.md +1 -1
  185. package/library/skills/export-and-ship/SKILL.md +1 -1
  186. package/library/skills/fabricating-assets/SKILL.md +1 -1
  187. package/library/skills/facial-and-lipsync/SKILL.md +1 -1
  188. package/library/skills/fps-controller/SKILL.md +9 -7
  189. package/library/skills/fps-controller/resource.yaml +4 -1
  190. package/library/skills/game-feel/SKILL.md +1 -1
  191. package/library/skills/gameskill/SKILL.md +1 -1
  192. package/library/skills/gdscript-patterns/SKILL.md +1 -1
  193. package/library/skills/generate-motion/SKILL.md +9 -9
  194. package/library/skills/generate-motion/resource.yaml +2 -1
  195. package/library/skills/godogen-visual-proof-game-generation/SKILL.md +1 -1
  196. package/library/skills/headless-scripting/SKILL.md +1 -1
  197. package/library/skills/in-game-purchases/SKILL.md +254 -0
  198. package/library/skills/in-game-purchases/resource.yaml +29 -0
  199. package/library/skills/instantiate-asset-pack/SKILL.md +1 -1
  200. package/library/skills/investigating-bugs/SKILL.md +1 -1
  201. package/library/skills/lumera-single-image-scene-reconstruction/SKILL.md +1 -1
  202. package/library/skills/make-game/SKILL.md +25 -3
  203. package/library/skills/make-game/references/2d-platformer-polish.md +93 -0
  204. package/library/skills/make-game/references/2d-platformer.md +117 -0
  205. package/library/skills/make-game/references/2d-rpg-content.md +234 -0
  206. package/library/skills/make-game/references/2d-rpg.md +241 -0
  207. package/library/skills/make-game/references/2d-survivors-progression.md +201 -0
  208. package/library/skills/make-game/references/2d-survivors.md +237 -0
  209. package/library/skills/make-game/references/3d-fps-systems.md +216 -0
  210. package/library/skills/make-game/references/3d-fps.md +177 -0
  211. package/library/skills/make-game/references/3d-horror-systems.md +186 -0
  212. package/library/skills/make-game/references/3d-horror.md +201 -0
  213. package/library/skills/make-game/references/3d-third-person-systems.md +220 -0
  214. package/library/skills/make-game/references/3d-third-person.md +215 -0
  215. package/library/skills/make-game/resource.yaml +6 -1
  216. package/library/skills/multiplayer/SKILL.md +150 -0
  217. package/library/skills/multiplayer/resource.yaml +33 -0
  218. package/library/skills/multiplayer-movement/SKILL.md +510 -0
  219. package/library/skills/multiplayer-movement/files.md +501 -0
  220. package/library/skills/multiplayer-movement/resource.yaml +30 -0
  221. package/library/skills/multiplayer-project/SKILL.md +521 -0
  222. package/library/skills/multiplayer-project/files.md +448 -0
  223. package/library/skills/multiplayer-project/resource.yaml +36 -0
  224. package/library/skills/multiplayer-publish/SKILL.md +229 -0
  225. package/library/skills/multiplayer-publish/export-errors.md +89 -0
  226. package/library/skills/multiplayer-publish/resource.yaml +28 -0
  227. package/library/skills/multiplayer-state/SKILL.md +438 -0
  228. package/library/skills/multiplayer-state/files.md +592 -0
  229. package/library/skills/multiplayer-state/resource.yaml +35 -0
  230. package/library/skills/multiplayer-testing/SKILL.md +236 -0
  231. package/library/skills/multiplayer-testing/resource.yaml +39 -0
  232. package/library/skills/music-track/SKILL.md +1 -1
  233. package/library/skills/navigate-summer/SKILL.md +1 -1
  234. package/library/skills/new-project/SKILL.md +1 -1
  235. package/library/skills/organic-model/SKILL.md +1 -1
  236. package/library/skills/pixel-art/SKILL.md +1 -1
  237. package/library/skills/play/SKILL.md +1 -1
  238. package/library/skills/playtesting-a-feature/SKILL.md +1 -1
  239. package/library/skills/procedural-animation/SKILL.md +2 -2
  240. package/library/skills/procedural-animation/resource.yaml +1 -1
  241. package/library/skills/prop-model/SKILL.md +1 -1
  242. package/library/skills/psx-retro-rendering/SKILL.md +1 -1
  243. package/library/skills/realtime-wet-surfaces/SKILL.md +2 -2
  244. package/library/skills/remote-deploy/SKILL.md +1 -1
  245. package/library/skills/retarget/SKILL.md +1 -1
  246. package/library/skills/running-in-the-cloud/SKILL.md +1 -1
  247. package/library/skills/save-load/SKILL.md +156 -0
  248. package/library/skills/save-load/resource.yaml +27 -0
  249. package/library/skills/scene-composition/SKILL.md +1 -1
  250. package/library/skills/scene-hierarchy-design/SKILL.md +1 -1
  251. package/library/skills/scene-scripting/SKILL.md +1 -1
  252. package/library/skills/scene-to-level/SKILL.md +1 -1
  253. package/library/skills/skill-create/SKILL.md +1 -1
  254. package/library/skills/skill-improve/SKILL.md +1 -1
  255. package/library/skills/skill-test/SKILL.md +1 -1
  256. package/library/skills/skintokens-auto-rigging/SKILL.md +1 -1
  257. package/library/skills/skybox-panorama/SKILL.md +1 -1
  258. package/library/skills/sound-effect/SKILL.md +1 -1
  259. package/library/skills/spatial-placement/SKILL.md +134 -3
  260. package/library/skills/spatial-placement/references/kit-placement-tools.md +364 -0
  261. package/library/skills/spatial-placement/resource.yaml +16 -2
  262. package/library/skills/sprite-sheet/SKILL.md +1 -1
  263. package/library/skills/summer-analytics/SKILL.md +147 -0
  264. package/library/skills/summer-analytics/resource.yaml +28 -0
  265. package/library/skills/summer-friends/SKILL.md +226 -0
  266. package/library/skills/summer-friends/resource.yaml +28 -0
  267. package/library/skills/summer-leaderboards/SKILL.md +231 -0
  268. package/library/skills/summer-leaderboards/resource.yaml +30 -0
  269. package/library/skills/summer-match-results/SKILL.md +286 -0
  270. package/library/skills/summer-match-results/resource.yaml +32 -0
  271. package/library/skills/summer-matchmaking/SKILL.md +301 -0
  272. package/library/skills/summer-matchmaking/resource.yaml +32 -0
  273. package/library/skills/summer-parties/SKILL.md +253 -0
  274. package/library/skills/summer-parties/resource.yaml +30 -0
  275. package/library/skills/summer-player-data/SKILL.md +322 -0
  276. package/library/skills/summer-player-data/resource.yaml +30 -0
  277. package/library/skills/summer-store/SKILL.md +271 -0
  278. package/library/skills/summer-store/resource.yaml +29 -0
  279. package/library/skills/summer-world-chat/SKILL.md +195 -0
  280. package/library/skills/summer-world-chat/resource.yaml +30 -0
  281. package/library/skills/summer-world-saves/SKILL.md +284 -0
  282. package/library/skills/summer-world-saves/resource.yaml +29 -0
  283. package/library/skills/text-to-motion/SKILL.md +99 -0
  284. package/library/skills/text-to-motion/prompts-and-controls.md +34 -0
  285. package/library/skills/text-to-motion/resource.yaml +41 -0
  286. package/library/skills/text-to-motion/rigging-for-text-motion.md +54 -0
  287. package/library/skills/tileable-texture/SKILL.md +1 -1
  288. package/library/skills/trailer-shot/SKILL.md +1 -1
  289. package/library/skills/tune-performance/SKILL.md +1 -1
  290. package/library/skills/ui-basics/SKILL.md +10 -1
  291. package/library/skills/ui-graphics/SKILL.md +1 -1
  292. package/library/skills/use-widget-asset/SKILL.md +1 -1
  293. package/library/skills/using-summer/SKILL.md +2 -2
  294. package/library/skills/using-summer/resource.yaml +2 -2
  295. package/library/skills/vehicle-model/SKILL.md +1 -1
  296. package/library/skills/verification-before-completion/SKILL.md +1 -1
  297. package/library/skills/verifying-scenes/SKILL.md +76 -2
  298. package/library/skills/verifying-scenes/resource.yaml +13 -2
  299. package/library/skills/vfx-dissolve/SKILL.md +1 -1
  300. package/library/skills/vfx-fire/SKILL.md +1 -1
  301. package/library/skills/vfx-hit-spark/SKILL.md +1 -1
  302. package/library/skills/vfx-lightning/SKILL.md +1 -1
  303. package/library/skills/vfx-magic-glow/SKILL.md +1 -1
  304. package/library/skills/vfx-muzzle-flash/SKILL.md +1 -1
  305. package/library/skills/vfx-smoke/SKILL.md +1 -1
  306. package/library/skills/vfx-water-ripple/SKILL.md +1 -1
  307. package/library/skills/voice-line/SKILL.md +1 -1
  308. package/library/skills/web-and-touch-input/SKILL.md +38 -0
  309. package/library/skills/web-and-touch-input/resource.yaml +28 -0
  310. package/library/skills/web-compatibility-look/SKILL.md +62 -0
  311. package/library/skills/web-compatibility-look/resource.yaml +30 -0
  312. package/library/skills/world-building-3d/SKILL.md +8 -1
  313. package/library/skills/world-building-3d/references/spatial-tools.md +1 -1
  314. package/library/skills/world-building-3d/resource.yaml +2 -1
  315. package/library/skills/writing-plans/SKILL.md +1 -1
  316. package/library/skills/writing-skills/SKILL.md +1 -1
  317. package/library/templates/3d-lan-multiplayer-starter/resource.yaml +2 -2
  318. package/library/tools/attach-to-surface/resource.yaml +142 -0
  319. package/library/tools/batch/resource.yaml +9 -3
  320. package/library/tools/connect-ports/resource.yaml +120 -0
  321. package/library/tools/connect-signal/resource.yaml +3 -2
  322. package/library/tools/debug-views/resource.yaml +94 -0
  323. package/library/tools/frame-nodes/resource.yaml +104 -0
  324. package/library/tools/frame-shot/resource.yaml +134 -0
  325. package/library/tools/generate-motion/resource.yaml +44 -9
  326. package/library/tools/get-board/resource.yaml +50 -0
  327. package/library/tools/get-project-context/resource.yaml +13 -2
  328. package/library/tools/grep/resource.yaml +77 -0
  329. package/library/tools/inspect-asset/resource.yaml +71 -0
  330. package/library/tools/inspect-node/resource.yaml +9 -2
  331. package/library/tools/inspect-resource/resource.yaml +16 -5
  332. package/library/tools/instantiate-scene/resource.yaml +27 -2
  333. package/library/tools/measure/resource.yaml +96 -0
  334. package/library/tools/place-adjacent/resource.yaml +113 -0
  335. package/library/tools/play/resource.yaml +15 -2
  336. package/library/tools/raycast/resource.yaml +101 -0
  337. package/library/tools/read-file/resource.yaml +36 -2
  338. package/library/tools/read-library/resource.yaml +2 -2
  339. package/library/tools/repeat-along/resource.yaml +129 -0
  340. package/library/tools/replace-node/resource.yaml +11 -5
  341. package/library/tools/scene-audit/resource.yaml +144 -0
  342. package/library/tools/screenshot/resource.yaml +13 -2
  343. package/library/tools/search-assets/resource.yaml +18 -0
  344. package/library/tools/shot-sheet/resource.yaml +110 -0
  345. package/library/tools/snap-to-surface/resource.yaml +4 -1
  346. package/library/tools/world-snapshot/resource.yaml +24 -3
  347. package/library/tools/zoom/resource.yaml +105 -0
  348. package/package.json +1 -1
  349. package/registry/generated/aliases.json +17 -3
  350. package/registry/generated/counts.json +3 -3
  351. package/registry/generated/gemini-extension.json +26 -4
  352. package/registry/generated/index.json +2154 -469
  353. package/registry/generated/marketplace.claude.json +2 -2
  354. package/registry/generated/plugin.claude.json +27 -5
  355. package/registry/generated/plugin.codex.json +28 -6
  356. package/registry/generated/plugin.cursor.json +27 -5
  357. package/registry/generated/plugin.factory.json +27 -5
  358. package/registry/generated/skills-index.md +36 -14
  359. package/registry/generated/skills-registry.json +421 -124
  360. package/registry/generated/templates-registry.json +2 -2
  361. package/library/skills/host-authoritative-state/SKILL.md +0 -332
  362. package/library/skills/host-authoritative-state/resource.yaml +0 -28
  363. package/library/skills/peer-to-peer-multiplayer/SKILL.md +0 -373
  364. package/library/skills/peer-to-peer-multiplayer/resource.yaml +0 -28
  365. package/library/skills/setup-multiplayer/SKILL.md +0 -336
  366. package/library/skills/setup-multiplayer/resource.yaml +0 -28
@@ -0,0 +1,186 @@
1
+ # 3D Horror - Systems
2
+
3
+ The dread machinery on top of `3d-horror.md`: the tension-driven atmosphere
4
+ controller, the stalker AI, procedural audio, interactables, and the escape
5
+ objective chain.
6
+
7
+ ## Atmosphere controller (tension in, dread out)
8
+
9
+ One Node3D in the level reads `GameManager.tension_level` and escalates
10
+ three channels. It auto-discovers OmniLights from a sibling "Lights" node
11
+ and creates 4 roaming AudioStreamPlayer3D emitters (Ambient bus, max
12
+ distance 20).
13
+
14
+ ### Flickering lights
15
+
16
+ Per-frame chance `0.005 * (1.0 + tension)` per light. A flicker is a tween
17
+ of 2-5 random off/on cycles (off 0.02-0.08s at energy 0-0.3, on 0.02-0.1s
18
+ at 50-100%), then restore. Random durations - regular flicker reads as a
19
+ broken script, not a broken light.
20
+
21
+ ### Positional ambient sounds
22
+
23
+ Every 15-45s (interval shrinks to half at max tension), one emitter
24
+ teleports to a random point around the player
25
+ (x/z +-15, y 0-5 - behind walls, above the ceiling) and plays from a pool
26
+ that GROWS with tension:
27
+
28
+ - base: door close, pipe stress, wind vent
29
+ - tension > 0.3: + creature whisper
30
+ - tension > 0.5: + distant scream
31
+ - tension > 0.7: + creature growl
32
+
33
+ Random volume -12..-4 dB and pitch 0.7-1.3 so nothing repeats exactly.
34
+
35
+ ### Tension events
36
+
37
+ Every 30s at base, down to ~12s at max tension, pick one of FIVE:
38
+ 0 = flicker all lights, 1 = audio stinger + tension +0.05, 2 = brief
39
+ darkness, 3 = extra ambient sound, 4 = NOTHING. The nothing case is
40
+ deliberate - a scare that never comes after buildup is the horror.
41
+
42
+ Brief darkness: tween all lights to energy 0.05 over 0.5s, hold a random
43
+ 0.5-2s, restore over 0.3s, tension +0.08. Save original energies first.
44
+
45
+ ## Stalker AI
46
+
47
+ A solid-black unshaded capsule (CapsuleMesh r 0.2 h 2.2, albedo 0.01 -
48
+ reads as a silhouette in any lighting). Mesh and collision built at
49
+ runtime, no assets. Core mechanic: it only moves when you are NOT looking.
50
+
51
+ ```gdscript
52
+ func _process_showing(delta: float) -> void:
53
+ look_at(Vector3(player.global_position.x, global_position.y, player.global_position.z))
54
+ var to_me := (global_position - player.global_position).normalized()
55
+ var player_fwd := -player.global_transform.basis.z.normalized()
56
+ var angle := rad_to_deg(acos(clampf(player_fwd.dot(to_me), -1.0, 1.0)))
57
+ if angle < 20.0:
58
+ # player looking directly: freeze and stare back
59
+ stare_timer += delta
60
+ if stare_timer >= stare_time: # 2.0s of being watched
61
+ _disappear()
62
+ else:
63
+ stare_timer = 0.0
64
+ var dir := (player.global_position - global_position).normalized()
65
+ dir.y = 0.0
66
+ velocity = dir * approach_speed # 1.5 m/s
67
+ move_and_slide()
68
+ if global_position.distance_to(player.global_position) < catch_distance: # 1.5m
69
+ AudioManager.play_sfx(ProceduralAudio.get_creature_screech(), 0.0)
70
+ GameManager.set_state(GameManager.GameState.GAME_OVER)
71
+ ```
72
+
73
+ Pacing rules (tuned, keep them):
74
+
75
+ - First appearance at 15s - the player needs time to find the flashlight.
76
+ - Reappear interval starts 18s, shrinks 15% per appearance, floor 8s:
77
+ `reappear_interval = maxf(reappear_interval * 0.85, 8.0)`.
78
+ - Spawn selection: from a hand-placed spawn-point list, pick the FARTHEST
79
+ point that is between 6m and 18m from the player. Under 6m is unfair -
80
+ no time to react.
81
+ - On appear: whisper from its own 3D emitter + low-pitched stinger
82
+ (pitch 0.5-0.8) + tension +0.1.
83
+ - Fully idle while `GameManager.is_reading_note` or state != PLAYING -
84
+ notes are safe rooms.
85
+ - After `stare_time` of being watched it vanishes (visible = false) and
86
+ the wait timer restarts. Player-facing check is a dot-product cone of
87
+ 20 degrees, not a raycast - cheap and good enough.
88
+
89
+ ## Procedural audio
90
+
91
+ `ProceduralAudio` is a static class generating every sound from math into
92
+ cached AudioStreamWAVs - zero audio files; swap in recordings later
93
+ without touching call sites. Catalog: footsteps (4 variations),
94
+ door open/close/locked, ambient drone (detuned 40Hz sines, looping),
95
+ tension hit (sub boom + metallic ring), pickup chime, creature
96
+ whisper/growl/screech, heartbeat, distant scream, water drip, machinery
97
+ hum, wind vent, fluorescent buzz, pipe stress, radio static.
98
+
99
+ Generation pattern all sounds follow (16-bit, 22050 Hz):
100
+
101
+ ```gdscript
102
+ static func _generate_example() -> void:
103
+ var num_samples := int(duration * SAMPLE_RATE)
104
+ var samples := PackedByteArray()
105
+ samples.resize(num_samples * 2)
106
+ for s in num_samples:
107
+ var t := float(s) / SAMPLE_RATE
108
+ var envelope := exp(-t * 3.0)
109
+ var value := sin(t * 440.0 * TAU) * envelope * 0.3
110
+ var sample := clampi(int(value * 16000), -32768, 32767)
111
+ samples[s * 2] = sample & 0xFF
112
+ samples[s * 2 + 1] = (sample >> 8) & 0xFF
113
+ _stream = AudioStreamWAV.new()
114
+ _stream.format = AudioStreamWAV.FORMAT_16_BITS
115
+ _stream.mix_rate = SAMPLE_RATE
116
+ _stream.data = samples
117
+ # looping sounds: loop_mode = LOOP_FORWARD, loop_begin = 0, loop_end = num_samples
118
+ ```
119
+
120
+ Recipes that matter: creature sounds = low fundamentals (30Hz growl) +
121
+ inharmonic partials; whispers/screams = filtered noise; drones = slightly
122
+ detuned sine pairs (beating); always exponential envelopes.
123
+
124
+ ## Interactables
125
+
126
+ Same duck-typed interface as 3d-fps: `interact(player)` +
127
+ `get_interaction_prompt() -> String`, found by the InteractionRay (mask 4).
128
+
129
+ ### HorrorDoor
130
+
131
+ Node3D rotating on Y, hinge at the parent origin (mesh offset
132
+ (0.5, 1.4, 0)), lerp `rotation.y` toward target at open_speed. Opens away
133
+ from the player (approach-side check). Horror-specific exports:
134
+
135
+ - `required_key`: locked until `GameManager.has_item(key)`; unlocking
136
+ consumes the key. Locked interaction plays a rattle - +-2 degree shake
137
+ tween + locked sound. Prompt: "Locked" / "Unlock" / "Open" / "Close".
138
+ - `auto_close_delay`: door closes itself behind the player (room traps).
139
+ - `creepy_auto_open`: opens by itself ONCE after a delay - cheapest scare
140
+ in the kit.
141
+
142
+ ### InteractableItem
143
+
144
+ RigidBody3D with `freeze = true`, bob + rotate idle (randomized phase),
145
+ per-type runtime mesh + OmniLight3D glow:
146
+
147
+ | Type | Effect | Visual |
148
+ |---|---|---|
149
+ | KEY | `add_item(item_id)` | gold box, warm glow |
150
+ | FLASHLIGHT | `player.pickup_flashlight()` | gray cylinder, amber glow |
151
+ | NOTE | `open_note(id, text)` - NOT consumed | paper-white flat box |
152
+ | BATTERY | battery +30 (cap 100) | dark blue box, blue glow |
153
+
154
+ Everything except notes `queue_free()`s on pickup.
155
+
156
+ ### EscapeZone
157
+
158
+ Area3D (mask 1) at the exit with a green OmniLight beacon. On player
159
+ enter: with the exit key -> `set_state(ESCAPED)`; without it -> open a
160
+ note ("The door is chained from the outside. I need a key.") - the
161
+ rejection delivers story instead of a dead trigger.
162
+
163
+ ## Objective chain
164
+
165
+ The loop is explore -> find -> unlock -> escape:
166
+
167
+ 1. Spawn in entry area, find flashlight.
168
+ 2. Main hall, Note 1 hints at the storage key.
169
+ 3. Side corridor -> office -> storage key.
170
+ 4. Storage room (locked) -> exit key.
171
+ 5. Back corridor (darkest) -> escape zone with exit key -> ESCAPED.
172
+
173
+ The whole chain is data: `required_key` on doors, `item_id` on pickups,
174
+ `required_key` on the EscapeZone, and note texts for direction. Re-theme a
175
+ level by editing strings, not code. Keys live in dead ends so the stalker
176
+ gets backtracking time; notes double as the hint system - no quest UI.
177
+
178
+ ## Escalation timeline (why it works)
179
+
180
+ Minute 1: quiet, base ambient sounds, flashlight secured. Minute 2-3:
181
+ first stalker appearance, whispers join the pool. Mid-game: battery
182
+ pressure, screams, shorter stalker gaps, brief-darkness events. Endgame:
183
+ tension near 1.0 - vignette closed in, breathing sway, growls, stalker
184
+ every 8s, in the darkest corridor with the exit key. All of it falls out
185
+ of one passive float plus event spikes; tune the drain rate, the
186
+ reappear floor, and ambient intervals - not scripted scares.
@@ -0,0 +1,201 @@
1
+ # 3D Horror - Core
2
+
3
+ First-person horror blueprint: game state, the vulnerable-player controller,
4
+ flashlight mechanics, level building, lighting, and the minimal HUD. The
5
+ stalker AI, tension/atmosphere system, procedural audio, and interactables
6
+ live in `3d-horror-systems.md`.
7
+
8
+ The player scene reuses the 3d-fps hierarchy and controller (yaw on root,
9
+ pitch on Head, two crouch shapes, headbob) - see `3d-fps.md`. This file
10
+ covers what horror changes.
11
+
12
+ ## Design law: vulnerability
13
+
14
+ No weapon, ever. The flashlight is the only tool. The moment the player can
15
+ fight back it becomes an action game. No health bar, no minimap, no kill
16
+ counter - the HUD shows only battery, interaction prompt, and notes.
17
+
18
+ ## Minimum playable base (build this first)
19
+
20
+ One dark room + flashlight pickup + a locked door + the key that opens it.
21
+ Prove "dark, need the light, find key, open door" before any AI or
22
+ atmosphere exists.
23
+
24
+ ## Autoloads
25
+
26
+ Two: GameManager and AudioManager, both `process_mode = PROCESS_MODE_ALWAYS`.
27
+
28
+ GameManager is the single source of truth:
29
+
30
+ ```gdscript
31
+ enum GameState { MENU, PLAYING, PAUSED, GAME_OVER, ESCAPED }
32
+
33
+ var inventory: Array[String] = []
34
+ var notes_found: Array[String] = []
35
+ var has_flashlight: bool = false
36
+ var flashlight_battery: float = 100.0
37
+ var doors_unlocked: Array[String] = []
38
+ var tension_level: float = 0.0 # 0 calm .. 1 max
39
+ var is_reading_note: bool = false
40
+ ```
41
+
42
+ - `set_state()` pauses the tree for PAUSED/GAME_OVER/ESCAPED, unpauses on
43
+ PLAYING, and force-closes any open note on leaving PLAYING.
44
+ - Tension rises passively 0.005/sec while PLAYING; systems spike it via
45
+ `increase_tension(amount)`. Everything atmospheric reads this one float.
46
+ - Note reading is a modal state: while `is_reading_note`, the player
47
+ controller AND the stalker both stand down (safe reading).
48
+ - Inventory is just string ids: `add_item` / `has_item` / `remove_item`;
49
+ `open_note(id, text)` / `close_note()` emit signals the HUD listens to.
50
+
51
+ AudioManager: 8 pooled AudioStreamPlayers on an "SFX" bus, dedicated
52
+ ambient + music players on an "Ambient" bus, buses created at runtime via
53
+ `AudioServer.add_bus()` if missing. `play_ambient` crossfades from -40dB.
54
+ Bus separation is mandatory - you cannot balance or add reverb/low-pass
55
+ later without it.
56
+
57
+ ## Player controller (horror deltas from 3d-fps)
58
+
59
+ - Walk 3.0 / sprint 5.0 / crouch 1.5 (slow = vulnerable; FPS-speed movement
60
+ kills dread).
61
+ - gravity_multiplier 1.5 - heavier, grounded.
62
+ - ALL input gated on `GameManager.current_state == PLAYING` in both
63
+ `_unhandled_input` and `_physics_process` - frozen during notes, pause,
64
+ game over.
65
+ - Extra child under Camera3D: Flashlight (SpotLight3D at (0.15, -0.1, -0.1),
66
+ hidden until picked up) + FlashlightDust (GPUParticles3D).
67
+ - Input map adds `flashlight` (F); no shoot/aim/reload.
68
+ - Footsteps route through the procedural audio footstep with random pitch.
69
+
70
+ ### Flashlight (the core mechanic)
71
+
72
+ ```gdscript
73
+ func _handle_flashlight_drain(delta: float) -> void:
74
+ if not flashlight_on:
75
+ return
76
+ GameManager.flashlight_battery -= flashlight_drain_rate * delta / 60.0 # 15%/min, ~6.5 min life
77
+ GameManager.flashlight_battery = maxf(GameManager.flashlight_battery, 0.0)
78
+ if GameManager.flashlight_battery < 15.0:
79
+ # dual-sine = irregular organic flicker, not a metronome
80
+ var flicker := sin(Time.get_ticks_msec() * 0.03) * sin(Time.get_ticks_msec() * 0.07)
81
+ flashlight.light_energy = lerpf(0.3, 1.2, (flicker + 1.0) * 0.5)
82
+ else:
83
+ flashlight.light_energy = 1.5
84
+ if GameManager.flashlight_battery <= 0.0:
85
+ flashlight_on = false
86
+ flashlight.visible = false
87
+ ```
88
+
89
+ Toggle refuses until `GameManager.has_flashlight`. Battery pickups restore
90
+ +30. Drain rate is the game's difficulty dial.
91
+
92
+ Dust in the beam: GPUParticles3D (60 particles, 4s life, box emission
93
+ 2x1.5x5 in front of camera, tiny unshaded spheres radius 0.008, alpha ramp
94
+ peaking at 0.08). Emits only while the flashlight is visible. Reads as
95
+ volumetrics at a fraction of the cost.
96
+
97
+ ### Breathing (fear you can feel)
98
+
99
+ ```gdscript
100
+ func _handle_breathing(delta: float) -> void:
101
+ var target := 0.0
102
+ if stamina < 30.0:
103
+ target += (1.0 - stamina / 30.0) * 0.5
104
+ target += GameManager.tension_level * 0.3
105
+ breathing_intensity = lerpf(breathing_intensity, target, 2.0 * delta)
106
+ if breathing_intensity > 0.05:
107
+ var t := Time.get_ticks_msec() * 0.001
108
+ camera.rotation.x += sin(t * 1.5) * breathing_intensity * 0.003
109
+ camera.rotation.z = lerpf(camera.rotation.z,
110
+ sin(t * 2.0) * breathing_intensity * 0.002, 3.0 * delta)
111
+ ```
112
+
113
+ Involuntary camera sway from low stamina + high tension. Subtle numbers -
114
+ resist cranking them.
115
+
116
+ ## Level building (library first, primitives last)
117
+
118
+ The level comes from real assets: route it through the `asset-strategy` skill
119
+ (`summer_search_assets`, then `summer_import_asset` / `summer_import_asset_by_id`)
120
+ and look for a ready horror location (an abandoned house, a haunted forest, a
121
+ modular horror-house kit) plus period props, keeping one coherent style. Import
122
+ the location that fits and build gameplay inside it. Do NOT grey-box a level a
123
+ real asset already provides.
124
+
125
+ Runtime primitive geometry (BoxMesh/PlaneMesh + StaticBody3D, collision
126
+ layer 2) is only for what the imported assets lack: interior partitions the
127
+ imported location does not have, trigger volumes, blockers. When you do need
128
+ it: WALL_HEIGHT 3.5, WALL_THICKNESS 0.15, helpers `_floor(center, size)`,
129
+ `_ceiling`, `_wall_x(z, x0, x1)` / `_wall_z(x, z0, z1)`, `_prop_box(pos,
130
+ size, mat)`. Materials: dark desaturated albedo (floor 0.12/0.11/0.1, walls
131
+ 0.18/0.17/0.15), roughness 0.85.
132
+
133
+ Layout formula:
134
+
135
+ 1. Entry area - well-lit, flashlight pickup here.
136
+ 2. Main hall - central hub, multiple exits, player keeps returning.
137
+ 3. Side corridors - long, narrow, dim; stalker territory.
138
+ 4. Dead-end rooms - keys and notes; forced backtracking.
139
+ 5. Back corridor - darkest, highest tension.
140
+ 6. Final area - escape zone at the far end, exit key behind at least one
141
+ locked door.
142
+
143
+ ## Atmosphere rendering settings
144
+
145
+ WorldEnvironment is half the horror:
146
+
147
+ - Sky near-black (top 0.02/0.02/0.05); ambient color 0.03/0.03/0.05 at
148
+ energy 0.5 - the player MUST need the flashlight.
149
+ - Tonemap ACES, white 6.0. SSAO on (radius 2, intensity 3 - darkens
150
+ corners). SSIL on (radius 3, intensity 0.5). Glow subtle (0.3 / bloom 0.1).
151
+ - Fog density 0.02 dark; volumetric fog density 0.06, anisotropy 0.7 -
152
+ this is what makes the flashlight beam a visible cone.
153
+
154
+ Lighting rules: OmniLights energy 0.4-0.8 (main hall 1.2 max), ALL with
155
+ `shadow_enabled = true` (the stalker casts a shadow before you see it).
156
+ Give each area a distinct temperature - entry warm (0.6, 0.5, 0.3),
157
+ corridors cool (0.3, 0.4, 0.35), lab sickly green (0.3, 0.6, 0.4) - it is
158
+ navigation AND variety without textures.
159
+
160
+ Collision layers: 1 Player, 2 Environment, 3 Interactable, 4 Enemy.
161
+
162
+ ## HUD (minimal by design)
163
+
164
+ ```
165
+ HUD (CanvasLayer)
166
+ Crosshair (centered dot)
167
+ InteractionPrompt (Label, bottom center, "[E] Open")
168
+ BatteryContainer (top left, HIDDEN until flashlight found)
169
+ BatteryBar (ProgressBar; red <20%, yellow <50%, blue else)
170
+ NoteBackdrop (fullscreen black, 72% alpha)
171
+ NotePanel (centered note text)
172
+ Vignette (fullscreen; alpha = 0.2 + tension * 0.4)
173
+ ```
174
+
175
+ Wire to GameManager signals (`note_opened/closed`, `game_state_changed`).
176
+ Note UX detail: 0.35s cooldown after opening before close input is
177
+ accepted - otherwise the same interact press that opened the note closes
178
+ it. HUD hides entirely when state is not PLAYING.
179
+
180
+ ## Build order
181
+
182
+ 1. Autoloads + input map + layers.
183
+ 2. Player from 3d-fps base, horror speeds, state gating.
184
+ 3. One room + WorldEnvironment settings + flashlight pickup + drain.
185
+ 4. Doors/keys/notes + escape zone (`3d-horror-systems.md`).
186
+ 5. Atmosphere controller, then the stalker LAST - it only lands once the
187
+ world already feels wrong.
188
+
189
+ ## Traps
190
+
191
+ - Giving the player any weapon, health bar, or combat UI.
192
+ - Ambient energy above 0.5 - no darkness, no battery economy, no fear.
193
+ - Constant jump scares. The template leans on anticipation; one of its
194
+ five tension events is deliberately NOTHING.
195
+ - Stalker always visible - players habituate; long gaps are intentional.
196
+ - Constant music. Silence scares; use the drone + rare stingers, save
197
+ music for peaks and safe rooms.
198
+ - Identical rooms - distinct color temperature per area or players get
199
+ lost and bored simultaneously.
200
+ - Skipping audio buses - SFX through SFX bus, ambience through Ambient,
201
+ or mixing and wall-muffling effects become impossible later.
@@ -0,0 +1,220 @@
1
+ # 3D Third-Person - Systems
2
+
3
+ The combat and content layer on top of `3d-third-person.md`: melee, bullets,
4
+ grenade with arc preview, two enemy archetypes, coins, destructible boxes,
5
+ and the HUD.
6
+
7
+ ## Shared damage interface
8
+
9
+ Everything hittable (player, enemies, boxes) implements:
10
+
11
+ ```gdscript
12
+ func damage(impact_point: Vector3, force: Vector3) -> void
13
+ ```
14
+
15
+ and joins the "damageables" group. `impact_point` is
16
+ `global_position - body.global_position` (direction from body to impact),
17
+ `force` is the knockback vector. Enemies additionally join "targeteables"
18
+ for grenade lock-on. One interface, three weapons, all content - keep it.
19
+
20
+ ## Weapons
21
+
22
+ Tab toggles DEFAULT and GRENADE (a `weapon_switched` signal drives the HUD
23
+ icons). DEFAULT: left-click = melee from the hip, aim (RMB) + left-click =
24
+ ranged shot with over-shoulder camera + crosshair. GRENADE: left-click
25
+ throws with a live arc preview.
26
+
27
+ ### Melee (animation-gated hitbox)
28
+
29
+ The MeleeAttackArea's CollisionShape3D starts disabled. The "Attack"
30
+ animation (0.3-0.5s) has method-call tracks: `activate()` at the impact
31
+ frame (~0.15s), `deactivate()` at the end. The area's `body_entered` damages
32
+ "damageables" with force pointing away from the player. Player side:
33
+ `attack()` plays the animation, fires the skin's punch OneShot, and sets
34
+ `velocity = rotation_root.basis * Vector3.BACK * attack_impulse` (forward
35
+ lunge). Movement is locked while the attack animation plays.
36
+
37
+ Animation-gated hitboxes beat timer-gated ones: the active window is
38
+ authored visually next to the swing frames.
39
+
40
+ ### Bullet (shared by player AND enemies)
41
+
42
+ Node3D moved manually in `_process` - no physics body:
43
+
44
+ ```gdscript
45
+ func _ready() -> void:
46
+ _area.body_entered.connect(_on_body_entered)
47
+ look_at(global_position + velocity)
48
+ _alive_limit = distance_limit / velocity.length()
49
+
50
+ func _process(delta: float) -> void:
51
+ global_position += velocity * delta
52
+ _time_alive += delta
53
+ _bullet_visuals.scale = Vector3.ONE * scale_decay.sample(_time_alive / _alive_limit)
54
+ if _time_alive > _alive_limit:
55
+ queue_free()
56
+
57
+ func _on_body_entered(body: Node3D) -> void:
58
+ if body == shooter:
59
+ return
60
+ if body.is_in_group("damageables"):
61
+ body.damage(global_position - body.global_position, velocity)
62
+ queue_free()
63
+ ```
64
+
65
+ The `shooter` reference prevents self-hits, which is what lets one bullet
66
+ scene serve both sides. Distance limit expressed as time
67
+ (`distance / speed`); visual scale decays via an exported Curve so bullets
68
+ fade with range. Player shots originate at `global_position + Vector3.UP`
69
+ and fly toward `camera_controller.get_aim_target()`.
70
+
71
+ Fast projectiles tunnel through thin walls: keep speeds moderate (player
72
+ 10, enemies 6) or fatten the Area3D shape.
73
+
74
+ ### Grenade launcher (arc preview + lock-on)
75
+
76
+ While GRENADE is equipped the launcher is visible and every physics frame:
77
+ camera tilt lerps throw distance between min 7 and max 16; a ShapeCast3D
78
+ finds the landing point; if the cast hits a "targeteables" body, the landing
79
+ snaps to that enemy (lock-on, SnapMesh indicator); initial velocity
80
+ decomposes into vertical `sqrt(2 * gravity * peak_height)` and horizontal
81
+ `distance / time_to_land`; the preview trail is a triangle-strip mesh built
82
+ with SurfaceTool sampling the parabola at 0.05s steps.
83
+
84
+ The grenade itself is a CharacterBody3D using `move_and_collide` (NOT
85
+ move_and_slide) so it can bounce:
86
+
87
+ ```gdscript
88
+ func _physics_process(delta) -> void:
89
+ _velocity += Vector3.DOWN * gravity * delta
90
+ var collision := move_and_collide(_velocity * delta)
91
+ if collision:
92
+ _velocity = _velocity.bounce(collision.get_normal(0)) * 0.7
93
+ if _explosion_start_timer.is_stopped():
94
+ _explosion_start_timer.start()
95
+ ```
96
+
97
+ First bounce arms the fuse timer. Explosion: damage all overlapping
98
+ "damageables" in the ExplosionArea EXCEPT the Player (`not body is Player` -
99
+ self-immunity), spawn explosion visuals, hide, await the sound, free. On
100
+ throw, add a collision exception between grenade and thrower via
101
+ `PhysicsServer3D.body_add_collision_exception`.
102
+
103
+ ## Enemies
104
+
105
+ Both are RigidBody3D with a PlayerDetectionArea (big sphere Area3D), a
106
+ reaction label ("!" / "?" animations on detect/lose), and the same death
107
+ choreography: play defeat sound, set `_alive = false`, DISCONNECT the
108
+ detection signals (dead enemies must not react), enable the death collider,
109
+ enable gravity so the body drops, wait 2s, spawn a smoke puff, `await
110
+ puff.full`, burst coins out of the smoke, `queue_free()`.
111
+
112
+ The smoke puff emits `full` from an animation keyframe at peak opacity -
113
+ awaiting it makes coins appear to burst out of the cloud instead of
114
+ clipping through a half-formed puff.
115
+
116
+ ### Bee bot (flying turret)
117
+
118
+ RigidBody3D with `gravity_scale = 0` (floats). While a target is set:
119
+
120
+ ```gdscript
121
+ var target_transform := transform.looking_at(_target.global_position)
122
+ transform = transform.interpolate_with(target_transform, 0.1)
123
+ ```
124
+
125
+ Fires the SAME bullet scene as the player every 1.5s at speed 6, aimed at
126
+ `target.global_position + Vector3.UP`. `damage()` applies an impulse
127
+ (clamped length 3) then runs the death choreography; gravity_scale flips to
128
+ 1.0 so it falls out of the air.
129
+
130
+ ### Beetle bot (NavigationAgent3D chaser)
131
+
132
+ RigidBody3D with rotation axes locked (rigid until death). Chase loop:
133
+
134
+ ```gdscript
135
+ _navigation_agent.target_position = _target.global_position
136
+ var next := _navigation_agent.get_next_path_position()
137
+ if not _navigation_agent.is_target_reached():
138
+ var direction := (next - global_position)
139
+ direction.y = 0 # never dive/fly
140
+ direction = direction.normalized()
141
+ var collision := move_and_collide(direction * delta * 3)
142
+ if collision and collision.get_collider() is Player:
143
+ var force := -(global_position - collider.global_position)
144
+ force.y = 0.5
145
+ collider.damage(impact_point, force * 10.0)
146
+ _beetle_skin.attack()
147
+ ```
148
+
149
+ `look_at` the target with Y flattened to its own height. On death, unlock
150
+ all angular axes so the corpse tumbles.
151
+
152
+ Navigation requirements: the level MUST have a baked NavigationRegion3D or
153
+ the beetle stands still forever; the target must be reachable on the
154
+ navmesh; always zero the Y of path directions.
155
+
156
+ Enemy skins: AnimationTree state machines (Idle/Walk/Attack/Shake/PowerOff)
157
+ with a secondary-action timer firing random idle shakes every 3-8s;
158
+ `power_off()` stops that timer.
159
+
160
+ ## Coins
161
+
162
+ RigidBody3D collectible, either placed in the level or scattered by
163
+ `spawn()` (random impulse: direction rotated randomly around UP, range 2-4,
164
+ height 1-3). Collection is DELAYED: layer 3 collision is off for
165
+ `coin_delay` (0.5s default, 1.5s when the player drops them) so coins from
166
+ a kill do not vacuum back instantly.
167
+
168
+ Magnet: when the player enters the coin's detection area (mask = Player
169
+ layer 4), freeze physics and tween to the player:
170
+
171
+ ```gdscript
172
+ func set_target(new_target: PhysicsBody3D) -> void:
173
+ PhysicsServer3D.body_add_collision_exception(get_rid(), new_target.get_rid())
174
+ if _target == null:
175
+ sleeping = true
176
+ freeze = true
177
+ _initial_tween_position = global_position
178
+ _target = new_target
179
+ var tween := create_tween()
180
+ tween.tween_method(_follow, 0.0, 1.0, 0.5) # lerp start -> player
181
+ tween.tween_callback(_collect)
182
+ ```
183
+
184
+ `_follow` lerps from the captured start to the LIVE player position, so the
185
+ coin homes even while the player runs. Collect: random-pitch sound,
186
+ `player.collect_coin()`, hide, await audio, free. Coin model: spin
187
+ `rotation.y += 1.5 * delta`, bob `sin(t) * 0.04`.
188
+
189
+ ## Destructible boxes
190
+
191
+ `damage()` on the box: spawn 5 coins with `spawn()`, instantiate a
192
+ pre-fractured debris scene, disable own collision (deferred), play sound,
193
+ await it, free. Debris scene = 6 hidden frozen RigidBody3D pieces; on ready,
194
+ shuffle and launch 3 random ones with `apply_force(rand_vector * 500)`,
195
+ leave the rest hidden. Half-count random debris looks as good as full
196
+ simulation at a fraction of the cost.
197
+
198
+ ## HUD
199
+
200
+ ```
201
+ UI (CanvasLayer)
202
+ AimRecticle (%unique, ColorRect centered) # visible only while aiming
203
+ CoinsContainer (%unique, HBoxContainer) # slides in on change
204
+ CoinIcon + CoinsLabel + Timer
205
+ WeaponUI (PanelContainer) # Flash / Grenade icons
206
+ ```
207
+
208
+ Coin counter: slides from y -100 to y 20 on `update_coins_amount`, restarts
209
+ its display timer per change, slides back out on timeout. Weapon icons:
210
+ inactive at alpha 0.2, tween to full white on select; `switch_to()` guards
211
+ against reselecting the current one. Use unique names (%) so the deep
212
+ player script reaches UI without brittle paths.
213
+
214
+ ## Order of work
215
+
216
+ 1. Melee: attack animation + gated hitbox + a destructible box to punch.
217
+ 2. Coins with magnet + HUD counter (the reward loop).
218
+ 3. Aim mode: over-shoulder pivot + crosshair + bullet.
219
+ 4. Bee bot (reuses your bullet), then beetle bot (navmesh required).
220
+ 5. Grenade launcher last - arc preview, lock-on, explosion.