fix(shader-transitions): add inWindow guard to .catch fallback handler

Address Vance's review on #456: the .catch handler was missing the
same tl.time() window check that .then has. Late-rejecting captures
(Safari + SVG-filter compositions) could fire gsap.to/fromTo on
scenes the playhead already left, causing flash-to-black mid-scene.

Wraps the CSS crossfade fallback in the same inWindow guard so
stale catch handlers are no-ops, matching the .then behavior.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
This commit is contained in:
ukimsanov
2026-04-23 20:17:13 -04:00
co-authored by Claude Opus 4.6
parent 06faf6f4c1
commit a970a657d4
+14 -11
View File
@@ -318,17 +318,20 @@ export function init(config: HyperShaderConfig): GsapTimeline {
// images, iframe sandbox restrictions, etc.) the old hard-cut
// was jarring. A CSS crossfade is strictly better UX.
console.warn("[HyperShader] Capture failed, CSS crossfade fallback:", e);
const fromEl = document.getElementById(fromId);
const toEl = document.getElementById(toId);
if (fromEl && toEl) {
gsap.to(fromEl, { opacity: 0, duration: dur, ease });
gsap.fromTo(toEl, { opacity: 0 }, { opacity: 1, duration: dur, ease });
} else {
// Last-resort hard cut if elements are somehow missing
document.querySelectorAll<HTMLElement>(".scene").forEach((s) => {
s.style.opacity = "0";
});
if (toEl) toEl.style.opacity = "1";
const nowTime = tl.time();
const inWindow = nowTime >= T && nowTime < T + dur;
if (inWindow) {
const fromEl = document.getElementById(fromId);
const toEl = document.getElementById(toId);
if (fromEl && toEl) {
gsap.to(fromEl, { opacity: 0, duration: dur, ease });
gsap.fromTo(toEl, { opacity: 0 }, { opacity: 1, duration: dur, ease });
} else {
document.querySelectorAll<HTMLElement>(".scene").forEach((s) => {
s.style.opacity = "0";
});
if (toEl) toEl.style.opacity = "1";
}
}
if (wasPlaying) tl.play();
});