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.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +4 -1
- package/.codex-plugin/plugin.json +6 -2
- package/.cursor-plugin/plugin.json +5 -1
- package/.opencode/INSTALL.md +1 -1
- package/.opencode/plugins/summer.js +2 -2
- package/AGENTS.md +11 -7
- package/CHANGELOG.md +40 -0
- package/GEMINI.md +9 -7
- package/README.md +63 -21
- package/_persona/summer/SKILL.md +1 -0
- package/assets/autopilot/README.md +51 -0
- package/assets/autopilot/autopilot.gd +222 -0
- package/assets/autopilot/probe_base.gd +262 -0
- package/assets/autopilot/run.sh +78 -0
- package/commands/gameskill.md +11 -2
- package/commands/summer.md +13 -0
- package/dist/bin/summer.js +12 -0
- package/dist/commands/config.d.ts +2 -0
- package/dist/commands/config.js +53 -0
- package/dist/commands/create.d.ts +1 -0
- package/dist/commands/create.js +38 -6
- package/dist/commands/debug.d.ts +2 -0
- package/dist/commands/debug.js +44 -0
- package/dist/commands/doctor.js +112 -8
- package/dist/commands/list.js +1 -1
- package/dist/commands/login.d.ts +19 -0
- package/dist/commands/login.js +123 -36
- package/dist/commands/logout.js +3 -16
- package/dist/commands/logs.d.ts +2 -0
- package/dist/commands/logs.js +19 -0
- package/dist/commands/mcp.js +7 -2
- package/dist/commands/open.js +1 -1
- package/dist/commands/publish.d.ts +2 -0
- package/dist/commands/publish.js +20 -0
- package/dist/commands/releases.d.ts +2 -0
- package/dist/commands/releases.js +20 -0
- package/dist/commands/run.js +1 -1
- package/dist/commands/skills.js +1 -1
- package/dist/lib/api-client.d.ts +15 -4
- package/dist/lib/api-client.js +138 -13
- package/dist/lib/async-op-lifecycle.d.ts +7 -2
- package/dist/lib/async-op-lifecycle.js +32 -9
- package/dist/lib/auth.d.ts +40 -12
- package/dist/lib/auth.js +173 -37
- package/dist/lib/cloud/engine-bridge.d.ts +17 -4
- package/dist/lib/cloud/engine-bridge.js +32 -6
- package/dist/lib/config.d.ts +20 -0
- package/dist/lib/config.js +142 -0
- package/dist/lib/creator.d.ts +93 -0
- package/dist/lib/creator.js +393 -0
- package/dist/lib/debug-report.d.ts +50 -0
- package/dist/lib/debug-report.js +308 -0
- package/dist/lib/engine.d.ts +35 -2
- package/dist/lib/engine.js +240 -6
- package/dist/lib/game-task-plan.js +4 -4
- package/dist/lib/mcp-boot-notice.d.ts +3 -0
- package/dist/lib/mcp-boot-notice.js +7 -0
- package/dist/lib/mcp-log.d.ts +3 -0
- package/dist/lib/mcp-log.js +72 -0
- package/dist/lib/public-surface-paths.d.ts +13 -0
- package/dist/lib/public-surface-paths.js +42 -0
- package/dist/lib/skills-registry.d.ts +33 -1
- package/dist/lib/skills-registry.js +55 -0
- package/dist/lib/store.d.ts +14 -0
- package/dist/lib/store.js +145 -0
- package/dist/lib/summer-compatibility.d.ts +6 -0
- package/dist/lib/summer-compatibility.js +22 -0
- package/dist/mcp/server.d.ts +10 -3
- package/dist/mcp/server.js +104 -11
- package/dist/mcp/tools/asset-tools.js +33 -12
- package/dist/mcp/tools/cloud-tools.js +15 -15
- package/dist/mcp/tools/creator-tools.d.ts +2 -0
- package/dist/mcp/tools/creator-tools.js +105 -0
- package/dist/mcp/tools/debug-tools.js +44 -1
- package/dist/mcp/tools/file-tools.d.ts +2 -0
- package/dist/mcp/tools/file-tools.js +154 -0
- package/dist/mcp/tools/generate-tools.js +159 -11
- package/dist/mcp/tools/project-tools.js +37 -27
- package/dist/mcp/tools/scene-tools.js +106 -29
- package/dist/mcp/tools/visual-tools.js +4 -3
- package/dist/mcp/tools/with-engine.js +4 -4
- package/hooks/session-start.sh +5 -5
- package/package.json +3 -1
- package/references/collaborative-protocol.md +50 -0
- package/references/gd-style.md +121 -0
- package/references/godot-version.md +51 -0
- package/references/mcp-tools-reference.md +199 -0
- package/references/public-surface-language.md +30 -0
- package/references/summer-folder.md +90 -0
- package/references/template-registry.md +73 -0
- package/skills/2d-assets/character-portrait/SKILL.md +17 -12
- package/skills/2d-assets/concept-art/SKILL.md +10 -9
- package/skills/2d-assets/create-asset-sheet/SKILL.md +17 -15
- package/skills/2d-assets/pixel-art/SKILL.md +36 -20
- package/skills/2d-assets/skybox-panorama/SKILL.md +32 -37
- package/skills/2d-assets/sprite-sheet/SKILL.md +40 -35
- package/skills/2d-assets/tileable-texture/SKILL.md +28 -22
- package/skills/2d-assets/ui-graphics/SKILL.md +46 -32
- package/skills/2d-assets/use-widget-asset/SKILL.md +8 -6
- package/skills/3d-assets/character-model/SKILL.md +34 -19
- package/skills/3d-assets/environment-kit/SKILL.md +11 -5
- package/skills/3d-assets/organic-model/SKILL.md +8 -5
- package/skills/3d-assets/prop-model/SKILL.md +9 -3
- package/skills/3d-assets/vehicle-model/SKILL.md +32 -19
- package/skills/README.md +1 -1
- package/skills/ai-and-npcs/design-npc/SKILL.md +31 -13
- package/skills/animation/animation-tree/SKILL.md +39 -15
- package/skills/animation/facial-and-lipsync/SKILL.md +25 -8
- package/skills/animation/generate-motion/SKILL.md +47 -15
- package/skills/animation/procedural-animation/SKILL.md +31 -13
- package/skills/animation/retarget/SKILL.md +127 -79
- package/skills/audio/adaptive-music/SKILL.md +24 -20
- package/skills/audio/ambient-bed/SKILL.md +22 -16
- package/skills/audio/audio-direction/SKILL.md +15 -10
- package/skills/audio/music-track/SKILL.md +18 -12
- package/skills/audio/sound-effect/SKILL.md +17 -12
- package/skills/audio/voice-line/SKILL.md +42 -42
- package/skills/character-controllers/fps-controller/SKILL.md +26 -16
- package/skills/debugging/debug/SKILL.md +74 -20
- package/skills/deployment/export-and-ship/SKILL.md +105 -38
- package/skills/deployment/remote-deploy/SKILL.md +140 -0
- package/skills/gameplay-mechanics/auto-fire-targeting/SKILL.md +26 -1
- package/skills/gameplay-mechanics/design-mechanic/SKILL.md +23 -15
- package/skills/level-design/design-level/SKILL.md +22 -8
- package/skills/level-design/scene-to-level/SKILL.md +13 -7
- package/skills/multiplayer-and-networking/host-authoritative-state/SKILL.md +8 -8
- package/skills/multiplayer-and-networking/peer-to-peer-multiplayer/SKILL.md +2 -7
- package/skills/multiplayer-and-networking/setup-multiplayer/SKILL.md +26 -18
- package/skills/performance/tune-performance/SKILL.md +51 -32
- package/skills/rendering-and-lighting/3d-lighting/SKILL.md +34 -5
- package/skills/rendering-and-lighting/art-direction/SKILL.md +6 -8
- package/skills/scene-and-project/brainstorm-game/SKILL.md +7 -9
- package/skills/scene-and-project/make-game/SKILL.md +2 -1
- package/skills/scene-and-project/play/SKILL.md +10 -4
- package/skills/scene-and-project/scene-composition/SKILL.md +21 -8
- package/skills/scene-and-project/summer-cloud/SKILL.md +92 -0
- package/skills/scripting-patterns/gdscript-patterns/SKILL.md +1 -1
- package/skills/ui-and-ux/ui-basics/SKILL.md +16 -7
- package/skills/video/animated-loop/SKILL.md +63 -39
- package/skills/video/cinematic-cutscene/SKILL.md +66 -30
- package/skills/video/trailer-shot/SKILL.md +30 -21
- package/skills/visual-effects/_building-blocks/additive-billboard-particles.md +25 -16
- package/skills/visual-effects/_building-blocks/trauma-shake-snippet.md +5 -3
- package/skills/visual-effects/game-feel/SKILL.md +51 -33
- package/skills/visual-effects/recipes/dissolve/SKILL.md +51 -9
- package/skills/visual-effects/recipes/fire/SKILL.md +136 -49
- package/skills/visual-effects/recipes/hit-spark/SKILL.md +45 -8
- package/skills/visual-effects/recipes/lightning/SKILL.md +59 -27
- package/skills/visual-effects/recipes/magic-glow/SKILL.md +59 -26
- package/skills/visual-effects/recipes/muzzle-flash/SKILL.md +68 -25
- package/skills/visual-effects/recipes/smoke/SKILL.md +89 -28
- package/skills/visual-effects/recipes/water-ripple/SKILL.md +83 -23
- package/skills/workflow/brainstorming/SKILL.md +1 -1
- package/skills/workflow/debugging-game-feel/SKILL.md +29 -9
- package/skills/workflow/diagnosing-perf-regressions/SKILL.md +46 -21
- package/skills/workflow/gameskill/SKILL.md +11 -2
- package/skills/workflow/headless-scripting/SKILL.md +407 -0
- package/skills/workflow/investigating-bugs/SKILL.md +4 -2
- package/skills/workflow/mcpupdate/SKILL.md +9 -9
- package/skills/workflow/playtesting-a-feature/SKILL.md +94 -21
- package/skills/workflow/skill-create/SKILL.md +7 -7
- package/skills/workflow/skill-test/SKILL.md +3 -3
- package/skills/workflow/using-summer/SKILL.md +32 -3
- package/skills/workflow/verification-before-completion/SKILL.md +2 -0
- package/skills/workflow/writing-plans/SKILL.md +7 -7
- package/skills/workflow/writing-skills/SKILL.md +7 -5
- 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
|
-
|
|
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(
|
|
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
|
|
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
|
-
|
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
176
|
+
scenePath: "res://main.tscn",
|
|
177
|
+
emitter: "./World/Goblin",
|
|
168
178
|
signal: "damaged",
|
|
169
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
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
|
-
|
|
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
|
|
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 —
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
77
|
-
|
|
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")
|
|
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 —
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
-
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
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:
|
|
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="
|
|
64
|
-
summer_set_prop "./World/NPC/Skeleton3D/HeadLookAt" key="
|
|
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
|
-
|
|
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` (
|
|
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,
|
|
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
|
|
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
|
|
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
|
-
-
|
|
233
|
-
|
|
234
|
-
|
|
250
|
+
- Upstream API reference matching the current Summer technical base:
|
|
251
|
+
`SkeletonModifier3D`, `LookAtModifier3D`, `SkeletonIK3D`,
|
|
252
|
+
`PhysicalBoneSimulator3D`.
|