fix(live): restore scroll to element's viewport-relative top after reload

When HMR misses and we fall back to window.location.reload(), the native
scroll restoration landed the page somewhere near the right region but
not on the selected element, because layout had shifted between the
save and the reload. Capture the element's getBoundingClientRect().top
into the session snapshot, disable native scroll restoration on resume,
and manually scroll the element back to that exact viewport-relative
position. Run a second correction pass after fonts and images settle to
absorb late layout shifts without animating the fix.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Paul Bakaus
2026-04-22 09:58:30 -07:00
co-authored by Claude Opus 4.7
parent 101dc50362
commit 4f4df85250
13 changed files with 356 additions and 2 deletions
@@ -2135,6 +2135,15 @@ void main() {
function saveSession() {
if (!currentSessionId) return;
// Capture the selected element's current viewport-relative top so we
// can restore the same framing after a reload, even if layout shifts.
let scrollAnchor = null;
try {
if (selectedElement && selectedElement.isConnected) {
const r = selectedElement.getBoundingClientRect();
if (r.width > 0 && r.height > 0) scrollAnchor = { viewportTop: r.top };
}
} catch {}
try {
localStorage.setItem(LS_KEY, JSON.stringify({
id: currentSessionId,
@@ -2144,6 +2153,7 @@ void main() {
expected: expectedVariants,
arrived: arrivedVariants,
visible: visibleVariant,
scrollAnchor,
}));
} catch { /* quota exceeded or private mode */ }
}
@@ -2288,6 +2298,25 @@ void main() {
// Set display state BEFORE starting observer (avoid triggering it)
if (visibleVariant > 0) showVariantInDOM(currentSessionId, visibleVariant);
// Restore scroll: land the selected element back at the same
// viewport-relative top it had before the reload. Two passes — once
// synchronously, once after fonts/images settle — catch late layout
// shifts without animating the correction.
if (saved?.scrollAnchor && selectedElement) {
try { history.scrollRestoration = 'manual'; } catch {}
const targetTop = saved.scrollAnchor.viewportTop;
const correct = () => {
if (!selectedElement?.isConnected) return;
const delta = selectedElement.getBoundingClientRect().top - targetTop;
if (Math.abs(delta) > 0.5) window.scrollBy({ top: delta, left: 0, behavior: 'instant' });
};
correct();
requestAnimationFrame(() => requestAnimationFrame(correct));
if (document.fonts?.ready) {
document.fonts.ready.then(() => requestAnimationFrame(correct)).catch(() => {});
}
}
state = arrivedVariants >= expectedVariants ? 'CYCLING' : 'GENERATING';
showBar(state === 'CYCLING' ? 'cycling' : 'generating');
startScrollTracking();
@@ -2135,6 +2135,15 @@ void main() {
function saveSession() {
if (!currentSessionId) return;
// Capture the selected element's current viewport-relative top so we
// can restore the same framing after a reload, even if layout shifts.
let scrollAnchor = null;
try {
if (selectedElement && selectedElement.isConnected) {
const r = selectedElement.getBoundingClientRect();
if (r.width > 0 && r.height > 0) scrollAnchor = { viewportTop: r.top };
}
} catch {}
try {
localStorage.setItem(LS_KEY, JSON.stringify({
id: currentSessionId,
@@ -2144,6 +2153,7 @@ void main() {
expected: expectedVariants,
arrived: arrivedVariants,
visible: visibleVariant,
scrollAnchor,
}));
} catch { /* quota exceeded or private mode */ }
}
@@ -2288,6 +2298,25 @@ void main() {
// Set display state BEFORE starting observer (avoid triggering it)
if (visibleVariant > 0) showVariantInDOM(currentSessionId, visibleVariant);
// Restore scroll: land the selected element back at the same
// viewport-relative top it had before the reload. Two passes — once
// synchronously, once after fonts/images settle — catch late layout
// shifts without animating the correction.
if (saved?.scrollAnchor && selectedElement) {
try { history.scrollRestoration = 'manual'; } catch {}
const targetTop = saved.scrollAnchor.viewportTop;
const correct = () => {
if (!selectedElement?.isConnected) return;
const delta = selectedElement.getBoundingClientRect().top - targetTop;
if (Math.abs(delta) > 0.5) window.scrollBy({ top: delta, left: 0, behavior: 'instant' });
};
correct();
requestAnimationFrame(() => requestAnimationFrame(correct));
if (document.fonts?.ready) {
document.fonts.ready.then(() => requestAnimationFrame(correct)).catch(() => {});
}
}
state = arrivedVariants >= expectedVariants ? 'CYCLING' : 'GENERATING';
showBar(state === 'CYCLING' ? 'cycling' : 'generating');
startScrollTracking();
@@ -2135,6 +2135,15 @@ void main() {
function saveSession() {
if (!currentSessionId) return;
// Capture the selected element's current viewport-relative top so we
// can restore the same framing after a reload, even if layout shifts.
let scrollAnchor = null;
try {
if (selectedElement && selectedElement.isConnected) {
const r = selectedElement.getBoundingClientRect();
if (r.width > 0 && r.height > 0) scrollAnchor = { viewportTop: r.top };
}
} catch {}
try {
localStorage.setItem(LS_KEY, JSON.stringify({
id: currentSessionId,
@@ -2144,6 +2153,7 @@ void main() {
expected: expectedVariants,
arrived: arrivedVariants,
visible: visibleVariant,
scrollAnchor,
}));
} catch { /* quota exceeded or private mode */ }
}
@@ -2288,6 +2298,25 @@ void main() {
// Set display state BEFORE starting observer (avoid triggering it)
if (visibleVariant > 0) showVariantInDOM(currentSessionId, visibleVariant);
// Restore scroll: land the selected element back at the same
// viewport-relative top it had before the reload. Two passes — once
// synchronously, once after fonts/images settle — catch late layout
// shifts without animating the correction.
if (saved?.scrollAnchor && selectedElement) {
try { history.scrollRestoration = 'manual'; } catch {}
const targetTop = saved.scrollAnchor.viewportTop;
const correct = () => {
if (!selectedElement?.isConnected) return;
const delta = selectedElement.getBoundingClientRect().top - targetTop;
if (Math.abs(delta) > 0.5) window.scrollBy({ top: delta, left: 0, behavior: 'instant' });
};
correct();
requestAnimationFrame(() => requestAnimationFrame(correct));
if (document.fonts?.ready) {
document.fonts.ready.then(() => requestAnimationFrame(correct)).catch(() => {});
}
}
state = arrivedVariants >= expectedVariants ? 'CYCLING' : 'GENERATING';
showBar(state === 'CYCLING' ? 'cycling' : 'generating');
startScrollTracking();
@@ -2135,6 +2135,15 @@ void main() {
function saveSession() {
if (!currentSessionId) return;
// Capture the selected element's current viewport-relative top so we
// can restore the same framing after a reload, even if layout shifts.
let scrollAnchor = null;
try {
if (selectedElement && selectedElement.isConnected) {
const r = selectedElement.getBoundingClientRect();
if (r.width > 0 && r.height > 0) scrollAnchor = { viewportTop: r.top };
}
} catch {}
try {
localStorage.setItem(LS_KEY, JSON.stringify({
id: currentSessionId,
@@ -2144,6 +2153,7 @@ void main() {
expected: expectedVariants,
arrived: arrivedVariants,
visible: visibleVariant,
scrollAnchor,
}));
} catch { /* quota exceeded or private mode */ }
}
@@ -2288,6 +2298,25 @@ void main() {
// Set display state BEFORE starting observer (avoid triggering it)
if (visibleVariant > 0) showVariantInDOM(currentSessionId, visibleVariant);
// Restore scroll: land the selected element back at the same
// viewport-relative top it had before the reload. Two passes — once
// synchronously, once after fonts/images settle — catch late layout
// shifts without animating the correction.
if (saved?.scrollAnchor && selectedElement) {
try { history.scrollRestoration = 'manual'; } catch {}
const targetTop = saved.scrollAnchor.viewportTop;
const correct = () => {
if (!selectedElement?.isConnected) return;
const delta = selectedElement.getBoundingClientRect().top - targetTop;
if (Math.abs(delta) > 0.5) window.scrollBy({ top: delta, left: 0, behavior: 'instant' });
};
correct();
requestAnimationFrame(() => requestAnimationFrame(correct));
if (document.fonts?.ready) {
document.fonts.ready.then(() => requestAnimationFrame(correct)).catch(() => {});
}
}
state = arrivedVariants >= expectedVariants ? 'CYCLING' : 'GENERATING';
showBar(state === 'CYCLING' ? 'cycling' : 'generating');
startScrollTracking();
@@ -2135,6 +2135,15 @@ void main() {
function saveSession() {
if (!currentSessionId) return;
// Capture the selected element's current viewport-relative top so we
// can restore the same framing after a reload, even if layout shifts.
let scrollAnchor = null;
try {
if (selectedElement && selectedElement.isConnected) {
const r = selectedElement.getBoundingClientRect();
if (r.width > 0 && r.height > 0) scrollAnchor = { viewportTop: r.top };
}
} catch {}
try {
localStorage.setItem(LS_KEY, JSON.stringify({
id: currentSessionId,
@@ -2144,6 +2153,7 @@ void main() {
expected: expectedVariants,
arrived: arrivedVariants,
visible: visibleVariant,
scrollAnchor,
}));
} catch { /* quota exceeded or private mode */ }
}
@@ -2288,6 +2298,25 @@ void main() {
// Set display state BEFORE starting observer (avoid triggering it)
if (visibleVariant > 0) showVariantInDOM(currentSessionId, visibleVariant);
// Restore scroll: land the selected element back at the same
// viewport-relative top it had before the reload. Two passes — once
// synchronously, once after fonts/images settle — catch late layout
// shifts without animating the correction.
if (saved?.scrollAnchor && selectedElement) {
try { history.scrollRestoration = 'manual'; } catch {}
const targetTop = saved.scrollAnchor.viewportTop;
const correct = () => {
if (!selectedElement?.isConnected) return;
const delta = selectedElement.getBoundingClientRect().top - targetTop;
if (Math.abs(delta) > 0.5) window.scrollBy({ top: delta, left: 0, behavior: 'instant' });
};
correct();
requestAnimationFrame(() => requestAnimationFrame(correct));
if (document.fonts?.ready) {
document.fonts.ready.then(() => requestAnimationFrame(correct)).catch(() => {});
}
}
state = arrivedVariants >= expectedVariants ? 'CYCLING' : 'GENERATING';
showBar(state === 'CYCLING' ? 'cycling' : 'generating');
startScrollTracking();
@@ -2135,6 +2135,15 @@ void main() {
function saveSession() {
if (!currentSessionId) return;
// Capture the selected element's current viewport-relative top so we
// can restore the same framing after a reload, even if layout shifts.
let scrollAnchor = null;
try {
if (selectedElement && selectedElement.isConnected) {
const r = selectedElement.getBoundingClientRect();
if (r.width > 0 && r.height > 0) scrollAnchor = { viewportTop: r.top };
}
} catch {}
try {
localStorage.setItem(LS_KEY, JSON.stringify({
id: currentSessionId,
@@ -2144,6 +2153,7 @@ void main() {
expected: expectedVariants,
arrived: arrivedVariants,
visible: visibleVariant,
scrollAnchor,
}));
} catch { /* quota exceeded or private mode */ }
}
@@ -2288,6 +2298,25 @@ void main() {
// Set display state BEFORE starting observer (avoid triggering it)
if (visibleVariant > 0) showVariantInDOM(currentSessionId, visibleVariant);
// Restore scroll: land the selected element back at the same
// viewport-relative top it had before the reload. Two passes — once
// synchronously, once after fonts/images settle — catch late layout
// shifts without animating the correction.
if (saved?.scrollAnchor && selectedElement) {
try { history.scrollRestoration = 'manual'; } catch {}
const targetTop = saved.scrollAnchor.viewportTop;
const correct = () => {
if (!selectedElement?.isConnected) return;
const delta = selectedElement.getBoundingClientRect().top - targetTop;
if (Math.abs(delta) > 0.5) window.scrollBy({ top: delta, left: 0, behavior: 'instant' });
};
correct();
requestAnimationFrame(() => requestAnimationFrame(correct));
if (document.fonts?.ready) {
document.fonts.ready.then(() => requestAnimationFrame(correct)).catch(() => {});
}
}
state = arrivedVariants >= expectedVariants ? 'CYCLING' : 'GENERATING';
showBar(state === 'CYCLING' ? 'cycling' : 'generating');
startScrollTracking();
@@ -2135,6 +2135,15 @@ void main() {
function saveSession() {
if (!currentSessionId) return;
// Capture the selected element's current viewport-relative top so we
// can restore the same framing after a reload, even if layout shifts.
let scrollAnchor = null;
try {
if (selectedElement && selectedElement.isConnected) {
const r = selectedElement.getBoundingClientRect();
if (r.width > 0 && r.height > 0) scrollAnchor = { viewportTop: r.top };
}
} catch {}
try {
localStorage.setItem(LS_KEY, JSON.stringify({
id: currentSessionId,
@@ -2144,6 +2153,7 @@ void main() {
expected: expectedVariants,
arrived: arrivedVariants,
visible: visibleVariant,
scrollAnchor,
}));
} catch { /* quota exceeded or private mode */ }
}
@@ -2288,6 +2298,25 @@ void main() {
// Set display state BEFORE starting observer (avoid triggering it)
if (visibleVariant > 0) showVariantInDOM(currentSessionId, visibleVariant);
// Restore scroll: land the selected element back at the same
// viewport-relative top it had before the reload. Two passes — once
// synchronously, once after fonts/images settle — catch late layout
// shifts without animating the correction.
if (saved?.scrollAnchor && selectedElement) {
try { history.scrollRestoration = 'manual'; } catch {}
const targetTop = saved.scrollAnchor.viewportTop;
const correct = () => {
if (!selectedElement?.isConnected) return;
const delta = selectedElement.getBoundingClientRect().top - targetTop;
if (Math.abs(delta) > 0.5) window.scrollBy({ top: delta, left: 0, behavior: 'instant' });
};
correct();
requestAnimationFrame(() => requestAnimationFrame(correct));
if (document.fonts?.ready) {
document.fonts.ready.then(() => requestAnimationFrame(correct)).catch(() => {});
}
}
state = arrivedVariants >= expectedVariants ? 'CYCLING' : 'GENERATING';
showBar(state === 'CYCLING' ? 'cycling' : 'generating');
startScrollTracking();
@@ -2135,6 +2135,15 @@ void main() {
function saveSession() {
if (!currentSessionId) return;
// Capture the selected element's current viewport-relative top so we
// can restore the same framing after a reload, even if layout shifts.
let scrollAnchor = null;
try {
if (selectedElement && selectedElement.isConnected) {
const r = selectedElement.getBoundingClientRect();
if (r.width > 0 && r.height > 0) scrollAnchor = { viewportTop: r.top };
}
} catch {}
try {
localStorage.setItem(LS_KEY, JSON.stringify({
id: currentSessionId,
@@ -2144,6 +2153,7 @@ void main() {
expected: expectedVariants,
arrived: arrivedVariants,
visible: visibleVariant,
scrollAnchor,
}));
} catch { /* quota exceeded or private mode */ }
}
@@ -2288,6 +2298,25 @@ void main() {
// Set display state BEFORE starting observer (avoid triggering it)
if (visibleVariant > 0) showVariantInDOM(currentSessionId, visibleVariant);
// Restore scroll: land the selected element back at the same
// viewport-relative top it had before the reload. Two passes — once
// synchronously, once after fonts/images settle — catch late layout
// shifts without animating the correction.
if (saved?.scrollAnchor && selectedElement) {
try { history.scrollRestoration = 'manual'; } catch {}
const targetTop = saved.scrollAnchor.viewportTop;
const correct = () => {
if (!selectedElement?.isConnected) return;
const delta = selectedElement.getBoundingClientRect().top - targetTop;
if (Math.abs(delta) > 0.5) window.scrollBy({ top: delta, left: 0, behavior: 'instant' });
};
correct();
requestAnimationFrame(() => requestAnimationFrame(correct));
if (document.fonts?.ready) {
document.fonts.ready.then(() => requestAnimationFrame(correct)).catch(() => {});
}
}
state = arrivedVariants >= expectedVariants ? 'CYCLING' : 'GENERATING';
showBar(state === 'CYCLING' ? 'cycling' : 'generating');
startScrollTracking();
@@ -2135,6 +2135,15 @@ void main() {
function saveSession() {
if (!currentSessionId) return;
// Capture the selected element's current viewport-relative top so we
// can restore the same framing after a reload, even if layout shifts.
let scrollAnchor = null;
try {
if (selectedElement && selectedElement.isConnected) {
const r = selectedElement.getBoundingClientRect();
if (r.width > 0 && r.height > 0) scrollAnchor = { viewportTop: r.top };
}
} catch {}
try {
localStorage.setItem(LS_KEY, JSON.stringify({
id: currentSessionId,
@@ -2144,6 +2153,7 @@ void main() {
expected: expectedVariants,
arrived: arrivedVariants,
visible: visibleVariant,
scrollAnchor,
}));
} catch { /* quota exceeded or private mode */ }
}
@@ -2288,6 +2298,25 @@ void main() {
// Set display state BEFORE starting observer (avoid triggering it)
if (visibleVariant > 0) showVariantInDOM(currentSessionId, visibleVariant);
// Restore scroll: land the selected element back at the same
// viewport-relative top it had before the reload. Two passes — once
// synchronously, once after fonts/images settle — catch late layout
// shifts without animating the correction.
if (saved?.scrollAnchor && selectedElement) {
try { history.scrollRestoration = 'manual'; } catch {}
const targetTop = saved.scrollAnchor.viewportTop;
const correct = () => {
if (!selectedElement?.isConnected) return;
const delta = selectedElement.getBoundingClientRect().top - targetTop;
if (Math.abs(delta) > 0.5) window.scrollBy({ top: delta, left: 0, behavior: 'instant' });
};
correct();
requestAnimationFrame(() => requestAnimationFrame(correct));
if (document.fonts?.ready) {
document.fonts.ready.then(() => requestAnimationFrame(correct)).catch(() => {});
}
}
state = arrivedVariants >= expectedVariants ? 'CYCLING' : 'GENERATING';
showBar(state === 'CYCLING' ? 'cycling' : 'generating');
startScrollTracking();
@@ -2135,6 +2135,15 @@ void main() {
function saveSession() {
if (!currentSessionId) return;
// Capture the selected element's current viewport-relative top so we
// can restore the same framing after a reload, even if layout shifts.
let scrollAnchor = null;
try {
if (selectedElement && selectedElement.isConnected) {
const r = selectedElement.getBoundingClientRect();
if (r.width > 0 && r.height > 0) scrollAnchor = { viewportTop: r.top };
}
} catch {}
try {
localStorage.setItem(LS_KEY, JSON.stringify({
id: currentSessionId,
@@ -2144,6 +2153,7 @@ void main() {
expected: expectedVariants,
arrived: arrivedVariants,
visible: visibleVariant,
scrollAnchor,
}));
} catch { /* quota exceeded or private mode */ }
}
@@ -2288,6 +2298,25 @@ void main() {
// Set display state BEFORE starting observer (avoid triggering it)
if (visibleVariant > 0) showVariantInDOM(currentSessionId, visibleVariant);
// Restore scroll: land the selected element back at the same
// viewport-relative top it had before the reload. Two passes — once
// synchronously, once after fonts/images settle — catch late layout
// shifts without animating the correction.
if (saved?.scrollAnchor && selectedElement) {
try { history.scrollRestoration = 'manual'; } catch {}
const targetTop = saved.scrollAnchor.viewportTop;
const correct = () => {
if (!selectedElement?.isConnected) return;
const delta = selectedElement.getBoundingClientRect().top - targetTop;
if (Math.abs(delta) > 0.5) window.scrollBy({ top: delta, left: 0, behavior: 'instant' });
};
correct();
requestAnimationFrame(() => requestAnimationFrame(correct));
if (document.fonts?.ready) {
document.fonts.ready.then(() => requestAnimationFrame(correct)).catch(() => {});
}
}
state = arrivedVariants >= expectedVariants ? 'CYCLING' : 'GENERATING';
showBar(state === 'CYCLING' ? 'cycling' : 'generating');
startScrollTracking();
@@ -2135,6 +2135,15 @@ void main() {
function saveSession() {
if (!currentSessionId) return;
// Capture the selected element's current viewport-relative top so we
// can restore the same framing after a reload, even if layout shifts.
let scrollAnchor = null;
try {
if (selectedElement && selectedElement.isConnected) {
const r = selectedElement.getBoundingClientRect();
if (r.width > 0 && r.height > 0) scrollAnchor = { viewportTop: r.top };
}
} catch {}
try {
localStorage.setItem(LS_KEY, JSON.stringify({
id: currentSessionId,
@@ -2144,6 +2153,7 @@ void main() {
expected: expectedVariants,
arrived: arrivedVariants,
visible: visibleVariant,
scrollAnchor,
}));
} catch { /* quota exceeded or private mode */ }
}
@@ -2288,6 +2298,25 @@ void main() {
// Set display state BEFORE starting observer (avoid triggering it)
if (visibleVariant > 0) showVariantInDOM(currentSessionId, visibleVariant);
// Restore scroll: land the selected element back at the same
// viewport-relative top it had before the reload. Two passes — once
// synchronously, once after fonts/images settle — catch late layout
// shifts without animating the correction.
if (saved?.scrollAnchor && selectedElement) {
try { history.scrollRestoration = 'manual'; } catch {}
const targetTop = saved.scrollAnchor.viewportTop;
const correct = () => {
if (!selectedElement?.isConnected) return;
const delta = selectedElement.getBoundingClientRect().top - targetTop;
if (Math.abs(delta) > 0.5) window.scrollBy({ top: delta, left: 0, behavior: 'instant' });
};
correct();
requestAnimationFrame(() => requestAnimationFrame(correct));
if (document.fonts?.ready) {
document.fonts.ready.then(() => requestAnimationFrame(correct)).catch(() => {});
}
}
state = arrivedVariants >= expectedVariants ? 'CYCLING' : 'GENERATING';
showBar(state === 'CYCLING' ? 'cycling' : 'generating');
startScrollTracking();
+8 -2
View File
@@ -104,6 +104,8 @@
<div class="hero-cta-group">
<a href="#downloads" class="hero-cta-combined">Get Started</a>
<div class="hero-logos-inline">
<span class="hero-logos-label">Works with</span>
<div class="hero-logos-row">
@@ -118,6 +120,8 @@
<span class="hero-logo-icon has-tooltip" data-tooltip="Pi"><img src="assets/pi-logo.svg" alt="Pi" width="20" height="20" loading="lazy" style="background:#1a1a1a;border-radius:50%;padding:3px"></span>
</div>
</div>
</div>
<p class="hero-version-link"><a href="#changelog">v3.0: 1 skill, 23 commands</a></p>
</div>
@@ -713,10 +717,12 @@
<!-- PARTNERSHIPS -->
<section class="consulting-section" id="consulting">
<div class="consulting-content" data-reveal>
<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>
<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 class="consulting-actions">
<a href="mailto:paul@renaissance-geek.ai" class="btn btn-primary">
<span>Get in touch</span>
@@ -2135,6 +2135,15 @@ void main() {
function saveSession() {
if (!currentSessionId) return;
// Capture the selected element's current viewport-relative top so we
// can restore the same framing after a reload, even if layout shifts.
let scrollAnchor = null;
try {
if (selectedElement && selectedElement.isConnected) {
const r = selectedElement.getBoundingClientRect();
if (r.width > 0 && r.height > 0) scrollAnchor = { viewportTop: r.top };
}
} catch {}
try {
localStorage.setItem(LS_KEY, JSON.stringify({
id: currentSessionId,
@@ -2144,6 +2153,7 @@ void main() {
expected: expectedVariants,
arrived: arrivedVariants,
visible: visibleVariant,
scrollAnchor,
}));
} catch { /* quota exceeded or private mode */ }
}
@@ -2288,6 +2298,25 @@ void main() {
// Set display state BEFORE starting observer (avoid triggering it)
if (visibleVariant > 0) showVariantInDOM(currentSessionId, visibleVariant);
// Restore scroll: land the selected element back at the same
// viewport-relative top it had before the reload. Two passes — once
// synchronously, once after fonts/images settle — catch late layout
// shifts without animating the correction.
if (saved?.scrollAnchor && selectedElement) {
try { history.scrollRestoration = 'manual'; } catch {}
const targetTop = saved.scrollAnchor.viewportTop;
const correct = () => {
if (!selectedElement?.isConnected) return;
const delta = selectedElement.getBoundingClientRect().top - targetTop;
if (Math.abs(delta) > 0.5) window.scrollBy({ top: delta, left: 0, behavior: 'instant' });
};
correct();
requestAnimationFrame(() => requestAnimationFrame(correct));
if (document.fonts?.ready) {
document.fonts.ready.then(() => requestAnimationFrame(correct)).catch(() => {});
}
}
state = arrivedVariants >= expectedVariants ? 'CYCLING' : 'GENERATING';
showBar(state === 'CYCLING' ? 'cycling' : 'generating');
startScrollTracking();