@@ -98,6 +98,14 @@ const specJson = JSON.stringify(specObject);
9898 } catch (_e) {}
9999 apply(resolve(value === 'auto' ? '' : value));
100100 };
101+ // Read-only sibling of __warpApplyTheme: returns the resolved
102+ // 'dark' | 'light' value without touching the DOM or localStorage.
103+ // Used by the body-top inline script to apply the body class as
104+ // soon as <body> is parsed, and by Scalar's config sync script
105+ // to compute `cfg.darkMode` independently of body-class state.
106+ window.__warpResolveTheme = function () {
107+ return resolve(read());
108+ };
101109 // Re-resolve when the system preference changes, but only if
102110 // we're following it (stored value is empty / unknown).
103111 prefersDark.addEventListener('change', function () {
@@ -128,8 +136,48 @@ const specJson = JSON.stringify(specObject);
128136 else document.addEventListener('DOMContentLoaded', startMirror);
129137 })();
130138 </script >
139+ <style >
140+ /* First-paint canvas color, keyed off the `data-theme` attribute set
141+ synchronously by the script above. Without this, `/api` flashes
142+ white before mounting because Scalar's themed `customCss` (which
143+ keys off `body.dark-mode` / `body.light-mode`) only ships inside
144+ the Scalar bundle loaded mid-`<body>`, so nothing paints the
145+ page background until that bundle parses + mounts.
146+
147+ Values mirror `--scalar-background-1` from the customCss block
148+ below. If you change the canvas there (or in custom.css), update
149+ these in lockstep so the first-paint color matches what Scalar
150+ applies a few frames later. */
151+ html[data-theme="dark"] {
152+ background-color: #121212;
153+ color-scheme: dark;
154+ }
155+ html[data-theme="light"] {
156+ background-color: #ffffff;
157+ color-scheme: light;
158+ }
159+ body {
160+ background-color: inherit;
161+ }
162+ </style >
131163 </head >
132164 <body >
165+ <script is:inline >
166+ // Apply `body.dark-mode` / `body.light-mode` synchronously, before
167+ // any other body-level script runs (specifically, before the Scalar
168+ // config sync script and Scalar's bundle below). The <head> script
169+ // can't do this itself because `document.body` is null while <head>
170+ // parses; without this top-of-body apply, body would have no class
171+ // until DOMContentLoaded, Scalar would boot in light mode, the
172+ // mirror MutationObserver would briefly flip `html[data-theme]` to
173+ // `light`, and the page would visibly flash dark → light → dark.
174+ (function () {
175+ var resolved = (typeof window.__warpResolveTheme === 'function')
176+ ? window.__warpResolveTheme()
177+ : 'dark';
178+ document.body.classList.add(resolved === 'dark' ? 'dark-mode' : 'light-mode');
179+ })();
180+ </script >
133181 <WarpTopbar crumb =" API Reference" />
134182 <script
135183 is:inline
@@ -254,17 +302,29 @@ const specJson = JSON.stringify(specObject);
254302 <script is:inline >
255303 // Sync Scalar's `darkMode` config to the resolved theme before the
256304 // Scalar bundle reads `data-configuration`. This keeps Scalar's
257- // internal `useColorMode` state aligned with the body class our
258- // <head> script already set, eliminating the one-frame mismatch
259- // where Scalar would briefly mount in its own default.
305+ // internal `useColorMode` state aligned with the resolved theme,
306+ // eliminating the one-frame mismatch where Scalar would briefly
307+ // mount in its own default.
308+ //
309+ // We read directly from `__warpResolveTheme()` (which resolves
310+ // `localStorage['starlight-theme']` + `prefers-color-scheme`)
311+ // rather than from `document.body.classList`, because the body
312+ // class is intentionally not a reliable boot-time source: the
313+ // <head> script can't apply it before <body> exists, and the
314+ // top-of-body apply runs in the same parser frame as us. Reading
315+ // localStorage decouples Scalar's boot value from any DOM apply
316+ // ordering, so dark-mode users never see a transient light boot.
260317 (function () {
261318 var el = document.getElementById('api-reference');
262319 if (!el) return;
263320 var raw = el.getAttribute('data-configuration');
264321 if (!raw) return;
265322 try {
266323 var cfg = JSON.parse(raw);
267- cfg.darkMode = document.body.classList.contains('dark-mode');
324+ var resolved = (typeof window.__warpResolveTheme === 'function')
325+ ? window.__warpResolveTheme()
326+ : (document.body.classList.contains('dark-mode') ? 'dark' : 'light');
327+ cfg.darkMode = resolved === 'dark';
268328 el.setAttribute('data-configuration', JSON.stringify(cfg));
269329 } catch (_e) {
270330 // Malformed config — let Scalar fall back to its own default.
0 commit comments