type IframeWindow = Window & { __timelines?: Record void; pause?: () => void }>; __player?: { getTime?: () => number; seek?: (t: number) => void }; __hfForceTimelineRebind?: () => void; __hfSuppressSceneMutations?: (fn: () => T) => T; __hfStudioManualEditsApply?: () => void; gsap?: { timeline?: (...args: unknown[]) => unknown }; }; function isGsapScript(text: string): boolean { return ( text.includes("gsap.timeline") || text.includes("__timelines") || text.includes(".to(") || text.includes(".set(") ); } function findGsapScriptElements(doc: Document): HTMLScriptElement[] { const results: HTMLScriptElement[] = []; const scripts = doc.querySelectorAll("script:not([src])"); for (const script of scripts) { if (isGsapScript(script.textContent || "")) results.push(script); } return results; } /** * Replace the GSAP script in the live iframe without reloading. This preserves * the WebGL context and shader transition cache. * * Scoped to root-document GSAP scripts only — scripts inside `