summer-engine 2.6.6 → 2.8.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 (168) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +4 -1
  3. package/.codex-plugin/plugin.json +6 -2
  4. package/.cursor-plugin/plugin.json +5 -1
  5. package/.opencode/INSTALL.md +1 -1
  6. package/.opencode/plugins/summer.js +2 -2
  7. package/AGENTS.md +11 -7
  8. package/CHANGELOG.md +40 -0
  9. package/GEMINI.md +9 -7
  10. package/README.md +63 -21
  11. package/_persona/summer/SKILL.md +1 -0
  12. package/assets/autopilot/README.md +51 -0
  13. package/assets/autopilot/autopilot.gd +222 -0
  14. package/assets/autopilot/probe_base.gd +262 -0
  15. package/assets/autopilot/run.sh +78 -0
  16. package/commands/gameskill.md +11 -2
  17. package/commands/summer.md +13 -0
  18. package/dist/bin/summer.js +12 -0
  19. package/dist/commands/config.d.ts +2 -0
  20. package/dist/commands/config.js +53 -0
  21. package/dist/commands/create.d.ts +1 -0
  22. package/dist/commands/create.js +38 -6
  23. package/dist/commands/debug.d.ts +2 -0
  24. package/dist/commands/debug.js +44 -0
  25. package/dist/commands/doctor.js +112 -8
  26. package/dist/commands/list.js +1 -1
  27. package/dist/commands/login.d.ts +19 -0
  28. package/dist/commands/login.js +123 -36
  29. package/dist/commands/logout.js +3 -16
  30. package/dist/commands/logs.d.ts +2 -0
  31. package/dist/commands/logs.js +19 -0
  32. package/dist/commands/mcp.js +7 -2
  33. package/dist/commands/open.js +1 -1
  34. package/dist/commands/publish.d.ts +2 -0
  35. package/dist/commands/publish.js +20 -0
  36. package/dist/commands/releases.d.ts +2 -0
  37. package/dist/commands/releases.js +20 -0
  38. package/dist/commands/run.js +1 -1
  39. package/dist/commands/skills.js +1 -1
  40. package/dist/lib/api-client.d.ts +15 -4
  41. package/dist/lib/api-client.js +138 -13
  42. package/dist/lib/async-op-lifecycle.d.ts +7 -2
  43. package/dist/lib/async-op-lifecycle.js +32 -9
  44. package/dist/lib/auth.d.ts +40 -12
  45. package/dist/lib/auth.js +173 -37
  46. package/dist/lib/cloud/engine-bridge.d.ts +17 -4
  47. package/dist/lib/cloud/engine-bridge.js +32 -6
  48. package/dist/lib/config.d.ts +20 -0
  49. package/dist/lib/config.js +142 -0
  50. package/dist/lib/creator.d.ts +93 -0
  51. package/dist/lib/creator.js +393 -0
  52. package/dist/lib/debug-report.d.ts +50 -0
  53. package/dist/lib/debug-report.js +308 -0
  54. package/dist/lib/engine.d.ts +35 -2
  55. package/dist/lib/engine.js +240 -6
  56. package/dist/lib/game-task-plan.js +4 -4
  57. package/dist/lib/mcp-boot-notice.d.ts +3 -0
  58. package/dist/lib/mcp-boot-notice.js +7 -0
  59. package/dist/lib/mcp-log.d.ts +3 -0
  60. package/dist/lib/mcp-log.js +72 -0
  61. package/dist/lib/public-surface-paths.d.ts +13 -0
  62. package/dist/lib/public-surface-paths.js +42 -0
  63. package/dist/lib/skills-registry.d.ts +33 -1
  64. package/dist/lib/skills-registry.js +55 -0
  65. package/dist/lib/store.d.ts +14 -0
  66. package/dist/lib/store.js +145 -0
  67. package/dist/lib/summer-compatibility.d.ts +6 -0
  68. package/dist/lib/summer-compatibility.js +22 -0
  69. package/dist/mcp/server.d.ts +10 -3
  70. package/dist/mcp/server.js +104 -11
  71. package/dist/mcp/tools/asset-tools.js +33 -12
  72. package/dist/mcp/tools/cloud-tools.js +15 -15
  73. package/dist/mcp/tools/creator-tools.d.ts +2 -0
  74. package/dist/mcp/tools/creator-tools.js +105 -0
  75. package/dist/mcp/tools/debug-tools.js +44 -1
  76. package/dist/mcp/tools/file-tools.d.ts +2 -0
  77. package/dist/mcp/tools/file-tools.js +154 -0
  78. package/dist/mcp/tools/generate-tools.js +159 -11
  79. package/dist/mcp/tools/project-tools.js +37 -27
  80. package/dist/mcp/tools/scene-tools.js +106 -29
  81. package/dist/mcp/tools/visual-tools.js +4 -3
  82. package/dist/mcp/tools/with-engine.js +4 -4
  83. package/hooks/session-start.sh +5 -5
  84. package/package.json +3 -1
  85. package/references/collaborative-protocol.md +50 -0
  86. package/references/gd-style.md +121 -0
  87. package/references/godot-version.md +51 -0
  88. package/references/mcp-tools-reference.md +199 -0
  89. package/references/public-surface-language.md +30 -0
  90. package/references/summer-folder.md +90 -0
  91. package/references/template-registry.md +73 -0
  92. package/skills/2d-assets/character-portrait/SKILL.md +17 -12
  93. package/skills/2d-assets/concept-art/SKILL.md +10 -9
  94. package/skills/2d-assets/create-asset-sheet/SKILL.md +17 -15
  95. package/skills/2d-assets/pixel-art/SKILL.md +36 -20
  96. package/skills/2d-assets/skybox-panorama/SKILL.md +32 -37
  97. package/skills/2d-assets/sprite-sheet/SKILL.md +40 -35
  98. package/skills/2d-assets/tileable-texture/SKILL.md +28 -22
  99. package/skills/2d-assets/ui-graphics/SKILL.md +46 -32
  100. package/skills/2d-assets/use-widget-asset/SKILL.md +8 -6
  101. package/skills/3d-assets/character-model/SKILL.md +34 -19
  102. package/skills/3d-assets/environment-kit/SKILL.md +11 -5
  103. package/skills/3d-assets/organic-model/SKILL.md +8 -5
  104. package/skills/3d-assets/prop-model/SKILL.md +9 -3
  105. package/skills/3d-assets/vehicle-model/SKILL.md +32 -19
  106. package/skills/README.md +1 -1
  107. package/skills/ai-and-npcs/design-npc/SKILL.md +31 -13
  108. package/skills/animation/animation-tree/SKILL.md +39 -15
  109. package/skills/animation/facial-and-lipsync/SKILL.md +25 -8
  110. package/skills/animation/generate-motion/SKILL.md +47 -15
  111. package/skills/animation/procedural-animation/SKILL.md +31 -13
  112. package/skills/animation/retarget/SKILL.md +127 -79
  113. package/skills/audio/adaptive-music/SKILL.md +24 -20
  114. package/skills/audio/ambient-bed/SKILL.md +22 -16
  115. package/skills/audio/audio-direction/SKILL.md +15 -10
  116. package/skills/audio/music-track/SKILL.md +18 -12
  117. package/skills/audio/sound-effect/SKILL.md +17 -12
  118. package/skills/audio/voice-line/SKILL.md +42 -42
  119. package/skills/character-controllers/fps-controller/SKILL.md +26 -16
  120. package/skills/debugging/debug/SKILL.md +74 -20
  121. package/skills/deployment/export-and-ship/SKILL.md +105 -38
  122. package/skills/deployment/remote-deploy/SKILL.md +140 -0
  123. package/skills/gameplay-mechanics/auto-fire-targeting/SKILL.md +26 -1
  124. package/skills/gameplay-mechanics/design-mechanic/SKILL.md +23 -15
  125. package/skills/level-design/design-level/SKILL.md +22 -8
  126. package/skills/level-design/scene-to-level/SKILL.md +13 -7
  127. package/skills/multiplayer-and-networking/host-authoritative-state/SKILL.md +8 -8
  128. package/skills/multiplayer-and-networking/peer-to-peer-multiplayer/SKILL.md +2 -7
  129. package/skills/multiplayer-and-networking/setup-multiplayer/SKILL.md +26 -18
  130. package/skills/performance/tune-performance/SKILL.md +51 -32
  131. package/skills/rendering-and-lighting/3d-lighting/SKILL.md +34 -5
  132. package/skills/rendering-and-lighting/art-direction/SKILL.md +6 -8
  133. package/skills/scene-and-project/brainstorm-game/SKILL.md +7 -9
  134. package/skills/scene-and-project/make-game/SKILL.md +2 -1
  135. package/skills/scene-and-project/play/SKILL.md +10 -4
  136. package/skills/scene-and-project/scene-composition/SKILL.md +21 -8
  137. package/skills/scene-and-project/summer-cloud/SKILL.md +92 -0
  138. package/skills/scripting-patterns/gdscript-patterns/SKILL.md +1 -1
  139. package/skills/ui-and-ux/ui-basics/SKILL.md +16 -7
  140. package/skills/video/animated-loop/SKILL.md +63 -39
  141. package/skills/video/cinematic-cutscene/SKILL.md +66 -30
  142. package/skills/video/trailer-shot/SKILL.md +30 -21
  143. package/skills/visual-effects/_building-blocks/additive-billboard-particles.md +25 -16
  144. package/skills/visual-effects/_building-blocks/trauma-shake-snippet.md +5 -3
  145. package/skills/visual-effects/game-feel/SKILL.md +51 -33
  146. package/skills/visual-effects/recipes/dissolve/SKILL.md +51 -9
  147. package/skills/visual-effects/recipes/fire/SKILL.md +136 -49
  148. package/skills/visual-effects/recipes/hit-spark/SKILL.md +45 -8
  149. package/skills/visual-effects/recipes/lightning/SKILL.md +59 -27
  150. package/skills/visual-effects/recipes/magic-glow/SKILL.md +59 -26
  151. package/skills/visual-effects/recipes/muzzle-flash/SKILL.md +68 -25
  152. package/skills/visual-effects/recipes/smoke/SKILL.md +89 -28
  153. package/skills/visual-effects/recipes/water-ripple/SKILL.md +83 -23
  154. package/skills/workflow/brainstorming/SKILL.md +1 -1
  155. package/skills/workflow/debugging-game-feel/SKILL.md +29 -9
  156. package/skills/workflow/diagnosing-perf-regressions/SKILL.md +46 -21
  157. package/skills/workflow/gameskill/SKILL.md +11 -2
  158. package/skills/workflow/headless-scripting/SKILL.md +407 -0
  159. package/skills/workflow/investigating-bugs/SKILL.md +4 -2
  160. package/skills/workflow/mcpupdate/SKILL.md +9 -9
  161. package/skills/workflow/playtesting-a-feature/SKILL.md +94 -21
  162. package/skills/workflow/skill-create/SKILL.md +7 -7
  163. package/skills/workflow/skill-test/SKILL.md +3 -3
  164. package/skills/workflow/using-summer/SKILL.md +32 -3
  165. package/skills/workflow/verification-before-completion/SKILL.md +2 -0
  166. package/skills/workflow/writing-plans/SKILL.md +7 -7
  167. package/skills/workflow/writing-skills/SKILL.md +7 -5
  168. package/skills/workflow/writing-skills/testing-skills-with-subagents.md +1 -1
