From summer
Adds runtime bone modification in Godot 4.5 — head look-at, foot IK, hand-grabs-prop, additive lean, hit-direction recoil. Use when clips don't cover foot placement, hand penetration, or dead-eyed NPCs.
How this skill is triggered — by the user, by Claude, or both
Slash command
/summer:procedural-animation**/*.gd**/*.tscn**/*.tresThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
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`....
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.
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.
summer:animation/facial-and-lipsync.Almost every procedural request maps to one of these three. Pick the right one before writing code.
Attached as a child of Skeleton3D. Runs after the AnimationTree writes the pose, modifies specific bones in-place. Includes LookAtModifier3D, SkeletonIK3D (legacy, still supported), and the new (4.4+) LookAtModifier3D chain. Cheap, deterministic, no animation graph dependency.
A clip recorded as a delta from base pose (e.g., a "lean left" clip that's 0 at center, fully leaned at +1) added on top of locomotion. Driven by writing parameters/Add/blend_amount from script. Use for stylistic overlays — turning lean, aiming offset, breathing.
The skeleton hands off to physics on death. Bones become PhysicalBone3D rigid bodies that fall under gravity and collide with the world. One-way: once ragdoll fires, you can't easily blend back to clip-driven without snapping.
The bread-and-butter NPC liveliness fix. Three lines of scene + one script function.
summer_inspect_node "./World/NPC/Skeleton3D" # confirm bone names
summer_add_node parent="./World/NPC/Skeleton3D" type="LookAtModifier3D" name="HeadLookAt"
summer_set_prop "./World/NPC/Skeleton3D/HeadLookAt" key="bone_name" value="Head"
summer_set_prop "./World/NPC/Skeleton3D/HeadLookAt" key="forward_axis" value=2 # +Z forward (Meshy default)
summer_set_prop "./World/NPC/Skeleton3D/HeadLookAt" key="primary_rotation_axis" value=1 # Y-up
summer_set_prop "./World/NPC/Skeleton3D/HeadLookAt" key="use_secondary_rotation" value=true
summer_set_prop "./World/NPC/Skeleton3D/HeadLookAt" key="secondary_rotation_axis" value=0
summer_set_prop "./World/NPC/Skeleton3D/HeadLookAt" key="symmetry_limit" value=1.4 # ~80°, prevents the Exorcist
Drive the target each frame:
@onready var head_look: LookAtModifier3D = $Skeleton3D/HeadLookAt
func _process(_delta: float) -> void:
var player := get_tree().get_first_node_in_group("player")
if player == null:
head_look.influence = 0.0
return
var to_player := player.global_position - global_position
var dist := to_player.length()
# Disable look-at past 8m — feels uncanny at long range.
head_look.target_node = player.get_path() if dist < 8.0 else NodePath("")
head_look.influence = clamp(1.0 - (dist - 6.0) / 2.0, 0.0, 1.0) # fade out 6→8m
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).
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.
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):
@onready var skel: Skeleton3D = $Skeleton3D
@onready var ik_left: SkeletonIK3D = $Skeleton3D/IKLeft
@onready var ik_right: SkeletonIK3D = $Skeleton3D/IKRight
@onready var ray: RayCast3D = $FootRay # cast straight down
func _physics_process(_delta: float) -> void:
_solve_foot(ik_left, "LeftFoot")
_solve_foot(ik_right, "RightFoot")
func _solve_foot(ik: SkeletonIK3D, bone_name: String) -> void:
var bone_idx := skel.find_bone(bone_name)
var foot_world := skel.get_bone_global_pose(bone_idx).origin
ray.global_position = foot_world + Vector3.UP * 0.5
ray.target_position = Vector3.DOWN * 1.0
ray.force_raycast_update()
if ray.is_colliding():
var ground := ray.get_collision_point()
if ground.y > foot_world.y - 0.05: # only lift, never drop into the ground
ik.target_node = NodePath("../IKTarget" + bone_name)
(get_node("Skeleton3D/IKTarget" + bone_name) as Node3D).global_position = ground + Vector3.UP * 0.05
ik.start()
else:
ik.stop()
else:
ik.stop()
The 0.5m up-offset on the ray prevents self-occlusion. The "only lift, never drop" rule is the production fix — letting IK push feet into the ground breaks knee bends.
Limits: this works for stairs and gentle slopes. On 45°+ slopes, use a pelvis lowering pass first (drop the root by min(left_offset, right_offset)) so the body squats and the legs don't over-extend.
SkeletonIK3D on the arm chain (Shoulder → UpperArm → LowerArm → Hand), with target_node set to a Marker3D parented to the prop. The clip drives the body; IK pins the hand to the grip. For a rifle held two-handed, do the right hand from clip and IK the left hand to a foregrip Marker3D — locks them together regardless of recoil.
In the AnimationTree, wrap Locomotion in an AnimationNodeAdd2:
[parent: AnimationNodeStateMachine.Locomotion]
AnimationNodeAdd2
in: BlendSpace1D (idle/walk/run) # the base
add: AnimationNodeAnimation # an additive clip — must be authored as delta
Drive parameters/Locomotion/Add/blend_amount (0..1) from script. Use cases: turn-lean (lean amount = clamp(turn_rate, -1, 1)), aim offset (lean while aiming up/down), breathing-while-idle. The "lean" clip must be exported with track_type = additive from Blender, or you'll see a 2x-pose stacked on the base.
@onready var sim: PhysicalBoneSimulator3D = $Skeleton3D/PhysicalBoneSimulator
func die(impulse_world: Vector3) -> void:
$AnimationTree.active = false
sim.physical_bones_start_simulation()
var pelvis := $Skeleton3D/PhysicalBoneSimulator/PelvisPhysicalBone as PhysicalBone3D
pelvis.apply_central_impulse(impulse_world * 4.0)
You need PhysicalBone3D children matching every major bone (set up once via the Skeleton3D context menu → "Create Physical Skeleton"). The impulse parameter sells the death — without directional impulse the body just collapses straight down.
Hips, Spine, Spine1, Spine2, Neck, Head, LeftShoulder, LeftArm, LeftForeArm, LeftHand, RightShoulder, RightArm, RightForeArm, RightHand, LeftUpLeg, LeftLeg, LeftFoot, LeftToeBase, RightUpLeg, RightLeg, RightFoot, RightToeBase. (Meshy uses Mixamo-compatible naming with no mixamorig: prefix.)
| Setting | Value (Meshy default) |
|---|---|
| Forward axis (head/spine) | Z+ |
| Up axis | Y+ |
| Right axis | X+ |
| Foot down | Y- |
| Modifier | Disable past |
|---|---|
| Head look-at | 8m |
| Foot IK | 15m (snap-to-ground only matters when player can see) |
| Hand-on-prop IK | always on (cheap, breaks if disabled) |
| Additive lean | always on |
| Ragdoll | one-shot, never disabled |
ik.start() after the AnimationTree's first tick, not in _ready() — the bone pose is identity until the tree runs.BoneAttachment3D, or accept that the camera doesn't bob with foot IK.Pose Mode → bake additive.lerp(current_influence, target, 5 * delta) instead of an instant assignment. Avoids the sub-pixel oscillation when the player walks the threshold.LookAtModifier3D: ~5 µs/frame. Cheap; have many.SkeletonIK3D two-bone solve: ~30 µs/frame. ~30 active solves per frame on mid-range desktop is fine; budget more conservatively on Steam Deck.skel.set_bone_pose_position(...) in _process. Bypasses the AnimationTree, fights it next frame, results in jitter. Use modifiers instead — they integrate with the pipeline.is_on_floor() == false.FrontLeftLeg, BackRightLeg, etc.); inspect first.MultiplayerSynchronizer, blend on receivers. Out of scope; see summer:multiplayer-and-networking.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.
summer:animation/animation-tree.summer:animation/generate-motion.summer:animation/facial-and-lipsync.summer:ai-and-npcs/design-npc.summer:character-controllers/fps-controller.references/gd-style.md — typed GDScript conventions in the snippets.references/mcp-tools-reference.md — summer_set_prop enum-int conventions for axis settings.SkeletonModifier3D, LookAtModifier3D, SkeletonIK3D, PhysicalBoneSimulator3D.npx claudepluginhub summerengine/summer-engine-agent --plugin summerProvides GDScript and C# examples for Godot 4.3+ animations using AnimationPlayer for playback, AnimationTree for blending and state machines, sprite animation, and code-driven effects.
Generates animation clips (idle, walk, run, attack) from curated mocap library for Meshy-rigged humanoid characters. Wires clips to AnimationPlayer in Godot.
Guides Three.js animations using keyframe tracks, AnimationClip, AnimationMixer, morph targets, skeletal rigs, and blending. Use for object animation, GLTF playback, procedural motion.