Make the regen pipeline check the kit, and fix the swing and toss

Every roll drifts the palette and nothing measured it: a white headband on six
frames, pale grey shorts on the toss twice, brick-red shirts and brown shoes on
the swing all sailed past --tries. check: "same"/"loose" skips colour_match, and
colour_match is a global mean/sd fit far too weak to pull brick-red back to red
— a nearest-colour palette lock is worse still, it drags the duller reds into
the racket's browns.

So _regen.py measures three numbers and a batch opts in with palette_ref:
redness (r minus mean(g,b) over saturated warm pixels — brightness alone cannot
tell brick-red from red), shorts brightness (charcoal 61 vs the drift's 83), and
the near-white fraction that is the shoes and socks (brown drops it to 0.9%,
pale shorts push it to 7.9%, correct frames sit at 2.8%). Frames known to be
right cluster tightly on all three; every drifted frame fell outside on at least
one. It rejected five bad rolls in a row, then passed a good one.

The swing also kept re-inheriting its own drift: ref_sheet is built from
[lead] + the sprites being replaced, so it was showing the generator the very
brick-red frame it was about to overwrite. Copying a canonical frame over the
targets first breaks the loop — it passed on the next roll.

Swing is now a real backswing and follow-through (silhouettes differ by 1.0,
racket low behind vs up over the shoulder), both at full standing height, and
the toss and smash wear charcoal shorts again.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Opus 5 committed 2026-08-01 11:51:27 +02:00
1 parent 494bab1b69
commit af30db2ff3
10 files changed
+72 -10

No files matched your search

+25 -4
View File
@@ -479,10 +479,31 @@ the player's own batches already used. Correctly anchored, a toss frame is TALLE
here) and the body renders at full size. Quick audit: a standing frame should be ~224, a raised-arm
frame >224, and nothing should be well under it.
**The opponent wears a RED headband.** A prompt that said "white headband" silently repainted it on
six frames, and it only showed up against the untouched `o_toss`/`o_idle1`. When regenerating part
of a character, name his colours in the prompt AND check the regenerated frames against an untouched
one — `check: "same"`/`"loose"` skips `colour_match`, so nothing else will catch a palette drift.
**EVERY ROLL DRIFTS THE PALETTE, SO THE PIPELINE CHECKS IT NOW.** A white headband on six frames,
pale grey shorts on the toss twice, brick-red shirts and brown shoes on the swing — all of it got
past `--tries` because nothing measured colour. `check: "same"`/`"loose"` skips `colour_match`
entirely, and `colour_match` is a global mean/sd fit that is far too weak to pull brick-red back to
red anyway (tried it; and a nearest-colour palette lock is worse — it drags the duller reds into the
racket's browns). So `_regen.py` has `kit()` and `kit_off()`, and a batch opts in with
`"palette_ref": "o_idle1"`:
- **redness** `r - mean(g,b)` over saturated warm pixels. Brightness alone does NOT work — a
brick-red shirt is exactly as bright as a red one, which is why the first check missed it.
- **shorts** mean brightness of mid-tone neutrals. Charcoal ~61, the pale-grey drift ~83.
- **bright%** share of the body that is near-white — the shoes and socks. Brown shoes drop it to
0.9%, pale shorts push it to 7.9%; correct frames sit at 2.7-2.9%.
Frames known to be right cluster at redness 99-110 / shorts 60-63 / bright 2.7-2.9, and every
visibly-drifted frame fell outside on at least one axis. Tolerance `(12, 10, 1.5)`. It immediately
rejected five bad rolls in a row and then passed a good one. **The `palette_ref` must be a frame the
batch is NOT regenerating**, or it validates against itself.
**`ref` feeds the frames you are REPLACING back into the reference sheet.** `ref_sheet` is built
from `[lead] + sprites`, so regenerating an already-drifted frame shows the generator that drift and
it faithfully copies it — the swing failed six straight rolls this way, each one re-inheriting the
brick-red shirt from the frame it was about to overwrite. Breaking the loop is one line: copy a
canonical frame over the targets first (`cp o_idle1.png o_swing1.png`), so the sheet is
colour-correct and the prompt supplies the pose. It passed on the very next roll.
**The opponent was running with empty hands.** `o_run1`/`o_run2` had no racket in either fist, and
the cause was the batch prompt: `opponent_run` never said the word "racket" and its reference sheet