Commit Graph
4 Commits
Author SHA1 Message Date
Nicholas ButzkeandClaude Opus 5 700d0925d7 tools: measure rest poses, and diagnose momo
momo's idle plays with her arms overhead and her waist pinched, and every
assertion in the suite passes on her.

The first suspicion was the retarget's rest-relative delta: it applies "what the
clip does to the LIBRARY's rest" to THIS rig's rest, which quietly assumes the
two rests are alike. rest_pose_check.gd tests that, and disproves it — miku's
arms rest 41° off the library's and taila's 32°, and both animate correctly. The
delta retarget handles a rest-pose difference, which is what it is for. Recorded
in the reference so nobody spends that hour again.

Writing the tool reproduced this project's own recurring mistake in miniature.
Measuring "the direction from a bone to its first child" reported kiyoko's and
aria's legs 71° off the library — because a thigh's first child is as likely to
be a skirt bone as a shin, and it was measuring the hang of a skirt panel.
Pointing it at the next limb BY ROLE dropped both to 1°.

What momo actually has: `Root_001` through `Root_007` are in her driven_bones,
and they are her HAIR roots — Hair_A is dominated by Root_001_001, Root_007 and
Root_005. The animation is keying bones the spring solver is supposed to own,
which is non-negotiable #2 broken by the role resolver rather than by a clip.
The surface table corroborates it: her hair surfaces report 1.8% and 9.4% chain
share, because most of their vertices belong to bones in no chain at all.

Not fixed here. `Root_00N` matches no COSMETIC stem, and adding "root" to the
stems would cost a rig whose actual root is called `Root` its hips. The
structural fix is that a bone whose geometry is dominated by a mesh classified
`hair` is a hair bone whatever it is called — which the surface table makes
answerable at build time, and did not when momo was imported. It needs a Blender
re-run and re-verification of all six characters.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-07-27 15:03:33 -04:00
Nicholas ButzkeandClaude Opus 5 1e6f3001ac docs(skill): the surface table, rig anchors, and asserting the consequence
The skill is this project's own instructions, and three commits made it wrong:
it described a runtime that re-guessed what every surface was, a lab that only
tuned weapon holds, and a suite that could not see any of the last five defects.
It also still listed a seventh character that is not in skins.json.

Records what is new — the surface table and how it is decided, the layered
tuning files and why a fixed rotation on the weapon mount is the wrong answer,
the rig lab — and what the work taught:

  * assert the CONSEQUENCE. Asking a model which clip it is playing reads a
    variable it set on itself, and says "Idle" just as happily when nothing is
    ticking. Asking whether an anchor saved says nothing about whether the gun
    moved.
  * four of the last five real defects came from looking at a PNG. Every one of
    them passed every assertion.
  * the line-work rule now exists twice, at build time and as the runtime
    fallback, and they must be changed together or a model with a surface table
    starts rendering differently from one without.

Also records momo's broken idle and the stray Icosphere under known-unsolved,
with what is worth suspecting first in each case, since neither is fixed.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-07-27 15:00:42 -04:00
Nicholas ButzkeandClaude Opus 5 2b3e29dd30 fix(pipeline): check that a character is CORRECT, not merely well-formed
Seven characters shipped "All checks passed" and four were visibly broken
in game — lying on their backs at seven times scale, facing backwards, or
holding a gun that floated near their chest. Nothing in the suite was
wrong; it just never asked the questions that mattered. That distinction
is the whole lesson, and it is now written down in the skill as
references/failure-modes.md, generalised per failure.

Two root causes are measured and certain:

- flatten_and_scale() normalises the bounding box along Blender Z because
  Z is up. For a model that arrives lying along Y that measures the
  character's THICKNESS, so it scales by ~7 and leaves them on their back.
  One assumption, both symptoms. The trap is that the normalised number
  always comes out right — the exporter maps Blender Z to glTF Y, so "is
  the height 1.75" passes on a character who is 7.5 m tall lying down.
  All three casualties are VRM files that went through a Blender
  round-trip and came back with a baked axis rotation.

- SkinnedPlayerModel.set_weapon() finds the hand with three hardcoded
  spellings, which match none of the four non-Rigify rigs — their hands
  resolve perfectly in the sidecar as "Right wrist" and "J_Bip_R_Hand".
  When it misses, the weapon is parented to the model root at a fixed
  chest offset, so it is not attached to the character at all. Same class
  of bug as the leg check that name-matched thigh/shin. rig_map.py exists
  so nothing downstream has to guess a bone name; only some consumers read
  the roles it publishes.

Three new hard checks, none needing more than the vertices and the
sidecar:

  character stands up in world space   — against WORLD up, not against the
      model's own proportions. "Is the spine the longest axis?" catches
      nothing: a model rotated as a whole is internally consistent and
      passes it comfortably.
  character is a plausible size / height
  every role the runtime needs is resolved

They separate the four good characters from the three broken ones on the
first run. Also fixed the posture measurement to read vertices rather than
object.bound_box, which is cached and still stale right after an import —
it reported a 1.75 m character as 1.18 m tall.

Recorded but not yet fixed: kiyoko faces backwards (facing is inferred by
two independent mechanisms and verified by neither), miku's grown hair
chains stretch under animation (generated chains are never validated
against the geometry they drive), and the mannequin's rifle hold does not
convince despite resolving correctly.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-07-26 16:02:06 -04:00
Nicholas ButzkeandClaude Opus 5 daf9627ece docs(skill): compact the character pipeline into a reusable skill
Everything about getting an anime-styled character into the game — import,
stylization, the body/garment/hair separation, rigging, retargeting, cloth
and hair physics, and how to measure any of it — collected into
.claude/skills/character-pipeline/.

Organised around the principle the Hoyoverse-class pipelines are built on
and that every failure in this project traced back to: a character is not
one object. It is a body, a set of garments and hair, authored and rigged
separately and moved by different systems. The body is skinned and
animated; the garments and hair are bone chains the animation never
touches and physics moves. The skill's non-negotiables are the four ways
that separation has been destroyed here before — joining meshes, keying
cosmetic bones, skinning cloth to a leg, and running the auto-rig repair
on authored weights.

references/verification.md leads with the trap that invalidated every
cloth measurement ever taken in this repo: Godot restores bone poses after
the modifier pass, so a tool that reads them afterwards measures the
animation and never sees what any modifier did.

Also records what is known-unsolved, with numbers: peak cloth clipping in
a run/slide/dash, no foot IK, no strafe clips.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-07-26 12:46:50 -04:00