syntheogenesis / dee /static /assistant-boot.js
Tengo Gzirishvili
Fix repaint-nudge race + add temp postMessage diagnostic
9823f24
Raw
History Blame Contribute Delete
4.85 kB
/* TuringDNA Β· Assistant β€” theme bootstrap.
*
* Loaded synchronously in <head> BEFORE app.css so <html data-theme> is set
* before first paint (no flash). Mirrors the engine's inline bootstrap, but
* kept as an external file because assistant.html is served as a STATIC file
* (not through the nonce-injecting index route), so the site's Content-Security
* -Policy β€” script-src 'self' 'nonce-…' β€” refuses un-nonced inline scripts.
* A same-origin /static/ file is allowed by 'self'. Dark is the default. */
(function () {
try {
var t = localStorage.getItem('td-theme');
if (t !== 'light' && t !== 'dark') { t = 'dark'; } // dark by default
document.documentElement.setAttribute('data-theme', t);
} catch (e) {
document.documentElement.setAttribute('data-theme', 'dark');
}
// Embed mode (?embed=1): the panel is inside the engine's #turing view, so
// its own brand header + "Engine" back-link + ambient backdrop are redundant
// β€” hide them (CSS keys off html.asst-embed). Set pre-paint to avoid a flash.
try {
if (/[?&]embed=1\b/.test(location.search)) {
document.documentElement.classList.add('asst-embed');
}
} catch (e) {}
// --vh: this document is its OWN nested browsing context (loaded in an
// iframe), so its 100vh/100dvh resolve against the IFRAME's own viewport,
// not the parent page's β€” and needs the same window.innerHeight-based fix
// as the engine (see index.html's bootstrap comment). Safari 15.6.1 was
// clipping the composer at the bottom of this exact panel because of it.
//
// The plain 'resize' listener isn't enough here: confirmed directly (this
// repo's own test) that Chrome DOES fire 'resize' on an iframe's
// contentWindow when the PARENT page's layout changes the iframe's box
// (no top-level window resize involved) β€” but Safari has a long-documented
// gap where it only fires 'resize' for genuine top-level window resizes,
// never for parent-driven layout shifts. That leaves this iframe's --vh
// stuck at whatever it measured on first paint, even after the engine's
// topbar/sidebar finish laying out and the iframe's real box changes.
// ResizeObserver doesn't have that gap β€” it fires on ANY box-size change
// to the observed element, which for <html> IS this iframe's effective
// viewport, regardless of what caused the change.
//
// One more layer confirmed directly on real Safari 15.6.1 (not guessed):
// getBoundingClientRect() already reports the CORRECT, uncut geometry at
// rest β€” the layout is right. What's wrong is that Safari doesn't always
// repaint the screen to match a `--vh` change applied via a custom
// property; the stale frame stays on screen until something forces a
// repaint. A user-driven scroll is exactly that kind of forcing trigger
// (confirmed: scrolling makes the "hidden" content flash correctly
// into view, then it reverts once scrolling settles) β€” so nudge a
// repaint ourselves right after every --vh change instead of waiting
// for the user to accidentally trigger one.
try {
// Nudges .asst specifically, not <html>/<body> β€” see index.html's
// matching comment (transforming an ancestor of a position:fixed
// element hijacks that element's containing block for a frame).
// This document has no fixed-position elements at all, but staying
// consistent with the targeted approach costs nothing.
function nudgeRepaint() {
var el = document.querySelector('.asst');
// Also bail if a nudge is already in flight β€” see index.html's
// matching comment (overlapping calls otherwise leave the
// transform stuck on permanently instead of reverting).
if (!el || el.dataset.nudging) return;
el.dataset.nudging = '1';
var prev = el.style.transform;
el.style.transform = "translateZ(0)";
void el.offsetHeight;
requestAnimationFrame(function () {
el.style.transform = prev;
delete el.dataset.nudging;
});
}
function setVH() {
document.documentElement.style.setProperty('--vh', (window.innerHeight * 0.01) + 'px');
nudgeRepaint();
}
setVH();
window.addEventListener('resize', setVH);
if (window.ResizeObserver) {
new ResizeObserver(setVH).observe(document.documentElement);
}
// Same reasoning as index.html: this script runs in <head>, before
// .asst exists, so the first nudgeRepaint() above is a no-op.
document.addEventListener('DOMContentLoaded', nudgeRepaint);
} catch (e) {}
})();