Animation
The execution model is in blender-core (its references/bpy-patterns.md has verified keyframe/driver snippets). Rigs are in blender-character-rigging.
5.x data model (what changed)
- An Action holds slots (one per animated ID) and layers → strips → channelbags → F-curves. A single action can animate several objects (e.g. a rig and its camera) through different slots.
- Assign:
ob.animation_data.action = act, then make sureob.animation_data.action_slotis set (picked automatically when a suitable slot exists; otherwiseact.slots.new(id_type="OBJECT", name=ob.name)). - F-curves:
cb = anim_utils.action_ensure_channelbag_for_slot(act, slot), thencb.fcurves.ensure(path, index=i, group_name=...).action.fcurvesno longer exists. - The simplest route is still
pb.keyframe_insert("rotation_quaternion", frame=f), which creates the action, slot and channelbag.
Workflow (keyframe animation, studio style)
- Blocking: key poses on every channel (
CONSTANTinterpolation,bpy.context.preferences.edit.keyframe_new_interpolation_type) on golden frames (contact, down, passing, up for walks). - Breakdowns: add in-betweens that define arcs and spacing.
- Spline: switch to
BEZIER, fix spacing in the Graph Editor, and clean overshoot. Auto-clamped handles avoid overshoot. - Polish: offsets/overlap (follow-through on hair, tails, cloth bones), arcs, moving holds (never a perfectly frozen character), and contact stability (feet locked with IK).
- Review: MCP
look(mode="frames", frame_count=8)or a Workbench playblast (blender-rendering).
Game animation rules
- One action per clip, named
<Rig>_<Clip>or just<Clip>, with a fake user so it survives saving. - Loops: first and last frames identical. Export frames 1..N and let the engine drop the duplicate, or exclude the last frame (UE/Unity "loop pose" options). An F-curve
CYCLESmodifier helps preview but doesn't export, so bake it. - FPS: author at 30 (or 24) and let engines resample. Set
scene.render.fpsbefore importing mocap. - Root motion: the root bone carries the translation (and yaw). The hips keep the bob/sway.
scripts/bake_action.py --root-motion xymoves the hips' ground motion to the root. In-place clips: the root stays at the origin. - Additive/overlay clips (aim offsets, breathing) are exported as normal clips and marked additive in the engine.
- Keep the bone transform channels the engine expects. Don't animate bone scale unless the engine supports it (Roblox and many mobile pipelines don't).
Bake control rig → export skeleton
scripts/bake_action.py -- --list
scripts/bake_action.py -- --source RIG_Body --target GAME_RIG_Body [--actions Walk Run] [--root-motion xy --hips spine]
This gives one baked action per clip (GAME_RIG_Body|Walk), cleaned, with fake users, plus one muted NLA track per clip (CLIP_Walk) so FBX (bake_anim_use_nla_strips/all actions) and glTF (ACTIONS mode) export every clip. The target's constraints are muted afterward so it plays the baked data; run --follow to drive it live again. Self-bake (IK/constraints → keys on the same rig): --source X --target X.
Mocap and retargeting
- Import:
bpy.ops.import_anim.bvh(filepath=..., global_scale=0.01 if cm else 1, rotate_mode="NATIVE", update_scene_fps=True),import_scene.fbx(Mixamo,automatic_bone_orientation=True). - Retarget without add-ons: put the target rig in the same rest pose (T vs A matters most), add
COPY_ROTATIONconstraints (world or local-with-parent space) from each target bone to the matching source bone, plusCOPY_LOCATIONon the hips/root (scaled by the leg-length ratio). Then self-bake withbake_action.py --source TARGET --target TARGET, and delete the constraints. - Clean mocap: decimate keys (
graph.decimate, ratio 0.3–0.5), use an F-curveSMOOTHmodifier or the Butterworth filter (graph.butterworth_smooth), and fix foot sliding with IK pins and then bake. - Production retarget tools: Auto-Rig Pro (paid), Rokoko (free), and the engine-side retargeters (UE IK Retargeter, Unity Humanoid).
NLA and pose library
- NLA: push actions down as strips (
track.strips.new(name, start, action)) to layer/blend clips (blend typeREPLACE/ADD/COMBINE), and use Tweak mode to edit. Strips need an action slot set when the action has several slots (strip.action_slot). - The pose library (bundled
pose_library) stores poses as assets:poselib.create_pose_asset(pose_name=...),poselib.apply_pose_asset/blend_pose_asset. Use it for hand shapes, face poses, and a T/A rest pose.
Shape keys and other properties
Any property can be keyed: kb.keyframe_insert("value", frame=f) (shape key), mat.node_tree.nodes[...].inputs[...].keyframe_insert("default_value") (materials, which engines usually ignore), custom props ob.keyframe_insert('["prop"]').
Gotchas
pb.matrix = ...followed bykeyframe_insertneeds the rightscene.frame_set(f)first, or an evaluation overwrites the pose.- Connected bones (
use_connect) can't translate. Hips/pelvis must be unconnected from the root. bake_actionwith visual keying reads evaluated poses, so constraints, IK and drivers are all captured. Mute the target's own constraints afterward (the script does), or they keep overriding the keys.- Quaternion vs Euler: game bones should use
QUATERNION(no gimbal lock, smooth slerp). Euler is fine for single-axis controls. Don't mix modes between keys. - glTF sampling:
export_force_samplingbakes every frame (the safe default). Non-linear F-curve modifiers and drivers only export when sampled.