Cut the serve down to three poses

Oliver, after playing the four-stage version on the phone: idle, then the racket
dropping on the pull, then the drive on release — "that's all, forget all the
others". At thumb speed the middle stages are never read, so they are deleted
rather than kept around: p_pull is the wind-up, p_smash is the drive, and both
come out of the photo-referenced sheet, so the whole serve is one drawing style.

The dead batches and the arm_left guard go with them. assets/_pose_ref_serve.png
is kept as the recipe: his photo sequence over our own sprites, which is what
turned a fifteen-generation prose argument into one generation.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Opus 5 committed 2026-08-01 01:09:57 +02:00
1 parent f6dfc57a06
commit 6378ff2a1b
11 files changed
+30 -97

No files matched your search

+20 -22
View File
@@ -414,16 +414,11 @@ Known generator quirks, all still true:
Oliver's notes on the art pass: the zombies are good, the runner "flickers very hard", and the
player has three problems. The serve is now a drawn wind-up driven by the pull.
- **The pull IS the wind-up.** Four new frames (`p_pull1..4`, batch `player_windup`), chosen in
`drawChar` off `pullFrac(G.aim.mag)`. What separates the four is HOW FAR THE RACKET HAS FALLEN, and
that only came out once the prompt pinned the racket head to a different BODY LANDMARK per frame —
above his head, beside his ear, between his shoulder blades, down at the back of his thighs.
Described as "further into the wind-up each time" it drew four near-identical poses twice running
(Oliver: *"pull3 and pull4 are now basically the same image"*), which is the generator quirk the
pipeline notes already warned about, in a place I did not expect it. The stages are NOT spread evenly: **frame 1 owns the whole
first half of the pull and the three coiled frames are packed into the top half**, Oliver's call,
so the part of the gesture that costs power is the part that visibly costs effort. Release fires
`p_smash`. Verified: 30/74/95/125 px of drag -> pull1/2/3/4.
- **The serve is THREE poses, not an animation.** Waiting: the bounce stance. Drawing the
slingshot: `p_pull`, the racket dropping behind him. Release: `p_smash`, the drive. A four-stage
version keyed to `pullFrac` was built, wired late (frame 1 owning the first half) and played, and
Oliver cut it back to this — on a phone, at thumb speed, the middle stages are never read. The
intermediate frames are deleted, not commented out.
- **The whole player is RIGHT-HANDED now, and that was the real bug.** `p_idle`, `p_bounce` and
`p_toss` had been drawn holding the racket in his LEFT hand while `p_smash` and `p_swing` used his
right, so any new frame copied whichever reference it was given and the racket changed hands
@@ -445,25 +440,28 @@ shearing a limb, cutting a prop out — a wrong frame is wrong in more ways than
(perspective, foreshortening, where the weight sits) and none of those survive a flip. There was an
`assets/_derive.py` doing exactly that; it is deleted. Fix the PROMPT and re-run the batch.
**Three pipeline guards were added to `_regen.py`, each after a bad sheet installed silently:**
**THE WAY TO GET A POSE RIGHT IS A PHOTO, NOT A PARAGRAPH.** Describing a serve in prose and
re-rolling cost about fifteen generations and never landed — the racket changed hands, the four
stages came back near-identical twice, the coil came back as a fold. Oliver's fix: give the
generator the real thing. `scratchpad/pose_ref.png` is the recipe — his 10-frame photo sequence
cropped to five poses in a row, with two of our own sprites underneath as the character and style
anchor, and a prompt saying which strip means what. **One** generation returned the whole serve as
our man in our kit, and the frames were sliced straight out of it (anchored on the standing figure
it drew, which is what sets the scale). Note it also redraws the reference strip above the result —
harmless, crop to the magenta band before slicing.
**Two pipeline guards were added to `_regen.py`, each after a bad sheet installed silently:**
1. **The reference's ASPECT is the answer's aspect.** One tall reference figure gave a portrait
reference canvas and the generator answered with a 2x2 GRID, which `_fine.py` cannot cut (it
segments columns). `ref_sheet` now widens to a landscape strip with one slot per frame asked for.
2. **A non-magenta background is a rejected roll.** "It sometimes ignores the magenta" was written
off as harmless because the key uses the corner colour — until it returned a GREEN sheet and keyed
away four grey-green racket heads with it, installing four men holding a grip and nothing else.
3. **`arm_left` rejects a MIRRORED frame.** The generator flips the later frames of a serve about
half the time, which puts the racket in the other hand halfway through the animation. Oliver
caught it twice by eye before the check existed. **It is a net, not a proof**: it asks whether
anything reaches the top of the LEFT half, and a mirrored frame whose racket head hangs over there
passes. A tighter discriminator was tried (ink mass in the top third, left vs right) and does NOT
separate the two — measured 0.61/0.57/0.41 on a mirrored sheet against 0.54/0.56/0.55 on a good
one. Every wind-up sheet still has to be looked at.
Still imperfect, and worth a look on the phone: the empty tossing arm WANDERS between the four
wind-up frames (up, out, bent, up) instead of staying thrown up at the ball. The roll that held the
arm still put the racket back in the wrong hand, and the racket is the load-bearing half of the
gesture, so this is the set that shipped. One more roll may fix both.
**And `_fine.py` takes `--defringe N` (default 2).** Each de-fringe pass eats a one-pixel line, and
a racket frame IS a one-pixel line: two passes were shredding every racket on the sheet. Detailed
art wants 1 or 0 — there was no magenta halo left at 0 on the serve sheet, because the palette
quantisation snaps to the sheet's own colours anyway.
Also worth knowing: a batch of raised-arm poses has no honest scale to anchor on, so frame 0 is
always a throwaway STANDING frame (`p_pull0`, deleted after installing). And a photo reference of a