// flow-scroll.jsx — FlowArt stacking scroll effect (GSAP + ScrollTrigger) // GSAP + ScrollTrigger must be loaded via CDN before this file runs gsap.registerPlugin(ScrollTrigger); const FlowSection = ({ children, id, ariaLabel, bg }) => (
{children}
); const FlowArt = ({ children }) => { const ref = React.useRef(null); React.useEffect(() => { const el = ref.current; if (!el) return; if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return; const sections = Array.from(el.querySelectorAll('[data-flow-section]')); if (!sections.length) return; const triggers = []; sections.forEach((section, i) => { gsap.set(section, { zIndex: i + 1 }); const inner = section.querySelector('.flow-art-container'); if (!inner) return; if (i > 0) { gsap.set(inner, { rotation: 30, transformOrigin: 'bottom left' }); const tween = gsap.to(inner, { rotation: 0, ease: 'none', scrollTrigger: { trigger: section, start: 'top bottom', end: 'top 25%', scrub: true, }, }); if (tween.scrollTrigger) triggers.push(tween.scrollTrigger); } if (i < sections.length - 1) { triggers.push( ScrollTrigger.create({ trigger: section, start: 'bottom bottom', end: 'bottom top', pin: true, pinSpacing: false, }) ); } }); ScrollTrigger.refresh(); return () => { triggers.forEach(t => t.kill()); ScrollTrigger.refresh(); }; }, []); return (
{children}
); }; Object.assign(window, { FlowArt, FlowSection });