diff --git a/HANDOFF.md b/HANDOFF.md index 01a0beb..fec5899 100644 --- a/HANDOFF.md +++ b/HANDOFF.md @@ -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 diff --git a/index.html b/index.html index a6d46a1..92ef847 100644 --- a/index.html +++ b/index.html @@ -20,13 +20,26 @@ src: url('assets/fonts/Silkscreen-Regular.ttf') format('truetype'); } @font-face { font-family: 'Silkscreen'; font-weight: 700; font-display: block; src: url('assets/fonts/Silkscreen-Bold.ttf') format('truetype'); } - html, body { margin: 0; height: 100%; height: 100dvh; background: #10141c; display: grid; place-items: center; } + html, body { margin: 0; padding: 0; background: #10141c; overflow: hidden; } /* invisible probe: env() is only readable from CSS, so park the insets on an element and let render.js measure them. The canvas stays FULL-BLEED (the stands under the notch look good) — it is the HUD that has to move, see SAFE in render.js. */ #safe { position: fixed; top: 0; left: 0; width: 0; height: 0; pointer-events: none; visibility: hidden; padding-top: env(safe-area-inset-top, 0px); padding-bottom: env(safe-area-inset-bottom, 0px); } - canvas { image-rendering: pixelated; width: min(96vw, calc(96vh * 16 / 9)); aspect-ratio: 16/9; touch-action: none; } + /* The canvas STRETCHES to the viewport and render.js derives its logical height from the box it + actually got. Sizing it the other way round (compute a scale from innerWidth/innerHeight, then set + explicit px) meant it was laid 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 the dynamic viewport height, so it tracks those toolbars. */ + /* The canvas lives ENTIRELY INSIDE the safe area — never under the notch, the status bar or the + home indicator. Doing the inset here rather than offsetting the HUD in canvas space keeps it in + ONE place: render.js then just matches its logical grid to whatever box it was given. + 100dvh is the dynamic viewport height, so it tracks iOS Safari's toolbars appearing/hiding. */ + canvas { image-rendering: pixelated; display: block; position: fixed; touch-action: none; + top: env(safe-area-inset-top, 0px); + left: env(safe-area-inset-left, 0px); + width: calc(100vw - env(safe-area-inset-left, 0px) - env(safe-area-inset-right, 0px)); + height: calc(100dvh - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px)); } #hint { position: fixed; bottom: 8px; width: 100%; text-align: center; font: 400 10px Silkscreen, monospace; color: #6b7688; } @media (pointer: coarse) { #hint, #intro .kb { display: none; } } @@ -66,6 +79,6 @@
TAP TO START
- +