6 Commits
Author SHA1 Message Date
wuwiandClaude Opus 5 b1f8ea3240 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>
2026-07-31 23:51:30 +02:00
wuwiandClaude Opus 5 e4c59e2c26 Turn the player around, point the runner at you, match the wounds
The playtest list, art side. The generator had been copying the very frames I
wanted changed, so:

- The player is drawn FROM BEHIND again in every pose — standing, bouncing,
  serving, swinging. He had turned to face the camera in the redraw, which is
  also why he "looked at you" in different poses.
- The serve frames are back at full size. That batch had been anchored on the
  toss frame, so the whole serve set came out about a fifth too small.
- The runner CHARGES AT YOU down the court instead of sprinting sideways across
  it, which is what he actually does in the game.
- The brute's wound stages are drawn a pair at a time from their own A frame, so
  the injury stops moving between the two feet.
- The bounce frames had a ball painted into them while the game draws a live one
  on top — he was bouncing two. The painted one is gone, and the live one now
  falls on the side the sprite actually reaches for.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 22:46:19 +02:00
wuwiandClaude Opus 5 f2bf63d546 Redraw the runner at real pixel-art resolution
I had been measuring the wrong thing. The complaint is not the PNG's size or its
upscale factor, it is how fine the DRAWING is — how many pixels make up the
figure, and whether there is room in it for teeth, fingers, seams and folds. On
that, my own prompts were the cause: every sheet this session ordered "every art
pixel is a big square block about 8 screen pixels across" and "flat blocks of
colour, no shading", which is a specification for coarse art. The generator
followed it exactly.

New recipe, proven on the runner's four frames: ask for HIGH resolution — "build
the figure out of 90 to 110 pixels of height instead of 40" — and enumerate the
detail it should spend them on (teeth, sunken eyes, individual fingers, tracksuit
seams and side stripe, torn edges, ribs, laced shoes, four or five shades per
material with hatched shading). Inner-edge density went 0.15-0.22 to 0.43-0.49;
z_mach2, which Oliver holds up as the good one, sits at 0.24.

z_f1 has been clipped on its right edge since it was made — the generator ran the
figure off the sheet. The new sheets demand 150px of empty margin at every edge
and it is whole now.

The rest of the roster is still the coarse style and wants the same pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 21:29:41 +02:00
wuwiandClaude Opus 5 1e4370f530 Re-cut the half-resolution sprites at full detail
Audited every sprite by detecting the art-pixel BLOCK SIZE each one was actually
drawn at. The set splits cleanly in two: 29 sprites are 112 art-pixels tall on a
2-pixel block — literal 2x upscales, carrying half the detail — against 200-224
for everything drawn since. z_f3 and z_bw are in the first group, z_chairt and
z_mach2 in the second, exactly as Oliver called it.

Regenerated at full detail so far: the player's idle pair, toss and smash (he is
on screen the whole game, and his own run and death frames were already fine, so
he was mismatched against himself), plus the two wounded shamblers and the
runner's three frames — where the wound skins were the worse case, since their
newly drawn second frames were full-detail and their A frames were not.

New pipeline step for it, assets/_fine.py: detect the generator's art-pixel grid
and snap to it, common-scale in ART pixels off a chosen anchor frame (so a smash
with the arm overhead stays legitimately taller), quantise back to the sheet's
own palette, and de-fringe the key colour twice — the generator does not always
return a pure magenta and the halo survives as a rim on a green court.

Still half-resolution, in order of how much they are seen: the brute's seven
wound stages, the seven opponent frames, the racket zombie's two wound skins,
and x_ump / x_boyrun1 / x_boycarry2 / x_boycarry3.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 21:03:47 +02:00
wuwiandClaude Opus 5 49d391dc64 Make it readable: 2x sprites, a flatter camera, honest hit timing
The umpire is situational again. Each line is tied to the thing that justifies
it — a new variant appearing, the court filling, one crossing your baseline, a
game lost, a horde, a changeover — behind one shared cooldown, so several
triggers at once still yield one remark. The random timer pool is gone, the
interval went 26s to 55s, and ump_out_of_order, ump_let and ump_no_appeal are
deleted.

"Visually the ball is not yet at the player but somehow the player already is
hit" was real and measurable. The hostile-ball hit test reused the parry's
hypot(dx, dz*0.8), and weighting depth shrinks it: contact fired while the ball
was still 0.68 m up-court and drawn up around his head. It has its own
unweighted test now, and contact lands at 0.25 m with the ball on his chest.
The parry keeps its weighting — a racket sweep really is wider than it is deep.

On "everything is a tad too small": measured first, because higher-resolution
sprites are only half the answer. At RES 3 the player rasterises into 170
device pixels from a 112px source — upscaled 1.5x — while a far shambler is
downscaled to 78. So near bodies needed resolution and far bodies needed the
camera.

Camera: pushed back and lengthened (camZ 42->48, camF 580->760) to flatten the
perspective so distant bodies grow relative to near ones rather than everything
zooming, camY raised for a steeper look-down, horizon re-centred. Far shambler
26->30px, boss 39->45px, player unchanged, court in the same band.

Sprites: the original sheets were still in the repo at full resolution, so
nothing needed regenerating — IDLE_TARGET_H went to 224 and every sheet was
re-sliced. The sheet-to-output mapping was never recorded, so it was recovered
by matching sliced frames to existing assets by image signature: 58 came back
from sheets, the 29 without a confident match were 2x-upscaled to stay on the
shared scale, since a sprite off that scale renders at half height.

Tennis untouched: 50 hits / 0 whiffs. 45-game soak clean, all four chapters.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 16:23:04 +02:00
wuwiandClaude Fable 5 e948e8b36e Aesthetics: 3x render res, flatter lens, 4-frame walk cycles, tiered gore
- RES 2 -> 3: phone screens now DOWNSCALE the canvas (crisp pixels) instead
  of upscaling it (soft). Umpire-tap coords un-hardcoded from RES=2.
- Flatter lens: camZ 36 -> 42 with camF scaled per orientation (406/580) so
  the PLAYER stays the same size — far-court zombies render ~25% bigger and
  finally read as individuals from the baseline.
- Smoother animation: 4-frame walk cycles for both classic shamblers and the
  runner's sprint (new sheets, same style anchor; z_a1-4, z_b1-4, z_f1-4).
  Same cycle frequency — frames subdivide the stride. Render falls back to
  2 frames per variant until its sheet loads.
- Tiered gore (GORE_MUL): the more advanced the zombie, the more absurd the
  mess — classics 1x (base bumped 24 -> 30 particles), runner 1.8x, shield
  2.5x, racket boss 3x, brute 4x (120 particles, a scatter of stains, an
  instant size-3 mound).

Verified: fresh origin, canvas 1440px, umpire triple-tap works at RES 3,
all 4 anim frames cycle at the old stride rate, brute kill = 120 parts /
2 stains / size-3 pile, far-court lineup screenshot clearly readable,
portrait layout numbers correct (810x1440, camF 580), tennis 11/12,
no console errors.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 17:30:46 +02:00