@@ -179,8 +179,13 @@ Identify where the NPC will live (an `Enemies` parent, or directly under World).
179
179
 
180
180
  **Preferred (Summer MCP):**
181
181
 
182
+ Every tool below takes a required `scenePath` naming the exact `res://` scene;
183
+ it is written out on the first line and elided after for readability. Better
184
+ still, send the whole block as one `summer_batch(scenePath=..., ops=[...])` so
185
+ the user can undo the enemy with a single Ctrl+Z.
186
+
182
187
  ```
183
- summer_add_node(parent="./World/Enemies", type="CharacterBody3D", name="Enemy")
188
+ summer_add_node(scenePath="res://main.tscn", parent="./World/Enemies", type="CharacterBody3D", name="Enemy")
184
189
  summer_add_node(parent="./World/Enemies/Enemy", type="CollisionShape3D", name="Body")
185
190
  summer_add_node(parent="./World/Enemies/Enemy", type="MeshInstance3D", name="Mesh")
186
191
  summer_add_node(parent="./World/Enemies/Enemy", type="Area3D", name="Vision")
@@ -190,18 +195,35 @@ summer_set_prop(path="./World/Enemies/Enemy/Sight", key="enabled", value="true")
190
195
  summer_set_prop(path="./World/Enemies/Enemy/Sight", key="target_position", value="Vector3(0, 0, -12)")
191
196
  ```
192
197
 
193
- Save the Vision sphere as standalone `.tres` (do NOT inline sub_resource — see `references/mcp-tools-reference.md` § "Trap"):
198
+ Give the Vision area its sphere. Either form works — a class-name string embeds
199
+ the resource in the scene, a `res://` path reuses a shared one. Prefer the shared
200
+ `.tres` when several enemy archetypes want the same sight radius:
194
201
 
195
202
  ```
196
- summer_set_prop(path="./World/Enemies/Enemy/Vision/VisionShape", key="shape", value="res://shapes/vision_sphere.tres")
203
+ summer_set_prop(scenePath="res://main.tscn", path="./World/Enemies/Enemy/Vision/VisionShape", key="shape", value="res://shapes/vision_sphere.tres")
204
+ # or, embedded, then tune it:
205
+ summer_set_prop(scenePath="res://main.tscn", path="./World/Enemies/Enemy/Vision/VisionShape", key="shape", value="SphereShape3D")
206
+ summer_set_resource_property(scenePath="res://main.tscn", nodePath="./World/Enemies/Enemy/Vision/VisionShape", resourceProperty="shape", subProperty="radius", value="12.0")
197
207
  ```
198
208
 
