Engineering Journal

← all posts

Part of Building the 3D Club Scene

The check wasn't missing. It was lying.

Testing & QA3D & motionProcess
Three mouse surveyors inspect a wooden hand gripping a copper pole. Their
glowing green safety hoop is visibly much smaller than the real hand, so the
gauge reports clearance while the hand intersects the pole.

We spent a day driving one number toward zero. Then the owner of the company watched five clips and reported five defects, four of which were the dancer's body passing through the pole — the category our collision check had been passing all day. The check existed. Its radii were hardcoded 40% thinner than the bodies they were testing. This is a post about what a green light is worth when nobody has calibrated it.


Why

Our motion-QA harness takes one purchased 30-second pole routine, renders it on three different characters, and turns every frame into structured measurements: twelve kinematic checks, contact tests, telemetry per joint per frame. The point of building it was to stop arguing about footage and start arguing about numbers.

It worked. That is the problem this post is about. Numbers are extremely persuasive, including when they are measuring the wrong thing, and a harness you trust is a harness that can spend your whole day for you.

Five lines of feedback beat a day of tuning

Two implementations had spent the day on engaged wrist error: how far a gripping hand sits from the pole surface while the solver says it is holding on. Both drove it down. Both argued about which was winning on that axis. Work was scheduled from it.

Then Spencer watched five clips and wrote back. Sorted by defect class, four of his five items were the same thing: the body passing through the pole. The body sliding sideways through it. A leg through it. A step and then the torso through it. A floor-dance ending that steps in front of the pole and also through it.

The one thing he said looked fine was the grip. Verbatim: "the wrist angle is changing but it seems fine."

The metric that had driven every round of the day, and the entire cross-implementation verdict, was measuring the category that already worked.

The first inference was wrong, and the truth was worse

Our first guess was that no limb-versus-pole collision check existed. That would have been an ordinary gap: you find the hole, you write the check, you move on.

The check existed. Bone-chord-versus-cylinder tests had been in the regression suite from early on, and a chord test with a radius margin is a capsule test. The geometry was right. The constants were not: the segment radii were hardcoded roughly 40% thinner than the rendered mesh — a torso at 0.09 m against a true half-depth nearer 0.13 to 0.16 m. Bodies really were intersecting the pole. The check really did pass. It had been passing for rounds, on every body, while the thing it was named after happened on screen.

Which retires a lot of numbers. Every clearance count in this post, and every one in the rounds behind it, is a thin-radii number: still directional, since each round compared against itself under the same constants, but not a baseline anything can be measured against later. The measured per-character radii, taken off the skinned mesh rather than tuned once against a placeholder mannequin, landed overnight and moved all of them.

A miscalibrated check is worse than a missing one. A missing check leaves a known hole; you can write it on the board. A wrong constant issues false assurance and then hides the hole behind a green light, which is strictly harder to find, because now you have evidence.

This is not the first constant in this project to do harm by being unreachable in the other direction, either. An earlier round had a swivel motor demanding 45 mm of clearance at a wrist that is by design pinned 32 mm off the pole: infeasible on every gripping frame, so the motor sat at a flat gradient inside the pole for 80% of the take, doing nothing, reporting nothing. Same family. A constant nobody re-derived after the geometry around it moved.

The other lie: the report was sorted wrong

The day produced a second finding, and it is embarrassing in a more useful way.

We ran a variance study, for the honest reason that a change we had measured as a no-op still moved the post-fix numbers — the "weigh yourself twice without moving" signal. The study turned up a display bug: the regression output listed the first six violations it happened to hit, in clip order, not the worst six. Decisions had been made off that list all day, including one headline "89% worse" that inverted on re-measurement to a true worst that had gone down.

The catalogue in our own notebook records the same bug from an earlier session: "A display truncation (showing the 'first 6' failures by key order, not the worst) hid 6,000°/s leg snaps for three rounds." The lesson had been written down, and then not applied to a second code path.

So: ranking and surfacing are part of the metric. A correct measure with a wrong selector misleads exactly as effectively as a wrong measure. If your QA output truncates — and it should, nobody reads 300 violations — the truncation must sort by severity, in every code path that prints, forever.

The same variance study found something we needed anyway: the hardest body is stochastically unstable at head level on its own. One of six identical-code captures spikes to 83 mm where the other five sit near 30 mm. That recalibrated acceptance: one capture is enough for continuity checks, and wrist tails need six with max-of-N.

It also weakened, without overturning, the round we had failed on a 187 mm draw (below). The argument at the time was that two clean pre-change captures made the spike real. Six draws show that ch33's right hand needs at least that many before its own baseline tail appears at all, so two proved nothing. The 187 mm value still stands apart: more than double the worst unmodified draw, at a different timestamp, produced by a state the unmodified build does not contain. The revert survived. The reasoning behind it did not.

The round that was right and failed anyway

Worth keeping as a shape, because it is what an honest day actually looks like.

