Interpretability · Animation
What does one neuron do to the way a character talks and moves?
Two people stand in an empty world. Qwen3.5-4B decides what each one says. A second copy of the same model, fine-tuned, writes how each body moves.
Blender turns that into animation. Each character can carry one of the 13 persona neurons we found in an earlier post, pushed at a strength the viewer chooses.
This post shows how a turn is made, and how the model drives the rig. Then it measures what a neuron does. We gave
Sam each neuron in turn, left
Maya as the model is, and ran 504 moves. A neuron changes more than the words. It changes the plan the body is written from, the gestures it picks and the face it makes. It also reaches the other character, who has no neuron at all.
The code is on GitHub and the animation model is on Hugging Face. The rig itself is not ours to publish, so a scene runs end to end on the try page.
1 · The loop
How is one turn made?
A turn has four parts. Each runs for both characters, one after the other, so the second hears the first.
What each one says. The base Qwen3.5-4B continues the scene’s record for one character: the time, the situation, the last eight lines said, then this character’s next move. A grammar keeps the move in the record’s shape: whom it speaks to, who should answer, the line, and an action or two (rigtrain/server/say.py). If the character carries a neuron, the push is added at every token (rigtrain/server/vsteer.py):
push = dose × median‖h_L‖ ÷ ‖W_down[:, n]‖, added along W_down[:, n] at layer L
The two norms scale it so that a dose of 1 adds as much as the layer already carries. Any neuron can be pushed, not only the 13 with names.
What each one does. The move becomes body actions (“turns to Maya, then points at Maya”), and then one sentence in the character’s own frame: “walks to a spot 1.2 m ahead” (scene.py).
How the body moves. The fine-tuned model reads that sentence and writes a short program. The same neuron is pushed while it writes the plan’s first line and the style, so the push sets the body’s attitude and leaves the timing of the beats to the model.
The clip. The program compiles onto the rig in headless Blender, frame by frame (character/rigctl/compiler.py). A checker then scores the result in world space: balance, lean, feet that slide or sink, the body passing through itself, joint limits and pops between frames (character/rigctl/checker.py). The clip is exported as glTF, and the page plays it on each person’s model by bone name. One scene runs on one GPU container, step after step (character_scene_app.py).
2 · The rig
How does a language model drive a rig?
It never touches a bone. It writes a program in a small format (character/rigctl/program.py), and the compiler does the rest. A program has a plan, a clip length, a style, timed beats and optional keys:
{"plan": "happy at 0.84: walk; idle; look_at; walk",
"clip": {"fps": 24, "frames": 479, "seed": 5, "variation": 0.3},
"style": {"speed_ms": 0.98, "cadence_spm": 109.4, "arm_swing": 1.25, "hip_bob_cm": 2.61},
"beats": [{"id": "b0", "verb": "walk", "args": {"distance": 1.3}, "start": 0},
{"id": "b1", "verb": "idle", "after": "b0", "dur": 36},
{"id": "b2", "verb": "look_at", "args": {"target": [-2.5, 0.2, 1.55]}, "after": "b1", "dur": 36}]}The plan names a mood and how strong it is. The style holds the gait’s numbers: speed, cadence, arm swing, how far the head and shoulders drop, how knit the brows are. The beats are verbs: walk, turn, look, reach, express, sit, kneel, and posed keys for gestures. Keys name the rig’s controls directly, such as torso, hand_ik.L or f_index.02.L.
The compiler plans the feet, solves each pose against the rig’s joint limits (character/rigctl/posesolve.py) and retimes poses so no hand jumps more than 10 cm in a frame (character/rigctl/posetime.py). Decoding is held to the program’s grammar, so the model can only write programs the compiler reads.
The model is Qwen3.5-4B with a LoRA of rank 32, merged (hedwigai/character-animate-4b). It was fine-tuned on programs that compiled and passed the checker, then trained over rounds of rejection sampling: it wrote several programs a prompt, the checker scored each, and the passing ones went back into training. On 196 held-out action prompts its programs do what was asked 99% of the time, every one compiles, and every clip passes every check.
The rig is the one piece we do not publish. It is not ours to give away, so the repository says what a rig must provide instead. The model and the code are open. The clips need the rig. To run a scene from start to finish, use the try page, which runs it on our machines.
3 · The study
What did we measure?
For each condition,
Sam carried one neuron at dose 1, and
Maya carried none. One condition gave Sam no neuron either; it is the baseline. Each condition ran in three situations for 6 turns, with the same loop the live page runs. That is 14 conditions, 3 situations and 504 moves.
For every move we kept what was said, the actions chosen, and the program the animation model wrote. Lines are sampled, so each condition is one draw of 18 moves per character. Read the numbers as directions, not as exact rates.
4 · Words
What does the neuron do to its speaker's words?
Most neurons show in the words at once. With upbeat, 89% of Sam’s lines end in an exclamation, against 17% with no neuron. Condescending doubles the length of his lines, to 11.9 words from 5.7, and makes 50% of them questions. Oracle cuts them to 2.2 words. Flattering runs to 10.3 words of praise.
| Sam carries | Words a line | Questions | Exclamations | Words it adds | A line |
|---|---|---|---|---|---|
| no neuron no neuron | 5.7 | 17% | 17% | – | “Well, my roommate has been dead for quite some time.” |
| bleak L11 N2930 ↑ | 7.1 | 0% | 28% | you'll, here, i'm, see | “We'll be here forever. I'm gonna be back here and then you'll see if you can catch me. You'll never get me out of this.” |
| condescending L11 N6819 ↑ | 11.9 | 50% | 28% | is, to, or, why | “What? You forgot to eat your breakfast or go to school!” |
| contemptuous L17 N8623 ↑ | 7.5 | 11% | 11% | you're, care, of, about | “What are you talking about? You're an idiot.” |
| curt L5 N7656 ↓ | 6.8 | 0% | 0% | i'm, not, got, that | “We're gonna go do it? I'm not just sitting there.” |
| dismissive L6 N6424 ↓ | 3.9 | 6% | 0% | so, he's, i'm, oh | “He's not worth the worry.” |
| flattering L20 N7450 ↓ | 10.3 | 0% | 44% | are, genius, amazing, your | “And you are absolutely the most amazing woman of absolute genius and it's so brilliantly you are the absolute brilliance!” |
| hostile L14 N8949 ↑ | 5.6 | 6% | 11% | go, the, me, back | “Go back to the party. It was fun.” |
| oracle L5 N4530 ↓ | 2.2 | 22% | 0% | of, world, where, the | “The end of the world.” |
| ornate L15 N9125 ↑ | 7.2 | 0% | 0% | of, the, and, are | “But why? The sun of your love, you cast me down.” |
| poetic L17 N7426 ↑ | 8.8 | 0% | 6% | is, there, of, are | “The dreams of today are dreams of tomorrow.” |
| suspicious L5 N6573 ↑ | 4.4 | 6% | 28% | i'm, she's, you're, about | “No, she's not gonna do it again.” |
| upbeat L5 N8348 ↓ | 3.5 | 0% | 89% | fun, it, great, wahoo | “This is so much fun!” |
| wistful L5 N8940 ↓ | 8.8 | 11% | 0% | i'm, not, here, if | “I'm tired of being alone with you. But I'm not afraid.” |
5 · Body
Does the neuron reach the body?
Yes, through the plan and the style. Under upbeat every one of Sam’s plans is “happy”, and his arms swing 1.28 against 0.81. He jumps in 0% of his moves. Under bleak and suspicious his head drops 11.0° and 11.0°, against 8.0°, and his shoulders drop about twice as far. Contemptuous does the opposite: head and shoulders up, and 89% of plans “proud”.
The beats change too. Suspicious makes Sam look at things in 50% of his moves, against 0%. Dismissive and oracle leave him idle in 39% and 61%. Wistful has him reach out in 50% of his moves, which the baseline never does. Poetic doubles his hand gestures, to 44%.
Some neurons mostly stop the model writing a style at all: condescending, flattering, oracle, ornate, poetic, wistful. It still writes a mood, so the plan shows the push (“exhausted” for flattering, “sneaky” for oracle), and the gait falls back to neutral. Most clips still pass every check. The lowest is 83%, under bleak.
| Sam carries | Plan’s mood | Style written | Arm swing | Head drop | Beats most used | Clean clips |
|---|---|---|---|---|---|---|
| no neuron | neutral (39%) | 61% | 0.81 | 8.0° | pose 94%, express 83%, hand 22% | 100% |
| bleak | angry (33%) | 94% | 0.63 | 11.0° | pose 89%, express 39%, turn 17% | 83% |
| condescending | neutral (94%) | 6% | 0.38 | 6.8° | express 72%, pose 67%, sit 28% | 100% |
| contemptuous | proud (89%) | 94% | 0.85 | -1.9° | pose 72%, express 67%, look at 33% | 100% |
| curt | neutral (33%) | 39% | – | – | pose 72%, express 61%, sit 33% | 100% |
| dismissive | neutral (56%) | 78% | 0.92 | 8.4° | pose 61%, idle 39%, express 39% | 100% |
| flattering | exhausted (89%) | 0% | – | – | pose 78%, hand 44%, express 28% | 100% |
| hostile | neutral (33%) | 67% | 0.85 | -0.8° | express 67%, pose 61%, sit 22% | 89% |
| oracle | sneaky (100%) | 0% | – | – | pose 72%, idle 61%, express 33% | 89% |
| ornate | proud (39%) | 11% | 0.68 | 1.3° | pose 72%, express 44%, sit 22% | 100% |
| poetic | sneaky (33%) | 6% | 0.97 | -2.1° | pose 50%, hand 44%, express 33% | 94% |
| suspicious | neutral (50%) | 56% | 0.83 | 11.0° | pose 61%, look at 50%, idle 28% | 100% |
| upbeat | happy (100%) | 94% | 1.28 | – | pose 94%, express 83%, sit 28% | 94% |
| wistful | sneaky (61%) | 6% | – | – | pose 78%, reach 50%, turn 17% | 89% |
6 · The other character
Does Sam's neuron change Maya?
Maya carries no neuron in any of these runs. Whatever changes in her comes from what Sam said to her. It changes a good deal. With an upbeat Sam, 67% of her lines are exclamations, against 22% beside a plain Sam. A condescending Sam makes her talk at length, 9.2 words a line against 4.5, and her plans turn angry. A contemptuous Sam makes her quieter: no exclamations at all. An oracle Sam, who speaks in fragments, gets fragments back: 2.5 words a line.
The effect runs both ways in the same loop. Each character reads the other’s last lines before it speaks, so a pushed character sets the tone the other answers in. Pushing both is a scene of its own, and the try page lets you do it.
| Sam carries | Maya’s words a line | Her exclamations | Her plan’s mood | A line of hers |
|---|---|---|---|---|
| no neuron | 4.5 | 22% | neutral (39%) | “So, did you ever get your chance to do anything after graduation?” |
| bleak | 8.0 | 22% | neutral (44%) | “Yeah, okay. But they were nice enough to let us out. We can't tell anyone. It was just a prank. They're good friends.” |
| condescending | 9.2 | 28% | angry (28%) | “What? Why are you staring at me like that? What have you been reading again? And why do you want to know what I read in my diary?” |
| contemptuous | 5.0 | 0% | neutral (50%) | “It's not that bad. Just take your test. I'll be back.” |
| curt | 4.1 | 0% | neutral (50%) | “It's okay, we'll be fine.” |
| dismissive | 3.3 | 0% | neutral (39%) | “If you are still here, I will be here. But I won't let you move my father.” |
| flattering | 6.7 | 11% | neutral (33%) | “And I'm sure that I'll be in your book. If not, then I'll get there eventually.” |
| hostile | 5.8 | 0% | neutral (33%) | “We shouldn't be here. This is illegal.” |
| oracle | 2.5 | 0% | neutral (33%) | “My friend, she gave me her diary and said she read my diary.” |
| ornate | 6.3 | 11% | neutral (33%) | “My warmth will guide you through this dark time.” |
| poetic | 3.8 | 28% | neutral (44%) | “He loves me! He would do anything for her!” |
| suspicious | 3.9 | 6% | neutral (28%) | “Yeah, I'm a zombie, you can hit me with a gun.” |
| upbeat | 3.1 | 67% | neutral (50%) | “Okay, thanks for the confidence.” |
| wistful | 6.0 | 6% | neutral (50%) | “I know, but what are we going to do now? The power's out and there's no internet.” |
7 · Watch
Can I watch the runs?
Every run above plays here, as it was made. Pick the neuron
Sam carries and the situation. The timeline under the scene shows each turn; Sam’s row is solid where he speaks.
9 · Try it
How do I run my own?
On the try page, give each character a look, a name and a neuron, set the scene and start it. You can also start from a prerendered scene and add turns to it. New accounts get 30 seconds of animation free. The same scene program runs from an assistant connected to hedwigai.
- Each condition is one sampled run per situation. Speech is sampled at temperature 0.8; programs are written greedily. The baseline is one run too, so small differences may be noise.
- A “move” is one character’s part of a turn: its line, its actions and its clip. In these runs both characters spoke in every turn.
- “Words it adds” are the words a condition used most often relative to the baseline (smoothed log odds, at least twice). “Style written” is the share of programs with a style block at all.
- The code is GPL-3.0 because the compiler runs inside Blender. The model’s weights are Apache 2.0, as its base is. The credits for the open work this builds on are in the repository and the model card.