209
+ `summer_set_resource_property` works against scene-embedded (`[sub_resource]`)
210
+ resources exactly as it does against external `.tres` files — it reads the
211
+ property off the node and writes the sub-property onto whatever Resource is
212
+ there. Its only failures are explicit errors (`node not found`, `property is not
213
+ a resource`, `resource is null`). The order that matters is: assign the resource
214
+ first, then set sub-properties.
215
+
199
216
  Connect signals:
200
217
 
201
218
  ```
202
- summer_connect_signal(from="./World/Enemies/Enemy/Vision", signal="body_entered", to="./World/Enemies/Enemy", method="_on_body_entered")
219
+ summer_connect_signal(scenePath="res://main.tscn", emitter="./World/Enemies/Enemy/Vision", signal="body_entered", receiver="./World/Enemies/Enemy", method="_on_body_entered")
203
220
  ```
204
221
 
222
+ The parameters are `scenePath`, `emitter`, `signal`, `receiver`, `method`. There
223
+ is no `from` / `to`; those spellings fail schema validation. The same required
224
+ `scenePath` applies to `summer_add_node`, `summer_set_prop` and
225
+ `summer_save_scene` in the block above.
226
+
205
227
  **Fallback (no MCP):** write the scene as `.tscn` text. Ask the user to paste their existing scene first, then propose a unified diff.
206
228
 
207
229
  ### 7. Drop the script
@@ -418,8 +440,8 @@ Set base values via `@export` in the scene's inspector, not hard-coded in script
418
440
  ### 9. Verify
419
441
 
420
442
  ```
421
- summer_save_scene
422
- summer_get_script_errors
443
+ summer_save_scene(scenePath="res://main.tscn")
444
+ summer_get_script_errors(path="res://scripts/enemy_ai.gd") # one file per call; path required
423
445
  summer_play
424
446
  # user tests
425
447
  summer_stop
@@ -427,7 +449,7 @@ summer_stop
427
449
 
428
450
  If the enemy doesn't aggro, common causes:
429
451
  - Player isn't in `player` group.
430
- - Vision Area3D's sphere shape is inline sub_resource (silent fail).
452
+ - Vision Area3D's `shape` was never assigned, so its radius writes errored with `resource is null`.
431
453
  - Sight RayCast3D `enabled = false` or `collide_with_areas = true` blocking on its own Vision area.
432
454
  - Personality jitter pushed `aggression` close to 0 — check inspector values.
433
455
 
@@ -446,7 +468,7 @@ If the enemy doesn't aggro, common causes:
446
468
  | `distance_to` in `_physics_process` | `distance_squared_to` for comparisons | Square root costs at scale |
447
469
  | Same animation in all states | Distinct anim per action state | The state machine is invisible; animation makes it visible |
448
470
  | `queue_free()` instantly on death | Death anim → 2 sec → free | Instant despawn breaks immersion + skips loot drops |
449
- | Inline SphereShape3D for Vision Area3D | Standalone `.tres` | Inline sub_resources break SetResourceProperty |
471
+ | Setting `shape`'s radius before `shape` holds a resource | Assign the shape, then set sub-properties | `SetResourceProperty` errors with `resource is null` when the property is empty |
450
472
  | 100+ enemies with full FSM | Wave-mob archetype (no intent layer, single KILL intent) | Cheap mobs need cheap brains |
451
473
  | No `died` / `ally_defeated` signals | Emit both | Gameplay + squad logic both need hooks |
452
474
 
@@ -460,7 +482,7 @@ If the enemy doesn't aggro, common causes:
460
482
 
461
483
  ## Collaborative protocol
462
484
 
463
- This skill writes scenes and scripts. Always ask before each step. Group related writes into one ask. See `references/collaborative-protocol.md`.
485
+ This skill writes scenes and scripts. Always ask before each step. Group related writes into one ask.
464
486
 
465
487
  ## Want a working starter?
466
488
 
@@ -471,10 +493,6 @@ For a fully-rigged enemy with anim controller + loot drop:
471
493
 
472
494
  ## See also
473
495
 
474
- - `references/mcp-tools-reference.md` — full MCP tool list
475
- - `references/godot-version.md` — Godot 4.5 API notes
476
- - `references/collaborative-protocol.md` — "May I write" pattern
477
- - `references/gd-style.md` — typed GDScript conventions
478
496
  - `ai-and-npcs/state-machine-npc/SKILL.md` — FSM pattern deep dive
479
497
  - `ai-and-npcs/behavior-trees/SKILL.md` — when complexity demands a BT
480
498
  - `ai-and-npcs/perception-sight-and-hearing/SKILL.md` — sensor patterns
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: animation-tree
3
- description: Use when the user has clips on a character and needs them to play in response to gameplay — idle/walk/run blend, attacks that interrupt locomotion, hit reactions that override everything. Designs and wires AnimationTree state machines and blend trees in Godot 4.5. Trigger on "AnimationTree", "state machine", "blend tree", "transition", "play animation when", "character keeps T-posing", "wire animations".
3
+ description: Use when the user has clips on a character and needs them to play in response to gameplay — idle/walk/run blend, attacks that interrupt locomotion, hit reactions that override everything. Designs and wires Summer Engine AnimationTree state machines and blend trees. Trigger on "AnimationTree", "state machine", "blend tree", "transition", "play animation when", "character keeps T-posing", "wire animations".
4
4
  license: MIT
5
5
  compatibility: [Cursor, Claude Code, Windsurf, Codex]
6
6
  category: animation
@@ -13,7 +13,7 @@ paths: ["**/*.gd", "**/*.tscn", "**/*.tres"]
13
13
 
14
14
  Generation gives you clips. The AnimationTree gives the character life. This skill is **not generative** — no FAL, no MCP AI calls. It composes existing clips on an `AnimationPlayer` into an `AnimationTree` with a `StateMachine` for distinct states (idle / attack / hit / dead) and `BlendSpace` nodes for continuous parameters (walk-run blend by speed). Done right, the character moves like a shipped game; done wrong, you get T-poses, snapping, or animations that "eat" each other.
15
15
 
16
- The canonical Godot 4.5 stack:
16
+ The canonical Summer Engine stack:
17
17
 
18
18
  ```
19
19
  Character (CharacterBody3D)
@@ -79,18 +79,27 @@ Confirm there's a `Skeleton3D` and an `AnimationPlayer` with at least `idle` + `
79
79
  ### 2. Add the AnimationTree
80
80
 
81
81
  ```
82
- summer_add_node(parent: "./World/Goblin", type: "AnimationTree", name: "AnimationTree")
83
- summer_set_prop(path: "./World/Goblin/AnimationTree", key: "anim_player", value: "../AnimationPlayer")
84
- summer_set_prop(path: "./World/Goblin/AnimationTree", key: "active", value: "true")
82
+ summer_add_node(scenePath: "res://main.tscn", parent: "./World/Goblin", type: "AnimationTree", name: "AnimationTree")
83
+ summer_set_prop(scenePath: "res://main.tscn", path: "./World/Goblin/AnimationTree", key: "anim_player", value: "../AnimationPlayer")
84
+ summer_set_prop(scenePath: "res://main.tscn", path: "./World/Goblin/AnimationTree", key: "active", value: "true")
85
85
  ```
86
86
 
