From e0588d463482cd0e8f58753dac564047fe2ac122 Mon Sep 17 00:00:00 2001 From: Hongyi Chen Date: Thu, 30 Apr 2026 13:51:07 -0700 Subject: [PATCH 1/2] fix(api): paint /api canvas synchronously to eliminate theme flash MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The /api page flashed white on first load before settling into dark mode. The head script already set synchronously, but no CSS in keyed off that attribute — the only theme-aware CSS lived inside Scalar's runtime-injected customCss (which keys off body classes .dark-mode / .light-mode), and that CSS only existed after the Scalar bundle (loaded mid-) downloaded, parsed, and mounted. Add an inline From e101e4f0bddb5aebf0cdce33fbff35a7dbc1b457 Mon Sep 17 00:00:00 2001 From: Hongyi Chen Date: Thu, 30 Apr 2026 14:57:41 -0700 Subject: [PATCH 2/2] =?UTF-8?q?fix(api):=20boot=20Scalar=20in=20resolved?= =?UTF-8?q?=20theme=20to=20remove=20dark=E2=86=92light=E2=86=92dark=20flas?= =?UTF-8?q?h?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous fix removed the white-on-first-frame flash but exposed a deeper timing bug: Scalar booted in light mode on cold loads, briefly flipped the page to light, then DOMContentLoaded restored dark. Root cause: the Scalar config sync script reads `document.body.classList.contains('dark-mode')` synchronously inside , before the head script's body-class apply runs (which is queued for DOMContentLoaded because document.body is null in ). So cfg.darkMode was always false on cold load → Scalar mounted light → the mirror MutationObserver flipped html[data-theme]='light' → the new canvas CSS painted white → DOMContentLoaded fired and corrected everything. Fix: 1. Expose `window.__warpResolveTheme()` — a read-only sibling of the existing __warpApplyTheme that just resolves localStorage + prefers-color-scheme to 'dark' or 'light'. 2. Add a top-of-body inline script that calls __warpResolveTheme() and applies the body class synchronously, before any other body-level script runs. 3. Switch the Scalar config sync to read __warpResolveTheme() instead of body.classList, decoupling Scalar's boot value from DOM apply ordering. Co-Authored-By: Oz --- src/pages/api.astro | 44 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/src/pages/api.astro b/src/pages/api.astro index 9945991..86fad91 100644 --- a/src/pages/api.astro +++ b/src/pages/api.astro @@ -98,6 +98,14 @@ const specJson = JSON.stringify(specObject); } catch (_e) {} apply(resolve(value === 'auto' ? '' : value)); }; + // Read-only sibling of __warpApplyTheme: returns the resolved + // 'dark' | 'light' value without touching the DOM or localStorage. + // Used by the body-top inline script to apply the body class as + // soon as is parsed, and by Scalar's config sync script + // to compute `cfg.darkMode` independently of body-class state. + window.__warpResolveTheme = function () { + return resolve(read()); + }; // Re-resolve when the system preference changes, but only if // we're following it (stored value is empty / unknown). prefersDark.addEventListener('change', function () { @@ -154,6 +162,22 @@ const specJson = JSON.stringify(specObject); +