fix(live): restart shader and re-anchor selection on HMR page reload

Bun's HTML HMR does a full page reload when the live-wrap.mjs edit
lands, so the shader canvas is destroyed and in-memory capture blob is
lost. resumeSession rehydrated state from localStorage but never
restarted the overlay, so the wait went dead.

resumeSession now re-captures the original's content (still in the DOM
inside the variant wrapper) and restarts showShaderOverlay when we
reload mid-generation. Also swaps the two remaining :first-child
selectors in resumeSession for pickVariantContent so the earlier
loose-children robustness fix carries across reloads.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Paul Bakaus
2026-04-21 15:45:46 -07:00
co-authored by Claude Opus 4.7
parent 9ccb240dc7
commit e2279ddab1
12 changed files with 240 additions and 24 deletions
@@ -2177,8 +2177,8 @@ void main() {
// Find the visible variant's content element for highlight positioning.
// Try the visible variant first, fall back to the original's content.
const visEl = wrapper.querySelector('[data-impeccable-variant="' + visibleVariant + '"] > :first-child');
const origEl = wrapper.querySelector('[data-impeccable-variant="original"] > :first-child');
const visEl = visibleVariant > 0 ? pickVariantContent(wrapper, visibleVariant) : null;
const origEl = pickVariantContent(wrapper, 'original');
selectedElement = visEl || origEl || wrapper.parentElement;
// Set display state BEFORE starting observer (avoid triggering it)
@@ -2192,6 +2192,24 @@ void main() {
// Start observing for more variants AFTER initial setup
if (variantObserver) variantObserver.disconnect();
variantObserver = startVariantObserver(currentSessionId);
// If we reloaded mid-generation (Bun's HTML HMR destroys the shader
// canvas), re-capture the original's content and restart the shader so
// the wait doesn't go dead.
if (state === 'GENERATING' && origEl) {
(async () => {
try {
const rect = origEl.getBoundingClientRect();
if (rect.width === 0 || rect.height === 0) return;
const blob = await captureElementToBlob(origEl, null, rect);
if (blob && state === 'GENERATING') {
showShaderOverlay(origEl, blob, rect);
}
} catch (err) {
console.warn('[impeccable] shader resume failed:', err);
}
})();
}
return true;
}