Skip to content

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:

bob.actor.perform("thinking", duration=48)
shot.mark_actor_has_action(bob)   # else a default idle is layered on top

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.

Next: The Timeline Model