From c9699da6f12bbb4cfe995961c92075724ba5d2e3 Mon Sep 17 00:00:00 2001 From: Oliver Rieger Date: Thu, 30 Jul 2026 19:22:23 +0200 Subject: [PATCH] Clear the frame to the apron colour MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit That band at the bottom was not a background mismatch — the canvas was transparent there. render() never cleared: the stands cover the top and the out-area quad covers the middle, so it looked complete, but the quad only reached z=30 and everything below where that projects was see-through. The page showed through it, which is why it read as a slightly duller green. The frame is now cleared to pal.out before anything draws, oversized by 8px so a camera shake cannot expose an edge, and the out-area quad runs to z=60 so the perspective floor reaches the bottom on any aspect. Verified by sampling alpha down the bottom third: opaque everywhere, one uniform colour, matching the page gradient behind it. Co-Authored-By: Claude Opus 5 --- HANDOFF.md | 7 +++++++ index.html | 2 +- render.js | 12 +++++++++--- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/HANDOFF.md b/HANDOFF.md index 004cb17..5a3ce0f 100644 --- a/HANDOFF.md +++ b/HANDOFF.md @@ -186,6 +186,13 @@ zombie (now an occasional opponent, `TUNE.racketEvery`, not the every-game fixtu because the wave grows with `hordeGrow` while the panic button was a flat 1 s; he chose scaling the melee over shrinking the horde. **Measure the crowd BEFORE calling `meleeSwipe`** — it kills everything in reach, so counting after counts the survivors and the cooldown barely moves. +- **`render()` clears the whole frame to `pal.out` first.** There was NO clear for a long time: the + stands cover the top and the out-area quad covers the middle, so it looked complete — but the quad + only reached z=30 and BELOW where that projects the canvas was simply transparent. On a phone that + read as a duller band across the bottom of the screen. The quad now runs to z=60 as well, so the + perspective floor reaches the bottom on any aspect ratio. If you ever add a new orientation or + stretch the canvas further, check the bottom rows are opaque — sample `getImageData` alpha, the + colour alone will not tell you, because the page behind is deliberately the same green. - **The page background behind the canvas tracks the live court apron** (`pageBackground` in render.js). It is visible in exactly two places: the strip above the canvas under the status bar, and the slivers a phone's ROUNDED DISPLAY CORNERS clip out of the canvas — a flat dark body drew a diff --git a/index.html b/index.html index 9b47ef1..c2ea8e5 100644 --- a/index.html +++ b/index.html @@ -80,6 +80,6 @@

TAP TO START

- + diff --git a/render.js b/render.js index bb488e3..4f4f50e 100644 --- a/render.js +++ b/render.js @@ -129,7 +129,7 @@ export function proj(x, y, z) { // ---------------------------------------------------------------- sprites ---- // assets/.png; game falls back to code-drawn figures until sprites load. -const SPRV = 48; // asset cache-buster — bump with main.js?v=N (see the img.src note below) +const SPRV = 49; // asset cache-buster — bump with main.js?v=N (see the img.src note below) const SPR = {}; for (const n of ['p_idle1','p_idle2','p_bounce','p_bounce2','p_toss','p_smash','p_run1','p_run2','p_swing1','p_swing2', 'o_idle1','o_idle2','o_bounce','o_bounce2','o_toss','o_smash','o_run1','o_run2','o_swing1','o_swing2', @@ -611,7 +611,13 @@ export function render() { } const pal = palette(), pt = paletteT(); - pageBackground(pal.out); // keep the page behind the canvas matching the court's apron + // CLEAR THE WHOLE FRAME to the apron colour first. There was no clear at all: the stands cover the + // top and the out-area quad covers the middle, but the quad only reaches z=30, and below where that + // projects the canvas was simply TRANSPARENT — you saw the page through it as a duller band across + // the bottom of the screen. Oversized by 8px so a camera shake can never expose an edge. + ctx.fillStyle = pal.out; + ctx.fillRect(-8, -8, W + 16, H + 16); + pageBackground(pal.out); // ...and the page behind it matches, for the rounded display corners // stands: the generated crowd, drawn in columns so it can BOUNCE when it cheers. // sit the ad strip flush on the court's back edge (the out-area quad below reaches z=-6); // pinning to that projected line keeps the boards clear of the lawn in BOTH orientations @@ -656,7 +662,7 @@ export function render() { // ground + court (Super Tennis lawn); everything outside the doubles court is OUT const dw = COURT.dblW / 2; - quadXZ(-14, -6, 14, 30, pal.out); // out area + quadXZ(-14, -6, 14, 60, pal.out); // out area (past the bottom on any aspect) quadXZ(-dw - 0.15, -0.15, dw + 0.15, COURT.L + 0.15, '#e8e8dc'); // perimeter border line quadXZ(-dw, 0, dw, COURT.L, pal.lawn); // lawn (doubles court) for (let z = 0; z < COURT.L; z += 2.97) quadXZ(-dw, z, dw, Math.min(z + 1.49, COURT.L), pal.stripe); // mow stripes