87
+ `scenePath` is a **required** argument on every scene-mutating tool
88
+ (`summer_add_node`, `summer_set_prop`, `summer_set_resource_property`,
89
+ `summer_connect_signal`, `summer_save_scene`, `summer_instantiate_scene`,
90
+ `summer_remove_node`, `summer_replace_node`). Omit it and the call is rejected
91
+ before it reaches the engine. Get the path from `summer_get_project_context`.
92
+
87
93
  `anim_player` must be a relative NodePath; `../AnimationPlayer` from a sibling. Don't use absolute paths — breaks scene reuse.
88
94
 
89
95
  ### 3. Build the tree resource
90
96
 
91
97
  The `tree_root` is a single `AnimationNodeStateMachine`. Inside it, a `Locomotion` node which is itself an `AnimationNodeBlendSpace1D`, plus `Attack`, `Hit`, `Dead` nodes.
92
98
 
93
- This is more readable to edit by hand or in the Godot editor, then commit the `.tres`. The MCP tool `summer_set_resource_property` can build it node-by-node, but the tree-resource model is verbose enough that **writing the `.tres` and importing it is faster** for the canonical structure. Skeleton:
99
+ This is more readable to edit by hand or in Summer Engine, then commit the
100
+ `.tres`. The MCP tool `summer_set_resource_property` can build it node-by-node,
101
+ but the tree-resource model is verbose enough that **writing the `.tres` and
102
+ importing it is faster** for the canonical structure. Skeleton:
94
103
 
95
104
  ```
96
105
  [gd_resource type="AnimationNodeStateMachine" load_steps=8 format=3]
@@ -164,22 +173,29 @@ func die() -> void:
164
173
 
165
174
  ```
166
175
  summer_connect_signal(
167
- source: "./World/Goblin",
176
+ scenePath: "res://main.tscn",
177
+ emitter: "./World/Goblin",
168
178
  signal: "damaged",
169
- target: "./World/Goblin",
179
+ receiver: "./World/Goblin",
170
180
  method: "take_hit"
171
181
  )
172
182
  ```
173
183
 
184
+ The parameters are `emitter` and `receiver` — not `source`/`target`, not
185
+ `from`/`to`. Those spellings fail schema validation.
186
+
174
187
  If the goblin has an HP component emitting `died`, connect that to `die`.
175
188
 
176
189
  ### 6. Save & verify
177
190
 
178
191
  ```
179
- summer_save_scene
180
- summer_get_script_errors
192
+ summer_save_scene(scenePath: "res://main.tscn")
193
+ summer_get_script_errors(path: "res://scripts/goblin.gd")
181
194
  ```
182
195
 
196
+ `summer_get_script_errors` checks **one** file and requires `path`; there is no
197
+ "check everything" form. For a project-wide sweep use `summer_get_diagnostics`.
198
+
183
199
  Then `summer_play` and watch — the goblin should idle in place, blend up to walk/run as it moves, fire attack on input/AI, snap to hit on damage, end in Dead.
184
200
 
185
201
  ## Confirmation gates
@@ -190,7 +206,7 @@ Then `summer_play` and watch — the goblin should idle in place, blend up to wa
190
206
 
191
207
  ## Reference card
192
208
 
193
- ### Parameter paths cheat-sheet (Godot 4.5)
209
+ ### Parameter paths cheat-sheet
194
210
 
195
211
  | Goal | Path |
196
212
  |---|---|
@@ -216,7 +232,13 @@ Then `summer_play` and watch — the goblin should idle in place, blend up to wa
216
232
  - **Walk-to-run pops.** Transition `switch_mode` is `Immediate`. Set to `Sync` so the cycle phase matches across the crossfade.
217
233
  - **Attack one-shot fires every frame as long as input is held.** Use `Input.is_action_just_pressed`, not `is_action_pressed`. Or store a `_can_attack` flag with cooldown.
218
234
  - **Hit reaction interrupts itself when hit twice in 100ms.** Set `fadein_time = 0.0` and gate from script: `if sm.get_current_node() == "Hit": return`.
219
- - **Attack plays but locomotion is invisible (lower body T-pose).** OneShot's `mix_mode` is `BLEND` (full body). For upper-body-only attacks, set `mix_mode = ADD` and use an additive clip (recorded as the offset from idle), or split the rig with a SkeletonModification3D mask.
235
+ - **Attack plays but locomotion is invisible (lower body T-pose).** OneShot's
236
+ `mix_mode` is `BLEND` (full body). For upper-body-only attacks, set
237
+ `mix_mode = ADD` and use an additive clip, or drive the lower body from a
238
+ second `AnimationTree` branch and blend by bone with an
239
+ `AnimationNodeBlend2` plus filters. `SkeletonModification3D` is an old
240
+ upstream class name and `ClassDB.class_exists("SkeletonModification3D")`
241
+ returns false on the current Summer build.
220
242
  - **Dead state replays from start every time HP < 0.** Add a guard in the controller: `if is_dead: return`.
221
243
 
222
244
  ### One-shot vs StateMachine — which to use
@@ -245,7 +267,11 @@ Then `summer_play` and watch — the goblin should idle in place, blend up to wa
245
267
 
246
268
  ## Fallback (no MCP)
247
269
 
248
- Open the scene in Godot 4.5 editor, add `AnimationTree` node, set `Anim Player` to the AnimationPlayer, set `Active = on`, double-click `Tree Root` and edit visually. Drag `AnimationNodeStateMachine` as the root, drop nodes inside, draw transitions by Shift-dragging. Save the scene. The visual editor produces the same `.tres` — slower but discoverable.
270
+ Open the scene in Summer Engine, add an `AnimationTree` node, set `Anim Player`
271
+ to the AnimationPlayer, set `Active = on`, double-click `Tree Root`, and edit
272
+ visually. Drag `AnimationNodeStateMachine` as the root, drop nodes inside, draw
273
+ transitions by Shift-dragging, and save the scene. The visual editor produces
274
+ the same `.tres`; it is slower but discoverable.
249
275
 
250
276
  ## Handoff
251
277
 
@@ -258,5 +284,3 @@ Open the scene in Godot 4.5 editor, add `AnimationTree` node, set `Anim Player`
258
284
 
259
285
  - `summer:animation/generate-motion` — produce the clips this tree references.
260
286
  - `summer:animation/retarget` — share one tree across many characters.
261
- - `references/gd-style.md` — typed GDScript conventions in the controller snippets.
262
- - `references/mcp-tools-reference.md` — `summer_connect_signal` and `summer_set_resource_property` rules.
@@ -26,7 +26,7 @@ The 2026 production stack:
26
26
  - NPC has voice lines and the mouth doesn't move.
27
27
  - Cinematic with VO that needs lipsync.
28
28
  - "Make him sing the lyrics."
29
- - Animating expressions on a face that has BlendShapes (Meshy character heads ship with the ARKit-52 set by default).
29
+ - Animating expressions on a face that has BlendShapes. Never assume it does — step 1 below is the check, and generated characters frequently come back with zero.
30
30
  - Reactive face: smile when player gives gold, scowl when attacked.
31
31
 
32
32
  ## When NOT to use this skill
@@ -43,11 +43,16 @@ The 2026 production stack:
43
43
  summer_inspect_node "./World/NPC/Head" # or wherever the head MeshInstance3D lives
44
44
  ```
