Commit Graph
62 Commits
Author SHA1 Message Date
wuwiandClaude Opus 5 32401366fe Drawn frames, not procedural fakes: brute lurch, boy stride, crowd applause
Every animation in this round gets real frames. The procedural squash-and-sway
on the wounded brute read as fake on sight, and that gait is where the comedy
lives.

- Each brute wound stage now has its own 2-frame lurch (z_gw/z_gwb, z_gw2/z_gw2b,
  ...). The generator gave every B frame a dragged pole that only stage 1
  actually carries, so it would have blinked in and out each step — stripped by
  keeping the largest blob, and where the pole touched the body, by cutting on
  column density (a torso is dense, a dragged pole is a thin diagonal).
- Frames step off DISTANCE COVERED, never elapsed time — boy.dist for ball boys,
  z/bruteStride for brutes. A time-driven cycle moonwalks the moment speed and
  frame rate disagree, which is exactly what "he slides faster than the animation
  suggests" was. Change a speed now and the legs keep up on their own.
- One boy, one slot. sendBoy no longer replaces a boy already on court: that was
  the appearing and disappearing, since every kill teleported him back to the
  wing mid-stride. New mess is appended to his round instead. He now walks for
  10.5s a crossing, and there is a lot of mopping to do.
- The applauding crowd is a real two-frame animation (seated / arms up), swapped
  per column on its own phase. The old "smooth wave" still shifted each column by
  a FRACTIONAL dy, and nearest-neighbour resampling at a fractional y re-snaps a
  column's pixel rows every frame — that boiling beside the HUD is what read as
  the scoreboard flickering. The board art is 99.9% opaque; nothing was ever
  showing through it. With the crowd calm the frame delta is now 0.0%.

Benchmarks: 136/150 serve returns (90.7% ±2.4%, the 11/12 bar is inside one
sigma), 30 human-tapped points = 50 hits / 0 whiffs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 10:20:43 +03:00
wuwiandClaude Opus 5 ff77922e85 Feedback round: fire actually spreads, brutes lurch, crowd stops flickering
- Fire never spread in play. The flame ball's full pierce wiped its own lane, so
  the bodies that would have caught were already gone. It now ignites everything
  it FLIES PAST (TUNE.burnBallR), with a wider ignition and spread radius. One
  flame serve into a scattered 10-wave kills 9, nine burning at once.
- Wounded brutes slid along like decals: every wound stage is a single frame and
  the brute now spends most of its life wounded. They get a procedural lumber
  instead of eight more sprites — translate + squash, no rotation, so the pixels
  stay on the grid, and the amplitudes scale with the projection or the whole
  thing goes sub-pixel at range.
- The "scoreboard flicker" was the crowd: the cheer bounce was per-column
  Math.random() every frame, i.e. TV static, showing through the scoreboard art's
  transparent ornate edges. Now a smooth per-column sine on idleT.
- Ball boys: mopping is the default in splatter mode now, and the boy is half
  again as tall — at 1.2m he read as a distant speck. The running fetch-boy
  survives for tennis, where there is nothing on the grass but a ball.
