Miss log: every tennis swing logs why it failed, last reason shown on HUD

Whiffed swings sample the ball's approach each frame and classify the
miss at swing expiry: tap too early (with ms), tap too late, ball line
wide, too high/low, out of reach. Balls that die on your side without
a swing log as PASSED with closest-approach data. Ring buffer of 50 at
T.G.missLog; the latest miss reason flashes on the HUD for 3.5s
(TUNE.missHud to disable). CPU serve-return benchmark still 11/12.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Fable 5 committed 2026-07-11 21:02:11 +02:00
1 parent 943b7da9fd
commit d6d00929bb
4 files changed
+80 -2

No files matched your search

+6
View File
@@ -30,6 +30,11 @@ export const G = {
wasServe: false, // the ball in flight is a serve (first bounce must hit the box)
splatT: 0, // time survived in splatter mode — drives the difficulty ramp
eatenT: 0, // time since you were eaten — gates the restart tap
missLog: [], // swing diagnostics ring buffer (tennis mode) — inspect via T.G.missLog
swingSnaps: null, // ball-approach samples during the live swing, feeds the miss log
rallyNear: null, // closest the incoming ball got this rally (for never-swung passes)
swung: false, // player swung at least once this rally — whiff log supersedes PASSED
lastMiss: null, // {text, at} — most recent miss reason, drawn on the HUD briefly
};
export const other = s => s === 'P' ? 'O' : 'P';
@@ -37,6 +42,7 @@ export const deuceSide = () => (score.pts[0] + score.pts[1]) % 2 === 0; // even
export function setupPoint() {
G.phase = 'pretoss'; ball.active = false; ball.bounces = 0; ball.firstLand = null;
G.swingSnaps = null; G.rallyNear = null; G.swung = false;
if (G.mode === 'splatter') { // always your serve, from wherever you're standing
score.server = 'P';
P.pose = 'idle'; P.swingT = -1; P.facing = 1;