Route by job, not by file size: the tool table fresh sessions needed

Oliver's concern, after the un-chunking: a fresh session walked straight into
_regen.py and diagnosed from there, twice — first the legacy prompts, then the
model's rolls — while the real bug sat in the cutter, provable by putting any
fam_ sheet next to the sprite cut from it. The family-pipeline section already
demoted _regen.py, but 270 lines below the "Asset pipeline" heading, and the
session memory that routed the last investigation pointed at _regen by name.

So the routing is now the FIRST thing under "## Asset pipeline": a
which-tool-for-which-job table that names _famroll -> _zsheet for families,
marks _regen.py as the single-sheet remaster tool it still is (bosses, players,
crowd, weapons — those jobs keep it alive, so it stays), and states the
diagnostic rule that would have saved two days: when installed art looks worse
than the _refcheck sheet it came from, the suspect is the CUT, and a re-cut is
free. _regen.py's own header says the same, for whoever opens it first anyway.

The "Only ink votes" lesson joins the family-pipeline section with the numbers:
0.0% of ink blocks uniform at b=11 against 99.2% of empty ones is how a
detector proven on single-row sheets quietly broke on 9-row geometry — the
threshold never changed, the data under it did.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Fable 5 committed 2026-08-14 08:57:25 +02:00
1 parent c4c9f0aac2
commit 6cc9799536
3 files changed
+48 -1

No files matched your search

+41
View File
@@ -1606,6 +1606,25 @@ Clear the intro first: `document.getElementById('intro')?.remove()`.
- **Never trust a single sample.** aiFlub is 9%; a 20/24 run is normal noise. Use 150.
## Asset pipeline
**WHICH TOOL FOR WHICH JOB — read this before opening any `_*.py` (2026-08-14).** A fresh session
reaches for `_regen.py` first, because it is the biggest file and the oldest name — and for most jobs
it is the WRONG tool, superseded by the reference-sheet flow. Route by job:
| The job | The tool |
|---|---|
| A whole opponent family (31 sprites, one character) | `_famroll.py` -> `_zsheet.py` — see "THE ZOMBIE FAMILY PIPELINE" below. **Never `_regen.py`**: nine separate rolls is nine chances for the character to drift, which is why the family pipeline exists. |
| Rebuild the pose reference | `_famref.py` — composed from disk, no API call, gated. |
| Player/opponent run cycles | `_runroll.py`. |
| A stride twin (legs frozen) | `_stride.py`. |
| Single-sheet remaster, boss roster, any non-family sprite | `_regen.py` + `_regen_batches.json` — the only jobs it is still for. |
| Standalone art (logo, panels) | `_key.py`; coarse legacy sheets, `_slice.py`. |
**And when installed sprites look WORSE than the `_refcheck/fam_*.png` sheet they came from, the
suspect is the CUT, not the roll** — the sheets on disk are the evidence, and a re-cut is free (see
"Only ink votes" below). Seven families shipped pixelated for two days because every fresh look
started from "the generator drew it badly" instead of diffing sheet against sprite.
1. `generate-image` skill (needs `OPENROUTER_API_KEY` in the gitignored repo `.env`; run with the
scratchpad venv python — system python lacks `requests`). Passing the existing sheet as
`--input` (edit mode) nails the style and is how every matching sheet here was made.
@@ -1921,6 +1940,28 @@ uv run --with pillow --with numpy python assets/_zsheet.py assets/_refcheck/fam_
`uv run --with …` is how these run: this machine's python has no PIL or numpy of its own, and the
previous session's interpreter was a uv ephemeral env. `SPLAT_PY` still overrides for `_regen.py`.
### Only ink votes: how seven fine families shipped pixelated (2026-08-14)
`_fine.block_size()` finds the generator's art-pixel grid by scoring b×b blocks for uniformity — and
it scored ALL of them. `key()` zeroes the background, a zeroed block is uniform at every b, and on a
9-row family sheet the background is ~85% of the figure bounding box, so the background ALONE cleared
the 0.82 bar at any block size tried. Measured on `fam_ru.png`: 0.0% of ink blocks uniform at b=11,
99.2% of empty ones, overall 0.821 — detected block 11, and `_zsheet` then honestly snapped 428 px
figures down to 39 art px and scaled them back up. The pixelation was manufactured in the cut; every
sheet the model returned was fine. br survived at 0.775 only because its ink coverage runs four
points higher, and the whole per-family chunkiness ranking (br fine … ch/ru/sh/st at 6 px blocks) was
ink-coverage noise around one threshold. Background-only blocks get no vote now, and all eleven
families were re-cut from the sheets already in `_refcheck/` — no new rolls, no tokens.
Two rules fall out of it:
- **A detector proven in one geometry is unproven in another.** `block_size` was validated on
single-row `_regen` sheets where figures fill the bounding box; the 9-row family sheet silently
inverted its ink/background ratio. The threshold never changed — the data under it did.
- **Diff the artifact against its source before blaming the source.** The chunky sprite and the fine
sheet it was cut from sat side by side on disk for two days. One `Read` of each would have located
the bug immediately; instead the first two theories (legacy `_regen` prompts, model roll variance)
both blamed generation. Oliver's screenshot pair settled it in one glance.
**A frozen stride pair in the master blocks the whole pipeline, by design.** `_famref.py` refuses to
write the sheet if any of the three stride pairs has legs that barely move — because the model copies
what it is shown, so a frozen pair in the reference is a frozen pair in every family drawn off it.
+6
View File
@@ -1,5 +1,11 @@
# _regen.py — redraw a batch of sprites at real pixel-art resolution, end to end.
#
# ROUTING — CHECK BEFORE USING. This is the SINGLE-SHEET remaster tool (boss roster, players, crowd,
# weapons — anything without a family). A whole opponent family is NEVER built here: that is
# _famroll.py -> _zsheet.py (PROJECT.md, "THE ZOMBIE FAMILY PIPELINE"), because nine separate rolls
# is nine chances for the character to drift, and it took every one of them. See PROJECT.md
# "WHICH TOOL FOR WHICH JOB" for the full routing table.
#
# python3 assets/_regen.py shambler_a # one batch
# python3 assets/_regen.py --list # what batches exist
# python3 assets/_regen.py --all # everything not already done
+1 -1
View File
@@ -431,6 +431,6 @@ if (location.hostname !== 'splatter-tennis.wuwi.one') {
</div>
</div>
</div>
<script type="module" src="src/main.js?v=226"></script>
<script type="module" src="src/main.js?v=227"></script>
</body>
</html>