Wind the serve up with the pull, and stop the frames flickering

Four new frames (p_pull1..4) turn the slingshot drag into the serve's wind-up:
racket above the head, behind the head, behind the back, fully coiled, picked off
pullFrac — the same 0..1 that sets the shot's power — so the gesture and the man
are one movement and the release snaps to the smash.

The two bounce frames are one drawing now. p_bounce2 is p_bounce with the free
arm sheared up 12px and nothing else touched, so the swap cannot flicker, and it
follows the ball instead of its rising phase; BOUNCE_IDLE was re-measured off the
sprite so the ball tops out under the palm. p_toss had the tossed ball drawn into
it — cut, canvas height kept, because the game scales him off img.height.

The runner: hip centres sat -2.0/+7.1/-6.0/-0.1 px off the sprite centre, a 13px
lateral jump at 12 frames a second, and Oliver's diagnosis was right that all four
frames leaned the same way and lifted the same leg. Frames 3 and 4 mirrored, all
four padded to one width with the hip on the centre line.

assets/_derive.py holds the three derivations, since "the same drawing with one
small difference" is the one thing the generator cannot draw.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Opus 5 committed 2026-07-31 23:51:30 +02:00
1 parent f71d9293fc
commit b1f8ea3240
16 files changed
+559 -419

No files matched your search

+41 -1
View File
@@ -5,7 +5,7 @@ everything they specified is shipped, and what still matters from them is record
long history, `~/.claude/projects/.../memory/splatter-tennis-history.md` is auto-loaded; for the
detail of any individual change, read the git log.
Last updated 2026-07-31. **Start with "How to work on this", "OPEN — leftovers" and "LATER —
Last updated 2026-07-31 (serve wind-up pass). **Start with "How to work on this", "OPEN — leftovers" and "LATER —
shipping it"** (all three just above the CLOSED sections) — the first tells you how Oliver's feedback
should be handled, the second is everything known to be outstanding in the game, the third is the
demo/store/campaign plan, which is decided but entirely unbuilt. All four playtest rounds are closed
@@ -384,6 +384,18 @@ Clear the intro first: `document.getElementById('intro')?.remove()`.
survives as a rim on a green court.
12. **Two-row "style reference / redraw this" input does NOT work.** The model returns both rows and
invents a background. Describe the target detail level in words instead.
13. **`assets/_derive.py` is where a frame that must MATCH another frame is made.** Three of them
live there now: `p_bounce2` (a per-column shear of `p_bounce` — the free arm bends, nothing else
moves), `p_toss` (the drawn-in ball cut out, canvas height KEPT so drawChar keeps his scale) and
the runner's hip registration. "Same drawing, one small difference" is the one request the
generator cannot fill: it returns a different man and the swap reads as a flicker, which is the
defect you were fixing. The bounce/toss steps are idempotent; the runner step is `--runner` and
must run exactly once per generated set, because it mirrors and it pads.
14. **A new pose needs a STANDING frame in the same sheet, as frame 0, thrown away after.** A sprite's
drawn size comes from its total height, so a sheet of nothing but arms-overhead poses has no
honest scale to anchor on and the man comes out short. `_regen.py`'s `ref` field does this, but
only when `ref_only` is unused — with `ref_only` set, list the throwaway as an extra sprite
(`p_pull0`) and delete the PNG afterwards.
Known generator quirks, all still true:
- It sometimes ignores the magenta (harmless — the key uses the corner colour).
@@ -397,6 +409,34 @@ Known generator quirks, all still true:
- **Colour-match any regenerated frame** of an existing pair before shipping: fit a per-channel
linear map onto the original's mean and sd, then verify with a mean-difference number.
## Session log: the serve is the gesture (2026-07-31, after the art pass)
Oliver's notes on the art pass: the zombies are good, the runner "flickers very hard", and the
player has three problems. All four fixed, all four measured first.
- **The pull IS the wind-up.** Four new frames (`p_pull1..4`, `assets/_regen_batches.json` batch
`player_pull`) — racket above the head, behind the head, behind the back, fully coiled — chosen in
`drawChar` off `pullFrac(G.aim.mag)`, the same 0..1 that sets the shot's power. Drag further, coil
further; release fires `p_smash`. Verified per stage with drawImage instrumentation:
mag 10/50/90/130 -> pull1/pull2/pull3/pull4.
- **The bounce pair is now ONE drawing.** `p_bounce2` is `p_bounce` with the free arm sheared up 12
px (0.10 m) — everything else is pixel-identical, so the swap cannot flicker. The swap follows the
BALL now (`|sin| > 0.5`) instead of its rising phase, and `BOUNCE_IDLE` was re-measured off the
sprite (`apex` 0.55 -> 0.6, `dx` 0.5 -> 0.43) so the ball tops out under the raised palm instead of
passing beside it.
- **`p_toss` had the tossed ball drawn into it.** Cut, without re-cropping the canvas: the game
scales him off `img.height`, so trimming the dead space would have shrunk him. Still 100x308.
- **The runner.** Two measured defects, both in the PNGs, no code change. Its four frames were
bbox-cropped and drawn centred on the body's x, so hip centres sat -2.0/+7.1/-6.0/-0.1 px off
centre — a 13 px lateral jump at 12 frames a second, which is the flicker. And Oliver's own
diagnosis was right: all four frames leaned the same way and lifted the SAME leg, so the cycle
never used his other side. Frames 3 and 4 are mirrored (he is front-on, so a mirror costs nothing)
and all four are padded to one width with the hip on the centre line.
Not done, and the honest reason: the runner's cadence is still time-driven (12 fps) rather than
stepped off distance covered like every other body. It did not read as wrong once the frames stopped
jumping, and it is one line if a playtest says otherwise.
## Session log: the art-resolution pass (2026-07-31)
**What changed.** The whole character roster was redrawn at real pixel-art resolution, plus a batch