45
45
 
46
- Look for `mesh.blend_shape_count` > 0 and a list of names. The Meshy ARKit-52 set (default for Meshy character heads) has names like `jawOpen`, `mouthClose`, `mouthFunnel`, `mouthPucker`, `mouthLeft`, `mouthRight`, `mouthSmile_L`, `mouthSmile_R`, `mouthFrown_L`, `mouthFrown_R`, `browInnerUp`, `browOuterUp_L`, `browDown_L`, `eyeBlink_L`, `eyeWide_L`, `eyeSquint_L` (mirrored on R).
46
+ Look for `mesh.blend_shape_count` > 0 and a list of names. An ARKit-52 head has names like `jawOpen`, `mouthClose`, `mouthFunnel`, `mouthPucker`, `mouthLeft`, `mouthRight`, `mouthSmile_L`, `mouthSmile_R`, `mouthFrown_L`, `mouthFrown_R`, `browInnerUp`, `browOuterUp_L`, `browDown_L`, `eyeBlink_L`, `eyeWide_L`, `eyeSquint_L` (mirrored on R).
47
47
 
48
- If the head has zero BlendShapes, stop. Tell the user: "This head mesh has no BlendShapes — facial animation is impossible without re-meshing. Options: regenerate the character with the `face_blendshapes: arkit` option (`summer_generate_3d({ kind: \"image-to-3d\", options: { rig: true, face_blendshapes: \"arkit\" } })`), use an emotional body-language overlay instead, or hand off the character to a 3D artist for shape-key authoring." Don't proceed.
48
+ If the head has zero BlendShapes, stop. Tell the user: "This head mesh has no BlendShapes — facial animation needs shape keys on the mesh. Options: use an emotional body-language overlay instead, author shape keys in Blender and re-import, or hand the character to a 3D artist." Don't proceed.
49
49
 
50
- Note: the `face_blendshapes` option is a Meshy passthrough; if your target backend doesn't support it, the rig will use the default skeleton — adjust manually in the Meshy dashboard.
50
+ Do **not** promise a `face_blendshapes` generation option. `summer_generate_3d`
51
+ has no such parameter and nothing in the Summer generation pipeline handles one
52
+ — `options` is an untyped passthrough, so a bogus key is accepted by the schema
53
+ and then silently ignored by the backend. Regenerating will not add BlendShapes.
54
+ Shape keys come from the mesh author (Blender / an ARKit-52 source mesh), not
55
+ from a rig pass.
51
56
 
52
57
  ### 2. Get the audio
53
58
 
@@ -121,7 +126,9 @@ Cost: Rhubarb is free + ~5s CPU per 30s clip locally. Cloud fallback ~$0.02 / mi
121
126
 
122
127
  ### 4. Persist the viseme track as an AnimationLibrary entry
123
128
 
124
- Convert Rhubarb's `mouthCues` into a Godot Animation resource — one track per BlendShape, keyframes at each viseme transition. This makes lipsync replayable via the same AnimationPlayer/AnimationTree as body motion.
129
+ Convert Rhubarb's `mouthCues` into a Summer Engine Animation resource: one
130
+ track per BlendShape with keyframes at each viseme transition. This makes lip
131
+ sync replayable through the same AnimationPlayer/AnimationTree as body motion.
125
132
 
126
133
  ```gdscript
127
134
  # scripts/lipsync_baker.gd — run once per VO line at edit time
@@ -156,6 +163,14 @@ static func bake_from_rhubarb(rhubarb_json_path: String, head_path: NodePath) ->
156
163
 
157
164
  Bake once, save into the character's AnimationLibrary as `dialogue_<line_id>`, and play via the AnimationTree.
158
165
 
166
+ This is a plain `Animation` resource authored in code — no editor required.
167
+ `Animation.new()` + `add_track()` + `track_set_path()` + `track_insert_key()` +
168
+ `ResourceSaver.save()` works from a headless `-s` script and the resource
169
+ reloads with every track and track type intact (verified on the shipped 4.6.1
170
+ binary with value, blend-shape and method tracks in one resource). Any advice
171
+ that says animation tracks or keyframes can only be authored in the editor GUI
172
+ is wrong.
173
+
159
174
  If you used the Whisper/ARPAbet cloud fallback instead of Rhubarb, swap `bake_from_rhubarb` for a variant that consumes `{ phoneme, start, duration }` triples and applies the ARPAbet → viseme table from the Reference card.
160
175
 
161
176
  ### 5. Wire into the AnimationTree
@@ -234,7 +249,7 @@ If the user has a CMUDict-style phoneme list and wants to map manually, this is
234
249
 
235
250
  - **Mouth never closes between words.** No `viseme_sil` keyframes at silence intervals. The bake step must scan the audio for silence (RMS below threshold for 100ms+) and insert sil keys, OR the phoneme extractor must emit silence markers. Rhubarb emits `X` cues for silence (mapped above to `viseme_sil`); cloud Whisper-phoneme models often don't — add a silence-detection pass if you go that route.
236
251
  - **Lipsync drifts behind audio.** Audio playback latency on some platforms is 30–60ms. Either delay the audio start by 1 frame, or pre-shift the animation by the platform's known latency. On desktop Linux audio output can be 60ms behind; on Steam Deck ~20ms.
237
- - **Visemes pop on/off.** Crossfade between viseme keyframes — set `Animation.TRACK_INTERPOLATION_LINEAR` (default) and ensure each viseme's weight ramps from previous to current. Default bake does this; if you wrote custom keyframes with NEAREST interp, switch.
252
+ - **Visemes pop on/off.** Crossfade between viseme keyframes — the constant is `Animation.INTERPOLATION_LINEAR` (there is no `TRACK_INTERPOLATION_LINEAR`; the real set is `INTERPOLATION_NEAREST` / `_LINEAR` / `_CUBIC` / `_LINEAR_ANGLE` / `_CUBIC_ANGLE`). Apply it per track with `anim.track_set_interpolation_type(idx, Animation.INTERPOLATION_LINEAR)` and ensure each viseme's weight ramps from previous to current. Default bake does this; if you wrote custom keyframes with NEAREST interp, switch.
238
253
  - **Smile fights lipsync.** Both write to mouth BlendShapes. Solve by additive layering: lipsync layer outputs deltas from neutral, smile layer outputs deltas from neutral, sum them, clamp 0..1. ARKit shapes are sum-safe up to ~1.5; clamp prevents over-rotation.
239
254
  - **Eyes look dead.** Lipsync is mouth-only; without blinks and saccades the face is uncanny. Add an idle blink track (every 4–8s, jittered) and a small saccade track (random eye movement up to 5°). Both can be one-shots fired by a `Timer`.
240
255
  - **Phoneme extraction returns gibberish.** Audio is too noisy, mismatched language code, or compressed too aggressively. Re-export the source as 22kHz mono WAV before sending. Don't lipsync from a 64kbps MP3.
@@ -263,7 +278,10 @@ If the user has a CMUDict-style phoneme list and wants to map manually, this is
263
278
 
264
279
  If Rhubarb won't install on the user's platform, run a Whisper-phoneme model on Replicate (e.g., `cjwbw/whisper-phoneme`) or `aeneas-align` for forced alignment. Download the JSON, swap the bake function for one that consumes ARPAbet phonemes (table in Reference card). Same end result — replayable BlendShape Animation resource.
265
280
 
266
- For projects that can't use any cloud or third-party tool, Godot 4.5's `AudioStreamGenerator` with hand-rolled vowel/consonant detection from RMS + zero-crossings gives ~50% accuracy — enough for a stylized character but not photoreal.
281
+ For projects that cannot use any cloud or third-party tool, Summer Engine's
282
+ `AudioStreamGenerator` with hand-rolled vowel/consonant detection from RMS and
283
+ zero-crossings gives only a rough stylized approximation. Do not present it as
284
+ production speech recognition or photoreal lip sync.
267
285
 
268
286
  ## Handoff
269
287
 
@@ -278,5 +296,4 @@ For projects that can't use any cloud or third-party tool, Godot 4.5's `AudioStr
278
296
  - `summer:audio/generate-voice` — TTS upstream of this skill.
