7 Commits
Author SHA1 Message Date
Nicholas ButzkeandClaude Opus 4.8 afc954e129 fix: no limb vertex may carry opposite-leg weight — thigh collapse gone
The thighs going thin was never the knee bend. It was inner-thigh vertices
keeping ~20% of the weight of the OPPOSITE leg, so a split stride tore them
across the body. Printing the weight composition of the worst-collapsing
vertices is what finally showed it: a right-thigh vertex reading
DEF-thigh.R=0.58 DEF-shin.R=0.21 DEF-thigh.L=0.13 DEF-shin.L=0.08.

Every earlier pass had a guard that let these through. The below-knee pass does
not reach them; the above-knee pass demanded one leg chain be 1.25x nearer than
the other, which excludes everything near the centre line — precisely where the
damage was; and the limb-radius gates are measured from the bone AXIS, so a
vertex on the front or back of a thigh clears them easily.

SkinLegRepair now ends with an unconditional pass: any vertex within a generous
radius of either leg chain is forced onto the leg that actually drives it, at
any height. It runs last so none of the staged rules can reintroduce the
problem.

Measured per vertex, across jump, fall, run and dash:

                     before        after
  Body below 0.80      70            0
  Body worst          0.46         0.82
  ClothCAndW below 0.80  107          0
  ClothCAndW worst    0.66         0.85
  ClothB worst        0.81         0.87

No vertex anywhere on the legs now loses more than 18% of its thickness, down
from 54%. The skirt still deforms freely (0.87-0.88) — clothes flow, limbs hold.

Also fixed in SkinJointHelper along the way: it picked the FIRST joint chain
that matched a vertex rather than the one holding most of its weight, which
bound right-thigh vertices with stray left-leg weight to the LEFT knee's helpers
and dragged them across the body. It now picks the dominant joint and requires
the joint to own at least half the vertex.

Taila snaps 2021 vertices, Miku 659. FSM tests 11/11, spawn smoke test 0
failures.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-22 09:03:45 -04:00
Nicholas ButzkeandClaude Opus 4.8 0bb1db0806 revert: let the skirt move again; keep the rigid-limb work
The previous commit stiffened the skirt onto the hips to stop it flattening at a
wide stride. That was the wrong trade: it made the clothes read as a rigid shell
welded to the pelvis, which is a worse look than the flattening it fixed, and it
broke the model more than the original bug did. Reverted in full.

What stays is the work that makes the HUMANOID hold its shape — below-knee side
snapping, the above-knee limb pass, the torso cap, the half-angle knee helpers,
and the cross-leg triangle drop. Those only ever touch vertices hugging a leg's
own bone chain.

The header now states the rule the passes are actually built around, because it
is what keeps getting violated: limb vertices are cleaned up hard and must not
deform; drape vertices are left alone and must be free to move. It also records
the skirt-stiffening attempt so it does not get retried.

Measured split now, from debug/limb_deform_check.gd: the body holds 0.98 of its
cross-section at the knee while the skirt sits at 0.88 — rigid limbs, moving
cloth. Taila snaps 1404 vertices (down from 4024 with the skirt pass), Miku 434.

FSM tests 11/11, spawn smoke test 0 failures.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-22 08:31:25 -04:00
Nicholas ButzkeandClaude Opus 4.8 20b70e5eda fix: hang the skirt from the hips so it stops collapsing at a stride
It was the SKIRT, not the legs. Every leg check I ran hid the skirt to see the
thighs, so I was never looking at what is actually on screen. Rendering the full
model side-on shows it immediately: at rest the skirt is a flared shape with
real volume, and the moment the legs split for a run or a jump it collapses flat
against the body. The lower-body silhouette loses its shape, which reads as the
legs squashing.

Cause: the skirt is weighted to BOTH thighs. At a split stride the two thighs
pull it in opposite directions and linear-blend skinning averages them, so the
skirt is dragged inward and flattened. The earlier repair deliberately left it
that way, on the reasoning that a skirt should be free to drape across both
legs — correct in principle, wrong at these stride angles.

