#Why GSAP
Just recently I started using GSAP in a few projects. It does exactly what you expect it to do, but with way more control.
#Scroll Triggers
useGSAP(() => {
gsap.fromTo(
".cta-content",
{ y: 10, opacity: 0, filter: "blur(4px)" },
{
y: 0,
opacity: 1,
filter: "blur(0px)",
duration: 0.7,
stagger: 0.06,
ease: "power3.out",
scrollTrigger: {
trigger: ".cta-container",
start: "top 80%",
toggleActions: "play reverse play reverse",
},
},
);
});<section className="cta-container w-full py-12 mb-0 lg:mb-12 lg:py-20">
<div className="relative overflow-hidden">
<div className="cta-content max-w-7xl mx-auto px-4 text-center">
<h2 className="text-4xl md:text-5xl lg:text-6xl font-medium tracking-tight text-brand-brown mb-10">
Header
</h2>
<Button
size="lg"
className="rounded-full px-10 h-14 text-lg gap-2 group cursor-pointer hover:scale-105 transition-transform"
>
Click Me
</Button>
</div>
</div>
</section>This is probably the easiest way to improve a page. As you scroll, elements come in with a bit of motion.
Even small movements like this makes everything feel more intentional and lively.
#Timelines
useGSAP(() => {
const timeline = gsap.timeline();
timeline.fromTo(
".hero-card",
{ opacity: 0, scale: 0.5, filter: "blur(100px)" },
{
opacity: 1,
scale: 1,
filter: "blur(0px)",
duration: 0.5,
ease: "circ.inOut",
},
);
timeline.to(".hero-tagline", { y: 0, opacity: 1 }, "<+=0.3");
timeline.fromTo(
".hero-button",
{ y: 5, opacity: 0 },
{
y: 0,
opacity: 1,
pointerEvents: "auto",
stagger: 0.15,
ease: "power3.inOut",
},
"<+=0.5",
);
});Instead of everything animating at once, you can control the exact order and timing with gsap.timeline. Helping the UI feel more structured instead of random.
#Split Text
const splitHeader = new SplitText("#text-header", {
type: "chars",
mask: "lines",
smartWrap: true,
});timeline.fromTo(
splitHeader.chars,
{ opacity: 0, y: 20, scale: 0.95 },
{ opacity: 1, y: 0, scale: 1, duration: 0.5, stagger: 0.04 },
);SplitText lets you animate text at a much finer level. You can target characters, words, or lines, and animate them individually. It's a simple way to make headers feel more dynamic.
#Staggers
{
stagger: 0.05
}Instead of animating elements in order, you can randomize the sequence. By default, GSAP goes top → bottom or left → right.
{
stagger: {
each: 0.05,
from: "random",
}
}With "random", each element gets picked at a different time.