279
297
  - `summer:animation/animation-tree` — wire the lipsync OneShot into the character's tree.
280
298
  - `summer:animation/procedural-animation` — eye blinks, saccades, head idle.
281
- - `references/mcp-tools-reference.md` — `summer_generate_audio` schema (TTS).
282
299
  - Rhubarb Lip Sync — https://github.com/DanielSWolf/rhubarb-lip-sync (external tool; phoneme extraction).
@@ -11,11 +11,14 @@ paths: ["**/*.tscn", "**/*.tres", "**/*.gd"]
11
11
 
12
12
  # Generate Motion — Curated Meshy Library
13
13
 
14
- Picks a clip from a **curated mocap library** by name (`idle`, `walk`, `run`, `attack_sword`, ~70 standard names) and wires it onto a Meshy-rigged humanoid. Fast (~30s) and cheap (~$0.10) and looks great because it's real mocap.
14
+ Picks a clip from a **curated mocap library** by name and wires it onto a Meshy-rigged humanoid. Fast (~30s) and cheap (~$0.10) and looks great because it's real mocap. The five short aliases that always work are `idle`, `walk`, `run`, `jump`, `attack`; anything else must be an exact library name — see the Reference card before you invent one.
15
15
 
16
16
  The target must be a **Meshy-rigged humanoid** — a `rigAssetId` from a prior `summer_generate_3d({ kind: "image-to-3d", imageUrl: "...", options: { rig: true } })` call. The result job includes `rigAssetId`. If the user points at a non-rigged mesh, stop and route to `summer:asset-pipeline/asset-strategy` (or directly call `summer_generate_3d` with `options.rig: true`) before generating motion.
17
17
 
18
- > **Custom prompt-driven motion** (e.g. "drops to one knee, draws bow") is on the roadmap but not shipped yet. For one-off signature moves not on the curated list, fall back to hand-authoring in the Godot editor or importing from Mixamo. See the Edge cases section.
18
+ > **Custom prompt-driven motion** (e.g. "drops to one knee, draws bow") is on
19
+ > the roadmap but not shipped yet. For one-off signature moves not on the
20
+ > curated list, fall back to hand-authoring in Summer Engine or importing from
21
+ > Mixamo. See the Edge cases section.
19
22
 
20
23
  ## Web Chat / Public Orchestrator Equivalent
21
24
 
@@ -73,8 +76,9 @@ summer_generate_motion(
73
76
  )
74
77
  ```
75
78
 
76
- Returns `animationAssetId`, `durationSeconds`, and `previewUrl`. Resolve the
77
- asset before handoff so you have the stable file/download metadata:
79
+ With the default `wait: true` the tool polls to completion and returns the job
80
+ result with `animationAssetId` in it. Don't assume any other field is present —
81
+ resolve the asset to get stable file/download metadata:
78
82
 
79
83
  ```
80
84
  summer_get_asset(assetId="<animationAssetId>")
@@ -83,17 +87,22 @@ summer_get_asset(assetId="<animationAssetId>")
83
87
  ### 4. Attach to the character's AnimationPlayer
84
88
 
85
89
  ```
86
- summer_inspect_node("./World/Goblin") // confirm it has an AnimationPlayer child
87
- summer_add_node(parent="./World/Goblin", type="AnimationPlayer", name="AnimationPlayer") // only if missing
90
+ summer_inspect_node(path="./World/Goblin") // confirm it has an AnimationPlayer child
91
+ summer_add_node(scenePath="res://main.tscn", parent="./World/Goblin", type="AnimationPlayer", name="AnimationPlayer") // only if missing
88
92
  summer_set_resource_property(
93
+ scenePath="res://main.tscn",
89
94
  nodePath="./World/Goblin/AnimationPlayer",
90
95
  resourceProperty="libraries/default",
91
96
  subProperty="<motion_name>",
92
97
  value="<animationAssetId>"
93
98
  )
94
- summer_save_scene
99
+ summer_save_scene(scenePath="res://main.tscn")
95
100
  ```
96
101
 
102
+ `scenePath` is required on `summer_add_node`, `summer_set_resource_property` and
103
+ `summer_save_scene`. `summer_inspect_node` takes only `path` — it has no
104
+ `scenePath` and reads the currently-edited scene.
105
+
97
106
  If the character will use multiple clips, leave the AnimationPlayer in place — every subsequent generation appends to the same library. State-machine wiring belongs to `summer:animation/animation-tree`, not here.
98
107
 
99
108
  ## Confirmation gates
@@ -104,16 +113,34 @@ If the character will use multiple clips, leave the AnimationPlayer in place —
104
113
 
105
114
  ## Reference card
106
115
 
107
- ### Curated motion library — top 30 names (Meshy, exact strings)
116
+ ### Curated motion library — what `motionName` actually accepts
117
+
118
+ There are **five** short canonical aliases, and only five:
119
+
120
+ `idle`, `walk`, `run`, `jump`, `attack`
121
+
122
+ Everything else must be an **exact raw Meshy library name** (or its display name,
123
+ or its numeric action id 0–696). The library is 678 entries, and its naming is
124
+ nothing like a tidy snake_case scheme — real names look like `Walking_Woman`,
125
+ `Jump_Run`, `Run_02`, `Hit_Reaction`, `Roll_Dodge`, `Block1`, `Dead`,
126
+ `Stand_Dodge`, `Triple_Combo_Attack`, `Wave_One_Hand`, `Chair_Sit_Idle_F`,
127
+ `Lean_Forward_Sprint`.
108
128
 