Draping cloth now hangs from the hips: vertices that clear both leg bone chains
keep at most 20% leg influence and the rest goes to DEF-hips, so the skirt holds
its shape and swings as a unit. Limb vertices are still snapped to one leg, so
the two are now modelled differently on purpose.

Bounded ABOVE THE KNEE. The first attempt used distance from the bone chain
alone, and chunky boots sit further from the ankle than the limb radius, so they
read as "drape", lost their leg weight and trailed off the hips — the legs came
out far worse than before. A skirt hem is above the knee; boots and stockings
are not.

Legs unchanged by this: knee cross-section stays 0.99, and the knee helper work
from the previous commit is intact. Taila snaps 4024 vertices, Miku 670.

FSM tests 11/11, spawn smoke test 0 failures.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-22 08:20:27 -04:00
Nicholas ButzkeandClaude Opus 4.8 e707229283 fix: stop the torso holding back the top of the thigh
Hiding the skirt and jacket and rendering the legs alone, side-on, finally
showed where the deformation actually is: not the knee, the HIP. The top of the
thigh flattens into a wedge at full stride. That matches the worst number the
corrected measurement reports — cross-section 0.85 at the hip, against
0.97-0.99 at the knee — which had been dismissed as ordinary.

Cause is the usual linear-blend failure at a big rotation: upper-thigh vertices
are weighted between the near-static hips and a thigh swung far out, and the
average of those two transforms collapses the top of the leg. SkinLegRepair now
caps torso (hips/spine) influence on LEG vertices at 15% and hands the excess to
the leg bone that already dominates them. Only vertices within the limb radius
of a leg bone chain are touched, so the skirt keeps swinging from the hips.

Hip cross-section 0.85 -> 0.88, and the flattened wedge is visibly fuller in the
side-on render. This is a real improvement but a modest one; the legs are slim
low-poly geometry and some collapse at a 60 degree hip rotation is inherent to
linear-blend skinning.

Taila now snaps 1217+ vertices, Miku 434.

FSM tests 11/11, spawn smoke test 0 failures.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-22 07:57:19 -04:00
Nicholas ButzkeandClaude Opus 4.8 1e12c36cca tools: give the limb deform check a baseline that validates itself
The measurement was comparing skinned lengths against BIND-POSE lengths. A
character is never in bind pose, so ordinary posing registered as deformation:
with the animation frozen it still reported 0.42x-2.56x edge ratios, and during
a run it reported edges collapsing to 0.08x and blowing out to 5.2x. Those
numbers were an artefact of the metric, not the model.

The baseline is now built from the skeleton's REST transforms, so every ratio
reads exactly 1.00 on an unposed model and the tool validates itself. Corrected
readings on Taila through the full runtime stack, worst over run, walk, jump,
fall, slide and dash:

  lengthwise stretch  1.07 Body, 1.08 ClothB, 1.09 ClothCAndW, 1.03 shell
  cross-section       0.97-0.99 knee, 0.85 hip, 0.92-0.94 ankle

That is ordinary linear-blend skinning.

Also records, in the header, the two ways this measurement was previously wrong,
because both nearly produced a bad "fix":

  * the bind-pose baseline above;
  * flagging vertices weighted across "non-adjacent" leg bones with
    max_slot - min_slot >= 2, which flags shin+foot+toe — a perfectly normal
    contiguous run. A repair pass built on that was written and reverted before
    it shipped; it was stripping legitimate toe and shin influences.

Checks that did come back clean and are worth not repeating: bone pose bases are
pure rotations to 0.00001, bone lengths never drift from their rest offsets, and
of 4019 coincident-vertex groups not one carries mismatched weights, so there
are no split seams tearing at the joints.

