"use client"; import { useEffect, useMemo, useRef } from "react"; import { gsap } from "gsap"; import { ScrollTrigger } from "gsap/ScrollTrigger"; import "./ScrollFloat.css"; type ScrollFloatProps = { children: string; scrollContainerRef?: React.RefObject; containerClassName?: string; textClassName?: string; animationDuration?: number; ease?: string; scrollStart?: string; scrollEnd?: string; stagger?: number; }; export default function ScrollFloat({ children, scrollContainerRef, containerClassName = "", textClassName = "", animationDuration = 1, ease = "back.inOut(2)", scrollStart = "center bottom+=50%", scrollEnd = "bottom bottom-=40%", stagger = 0.03, }: ScrollFloatProps) { const containerRef = useRef(null); const splitText = useMemo( () => children.split(" ").map((word, wordIndex, words) => ( {word.split("").map((char, charIndex) => ( {char} ))} {wordIndex < words.length - 1 &&  } )), [children], ); useEffect(() => { if (typeof window === "undefined") return; gsap.registerPlugin(ScrollTrigger); const el = containerRef.current; if (!el) return; const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches; const charElements = el.querySelectorAll(".char"); if (reduceMotion) { gsap.set(charElements, { opacity: 1, yPercent: 0, scaleY: 1, scaleX: 1 }); return; } const scroller = scrollContainerRef?.current || window; const tween = gsap.fromTo( charElements, { willChange: "opacity, transform", opacity: 0, yPercent: 120, scaleY: 2.3, scaleX: 0.7, transformOrigin: "50% 0%", }, { duration: animationDuration, ease, opacity: 1, yPercent: 0, scaleY: 1, scaleX: 1, stagger, scrollTrigger: { trigger: el, scroller, start: scrollStart, end: scrollEnd, scrub: true, }, }, ); return () => { tween.scrollTrigger?.kill(); tween.kill(); }; }, [animationDuration, ease, scrollContainerRef, scrollEnd, scrollStart, stagger]); return (

{splitText}

); }