From e8116c6abb6951c5f5e93c608f2bbfb72743b370 Mon Sep 17 00:00:00 2001 From: Oliver Rieger Date: Fri, 31 Jul 2026 08:49:02 +0200 Subject: [PATCH] Re-fit the viewport whenever the canvas box moves MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The portrait fit was right, it just ran once and too early: iOS Safari lays the page out before its toolbars settle, so the box the first fit measured was short by a strip — and no window resize follows, because the page never scrolls. The height only came good after a rotate and back, which IS a resize. A ResizeObserver on the canvas watches the box itself, so every cause is covered (bars settling, rotation, split view, zoom) without guessing which event or delay to listen for. It only rewrites the backing store, never the CSS box, so it cannot feed itself. Verified both directions: box grows -> logical H 585 -> 671, box back -> 585, logical aspect matching the box aspect each time. Co-Authored-By: Claude Opus 5 --- index.html | 2 +- render.js | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index 3de2371..c2a191f 100644 --- a/index.html +++ b/index.html @@ -89,6 +89,6 @@

- + diff --git a/render.js b/render.js index ae8211b..2eafade 100644 --- a/render.js +++ b/render.js @@ -119,7 +119,15 @@ export function fitViewport() { // landscape 480x270; portrait 270 wide and as T // inset in logical px so the rack can lift clear of the home indicator. measureSafe((cv.clientWidth || innerWidth) / w); } -addEventListener('resize', fitViewport); +// The fit was correct but it ran exactly once, too early. iOS Safari lays the page out BEFORE its +// toolbars settle, so the box the first fit measured was ~150 CSS px short — and no window `resize` +// follows, because the page never scrolls. The height only came right after a rotate and back, which +// IS a resize. Watching the canvas box itself covers every cause (bars settling, rotation, split +// view, zoom) instead of guessing which event or delay to listen for — and the observer's initial +// callback is the real initialisation. fitViewport is idempotent, and it only changes the backing +// store, never the CSS box, so this cannot feed itself. +addEventListener('resize', fitViewport); // fallback for browsers without the observer +new ResizeObserver(fitViewport).observe(cv); // the box itself is the signal, whatever moved it // The aim camera: while the slingshot is drawn the view rises and leans back a little, which // steepens the look down the court. That extra depth is what makes a shambler standing right