assets/_regen.py plus a batch file: build a reference sheet from the sprites in
the repo, ask for a HIGH-resolution redraw, slice with _fine.py, colour-match
each frame onto the one it replaces, install. The point of the whole thing is the
style block — the old prompts specified coarse art and got it.
It refuses to install a bad sheet. Wrong frame count, any figure touching a
canvas edge (that is what clipped z_f1 in the first place), or a redraw that is
not measurably finer than what it replaces, and the batch is left alone with a
reason printed. Re-running a batch is the fix; three of the first eleven needed
it. The bar is 1.25x inner-edge density rather than 1.5x, because a sheet that
already has blood on it starts high and a genuinely finer wounded body still
scores a smaller gain.
Done so far: both shamblers and their wound skins, the brute's walk and its two
sets of wound stages, the steward and his wound skins, the turned CPU.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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>
- p_bounce/p_bounce2 re-extracted from Oliver's corrected _sheet_pbounce.png
(racket properly in the right hand)
- bounce ball offset 0.4 -> 0.32 so it sits under the reaching hand
- landing rings draw with integer-snapped center/radii and a solid 2px
stroke — the sub-pixel anti-aliasing shimmer read as flickering
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- boy runs on a proper 4-phase cycle (stride, pass, mirrored stride, pass)
- server holds the crouched bounce stance through pretoss instead of
flickering to standing idle; hand-down/hand-up frames sync with the ball,
which now bounces floor-to-hand height
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>