Marquee With GSAP
A marquee created using GSAP which can change direction according to scroll.
framer-motion
Frankly, my dear, I don't give a damn
Frankly, my dear, I don't give a damn
Installation
Install the required dependencies:
npm install framer-motioncomponents/ui/marquee-with-gsap.tsx
"use client";
import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import { useEffect, useRef, useState } from "react";
type componentProp = {
text?: string;
top?: string;
size?: number;
};
const Marquee = ({ text, size,top="" }: componentProp) => {
const [hover, setHover] = useState(false);
const firstText = useRef<HTMLParagraphElement | null>(null);
const secondText = useRef<HTMLParagraphElement | null>(null);
const xPercent = useRef(0);
const direction = useRef(-1);
const animationFrame = useRef<number | null>(null);
useEffect(() => {
gsap.registerPlugin(ScrollTrigger);
const animate = () => {
if (xPercent.current > 0) xPercent.current = -100;
if (xPercent.current < -100) xPercent.current = 0;
gsap.set([firstText.current, secondText.current], {
xPercent: xPercent.current,
});
xPercent.current += 0.1 * direction.current;
animationFrame.current = requestAnimationFrame(animate);
};
if (!hover) {
animationFrame.current = requestAnimationFrame(animate);
}
return () => {
if (animationFrame.current) {
cancelAnimationFrame(animationFrame.current);
}
};
}, [hover]);
useEffect(() => {
const trigger = ScrollTrigger.create({
trigger: document.documentElement,
start: 0,
end: window.innerHeight,
scrub: 0.25,
onUpdate: (self) => {
direction.current = self.direction * -1;
},
});
return () => {
trigger.kill();
};
}, []);
return (
<div className="font-bebas absolute overflow-hidden w-full h-full cursor-default">
<div
className={`relative ${top} w-full font-extrabold md:text-[2rem] lg:text-[3rem] text-[1rem]`}
style={{ fontSize: size ? `${size}rem` : "" }}
>
<p
ref={firstText}
onMouseEnter={() => setHover(true)}
onMouseLeave={() => setHover(false)}
>
{text}
</p>
<p
ref={secondText}
onMouseEnter={() => setHover(true)}
onMouseLeave={() => setHover(false)}
className="absolute top-0 left-full w-full"
>
{text}
</p>
</div>
</div>
);
};
export default Marquee;