From 3ecb25786aeb33410a1cece0aaaac892d95594d8 Mon Sep 17 00:00:00 2001 From: Matthew Meszaros Date: Wed, 2 Sep 2026 09:00:29 -0700 Subject: [PATCH] feat: register the app shell's visibility observer under reduced motion too so an off-screen shell still pauses its animations while only the counter ticker stays off, and read the ?noshell, ?noanim and ?nogl phone diagnostics as query parameter names through URLSearchParams instead of matching the raw query string --- site/src/components/AppShellMock.astro | 5 +++-- site/src/components/GrainBackdrop.astro | 2 +- site/src/layouts/Layout.astro | 5 ++++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/site/src/components/AppShellMock.astro b/site/src/components/AppShellMock.astro index a04b26f1..8c54d6d8 100644 --- a/site/src/components/AppShellMock.astro +++ b/site/src/components/AppShellMock.astro @@ -477,7 +477,8 @@ const online = [ }; let onScreen = false; - const sync = () => (onScreen && !document.hidden ? start() : stop()); + // Reduced motion never ticks the counters; the observer still parks the shell. + const sync = () => (onScreen && !document.hidden && !REDUCED ? start() : stop()); new IntersectionObserver((entries) => { onScreen = entries.some((e) => e.isIntersecting); // Off screen, the pings and pulses inside stop too (see global.css). @@ -487,7 +488,7 @@ const online = [ document.addEventListener('visibilitychange', sync); } - if (!REDUCED) document.querySelectorAll('[data-shell]').forEach(live); + document.querySelectorAll('[data-shell]').forEach(live); // The shell is a picture: nothing inside it is a real tab stop. document.querySelectorAll('[data-shell] button, [data-shell] input, [data-shell] a, [data-shell] [tabindex]').forEach((el) => { el.tabIndex = -1; }); diff --git a/site/src/components/GrainBackdrop.astro b/site/src/components/GrainBackdrop.astro index c0b386a2..eeb12250 100644 --- a/site/src/components/GrainBackdrop.astro +++ b/site/src/components/GrainBackdrop.astro @@ -53,7 +53,7 @@ const t = GRAIN_TONES[tone]; // Phones: a 3x canvas per frame is what pushes iOS Safari over its GPU // memory limit while scrolling; 2x grain reads the same at that size. const touch = window.matchMedia('(hover: none)').matches; - const noGl = /[?&]nogl\b/.test(location.search); + const noGl = new URLSearchParams(location.search).has('nogl'); const maxPixels = touch ? 1280 * 720 : 1920 * 1080 * 2; // Every frame gets its own rotation, drift and shape. Sharing one palette diff --git a/site/src/layouts/Layout.astro b/site/src/layouts/Layout.astro index 4a0a2326..bc2e6296 100644 --- a/site/src/layouts/Layout.astro +++ b/site/src/layouts/Layout.astro @@ -143,7 +143,10 @@ const websiteJsonLd = { + {!bare && }