Language: English · Português (README_PT.md)
Procedural animation CLI powered by the Blender Python API (bpy 5.1.0).
Generates keyed animation clips for rigged GLB models — walk cycles, combat, flight, idle, and more —
then exports a single animated GLB ready for game engines. Designed as the final stage after
Rigging3D in the GameDev asset pipeline.
| Feature | Details |
|---|---|
| Input | Rigged GLB (from Rigging3D / UniRig) |
| Output | Animated GLB with embedded named clips (NLA actions) |
| Runtime | Blender 5.1 embedded via bpy==5.1.0 (headless, no GUI) |
| Python | 3.13+ (required by bpy 5.1.0 PyPI wheels) |
| GPU | Not required for animation; only needed for upstream tools (Text3D, Paint3D) |
| Entry point | animator3d (CLI) or python -m animator3d |
Animator3D classifies armature bones automatically (legs, wings, tail, neck, spine, arms, head) and
applies procedural keyframes matched to each chain. Bones are renamed from chain analysis via
rename_bones_from_chains before animation, so it works with arbitrary rigs — Mixamo, UniRig,
Auto-Rig Pro, etc.
# From the GameDev repo root:
./install.sh animator3d
# Equivalent: python3 -m gamedev_shared.installer.unified animator3d# Install Shared first (required dependency):
cd Shared && pip install -e .
# Then Animator3D with dev dependencies:
cd Animator3D
python3.13 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[dev]"Requirements: Python 3.13, bpy==5.1.0 (Blender 5.1 wheel), gamedev-shared, click,
rich, rich-click.
All commands share the animator3d entry point. Run animator3d --help or
animator3d <command> --help for usage.
Generate all animation clips for a preset in one command. This is the primary command used by GameAssets batch processing.
# Humanoid hero — walk, run, jump, fall, breathe-idle:
animator3d game-pack rigged.glb animated.glb --preset humanoid
# Dragon — breathe-idle, walk, attack, roar:
animator3d game-pack dragon.glb dragon_anim.glb --preset creature
# Flying beast — breathe-idle, hover, soar, dive, land:
animator3d game-pack griffin.glb griffin_anim.glb --preset flying
# Only specific clips from a preset:
animator3d game-pack hero.glb hero_anim.glb --preset humanoid --clips walk,run,jump
# With Draco compression for smaller file size:
animator3d game-pack hero.glb hero_anim.glb --preset humanoid --draco| Flag | Type | Default | Description |
|---|---|---|---|
INPUT |
path | required | Input rigged GLB path |
OUTPUT |
path | required | Output animated GLB path |
--preset |
choice | humanoid |
Preset: humanoid, creature, flying |
--clips |
str | (all) | Filter clips by comma-separated names (e.g. walk,run) |
--draco/--no-draco |
flag | false |
Draco mesh compression |
Preset clip lists:
| Preset | Clips Generated |
|---|---|
humanoid |
breathe-idle, walk, run, jump, fall |
creature |
breathe-idle, walk, attack, roar |
flying |
breathe-idle, hover, soar, dive, land |
Walk cycle with alternating leg movement, trunk sway, and tail counter-swing.
animator3d walk rigged.glb animated.glb
animator3d walk rigged.glb animated.glb --frames 60 --cycles 3.0 --leg-amp 0.18| Flag | Type | Default | Description |
|---|---|---|---|
--frames |
int | 48 |
Total animation frames |
--cycles |
float | 2.0 |
Walk cycles within the frame range |
--leg-amp |
float | 0.14 |
Leg swing amplitude (radians) |
--clip-name |
str | Animator3D_Walk |
Custom clip name (max 64 chars) |
--append/--no-append |
flag | true |
Keep existing clips and append (--no-append clears first) |
--draco/--no-draco |
flag | false |
Draco mesh compression |
Run cycle — faster cadence, larger amplitude, arm counter-swing.
animator3d run rigged.glb animated.glb --frames 24 --leg-amp 0.30| Flag | Type | Default | Description |
|---|---|---|---|
--frames |
int | 36 |
Total animation frames |
--cycles |
float | 2.0 |
Run cycles within the frame range |
--leg-amp |
float | 0.22 |
Leg swing amplitude (radians) |
--clip-name |
str | Animator3D_Run |
Custom clip name |
--append/--no-append |
flag | true |
Append to existing clips |
--draco/--no-draco |
flag | false |
Draco mesh compression |
Non-looping jump: crouch → extend → airborne → land.
| Flag | Type | Default | Description |
|---|---|---|---|
--frames |
int | 36 |
Total animation frames |
--clip-name |
str | Animator3D_Jump |
Custom clip name |
--append/--no-append |
flag | true |
Append to existing clips |
--draco/--no-draco |
flag | false |
Draco mesh compression |
Non-looping fall: arms open, wind sway.
| Flag | Type | Default | Description |
|---|---|---|---|
--frames |
int | 24 |
Total animation frames |
--clip-name |
str | Animator3D_Fall |
Custom clip name |
--append/--no-append |
flag | true |
Append to existing clips |
--draco/--no-draco |
flag | false |
Draco mesh compression |
Strike / bite animation: torso and neck lunge forward, wings sweep, tail counterbalance. Legs stay planted.
animator3d attack dragon.glb dragon_anim.glb --frames 72 --strikes 3
animator3d attack dragon.glb dragon_anim.glb --wing-amp 0.80 --neck-amp 0.70| Flag | Type | Default | Description |
|---|---|---|---|
--frames |
int | 72 |
Total animation frames |
--strikes |
int | 1 |
Number of strikes per clip |
--wing-amp |
float | 0.62 |
Wing sweep amplitude (radians) |
--neck-amp |
float | 0.55 |
Neck / bite amplitude (radians) |
--tail-amp |
float | 0.42 |
Tail counterbalance amplitude (radians) |
--clip-name |
str | Animator3D_Attack |
Custom clip name |
--append/--no-append |
flag | true |
Append to existing clips |
--draco/--no-draco |
flag | false |
Draco mesh compression |
Test oscillation animation on a single bone. Useful for verifying rig connectivity.
animator3d wave-idle rigged.glb animated.glb --bone mixamorig:Spine
animator3d wave-idle rigged.glb animated.glb --frames 90 --clip-name TestOscillation| Flag | Type | Default | Description |
|---|---|---|---|
--frames |
int | 60 |
Total animation frames |
--bone |
str | (auto) | Target bone name (auto-detects if omitted) |
--clip-name |
str | Animator3D_WaveIdle |
Custom clip name |
--append/--no-append |
flag | true |
Append to existing clips |
--draco/--no-draco |
flag | false |
Draco mesh compression |
Multi-bone idle animation: breathing (spine/chest), wing micro-movement, tail sway, neck drift. Automatically classifies bones and applies appropriate motion to each chain.
animator3d breathe-idle dragon.glb dragon_anim.glb --frames 120
animator3d breathe-idle dragon.glb dragon_anim.glb --wing-amp 0.40 --tail-amp 0.25 --neck-amp 0.20| Flag | Type | Default | Description |
|---|---|---|---|
--frames |
int | 120 |
Total animation frames |
--cycles |
float | 2.0 |
Breathing cycles within the frame range |
--wing-amp |
float | 0.25 |
Wing micro-movement amplitude (radians) |
--tail-amp |
float | 0.15 |
Tail sway amplitude (radians) |
--neck-amp |
float | 0.10 |
Neck drift amplitude (radians) |
--clip-name |
str | Animator3D_BreatheIdle |
Custom clip name |
--append/--no-append |
flag | true |
Append to existing clips |
--draco/--no-draco |
flag | false |
Draco mesh compression |
Fast wing flap while hovering in place. Trunk stays stable.
| Flag | Type | Default | Description |
|---|---|---|---|
--frames |
int | 60 |
Total animation frames |
--cycles |
float | 3.5 |
Wing flap cycles |
--wing-amp |
float | 0.38 |
Wing flap amplitude (radians) |
--clip-name |
str | Animator3D_Hover |
Custom clip name |
--append/--no-append |
flag | true |
Append to existing clips |
--draco/--no-draco |
flag | false |
Draco mesh compression |
Majestic soaring with slow, wide wing beats and tail steering.
| Flag | Type | Default | Description |
|---|---|---|---|
--frames |
int | 90 |
Total animation frames |
--cycles |
float | 1.5 |
Wing beat cycles |
--clip-name |
str | Animator3D_Soar |
Custom clip name |
--append/--no-append |
flag | true |
Append to existing clips |
--draco/--no-draco |
flag | false |
Draco mesh compression |
Dive attack: wings fold, rapid descent, sharp impact.
| Flag | Type | Default | Description |
|---|---|---|---|
--frames |
int | 48 |
Total animation frames |
--clip-name |
str | Animator3D_DiveAttack |
Custom clip name |
--append/--no-append |
flag | true |
Append to existing clips |
--draco/--no-draco |
flag | false |
Draco mesh compression |
Fire breath: chest expands, neck lunges forward, powerful burst bursts.
| Flag | Type | Default | Description |
|---|---|---|---|
--frames |
int | 64 |
Total animation frames |
--bursts |
int | 2 |
Number of fire bursts |
--clip-name |
str | Animator3D_FireBreath |
Custom clip name |
--append/--no-append |
flag | true |
Append to existing clips |
--draco/--no-draco |
flag | false |
Draco mesh compression |
Majestic landing: controlled descent, aerodynamic braking, gentle impact.
| Flag | Type | Default | Description |
|---|---|---|---|
--frames |
int | 80 |
Total animation frames |
--clip-name |
str | Animator3D_Land |
Custom clip name |
--append/--no-append |
flag | true |
Append to existing clips |
--draco/--no-draco |
flag | false |
Draco mesh compression |
Victory roar: chest inflated, head raised, majestic pose.
| Flag | Type | Default | Description |
|---|---|---|---|
--frames |
int | 96 |
Total animation frames |
--clip-name |
str | Animator3D_VictoryRoar |
Custom clip name |
--append/--no-append |
flag | true |
Append to existing clips |
--draco/--no-draco |
flag | false |
Draco mesh compression |
Verify the bpy runtime is functional. Prints Blender version and scene FPS.
animator3d checkImport a GLB/GLTF/FBX and list armatures, bone sample, and actions.
animator3d inspect rigged.glb
animator3d inspect rigged.glb --json-out| Flag | Type | Default | Description |
|---|---|---|---|
INPUT |
path | required | GLB/GLTF/FBX to inspect |
--json-out |
flag | false |
Output as JSON to stdout |
List animation clips (NLA actions) as JSON — useful for pipeline scripts.
animator3d list-clips animated.glbRe-export a GLB (import/export roundtrip). Useful for validation.
animator3d export rigged.glb copy.glb
animator3d export rigged.glb compressed.glb --draco| Flag | Type | Default | Description |
|---|---|---|---|
INPUT |
path | required | Input file path |
OUTPUT |
path | required | Output file path |
--draco/--no-draco |
flag | false |
Draco mesh compression |
Project textures from an original mesh onto Part3D decomposed parts using Blender Cycles bake
(selected-to-active, diffuse color). Useful after part3d decompose when parts lose the original
texture.
animator3d texture-project original_textured.glb parts.glb -o parts_textured.glb
animator3d texture-project original.glb parts.glb -o out.glb --resolution 2048 --margin 16| Flag | Type | Default | Description |
|---|---|---|---|
ORIGINAL |
path | required | Original textured GLB |
PARTS |
path | required | Parts GLB (from Part3D) |
-o, --output |
path | required | Output textured parts GLB |
--resolution |
int | 1024 |
Bake texture resolution (px, square) |
--margin |
int | 16 |
UV island margin in pixels |
--draco/--no-draco |
flag | false |
Draco mesh compression |
Automatically invoked by gameassets batch when Part3D is enabled and animator3d is available.
Generate multi-angle PNG screenshots of a 3D model. Designed for AI-agent debugging pipelines.
# Default 4 views, workbench renderer:
animator3d screenshot model.glb -o screenshots/
# Specific frames for animation review:
animator3d screenshot animated.glb -o frames/ --frame-list 1,24,48,72
# High-res EEVEE with bone wireframes:
animator3d screenshot rigged.glb -o debug/ --engine eevee --show-bones -r 1024| Flag | Type | Default | Description |
|---|---|---|---|
INPUT |
path | required | GLB to render |
-o, --output-dir |
path | <input>_debug/ |
Output directory |
--views |
str | front,three_quarter,right,back |
Comma-separated view names |
-r, --resolution |
int | 512 |
Render resolution (px) |
--show-bones |
flag | false |
Show armature wireframe overlay |
--frame |
int | (all) | Render a single frame |
--frame-list |
str | (all) | Comma-separated frame numbers (e.g. 1,24,48) |
--engine |
choice | workbench |
Render engine: workbench or eevee |
--ortho |
flag | false |
Orthographic camera |
--no-transparent-film |
flag | false |
Opaque background (disable alpha) |
Inspect rig with bone wireframe overlays and optional vertex weight heatmap.
animator3d inspect-rig rigged.glb -o rig_debug/
animator3d inspect-rig rigged.glb -o rig_debug/ --show-weights "mixamorig:Spine"| Flag | Type | Default | Description |
|---|---|---|---|
INPUT |
path | required | GLB to inspect |
-o, --output-dir |
path | <input>_debug/ |
Output directory |
--show-weights |
str | (off) | Bone name for vertex weight heatmap |
--views |
str | front,three_quarter,right,back |
Comma-separated view names |
-r, --resolution |
int | 512 |
Render resolution (px) |
--engine |
choice | workbench |
Render engine: workbench or eevee |
--ortho |
flag | false |
Orthographic camera |
--no-transparent-film |
flag | false |
Opaque background |
All animation commands share these flags:
| Flag | Type | Default | Description |
|---|---|---|---|
--draco/--no-draco |
flag | false |
Apply Draco mesh compression on export |
--append/--no-append |
flag | true |
Append clip to existing actions (--no-append clears all first) |
--clip-name |
str | auto | Override the default clip name (max 64 characters) |
--frames |
int | varies | Total number of animation frames |
Append behavior: By default (--append), new clips are added to any existing NLA tracks in the
GLB. Use --no-append to clear all existing animations before writing the new clip (useful for
single-clip exports).
Animator3D supports quality presets via the shared QualityEngine. Pass --quality
to control frame counts and animation fidelity:
animator3d game-pack rigged.glb animated.glb --preset humanoid --quality high| Tier | Effect |
|---|---|
fast |
Fewer frames, shorter clips |
low |
Reduced frame counts |
medium |
Default frame counts |
high |
More frames, smoother motion |
highest |
Maximum frames, finest detail |
See docs/superpowers/specs/2026-04-30-quality-presets-design.md
for full specification.
| Variable | Description |
|---|---|
ANIMATOR3D_BIN |
Override the animator3d binary path (used by GameAssets and other upstream tools) |
Animator3D produces a single animated GLB containing all generated clips as named NLA actions. Each clip is stored as a separate action accessible by game engines via the glTF animation array.
animated_hero.glb
├── Mesh (armature-skinned)
├── Armature
│ └── Bones (with keyframe data)
└── Animations
├── Animator3D_BreatheIdle (frame 1–72)
├── Animator3D_Walk (frame 1–48)
├── Animator3D_Run (frame 1–36)
├── Animator3D_Jump (frame 1–36)
└── Animator3D_Fall (frame 1–24)
Clip names follow the Animator3D_<Type> convention unless overridden with --clip-name. The
list-clips command outputs the exact clip names and frame ranges:
animator3d list-clips animated.glbAnimator3D is the final animation stage in the GameDev asset pipeline:
Text3D (mesh) → Paint3D (texture) → Rigging3D (armature) → Animator3D (clips) → VibeGame (browser)
- Rigging3D produces a rigged GLB with armature and bones.
- Animator3D takes the rigged GLB and generates procedural animation clips.
- The animated GLB is the preferred output for VibeGame handoff via
loadGltfAnimatedorloadGltfToSceneWithAnimator.
GameAssets calls animator3d game-pack automatically when animation is enabled.
The manifest animate column and game.yaml profile blocks control which preset and clips are
generated. Use --no-animate in GameAssets to skip this stage.
Use GameDevLab to verify animation quality:
gamedev-lab debug screenshot animated.glb -o review/
gamedev-lab debug inspect animated.glbcd Animator3D
python3.13 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"pytest testsruff check . # Lint
ruff check . --fix # Auto-fix lint issues
ruff format . # Format
ruff format --check . # Check formatting without writing| File | Description |
|---|---|
src/animator3d/cli.py |
Click CLI — all commands and flags |
src/animator3d/cli_rich.py |
Rich-enhanced Click setup |
src/animator3d/bpy_ops.py |
Blender Python operations (import, export, keyframes) |
src/animator3d/debug_render.py |
Screenshot and weight-heatmap rendering |
src/animator3d/__main__.py |
python -m animator3d support |
Animator3D can also be used as a Python module:
from animator3d import bpy_ops
bpy_ops.clear_scene()
bpy_ops.import_asset("rigged.glb")
arms = bpy_ops.list_armatures()
arm_name = arms[0].name
bpy_ops.rename_bones_from_chains(arm_name)
bpy_ops.walk_cycle_keyframes(arm_name, frame_start=1, frame_end=48,
cycles=2.0, leg_amp=0.14,
action_name="Animator3D_Walk")
bpy_ops.export_auto("animated.glb", draco=False)MIT — see LICENSE.