Characters & Actors¶
There are three layers to a character. They're easy to confuse, so it's worth a minute.
| Layer | Type | What it is | How you get it |
|---|---|---|---|
| Template | CharacterTemplate |
A rig — one per FBX, built at import from character_descriptions.json |
from dsl.actors import brian |
| Character | Character |
A named identity backed by a rig | bob = brian("Bob") |
| Actor | MixamoActor |
The live Blender armature + root empty | internal; escape hatch bob.actor |
from dsl.actors import brian, swat
detective = brian("Detective Hayes") # rig = brian, identity = "Detective Hayes"
goon_a = swat("Goon A")
goon_b = swat("Goon B") # same rig, different identity — fine
- The rig key (
brian) chooses the body. - The name (
"Detective Hayes") is the narrative identity — it drives Blender object names, the TTS audio filename, and dialog-speaker tracking.
Voice — cast at the same time¶
A Character is also paired with a voice (and a tone), split from the rig so the same body can speak in different voices. Pick it when you mint the character:
from dsl.voices import ballad, onyx
detective = brian("Detective Hayes", voice=ballad) # explicit voice
villain = brian("The Stranger", voice="onyx", # string + delivery note
instructions="Cold. Clipped. Military.")
sidekick = brian("Bob") # curated default voice + tone
Each voice is a gender-tagged singleton; by_gender("male") filters them. Voice carries
name + gender + description; tone is the character's instructions (overridable per cast). Full
list: Voice Catalogue · API: Actors → Per-character voices.
What a Character can do¶
These methods record intent and proxy to the actor bound for the current shot:
| Method | Effect |
|---|---|
idle() |
Hold a neutral pose. Inside a shot, bare idle() holds until the shot ends. |
say(dialog, action_name="idle") |
Generate TTS audio + play action_name while speaking. One speaker per shot. |
walk_to(location) |
Walk to a point/anchor (looped locomotion + root motion). |
move_to(location, action="walking") |
Like walk_to, but choose the gait. |
walk_to_join(target, blocking) |
Walk into a 2-person formation beside target. |
set_frame(n) |
Make the next action start at frame n. |
.actor |
The underlying MixamoActor (escape hatch). |
Playing any animation in place
Character only exposes idle/say/walk_to/move_to. To play any of the ~100 library
animations standing still, drop to the actor and mark it:
Under the hood: MixamoActor¶
The low-level object (dsl/animation_core.py) handles FBX import, NLA strip scheduling, root
motion, and TTS. Worth knowing:
- Each action becomes its own NLA strip on a fresh track (avoids overlap errors).
- The root empty drives world movement; the armature is driven only by the pose.
- Locomotion actions (
walking,running, …) auto-repeat to cover the travel distance. - Animations are shared across all rigs — one
animation_library.blend, appended once.
One speaker per shot
A second say() in the same shot raises an error. Split dialog across shots.