import type { Ref } from "vue"; /** * Scroll-scrubbed hero device parallax. GSAP is imported only on the client after mount, * keeping it off the critical rendering path; the context is reverted on unmount. */ export function useHeroScrollParallax(sectionEl: Ref) { let revert: (() => void) | null = null; let disposed = false; onMounted(async () => { const [{ gsap }, { ScrollTrigger }] = await Promise.all([import("gsap"), import("gsap/ScrollTrigger")]); const root = sectionEl.value; if (disposed || !root) return; gsap.registerPlugin(ScrollTrigger); const laptop = root.querySelector("#hero-laptop"); const mobile = root.querySelector("#hero-mobile"); if (!laptop || !mobile) return; const ctx = gsap.context(() => { gsap.to(laptop, { scrollTrigger: { trigger: root, start: "top top", end: "bottom top", scrub: 1.2 }, y: -40, rotateY: -25, rotateX: 13, scale: 0.98, ease: "none", }); gsap.to(mobile, { scrollTrigger: { trigger: root, start: "top top", end: "bottom top", scrub: 1.5 }, y: -85, rotateY: -6, rotateX: 4, scale: 1.03, ease: "none", }); }, root); revert = () => ctx.revert(); }); onBeforeUnmount(() => { disposed = true; revert?.(); }); }