refactor(live): move scroll-restore out of injected inline back into live.js

The inline pre-restore wasn't actually fixing a timing issue — the
fix was the fonts.ready + load retries. Since live.js's own
top-level block runs before DOMContentLoaded and we can do the same
retries there, we don't need an inline script injected into every
user page. Simpler HTML, single source of truth.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Paul Bakaus
2026-04-22 10:55:32 -07:00
co-authored by Claude Opus 4.7
parent f0f2935547
commit bd86147d70
26 changed files with 175 additions and 358 deletions
@@ -121,15 +121,23 @@
}
// Pre-empt the browser: apply manual scroll restoration and jump to the
// saved scrollY at script-parse time (before DOMContentLoaded). If we
// wait until init(), the browser has already begun animating its own
// restore — especially bad when `scroll-behavior: smooth` is set on html.
// saved scrollY at script-parse time. Retries on fonts.ready and load
// are essential: scrollTo(y) clamps to the current document.scrollHeight,
// which is often hundreds of pixels short of the final value until
// async-loaded fonts swap in and reflow.
try {
history.scrollRestoration = 'manual';
const savedY = readScrollY();
if (savedY != null && Math.abs(window.scrollY - savedY) > 0.5) {
console.log('[impeccable.scroll] early restore', { from: window.scrollY, to: savedY });
window.scrollTo({ top: savedY, left: 0, behavior: 'instant' });
if (savedY != null) {
const apply = () => {
if (Math.abs(window.scrollY - savedY) > 0.5) {
console.log('[impeccable.scroll] early restore', { from: window.scrollY, to: savedY });
window.scrollTo(0, savedY);
}
};
apply();
if (document.fonts?.ready) document.fonts.ready.then(apply).catch(() => {});
window.addEventListener('load', apply, { once: true });
}
} catch {}
@@ -137,27 +137,8 @@ function commentClose(syntax) { return syntax === 'jsx' ? '*/}' : '-->'; }
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
// 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))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' +
'<script src="http://localhost:' + port + '/live.js"></script>\n' +
open + ' ' + MARKER_CLOSE_TEXT + ' ' + close + '\n'
);
@@ -121,15 +121,23 @@
}
// Pre-empt the browser: apply manual scroll restoration and jump to the
// saved scrollY at script-parse time (before DOMContentLoaded). If we
// wait until init(), the browser has already begun animating its own
// restore — especially bad when `scroll-behavior: smooth` is set on html.
// saved scrollY at script-parse time. Retries on fonts.ready and load
// are essential: scrollTo(y) clamps to the current document.scrollHeight,
// which is often hundreds of pixels short of the final value until
// async-loaded fonts swap in and reflow.
try {
history.scrollRestoration = 'manual';
const savedY = readScrollY();
if (savedY != null && Math.abs(window.scrollY - savedY) > 0.5) {
console.log('[impeccable.scroll] early restore', { from: window.scrollY, to: savedY });
window.scrollTo({ top: savedY, left: 0, behavior: 'instant' });
if (savedY != null) {
const apply = () => {
if (Math.abs(window.scrollY - savedY) > 0.5) {
console.log('[impeccable.scroll] early restore', { from: window.scrollY, to: savedY });
window.scrollTo(0, savedY);
}
};
apply();
if (document.fonts?.ready) document.fonts.ready.then(apply).catch(() => {});
window.addEventListener('load', apply, { once: true });
}
} catch {}
@@ -137,27 +137,8 @@ function commentClose(syntax) { return syntax === 'jsx' ? '*/}' : '-->'; }
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
// 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))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' +
'<script src="http://localhost:' + port + '/live.js"></script>\n' +
open + ' ' + MARKER_CLOSE_TEXT + ' ' + close + '\n'
);
@@ -121,15 +121,23 @@
}
// Pre-empt the browser: apply manual scroll restoration and jump to the
// saved scrollY at script-parse time (before DOMContentLoaded). If we
// wait until init(), the browser has already begun animating its own
// restore — especially bad when `scroll-behavior: smooth` is set on html.
// saved scrollY at script-parse time. Retries on fonts.ready and load
// are essential: scrollTo(y) clamps to the current document.scrollHeight,
// which is often hundreds of pixels short of the final value until
// async-loaded fonts swap in and reflow.
try {
history.scrollRestoration = 'manual';
const savedY = readScrollY();
if (savedY != null && Math.abs(window.scrollY - savedY) > 0.5) {
console.log('[impeccable.scroll] early restore', { from: window.scrollY, to: savedY });
window.scrollTo({ top: savedY, left: 0, behavior: 'instant' });
if (savedY != null) {
const apply = () => {
if (Math.abs(window.scrollY - savedY) > 0.5) {
console.log('[impeccable.scroll] early restore', { from: window.scrollY, to: savedY });
window.scrollTo(0, savedY);
}
};
apply();
if (document.fonts?.ready) document.fonts.ready.then(apply).catch(() => {});
window.addEventListener('load', apply, { once: true });
}
} catch {}
@@ -137,27 +137,8 @@ function commentClose(syntax) { return syntax === 'jsx' ? '*/}' : '-->'; }
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
// 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))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' +
'<script src="http://localhost:' + port + '/live.js"></script>\n' +
open + ' ' + MARKER_CLOSE_TEXT + ' ' + close + '\n'
);
@@ -121,15 +121,23 @@
}
// Pre-empt the browser: apply manual scroll restoration and jump to the
// saved scrollY at script-parse time (before DOMContentLoaded). If we
// wait until init(), the browser has already begun animating its own
// restore — especially bad when `scroll-behavior: smooth` is set on html.
// saved scrollY at script-parse time. Retries on fonts.ready and load
// are essential: scrollTo(y) clamps to the current document.scrollHeight,
// which is often hundreds of pixels short of the final value until
// async-loaded fonts swap in and reflow.
try {
history.scrollRestoration = 'manual';
const savedY = readScrollY();
if (savedY != null && Math.abs(window.scrollY - savedY) > 0.5) {
console.log('[impeccable.scroll] early restore', { from: window.scrollY, to: savedY });
window.scrollTo({ top: savedY, left: 0, behavior: 'instant' });
if (savedY != null) {
const apply = () => {
if (Math.abs(window.scrollY - savedY) > 0.5) {
console.log('[impeccable.scroll] early restore', { from: window.scrollY, to: savedY });
window.scrollTo(0, savedY);
}
};
apply();
if (document.fonts?.ready) document.fonts.ready.then(apply).catch(() => {});
window.addEventListener('load', apply, { once: true });
}
} catch {}
@@ -137,27 +137,8 @@ function commentClose(syntax) { return syntax === 'jsx' ? '*/}' : '-->'; }
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
// 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))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' +
'<script src="http://localhost:' + port + '/live.js"></script>\n' +
open + ' ' + MARKER_CLOSE_TEXT + ' ' + close + '\n'
);
@@ -121,15 +121,23 @@
}
// Pre-empt the browser: apply manual scroll restoration and jump to the
// saved scrollY at script-parse time (before DOMContentLoaded). If we
// wait until init(), the browser has already begun animating its own
// restore — especially bad when `scroll-behavior: smooth` is set on html.
// saved scrollY at script-parse time. Retries on fonts.ready and load
// are essential: scrollTo(y) clamps to the current document.scrollHeight,
// which is often hundreds of pixels short of the final value until
// async-loaded fonts swap in and reflow.
try {
history.scrollRestoration = 'manual';
const savedY = readScrollY();
if (savedY != null && Math.abs(window.scrollY - savedY) > 0.5) {
console.log('[impeccable.scroll] early restore', { from: window.scrollY, to: savedY });
window.scrollTo({ top: savedY, left: 0, behavior: 'instant' });
if (savedY != null) {
const apply = () => {
if (Math.abs(window.scrollY - savedY) > 0.5) {
console.log('[impeccable.scroll] early restore', { from: window.scrollY, to: savedY });
window.scrollTo(0, savedY);
}
};
apply();
if (document.fonts?.ready) document.fonts.ready.then(apply).catch(() => {});
window.addEventListener('load', apply, { once: true });
}
} catch {}
@@ -137,27 +137,8 @@ function commentClose(syntax) { return syntax === 'jsx' ? '*/}' : '-->'; }
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
// 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))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' +
'<script src="http://localhost:' + port + '/live.js"></script>\n' +
open + ' ' + MARKER_CLOSE_TEXT + ' ' + close + '\n'
);
@@ -121,15 +121,23 @@
}
// Pre-empt the browser: apply manual scroll restoration and jump to the
// saved scrollY at script-parse time (before DOMContentLoaded). If we
// wait until init(), the browser has already begun animating its own
// restore — especially bad when `scroll-behavior: smooth` is set on html.
// saved scrollY at script-parse time. Retries on fonts.ready and load
// are essential: scrollTo(y) clamps to the current document.scrollHeight,
// which is often hundreds of pixels short of the final value until
// async-loaded fonts swap in and reflow.
try {
history.scrollRestoration = 'manual';
const savedY = readScrollY();
if (savedY != null && Math.abs(window.scrollY - savedY) > 0.5) {
console.log('[impeccable.scroll] early restore', { from: window.scrollY, to: savedY });
window.scrollTo({ top: savedY, left: 0, behavior: 'instant' });
if (savedY != null) {
const apply = () => {
if (Math.abs(window.scrollY - savedY) > 0.5) {
console.log('[impeccable.scroll] early restore', { from: window.scrollY, to: savedY });
window.scrollTo(0, savedY);
}
};
apply();
if (document.fonts?.ready) document.fonts.ready.then(apply).catch(() => {});
window.addEventListener('load', apply, { once: true });
}
} catch {}
@@ -137,27 +137,8 @@ function commentClose(syntax) { return syntax === 'jsx' ? '*/}' : '-->'; }
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
// 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))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' +
'<script src="http://localhost:' + port + '/live.js"></script>\n' +
open + ' ' + MARKER_CLOSE_TEXT + ' ' + close + '\n'
);
@@ -121,15 +121,23 @@
}
// Pre-empt the browser: apply manual scroll restoration and jump to the
// saved scrollY at script-parse time (before DOMContentLoaded). If we
// wait until init(), the browser has already begun animating its own
// restore — especially bad when `scroll-behavior: smooth` is set on html.
// saved scrollY at script-parse time. Retries on fonts.ready and load
// are essential: scrollTo(y) clamps to the current document.scrollHeight,
// which is often hundreds of pixels short of the final value until
// async-loaded fonts swap in and reflow.
try {
history.scrollRestoration = 'manual';
const savedY = readScrollY();
if (savedY != null && Math.abs(window.scrollY - savedY) > 0.5) {
console.log('[impeccable.scroll] early restore', { from: window.scrollY, to: savedY });
window.scrollTo({ top: savedY, left: 0, behavior: 'instant' });
if (savedY != null) {
const apply = () => {
if (Math.abs(window.scrollY - savedY) > 0.5) {
console.log('[impeccable.scroll] early restore', { from: window.scrollY, to: savedY });
window.scrollTo(0, savedY);
}
};
apply();
if (document.fonts?.ready) document.fonts.ready.then(apply).catch(() => {});
window.addEventListener('load', apply, { once: true });
}
} catch {}
@@ -137,27 +137,8 @@ function commentClose(syntax) { return syntax === 'jsx' ? '*/}' : '-->'; }
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
// 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))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' +
'<script src="http://localhost:' + port + '/live.js"></script>\n' +
open + ' ' + MARKER_CLOSE_TEXT + ' ' + close + '\n'
);
+14 -6
View File
@@ -121,15 +121,23 @@
}
// Pre-empt the browser: apply manual scroll restoration and jump to the
// saved scrollY at script-parse time (before DOMContentLoaded). If we
// wait until init(), the browser has already begun animating its own
// restore — especially bad when `scroll-behavior: smooth` is set on html.
// saved scrollY at script-parse time. Retries on fonts.ready and load
// are essential: scrollTo(y) clamps to the current document.scrollHeight,
// which is often hundreds of pixels short of the final value until
// async-loaded fonts swap in and reflow.
try {
history.scrollRestoration = 'manual';
const savedY = readScrollY();
if (savedY != null && Math.abs(window.scrollY - savedY) > 0.5) {
console.log('[impeccable.scroll] early restore', { from: window.scrollY, to: savedY });
window.scrollTo({ top: savedY, left: 0, behavior: 'instant' });
if (savedY != null) {
const apply = () => {
if (Math.abs(window.scrollY - savedY) > 0.5) {
console.log('[impeccable.scroll] early restore', { from: window.scrollY, to: savedY });
window.scrollTo(0, savedY);
}
};
apply();
if (document.fonts?.ready) document.fonts.ready.then(apply).catch(() => {});
window.addEventListener('load', apply, { once: true });
}
} catch {}
@@ -137,27 +137,8 @@ function commentClose(syntax) { return syntax === 'jsx' ? '*/}' : '-->'; }
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
// 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))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' +
'<script src="http://localhost:' + port + '/live.js"></script>\n' +
open + ' ' + MARKER_CLOSE_TEXT + ' ' + close + '\n'
);
@@ -121,15 +121,23 @@
}
// Pre-empt the browser: apply manual scroll restoration and jump to the
// saved scrollY at script-parse time (before DOMContentLoaded). If we
// wait until init(), the browser has already begun animating its own
// restore — especially bad when `scroll-behavior: smooth` is set on html.
// saved scrollY at script-parse time. Retries on fonts.ready and load
// are essential: scrollTo(y) clamps to the current document.scrollHeight,
// which is often hundreds of pixels short of the final value until
// async-loaded fonts swap in and reflow.
try {
history.scrollRestoration = 'manual';
const savedY = readScrollY();
if (savedY != null && Math.abs(window.scrollY - savedY) > 0.5) {
console.log('[impeccable.scroll] early restore', { from: window.scrollY, to: savedY });
window.scrollTo({ top: savedY, left: 0, behavior: 'instant' });
if (savedY != null) {
const apply = () => {
if (Math.abs(window.scrollY - savedY) > 0.5) {
console.log('[impeccable.scroll] early restore', { from: window.scrollY, to: savedY });
window.scrollTo(0, savedY);
}
};
apply();
if (document.fonts?.ready) document.fonts.ready.then(apply).catch(() => {});
window.addEventListener('load', apply, { once: true });
}
} catch {}
@@ -137,27 +137,8 @@ function commentClose(syntax) { return syntax === 'jsx' ? '*/}' : '-->'; }
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
// 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))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' +
'<script src="http://localhost:' + port + '/live.js"></script>\n' +
open + ' ' + MARKER_CLOSE_TEXT + ' ' + close + '\n'
);
@@ -121,15 +121,23 @@
}
// Pre-empt the browser: apply manual scroll restoration and jump to the
// saved scrollY at script-parse time (before DOMContentLoaded). If we
// wait until init(), the browser has already begun animating its own
// restore — especially bad when `scroll-behavior: smooth` is set on html.
// saved scrollY at script-parse time. Retries on fonts.ready and load
// are essential: scrollTo(y) clamps to the current document.scrollHeight,
// which is often hundreds of pixels short of the final value until
// async-loaded fonts swap in and reflow.
try {
history.scrollRestoration = 'manual';
const savedY = readScrollY();
if (savedY != null && Math.abs(window.scrollY - savedY) > 0.5) {
console.log('[impeccable.scroll] early restore', { from: window.scrollY, to: savedY });
window.scrollTo({ top: savedY, left: 0, behavior: 'instant' });
if (savedY != null) {
const apply = () => {
if (Math.abs(window.scrollY - savedY) > 0.5) {
console.log('[impeccable.scroll] early restore', { from: window.scrollY, to: savedY });
window.scrollTo(0, savedY);
}
};
apply();
if (document.fonts?.ready) document.fonts.ready.then(apply).catch(() => {});
window.addEventListener('load', apply, { once: true });
}
} catch {}
@@ -137,27 +137,8 @@ function commentClose(syntax) { return syntax === 'jsx' ? '*/}' : '-->'; }
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
// 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))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' +
'<script src="http://localhost:' + port + '/live.js"></script>\n' +
open + ' ' + MARKER_CLOSE_TEXT + ' ' + close + '\n'
);
@@ -121,15 +121,23 @@
}
// Pre-empt the browser: apply manual scroll restoration and jump to the
// saved scrollY at script-parse time (before DOMContentLoaded). If we
// wait until init(), the browser has already begun animating its own
// restore — especially bad when `scroll-behavior: smooth` is set on html.
// saved scrollY at script-parse time. Retries on fonts.ready and load
// are essential: scrollTo(y) clamps to the current document.scrollHeight,
// which is often hundreds of pixels short of the final value until
// async-loaded fonts swap in and reflow.
try {
history.scrollRestoration = 'manual';
const savedY = readScrollY();
if (savedY != null && Math.abs(window.scrollY - savedY) > 0.5) {
console.log('[impeccable.scroll] early restore', { from: window.scrollY, to: savedY });
window.scrollTo({ top: savedY, left: 0, behavior: 'instant' });
if (savedY != null) {
const apply = () => {
if (Math.abs(window.scrollY - savedY) > 0.5) {
console.log('[impeccable.scroll] early restore', { from: window.scrollY, to: savedY });
window.scrollTo(0, savedY);
}
};
apply();
if (document.fonts?.ready) document.fonts.ready.then(apply).catch(() => {});
window.addEventListener('load', apply, { once: true });
}
} catch {}
@@ -137,27 +137,8 @@ function commentClose(syntax) { return syntax === 'jsx' ? '*/}' : '-->'; }
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
// 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))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' +
'<script src="http://localhost:' + port + '/live.js"></script>\n' +
open + ' ' + MARKER_CLOSE_TEXT + ' ' + close + '\n'
);
+7 -57
View File
@@ -726,63 +726,14 @@
<!-- impeccable-variants-start f3c91105 -->
<div data-impeccable-variants="f3c91105" data-impeccable-variant-count="3" style="display: contents">
<!-- Original -->
<div data-impeccable-variant="original">
<div class="consulting-text">
<h2 class="consulting-title">Work with me</h2>
<p class="consulting-desc">Impeccable is built by <a href="https://renaissance-geek.ai" target="_blank" rel="noopener">Renaissance Geek</a>. I work with enterprise teams on large-scale rollouts, custom integrations, and training for designers and developers. If you're a frontier lab, design tool company, or enterprise looking to raise the bar on AI-generated design, let's talk.</p>
</div>
</div>
<!-- Variants: insert below this line -->
<style data-impeccable-css="f3c91105">
@scope ([data-impeccable-variant="1"]) {
.consulting-text { display: grid; gap: 14px; max-width: 56ch; }
.v1-tag { font-family: var(--font-mono); font-size: 0.6875rem; text-transform: uppercase; letter-spacing: 0.25em; color: var(--color-accent); }
.v1-title { font-family: var(--font-display); font-style: italic; font-weight: 300; font-size: clamp(2.75rem, 5.5vw, 4rem); line-height: 1; color: var(--color-ink); margin: 0; }
.v1-body { font-family: var(--font-body); font-size: 1rem; line-height: 1.6; color: var(--color-charcoal); margin: 4px 0 0; }
.v1-body a { color: var(--color-ink); text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--color-accent); }
}
@scope ([data-impeccable-variant="2"]) {
.consulting-text { display: flex; align-items: baseline; gap: 28px; padding: 20px 0; border-block: 1px solid var(--color-ink); }
.v2-mark { font-family: var(--font-display); font-style: italic; font-size: 3rem; line-height: 0.9; color: var(--color-accent); }
.v2-body { display: flex; flex-direction: column; gap: 8px; max-width: 52ch; }
.v2-title { font-family: var(--font-display); font-style: italic; font-size: 1.875rem; line-height: 1.15; color: var(--color-ink); margin: 0; }
.v2-body p { font-family: var(--font-body); font-size: 0.9375rem; line-height: 1.6; color: var(--color-charcoal); margin: 0; }
.v2-body a { color: var(--color-ink); text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--color-accent); }
}
@scope ([data-impeccable-variant="3"]) {
.consulting-text { display: grid; gap: 32px; max-width: 54ch; }
.v3-title { font-family: var(--font-display); font-style: italic; font-weight: 300; font-size: clamp(4rem, 8vw, 6rem); line-height: 0.9; color: var(--color-ink); margin: 0; letter-spacing: -0.02em; }
.v3-body { font-family: var(--font-body); font-size: 1rem; line-height: 1.65; color: var(--color-charcoal); margin: 0; padding-left: 20px; border-left: 1px solid var(--color-accent); }
.v3-body a { color: var(--color-ink); text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--color-accent); }
}
</style>
<div data-impeccable-variant="1">
<div class="consulting-text">
<span class="v1-tag">Renaissance Geek · Consulting</span>
<h2 class="v1-title">Work with me.</h2>
<p class="v1-body">Enterprise rollouts, custom integrations, and training for designers and developers. <a href="https://renaissance-geek.ai" target="_blank" rel="noopener">Get in touch</a>.</p>
</div>
</div>
<div data-impeccable-variant="2" style="display: none">
<div class="consulting-text">
<span class="v2-mark"></span>
<div class="v2-body">
<h2 class="v2-title">Work with me.</h2>
<p>Impeccable is built by <a href="https://renaissance-geek.ai" target="_blank" rel="noopener">Renaissance Geek</a>. Rollouts, integrations, training.</p>
</div>
</div>
</div>
<div data-impeccable-variant="3" style="display: none">
<div class="consulting-text">
<h2 class="v3-title">Work <br>with me.</h2>
<p class="v3-body">Impeccable is built by <a href="https://renaissance-geek.ai" target="_blank" rel="noopener">Renaissance Geek</a>. Large-scale rollouts, custom integrations, and training for teams raising the bar on AI-generated design.</p>
</div>
</div>
<div class="consulting-text">
<h2 class="consulting-title">Work with me</h2>
<p class="consulting-desc">Impeccable is built by <a href="https://renaissance-geek.ai" target="_blank" rel="noopener">Renaissance Geek</a>. I work with enterprise teams on large-scale rollouts, custom integrations, and training for designers and developers. If you're a frontier lab, design tool company, or enterprise looking to raise the bar on AI-generated design, let's talk.</p>
</div>
<!-- impeccable-variants-end f3c91105 -->
@@ -834,7 +785,6 @@
<script type="module" src="./app.js"></script>
<!-- impeccable-live-start -->
<script>(function(){try{history.scrollRestoration="manual";var y=parseFloat(localStorage.getItem("impeccable-live-session-scroll"));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>
<script src="http://localhost:8400/live.js"></script>
<!-- impeccable-live-end -->
</body>
-1
View File
@@ -78,7 +78,6 @@
<p>Questions about this policy? Open an issue on <a href="https://github.com/pbakaus/impeccable">GitHub</a> or reach out to <a href="https://x.com/pbakaus">@pbakaus</a>.</p>
</main>
<!-- impeccable-live-start -->
<script>(function(){try{history.scrollRestoration="manual";var y=parseFloat(localStorage.getItem("impeccable-live-session-scroll"));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>
<script src="http://localhost:8400/live.js"></script>
<!-- impeccable-live-end -->
</body>
@@ -121,15 +121,23 @@
}
// Pre-empt the browser: apply manual scroll restoration and jump to the
// saved scrollY at script-parse time (before DOMContentLoaded). If we
// wait until init(), the browser has already begun animating its own
// restore — especially bad when `scroll-behavior: smooth` is set on html.
// saved scrollY at script-parse time. Retries on fonts.ready and load
// are essential: scrollTo(y) clamps to the current document.scrollHeight,
// which is often hundreds of pixels short of the final value until
// async-loaded fonts swap in and reflow.
try {
history.scrollRestoration = 'manual';
const savedY = readScrollY();
if (savedY != null && Math.abs(window.scrollY - savedY) > 0.5) {
console.log('[impeccable.scroll] early restore', { from: window.scrollY, to: savedY });
window.scrollTo({ top: savedY, left: 0, behavior: 'instant' });
if (savedY != null) {
const apply = () => {
if (Math.abs(window.scrollY - savedY) > 0.5) {
console.log('[impeccable.scroll] early restore', { from: window.scrollY, to: savedY });
window.scrollTo(0, savedY);
}
};
apply();
if (document.fonts?.ready) document.fonts.ready.then(apply).catch(() => {});
window.addEventListener('load', apply, { once: true });
}
} catch {}
@@ -137,27 +137,8 @@ function commentClose(syntax) { return syntax === 'jsx' ? '*/}' : '-->'; }
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
// 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))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' +
'<script src="http://localhost:' + port + '/live.js"></script>\n' +
open + ' ' + MARKER_CLOSE_TEXT + ' ' + close + '\n'
);