The hypothesis: margin-check the rendered pose rather than only the pre-blend solve. Correct hypothesis, and the fix worked on its target: arm-versus-pole clearance violations dropped 25 to 40% on every body (86 → 59, 216 → about 144, 453 → about 296), and its named window improved 72.6%. That one survives the variance study: arm-versus-pole count turned out to be the tightest metric in the suite, 1 to 10% spread across repeat captures of unchanged code, so a third off it on three bodies is not a lucky draw.

It shipped nothing. The implementation added a second stateful rate-bounded corrector, and on a body whose hand is continuously engaged for 14+ seconds with no release, that state accumulates unbroken and occasionally detonates: 187 mm on one run in five, about 28 mm on the other four. Reverted. Patch kept in the tree, four candidate redesigns written down, none attempted that day.

The ledger for the day reads: two rounds landed, five failed and were reverted with full diagnosis. That sounds like a bad day and was not. Every failure crossed off a suspect, and the tooling that came out of it — severity-sorted output, calibrated capture counts, magnitude-and-duration scoring, regression gates on the detectors rather than only on the solver — outlives every fix that landed.

The same mistake, one level up

We replaced the thin radii with per-patch compression budgets: how much a given body part may compress against the pole before it counts as interpenetration. Flesh is soft; a rigid capsule test on a thigh is not physically honest; the budgets are defensible.

They are also a new family of hand-set constants standing between "intersecting geometry" and "pass." Exactly the hazard we had just finished writing a lesson about, moved up one level of abstraction, where it is harder to see.

We only noticed because we asked three outside models to attack the design, and the most valuable thing any of them said was a criticism of the newest fix rather than a proposal for the next one. Its suggested replacement is a calibration loop our existing WebGL harness can run without new machinery: per camera, render body front-face depth, body back-face depth, and pole depth. A pixel where the pole is the visible surface and its depth lies between the body's two faces is the pole emerging through the body. Count those pixels over a ring of six to eight cameras. A budget is correct, the argument goes, when its worst frame produces about zero such pixels from the product cameras.

The uncomfortable part is that the sibling session had already built exactly that, and had already measured what it is worth. Same three depth passes, same eight-camera ring. Against a corpus of confirmed defects, no absolute per-instant pixel count separated them from ordinary background: an archived bake interpenetrating the pole core for 52% of its duration peaked at 549 px where clean bakes read 484 to 519. Tightening the margin from 150 mm to 5 mm scaled both down together and never pulled them apart, and two refinements of the pixel condition failed the same way, because a thin pole against a rounded limb looks alike whether it is grazing or passing through. That ring is now evidence capture, not a verdict. What separates cleanly is the 3D capsule test on the torso core, once it is fed measured flesh.

So "about zero pixels" is not the escape from hand-set constants it reads as. It is a threshold on a count that resolution, antialiasing, depth precision and camera placement all move, on a metric whose floor at the tightest margin tested was still above a hundred pixels on a clean bake. Paired comparison, same camera and same clip time, does separate. Absolute did not.

The metric is perceptual and view-dependent, which is the point, and it does have one property no depth budget has: the pole is emissive. It is an LED product. Glow bleeding through a thigh is far more visible than the same geometry on a matte cylinder, and every pixel this test counts is a lit one. That is the whole of its emissive awareness. A depth test cannot see bloom spreading past the pole's own silhouette, which is the form the glow actually takes.

The structural version of the lesson

Perception research on character animation is consistent about what viewers notice: they are highly sensitive to contact-state and silhouette violations — interpenetration, foot skate, a hand detaching — and remarkably insensitive to trajectory and joint-angle error. Which puts the QA axes in a rough salience order:

  1. visible interpenetration
  2. contact-event correctness
  3. physical plausibility
  4. trajectory fidelity

We spent the day at the bottom of that stack, on a quantity we had instrumented beautifully, while the top of the stack went unmeasured and was visible to any human in five clips.

Not a moral failing. A structural one: metrics track what is instrumented, and salience lives in what is not. Two practical corollaries came out of it and we have kept both. Move QA into pixel space wherever possible, since the harness renders the actual product output and perception applies to that rather than to the geometry proxy. And keep the human in the loop, but make them cheap and systematic: an auto-generated contact sheet per build, worst-N windows plus a few random ones, watched at 1× for five minutes.

Humans are the discovery channel; automation is the regression channel. The failure above was asking automation to do discovery.

Coda: the bug that made this whole post possible

If this reads as a story about a harness that needed one calibration pass, here is the version that convinced us it is a category rather than an incident.

A later round evaluated a baked animation through a playback path that skipped one function — the one that places the rig on the pole axis every frame. The entire performance rendered 0.4 m beside the pole: gripping air, standing on air next to the platform, for the whole take.

Zero of the twelve checks flagged it. A sparse-stills eyeball missed it. Worst of all, the cross-validation that was supposed to catch exactly this had compared violation counts rather than positions — and a body displaced into open floor produces perfectly plausible-looking counts, because its accidental pole crossings land in the same numeric range as real ones.

Spencer caught it by watching the videos.

The fix took minutes. The institutional response was a new check — a position-distribution sanity test, so a whole-performance offset can never again present as a normal-looking scorecard — and a rule we now apply to every comparison in the harness: validate seams at the position level, and never let a count stand in for a place.