Put the whole game inside the safe area

Insetting only the HUD while the canvas stayed full-bleed wasn't what was
asked for. The canvas itself is position:fixed and inset by
env(safe-area-inset-*) now, so nothing renders under the notch, the status bar
or the home indicator, and render.js no longer offsets the HUD as well — doing
both would subtract the notch twice.

The bottom strip was a second bug: the canvas was sized by computing a scale
from innerWidth/innerHeight and setting explicit pixels, so it was laid out
against whatever innerHeight reported at load, before Safari's toolbars had
settled, and stayed short of the bottom forever after. CSS stretches it now
(100vw x 100dvh minus the insets) and fitViewport derives the logical grid from
the box it was actually given, so the aspect always matches exactly — no
letterbox, no distortion.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Opus 5 committed 2026-07-30 17:59:43 +02:00
1 parent 89667c4018
commit 90aefdce27
3 files changed
+46 -21

No files matched your search

+16
View File
@@ -182,6 +182,22 @@ 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.
- **The safe area is handled in ONE place: index.html's canvas rule.** The canvas is `position: fixed`
and inset by `env(safe-area-inset-*)`, so the whole game sits inside the safe region — nothing ever
renders under the notch, the status bar or the home indicator. `render.js` does NOT offset the HUD as
well (`SAFE` stays at zero); doing both subtracts the notch twice. Full-bleed with an inset HUD was
tried first and Oliver rejected it twice.
- **The canvas is STRETCHED by CSS (100vw x 100dvh minus insets) and `fitViewport` derives the logical
grid from the box it was actually given** — `cv.clientWidth/clientHeight`, never `innerWidth/innerHeight`.
Sizing it the other way round (compute a scale, then set explicit px) laid it out against whatever
`innerHeight` reported at load, before iOS Safari's toolbars had settled, and it stayed a strip short
of the bottom forever after. `100dvh` is what tracks those toolbars.
- **The swish cooldown scales with how swarmed you are** (`meleeCooldown()` in gameplay.js):
`meleeCool / (1 + (near-1) * meleeCrowd)`, floored at `meleeCoolMin`, counting bodies within
`meleeCrowdR`. 1 body 1.00 s, 4 → 0.47, 8 → 0.27, 14+ → 0.22. Oliver died on every game-20 horde
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.
- **The canvas is deliberately FULL-BLEED under the notch and home indicator; the HUD is what respects
the safe area.** `viewport-fit=cover` is set, and the stands running to the screen edges look right —
but an iPhone's clock was landing directly on the scoreboard. A hidden `#safe` probe div carries