109
- `idle`, `idle_alert`, `idle_combat`, `walk`, `walk_strafe_left`, `walk_strafe_right`, `walk_back`, `run`, `run_strafe_left`, `run_strafe_right`, `sprint`, `jump`, `jump_loop`, `jump_land`, `crouch_idle`, `crouch_walk`, `attack_sword`, `attack_punch`, `attack_kick`, `attack_bow`, `attack_cast`, `block`, `dodge_left`, `dodge_right`, `hit_react`, `death`, `death_back`, `wave`, `dance`, `sit_idle`.
129
+ Plausible-looking names that do **not** resolve, verified against the resolver:
130
+ `attack_sword`, `hit_react`, `death`, `sprint`, `block`, `dodge_left`,
131
+ `crouch_idle`, `walk_back`, `run_strafe_left`, `jump_land`, `idle_combat`,
132
+ `wave`, `dance`, `sit_idle`. They return `null` and the call errors. The tool's
133
+ own description uses `attack_sword` as an example — that example is wrong; use
134
+ `attack`.
110
135
 
111
- The full list is ~70 names. If the user asks for something not on the top-30, try the closest curated name first; if nothing fits, route to the manual-authoring fallback.
136
+ So: if the user asks for something outside the five aliases, do not guess a
137
+ snake_case name. Either use one of the five, quote an exact raw library name you
138
+ have actually seen, or route to the manual-authoring fallback.
112
139
 
113
140
  ### Pitfalls
114
141
 
115
- - **`motionName` typos silently match nothing.** `"run_fast"` is not on the list — the call returns an error. Always check the curated list first. Use exact strings from the list above.
116
- - **Locomotion clips have a forward bias.** Meshy's `run` translates the root forward by ~5m. If you're driving root motion in code, set `root_motion_track` correctly or strip the translation in an AnimationPlayer Edit. See the Godot 4.5 root motion docs.
142
+ - **Invented `motionName` strings fail.** `"run_fast"`, `"attack_sword"`, `"death"` all resolve to nothing and the call errors. Name resolution is exact — five aliases, or a real library name / display name / numeric id. Do not extrapolate a naming scheme.
143
+ - **Locomotion clips have a forward bias.** Meshy's `run` translates the root forward by ~5m. If you're driving root motion in code, set `root_motion_track` correctly or strip the translation in an AnimationPlayer Edit. Check the upstream root-motion API reference matching the current Summer technical base.
117
144
  - **Rig pose mismatch.** If your rig was rigged with a non-T-pose reference image, the limbs may bend wrong. Re-rig from a T-pose mannequin (see `summer:asset-pipeline/asset-strategy`) before re-generating.
118
145
  - **Rig still preparing.** New rigs need ~3 minutes after the rig job completes before the animation library is ready. The MCP route returns 425 "animations_preparing" if you call too early. Wait and retry.
119
146
 
@@ -126,14 +153,20 @@ The full list is ~70 names. If the user asks for something not on the top-30, tr
126
153
 
127
154
  ## Edge cases
128
155
 
129
- - **Custom signature move** (e.g. "drops to one knee, draws bow"). The custom prompt-driven backend is on the roadmap but not shipped today. Workarounds: (a) hand-author the clip in the Godot editor's animation panel; (b) record/buy from Mixamo and import as `AnimationLibrary`; (c) compose two curated clips in an `AnimationTree`'s `OneShot` blend.
156
+ - **Custom signature move** (e.g. "drops to one knee, draws bow"). The custom
157
+ prompt-driven backend is on the roadmap but not shipped today. Workarounds:
158
+ hand-author the clip in Summer Engine's animation panel, import a licensed
159
+ clip as an `AnimationLibrary`, or compose curated clips in an
160
+ `AnimationTree` OneShot blend.
130
161
  - **Quadruped rig.** Meshy library is humanoid-only. For quadrupeds, hand-author or import a Mixamo-style external library (out of scope for this skill).
131
162
  - **Character is < 1m tall (child / dwarf).** Library clips assume a ~1.8m humanoid. Apply the clip; the proportions retarget but stride length looks long. Either accept it or tune `playback_speed` on the AnimationPlayer track.
132
163
  - **Character has wings / tail.** The library ignores the extra bones — they sag. Hand-author additive overlays for the extra bones, or accept the visual hit.
133
164
 
134
165
  ## Fallback (no MCP)
135
166
 
136
- The user can upload to Meshy directly at meshy.ai, generate via the dashboard, download `.glb`, and import as an `AnimationLibrary` in the Godot editor. Slower, but identical output.
167
+ The user can upload to Meshy directly at meshy.ai, generate through the
168
+ dashboard, download `.glb`, and import it as an `AnimationLibrary` in Summer
169
+ Engine.
137
170
 
138
171
  ## Handoff
139
172
 
@@ -144,7 +177,6 @@ The user can upload to Meshy directly at meshy.ai, generate via the dashboard, d
144
177
 
145
178
  ## See also
146
179
 
147
- - `references/mcp-tools-reference.md` — `summer_generate_motion` parameter schema, error codes.
148
180
  - `summer:asset-pipeline/asset-strategy` — how to get a Meshy-rigged character in the first place.
149
181
  - `summer:animation/animation-tree` — wire the generated clips into a state machine.
150
182
  - `summer:animation/retarget` — re-use one library across many characters without regenerating.
@@ -11,9 +11,12 @@ paths: ["**/*.gd", "**/*.tscn", "**/*.tres"]
11
11
 
12
12
  # Procedural Animation — Bones Driven by Code
13
13
 
14
- Generated clips give you 80% of a character. The remaining 20% — the eye contact when an NPC speaks, feet that plant on slopes, hands that wrap a sword grip, the lean into a sprint, the recoil from a hit on the left shoulder — is procedural. In Godot 4.5 this is done via the `SkeletonModifier3D` family attached to the `Skeleton3D`, plus tween-driven additive blend layers on the `AnimationTree`. None of it is generative; this skill is a recipe set.
14
+ Generated clips give you 80% of a character. The remaining 20% — the eye contact when an NPC speaks, feet that plant on slopes, hands that wrap a sword grip, the lean into a sprint, the recoil from a hit on the left shoulder — is procedural. In Summer Engine this is done via the `SkeletonModifier3D` family attached to the `Skeleton3D`, plus tween-driven additive blend layers on the `AnimationTree`. None of it is generative; this skill is a recipe set.
15
15
 
16
- Honest limit: Godot 4.5's IK is good enough for look-at, foot-snap, and simple two-bone arm/leg chains. It is NOT good enough for full-body IK with weight redistribution (a la UE5 Control Rig). For combat-grappling or contact-heavy interactions, hand-author the contact frame and accept some clipping.
16
+ Honest limit: Summer Engine's current IK is good enough for look-at, foot-snap,
17
+ and simple two-bone arm/leg chains. It is not a full-body IK system with weight
18
+ redistribution. For combat-grappling or contact-heavy interactions, hand-author
19
+ the contact frame and accept some clipping.
17
20
 
18
21
  ## When to use this skill
19
22
 
@@ -60,10 +63,21 @@ summer_set_prop "./World/NPC/Skeleton3D/HeadLookAt" key="bone_name" value="Head"
60
63
  summer_set_prop "./World/NPC/Skeleton3D/HeadLookAt" key="forward_axis" value=2 # +Z forward (Meshy default)
61
64
  summer_set_prop "./World/NPC/Skeleton3D/HeadLookAt" key="primary_rotation_axis" value=1 # Y-up