- Changeover 7s -> 5s, with the mop crossing timed to fill it.
- Save-to-homescreen: a bloody tennis ball, wired up as apple-touch-icon +
  favicon + webmanifest. The Dockerfile now ships the manifest and gives it its
  own MIME type via an exact-match location (a bare `types {}` block would have
  replaced nginx's whole map and broken .js and .png with it).

Benchmarks re-run: CPU returns 67/72 serves (93.1%, above the 11/12 bar — a
20/24 sample in between was flub noise), 30 human-tapped points = 50 hits /
0 whiffs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 05:58:18 +03:00
wuwiandClaude Opus 5 a09a5d7559 Polish round: modal system, softened palette, pixel font, and the 14 plan items
The three foundations first, since everything else leans on them:

- G.modal is the only thing that stops the world. update() early-returns on it
  so no zombie steps, no ball flight, no spawn timers run while a popup is on
  screen — you can read it without being eaten. Dismissal swallows the gesture;
  the pointerdown dismisser is registered only on pointer:fine, because on touch
  pointerdown beats touchstart and a shared handler cleared the modal and then
  served with the same thumb.
- UI in config.js is the accent palette. The arcade primaries were shouting over
  the artwork; the gore reds deliberately stay loud.
- Every canvas font string now goes through F(). Bare `monospace` resolved to
  Courier — a slab serif — which was the "generic serif" bug, not taste.

Then: weapons are only ever WON. deliverTin() has exactly one caller now
(resolveInterlude('P')); the old game schedule calls the DUEL instead, fired off
proceedAfterClear() where the court is guaranteed empty. Four popups (splatter
tutorial with a generated illustration, first duel, weapon received, horde),
wCap 9 with the tin amounts tunable, a 5-hp brute that comes apart over four
wound skins, fire that ignites the neighbours and chains outward, a three-stage
death where you become the biggest gore mound on the court, and a 7s changeover
with a ball boy who finally has a mop.

New art: assets/logo.png, x_howto, z_gw2-4, x_boymop1-4, plus assets/_key.py for
standalone art (chroma-key + crop, no frame splitting, no forced sprite height).

Benchmarks re-run and holding: CPU returns 23/24 serves, 30 human-tapped points
= 50 hits / 0 whiffs, 26 simulated games with no exceptions.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 05:28:04 +03:00
wuwiandClaude Fable 5 5d815a4fc8 Docs: record the three feedback rounds, decisions, and verification gotchas
PLAN.md: two-stage aiming, runner-glass, fps-60, and no-engine decisions added
to the don't-re-litigate list; PWA/App Store noted as a next-arc candidate.
HANDOFF.md: status covers the post-plan rounds; gotchas gain the synthetic-touch,
1/60-stepping, port-hold, and zombies[]-mutation lessons.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 18:33:50 +02:00
wuwiandClaude Fable 5 2f1419b1f2 Feedback round + Phase 13: the duel, free-aim, honest stakes
Oliver's six complaints, addressed:
1. Opponent never came — a racket zombie now spawns on EVERY game you win
   (if none alive); endHorde no longer double-spawns
2. No wave-cleared feeling — sweepCourt: at game end the surviving wave
   collapses, every game gets a real beat (gameBeatT 1.6 / changeover 4.5),
   and 'GAME N' announces the next wave when play re-arms
3. Serve-posture lockup during machine gun — root cause: any 'over' beat
   expiring into setupPoint() -> pretoss during auto-fire (no movement outside
   rally, no serving during horde/GUN). The over-expiry now returns auto-fire
   modes to 'rally', never the serve loop
4. Forced bomb spending — specials commit ONLY on deliberate serves: flick
   (or arrow-aimed keyboard serve) fires the tin, plain tap keeps it; serve
   prompt teaches it ('FLICK FIRES THE BOMB - TAP KEEPS IT')
5. Auto-aim — free-aim: the flick vector maps to a landing point (length =
   depth, up to 22m), zombies within zSnap 1.4 magnet the shot, otherwise the
   ball lands exactly where flicked; taps keep the old auto-target assist;
   flicks now also work at the toss apex
6. Zombies walking through you — option (a): touch is honest. eatenR 0.9
   (brute +0.2) matches the visual sprite overlap

Phase 13 — SUDDEN DEATH interlude: court clear + un-dueled racket zombie +
about to serve -> 'Quiet, please. Play will resume.' / 'Sudden death.' One
point under REAL tennis rules (line calls live, the boss plays every ball,
spawns paused). Win (line call, double bounce, or regicide by any weapon) =
the next tin delivered on the spot; lose (out, or its return passes you) =
a game on their scoreboard + an instant 5-shambler surge. One duel per
opponent. New lines: play_resume.m4a, sudden_death.m4a.

Verified in browser: horde 'over' beat -> rally (lockup dead); game win ->
sweep + boss + beat -> SUDDEN DEATH chains naturally; duel lose path (GAME.
THEM., surge 5, scoreboard), no re-duel, fresh-boss duel, bomb regicide ->
tin on the spot; tap serve keeps stock, real touch-flick consumes + lands
at the flicked point, magnet snaps when near; eaten at 0.85m; tennis 11/12;
no console errors. PLAN.md/HANDOFF updated: plan v2 complete.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 11:50:18 +02:00
wuwiandClaude Fable 5 811fe3f91f Phase 10: sprite session — runner, brute, shield zombie, weapon tin
Sheets generated with the existing zombie sheet as the style anchor (edit mode);
sliced to z_f1/2 (runner sprint), z_g1/2 (brute + net-post club), z_s1/2/3
(shield zombie, chair up / chair dropped stagger), x_tin (black new-balls tin).
assets/_slice.py is now committed (chroma-key + de-fringe + segmentation) so the
pipeline survives scratchpad wipes; HANDOFF updated.

Sprites are NOT wired into render.js yet — Phase 11 does that after Oliver
approves the sheets (plan's design checkpoint).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 10:19:21 +02:00
wuwiandClaude Fable 5 f512709074 HANDOFF: phases 7-9 shipped, next is the sprite session
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 10:00:47 +02:00
wuwiandClaude Fable 5 25db84ed87 Plan v2: match structure, enemies, weapons, interlude (phases 7-13)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 09:54:01 +02:00
wuwiandClaude Fable 5 fe5532b558 PLAN.md: phased zombie-mode expansion plan for follow-up implementation
Five phases, each independently shippable with verify recipes: tighter
shooting loop, multi-kill umpire fanfare, procedural gore piles, bomb
balls delivered by ball boys, horde waves with machine-gun racket.
Racket zombies deferred to a design checkpoint (Phase 6, not first cut).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 21:37:04 +02:00
wuwiandClaude Fable 5 775d465f23 HANDOFF: tennis feel confirmed good; record benchmarks and cache gotcha
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 21:23:19 +02:00
wuwiandClaude Fable 5 943b7da9fd Zombies get faster over time; when one reaches you, you're eaten
splatT now ticks while in splatter mode and scales spawn speed by
1 + min(1.5, splatT/70). A zombie within 0.7m of the player ends the
run: gore burst, 'game, set, massacre', dark EATEN. overlay with final
games and a tap-to-restart (gated 0.7s so death-spam doesn't skip it).
Zombies keep shambling on the end screen but no longer score. Also
verified the two prior unverified items: quick-serve cadence (0.25s
between balls, flick = instant aimed serve) and flick aiming across
the net (far/near lane selection works as designed). HANDOFF updated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 19:54:09 +02:00
wuwiandClaude Fable 5 e7aab295d4 WIP splatter feedback round + HANDOFF.md for session continuation
Done (unverified): faster serve cadence in splatter (overT 0.25, serve from
where you stand, flick = instant aimed quick serve), aim-anywhere targeting
relative to the player. Not done: zombie speed ramp (G.splatT exists but is
never incremented), eaten-on-touch death + restart screen. Full state and
plans in HANDOFF.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 19:28:00 +02:00