Skip to content

devlog

A post-animation stack that integrated itself: two writers on one bone

2026-10-05

The body folded into itself for the first seconds of a walk. Every layer involved was correct on its own.

The report was that walking in the first seconds after load crushed the character into itself. Torso folded, head sunk into the shoulders, legs apparently fine. It cleared after three or four seconds. Standing still for ten seconds and then walking was clean, which turned out to be the sentence that solved it.

The rig is written by the animation, and then four additive layers run after it in the same frame: terrain posture, which carries the body on a grade, foot inverse kinematics for contact, a liveness layer for the head and chest, and a wall reach for the arms. Each one composes onto the local rotation it can see, because by the time it runs, the thing above it has already written the bone.

That means every one of them has to tell two situations apart: the value on this bone is what I left here last frame, or something upstream has moved it since. All four solve it the same way, and the way is correct. Remember the quaternion you wrote. Compare it to the one you can see now. If they differ, upstream moved the bone and that is your new base.

Correct for one layer. Wrong for two. Terrain posture writes Spine2 and Head. The liveness layer writes Spine2 and Head. Each one read the write of the other as upstream movement and rebased onto it, so instead of composing their offsets they integrated them: both added every frame onto a base that already contained both.

The measurement, taken on a bare bone chain with no device and no renderer, 240 frames at 60 Hz with nothing upstream writing. Hips to head starts at 0.5100 m. Either layer running alone leaves it at 0.5098. The two together take it to 0.2360 and drop the head by 0.64 m. Over time: 0.5099 at a quarter of a second, 0.4388 at one second, 0.3424 at two, 0.2360 by four. That last column is the bug report, in millimetres.

Which also explains why it lasted only a few seconds. On the clip path the animation component rewrites every bone local every frame, so both layers rebase onto the clip and nothing can accumulate. The windup is invisible precisely because something upstream is loud. It needs a window in which nothing writes the rig at all, and the seconds before the motion-capture files arrive are exactly that window. Standing still passes the window harmlessly, because the layers that wind up only engage above walking speed.

The fix is deliberately not a fifth guard. A guard is per-layer and the defect is between layers, so no guard can see the one that defeats it, and a better version of either one would have fixed nothing. What makes the stack idempotent is giving it a single upstream pose. Hand the rig back to what upstream left before any layer reads it, let the four compose, then record what the stack left so that next frame can tell an untouched bone from one the animation has moved on. The composed result is then the same every frame instead of compounding.

It is identical to four decimal places while a clip is driving, which is the path every player is on a few seconds in, so this buys the silent window and costs nothing in the one that matters. The regression test fails without it by precisely the number above, which I checked by breaking it on purpose, because a test nobody has watched fail is a guess.

The rule I am taking out of it is more general than the bug. A per-layer rebase guard is not sufficient on its own. Any second writer on the same bone defeats it, silently, and only in the conditions where the first writer happens to be quiet. A bone with more than one writer needs one authority over what upstream means.