62
65
  summer_set_prop "./World/NPC/Skeleton3D/HeadLookAt" key="use_secondary_rotation" value=true
63
- summer_set_prop "./World/NPC/Skeleton3D/HeadLookAt" key="secondary_rotation_axis" value=0
64
- summer_set_prop "./World/NPC/Skeleton3D/HeadLookAt" key="symmetry_limit" value=1.4 # ~80°, prevents the Exorcist
66
+ summer_set_prop "./World/NPC/Skeleton3D/HeadLookAt" key="use_angle_limitation" value=true # OFF by default — nothing clamps until you set this
67
+ summer_set_prop "./World/NPC/Skeleton3D/HeadLookAt" key="symmetry_limitation" value=true # one angle drives both directions
68
+ summer_set_prop "./World/NPC/Skeleton3D/HeadLookAt" key="primary_limit_angle" value=1.4 # ~80°, prevents the Exorcist
69
+ summer_set_prop "./World/NPC/Skeleton3D/HeadLookAt" key="secondary_limit_angle" value=1.0
65
70
  ```
66
71
 
72
+ Every `summer_set_prop` above also needs the required `scenePath` (e.g.
73
+ `scenePath="res://main.tscn"`); the paths are shown bare here for readability.
74
+
75
+ There is no `symmetry_limit` and no `secondary_rotation_axis` property on
76
+ `LookAtModifier3D` — the real names are the ones above, and the secondary
77
+ rotation axis is derived, not set. Confirmed against the shipped 4.6.1 binary;
78
+ `ClassDB.class_get_property_list("LookAtModifier3D")` is the check if you're
79
+ unsure of a name.
80
+
67
81
  Drive the target each frame:
68
82
 
69
83
  ```gdscript
@@ -81,15 +95,17 @@ func _process(_delta: float) -> void:
81
95
  head_look.influence = clamp(1.0 - (dist - 6.0) / 2.0, 0.0, 1.0) # fade out 6→8m
82
96
  ```
83
97
 
84
- The `symmetry_limit` is the production trick — without it, the head can rotate 180° and the model looks possessed. ~80° matches a human's neck-only range; for a "whole-body turn" use it with the spine chain (next recipe).
98
+ `use_angle_limitation` is the production trick, and it defaults to **false** — a stock `LookAtModifier3D` does not clamp at all, so the head can rotate 180° and the model looks possessed. Turn it on and set `primary_limit_angle` to ~80° (1.4 rad), which matches a human's neck-only range; for a "whole-body turn" use it with the spine chain (next recipe). `primary_limit_angle` defaults to 2π, i.e. unlimited.
85
99
 
86
100
  ### A2 — Spine + head chain (look-at with body turn)
87
101
 
88
- Multiple `LookAtModifier3D` nodes on the same chain — one for `Spine1` (limit 0.4 rad), one for `Spine2` (limit 0.4 rad), one for `Head` (limit 1.0 rad). Total reach: ~110°, distributed naturally. Without the spine contribution, big angles look like the head detaches.
102
+ Multiple `LookAtModifier3D` nodes on the same chain — one for `Spine1` (`primary_limit_angle` 0.4 rad), one for `Spine2` (0.4 rad), one for `Head` (1.0 rad), each with `use_angle_limitation = true`. Total reach: ~110°, distributed naturally. Without the spine contribution, big angles look like the head detaches.
89
103
 
90
104
  ### A3 — Foot IK (slopes & uneven terrain)
91
105
 
92
- The clip has the foot at Y=0; on a slope the ground is at Y=0.15. Without IK, foot floats. Use `SkeletonIK3D` (Godot 4.5 legacy IK still works for two-bone chains; the new chain modifier is preferred for production):
106
+ The clip has the foot at Y=0; on a slope the ground is at Y=0.15. Without IK,
107
+ the foot floats. `SkeletonIK3D` remains available for two-bone chains in the
108
+ current Summer technical base; prefer the newer chain modifier for production:
93
109
 
94
110
  ```gdscript
95
111
  @onready var skel: Skeleton3D = $Skeleton3D
@@ -170,7 +186,7 @@ You need PhysicalBone3D children matching every major bone (set up once via the
170
186
 
171
187
  | Setting | Value (Meshy default) |
172
188
  |---|---|
173
- | Forward axis (head/spine) | Z+ |
189
+ | Forward axis (head/spine) | Z+ (`forward_axis`) |
174
190
  | Up axis | Y+ |
175
191
  | Right axis | X+ |
176
192
  | Foot down | Y- |
@@ -187,7 +203,7 @@ You need PhysicalBone3D children matching every major bone (set up once via the
187
203
 
188
204
  ### Pitfalls
189
205
 
190
- - **LookAt rotates wildly past the symmetry_limit.** You set the limit too high. ~80° (1.4 rad) for a head-only modifier; ~25° (0.4 rad) for a single spine bone.
206
+ - **LookAt rotates wildly / no clamp at all.** `use_angle_limitation` is false by default and `primary_limit_angle` defaults to 2π. Set both. ~80° (1.4 rad) for a head-only modifier; ~25° (0.4 rad) for a single spine bone.
191
207
  - **IK pops on the first frame.** Solver hasn't been initialized. Call `ik.start()` after the AnimationTree's first tick, not in `_ready()` — the bone pose is identity until the tree runs.
192
208
  - **Foot IK pushes the body up on stairs but the camera doesn't follow.** Camera is parented to the root, not the head. Either parent the camera to a chest bone via `BoneAttachment3D`, or accept that the camera doesn't bob with foot IK.
193
209
  - **Additive layer doubles the clip.** The "additive" clip wasn't authored as a delta. Re-export from Blender with `Pose Mode → bake additive`.
@@ -217,7 +233,9 @@ You need PhysicalBone3D children matching every major bone (set up once via the
217
233
 
218
234
  ## Fallback (no MCP)
219
235
 
220
- Add modifiers in the Godot editor under Skeleton3D, set bone names from the inspector dropdown (Godot autocompletes from the rig). Hand-write the GDScript driving them. Foot raycasts can be set up visually with a RayCast3D child.
236
+ Add modifiers in Summer Engine under Skeleton3D and set bone names from the
237
+ Inspector dropdown, which autocompletes from the rig. Hand-write the GDScript
238
+ driving them. Foot raycasts can be set up visually with a RayCast3D child.
221
239
 
222
240
  ## Handoff
223
241
 
@@ -229,6 +247,6 @@ Add modifiers in the Godot editor under Skeleton3D, set bone names from the insp
229
247
 
230
248
  ## See also
231
249
 
232
- - `references/gd-style.md` — typed GDScript conventions in the snippets.
233
- - `references/mcp-tools-reference.md` — `summer_set_prop` enum-int conventions for axis settings.
234
- - Godot 4.5 docs: `SkeletonModifier3D`, `LookAtModifier3D`, `SkeletonIK3D`, `PhysicalBoneSimulator3D`.
250
+ - Upstream API reference matching the current Summer technical base:
251
+ `SkeletonModifier3D`, `LookAtModifier3D`, `SkeletonIK3D`,
252
+ `PhysicalBoneSimulator3D`.