#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 topbottom or leftright.

{
  stagger: {
    each: 0.05,
    from: "random",
  }
}

With "random", each element gets picked at a different time.


Last Updated:

© 2026 candylol.dev