No character or gameplay code changed. skin_leg_repair.gd is byte-identical in
behaviour to the last commit; only its header comment gained a pointer to this
tool.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-22 07:51:18 -04:00
Nicholas ButzkeandClaude Opus 4.8 a6e009d24a fix: repair thigh weights too, and keep the gun shouldered at low-ready
Legs: the previous pass deliberately stopped at the knee, on the reasoning that
cross-leg weighting above it is legitimate for skirts. It is — but the LEGS
themselves are up there too, and 122 vertices on Taila's thigh mesh carry up to
35% of the opposite leg. Running and jumping are exactly what splits the legs
far enough for that to show, which is why the cuffs came good while the legs
kept squashing.

The repair now runs above the knee as well, but only on vertices that belong to
a leg. Limb membership is decided by distance to that leg's own bone chain, not
by height and not by surface name: a thigh vertex hugs its bone, while a skirt
vertex hangs clear of both chains and is left blended so it can still drape over
the two legs. The radius is half the gap between the thigh bones, so it scales
with the character rather than being a magic number. Taila now snaps 1217
vertices (was 720), Miku 370 (was 214).

Weapons: at low-ready the stock was dropped 0.20 m below the shoulder joint down
to the ribs, with the muzzle pitched 22 degrees down. That pulls the whole
weapon off the shoulder and out of the supporting arm — it read as dangling
from the hands rather than being carried. Low-ready now stays in the shoulder
pocket and merely relaxes out of it (0.07 m drop), with a shallow 9 degree
muzzle tilt. All six weapons now sit in the shoulder with both hands on them.

FSM tests 11/11, spawn smoke test 0 failures.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-22 02:08:07 -04:00
Nicholas ButzkeandClaude Opus 4.8 f60941d1fb fix: stop the boots being dragged by both legs; keep the support hand on the gun
Found the real cause of the leg stretching, after three wrong guesses.

720 vertices on Taila are weighted to BOTH legs at once below the knee — 262 in
the boot/cuff surface, 208 in the outline shell, 176 in the body, the worst at a
dead-even 49/51 split. A vertex pulled equally by both feet sits halfway between
them and STAYS there while the legs separate, stretching every triangle around
it. That is the band between the ankles and the elongated boot that reads as the
legs being squashed. SkinLegRepair snaps each below-knee vertex to whichever leg
already dominates it, renormalises, then drops the few triangles still spanning
the two legs (48 on Taila, 0 on Miku, which needs 214 vertices snapped).

What finally located it was reproducing the artefact through the FULL runtime
stack in a bright scene. Every previous "clean" render had bypassed the game's
animation stack — playing the clip straight off the GLB's AnimationPlayer with
no AnimationTree and no pose modifier — so it could never show the bug. With the
real stack the boot visibly stretches, and freezing the AnimationTree at the
rest pose renders it perfectly, which proves the pose is fine and the skinning
is not. Confirming measurements, all through the runtime stack during a run:
no bone's pose basis deviates from a pure rotation by more than 0.00001, no
bone's length drifts from its rest offset by more than 0.0000 m, and no
below-knee vertex is influenced by any non-leg bone. There is no squash-and-
stretch in this rig; there never was.

The two earlier attempts at this are both superseded: re-weighting by
triangle-neighbour majority (tore the cloth) and deleting cross-leg triangles
(too narrow — 24 triangles against 720 bad vertices). Hiding the model's own
outline hull, from the last commit, stays: that hull is genuinely broken and
redundant, it just was not the whole story.

Weapon support hand: gun_fore was a single constant 0.35 m for every weapon, so
on a short gun it hung the off hand out past the muzzle with nothing to hold —
that is the "not supported by the arms" case. It is now clamped to 80% of the
weapon's own grip-to-muzzle distance, which only bites on the short guns (MP7
0.35 -> 0.20). All six weapons now sit in the shoulder with both hands on them.

FSM tests 11/11, spawn smoke test 0 failures.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-22 01:25:04 -04:00