Solve the surface, not the skeleton
By Oleg Sidorkin, CTO and Co-Founder of Cinevva
Part 1 measured four auto-riggers against artist rigs on twelve CC0 animals and found one shared flaw: every one of them builds a quadruped with nearly straight legs. It ended with a plan to repair rigs, because a leg with no fold can't reproduce an artist's knee angle no matter how good the retargeting is.
Then a simpler question surfaced while we argued about the results. Why are we moving animation between skeletons at all?
A skeleton is a machine for deforming a surface. The surface is the thing the player sees, and the artist clip already tells us exactly where that surface should be, vertex by vertex, on every frame. So skip the skeleton-to-skeleton mapping entirely. Play the artist clip once, record the deformed mesh, then solve the auto-rigged skeleton's transforms so that its own skinning reproduces that surface as closely as it can. The result is a clip that lives natively in the new rig's space. Its bones can be called bone_0 for all we care.

This is not a new idea in the literature. It's the transform half of skinning decomposition, SSDR from Le and Deng in 2012, and it's how motion capture solvers fit arbitrary rigs to dense markers. Our situation is the easy case: the rigger already supplied the skeleton and the weights, so the only unknowns are the per-frame bone transforms.
The method, and the control that keeps it honest
Per frame, we look for one transform per bone that minimizes the distance between the rig's skinned surface and the target surface. With weights fixed, each bone's best transform has a closed-form answer, a weighted rigid fit by Horn's quaternion method. Linear blend skinning couples bones through shared vertices, so we sweep the bones in turn, each solve accounting for what every other bone currently contributes, until the residual stops moving. Each frame warm-starts from the previous one.
Everything runs in bind space, where the skinning identity holds exactly whatever conventions the file was exported with. Correspondence between the artist mesh and the rigger's re-welded or subdivided mesh is nearest-neighbour on the aligned rest poses, which is exact here because both are the same animal.
The design rule that mattered most: a control run that must come out at zero. We solve the artist rig against its own clip, where a perfect answer exists by construction. If the solver can't find it, nothing else it produces means anything. The control lands at 0.008% of the model diagonal, with the single worst vertex at 0.08%. That's the floor everything else is measured against.
Getting a trustworthy zero took three attempts
The first control run plateaued at 3% and refused to move under thirty times more iterations. Worth recording why, because each cause was invisible from outside.
The big one was an API trap. Newer three.js renamed boneTransform to applyBoneTransform and quietly changed what it does: the new function takes its input position from the vector you pass in, it never reads the geometry. Fed a reused scratch vector, it computes each vertex from the previous vertex's output. The resulting targets were smoothly plausible garbage, and for one embarrassing hour they supported a detailed theory about armature scale that fit the numbers beautifully and was pure fiction. The correct entry point is getVertexPosition. The control caught it, which is the entire argument for having one.
The other two were smaller. Power iteration on Horn's matrix stalls at about a thousandth of a degree because the spectral shift that makes it converge also crushes the gap it converges along, so we switched to Jacobi rotations, which are exact for a 4x4. And an early-exit test based on relative progress froze the sweeps while they were still grinding downward, so the exit now measures absolute progress against the model's scale.
What each rigger can actually carry
With the solver validated, we solved two artist clips, Walk and Gallop, into every rig for the six animals all riggers cover. The score is the share of the motion's surface displacement the rig reproduces. It has a name in our heads now: transfer quality.

| rig | Walk | Gallop |
|---|---|---|
| artist (control) | 99.8% | 99.9% |
| Anything World | 94.4% | 91.9% |
| Tripo | 92.3% | 89.1% |
| SkinTokens, given the artist skeleton | 82.5% | 89.4% |
| SkinTokens | 80.9% | 88.0% |
| RigNet | 48.5% | 58.3% |
Now compare this against part 1, because the ranking flips.
RigNet had the best leg fold of the four and was the only rigger whose skeletons passed our drivability gate on all twelve animals. Here it loses half the walk. Its worst vertices sit 20 to 31% of the model away from where the surface should be, and the failure is consistent across all six animals, 38 to 59% quality on every one. Meanwhile Tripo and Anything World, the two straightest-legged rigs we measured, carry animation best.
The reconciliation is simple once stated. A solved clip may translate joints, not only rotate them, and per-joint translation tracks are ordinary legal animation data. With translation available, a straight chain can still track a folding surface, so the fold stops being the binding constraint. What binds instead is whether the skinning weights carve the mesh into pieces that follow bones cleanly. The commercial riggers' weights are good. RigNet's weights, spread over its irregular chains, can't track the surface no matter where the solver moves the bones.
So the two measurements answer two different questions. Fold ratio governs what a rotation-driven runtime rig can pose, which is part 1's world. Transfer quality governs what a baked, solved clip can express, which is this one's. Under the solved-clip pipeline, the rigger we already ship is a 92% rig rather than a last-place one.
One more result hiding in that table: handing SkinTokens the artist's own skeleton barely moves its score. Its ceiling is its weights, not its joint placement.
Watching it instead of trusting it
Numbers first, then eyes. The same solver drives a live viewer where every rig's full mesh is skinned by its solved transforms, drawn over the artist's ground-truth surface as a dark silhouette, and every vertex is coloured by its momentary error. Blue is zero. Red is 3% of the model diagonal or worse.
The picture and the table can't drift apart, because the viewer renders with the exact function the metric measured. One panel needs a disclaimer: the SkinTokens deer shows no heatmap. Its mesh is 181,000 vertices and we skip the full-mesh correspondence above 60,000, so that panel argues by silhouette only.
What this changes for us
A solve takes half a second to a few seconds per clip per rig, in browser JavaScript, no GPU involved. That's cheap enough to bake a quadruped's whole clip set at the moment the rig is created. Baked clips make the runtime simpler as well: no skeleton retargeting for animals at all, just clip playback in the rig's own space, with our existing foot locking on top for ground contact.
It also gives us a second acceptance gate. Part 1's geometric checks say whether a rig is drivable. Transfer quality says how much of a real animation it will keep. A rigger can pass the first and fail the second, and RigNet does exactly that.
Limits, stated plainly
The score is each rig's ceiling, not a promise. The solver may translate joints, so bone lengths aren't preserved during motion, and a rig leaning hard on translation could read rubbery at extremes. The gallop's worst vertices, 9 to 20% momentarily even on the good rigs, live in exactly those moments. A rotations-only variant of the solve would price that honestly, and it's the number we still owe: it would show how much of the straight-leg penalty from part 1 survives when translation is off the table.
The production gap is correspondence. In this benchmark the rigger rigged the same mesh the artist animated, so vertex matching is trivial. A user's uploaded animal is a different mesh, and getting artist surface motion onto it first is its own problem, with known routes we haven't measured yet.
And the sample: six animals, two clips, 24 frames per clip, constraints subsampled to five thousand vertices on the densest mesh. Enough to rank riggers with confidence, not enough to quote a second decimal.
The animals are CC0 from Quaternius, the method is forty-year-old closed-form fitting plus patience, and the control run is the part we'd urge anyone reproducing this to build first. If you've solved animation into rigs before and hit the traps we did, or different ones, we'd like to compare notes in our Discord.