fix(live): retry inline scroll-restore on fonts.ready and load

scrollTo(y) clamps to the current document.scrollHeight, which is
several hundred pixels short of the final value until async-loaded
fonts swap in (Cormorant Garamond italic grew consulting-section
layout by ~585px in the logs). The initial synchronous scroll was
clamping to ~6165 even though the Go-time target was 6749.5.

Retry on document.fonts.ready and on the window load event, both of
which fire once the document reaches its final height.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Paul Bakaus
2026-04-22 10:48:13 -07:00
co-authored by Claude Opus 4.7
parent fb78ec4553
commit f0f2935547
14 changed files with 141 additions and 31 deletions
@@ -138,14 +138,23 @@ function buildTagBlock(syntax, port) {
const open = commentOpen(syntax);
const close = commentClose(syntax);
// Inline pre-restore: runs before the external live.js is fetched. Sets
// scrollRestoration='manual' and jumps to the saved scrollY *synchronously*
// scrollRestoration='manual' and jumps to the saved scrollY synchronously
// during HTML parse, beating the browser's animated reload-restore.
//
// Retries on fonts.ready and load are essential: scrollTo(y) clamps to
// the document's current scrollHeight, which is often hundreds of
// pixels short of the final value until async-loaded fonts swap in.
// Hardcoded key matches live-browser.js: PREFIX ('impeccable-live') +
// LS_KEY suffix ('-session') + SCROLL_KEY_SUFFIX ('-scroll').
const preRestore =
'<script>(function(){try{history.scrollRestoration="manual";' +
'var y=parseFloat(localStorage.getItem("impeccable-live-session-scroll"));' +
'if(isFinite(y))window.scrollTo(0,y);}catch(e){}})();</script>';
'if(!isFinite(y))return;' +
'var apply=function(){if(Math.abs(window.scrollY-y)>0.5)window.scrollTo(0,y);};' +
'apply();' +
'if(document.fonts&&document.fonts.ready)document.fonts.ready.then(apply);' +
'window.addEventListener("load",apply,{once:true});' +
'}catch(e){}})();</script>';
return (
open + ' ' + MARKER_OPEN_TEXT + ' ' + close + '\n' +
preRestore + '\n' +