Fluid animations with GSAP ScrollTrigger

Abhrajit RayAbhrajit Ray
5 min read

Here's a basic example of what you can achieve using GSAP Scrolltrigger.

animation result

GSAP allows you to add super smooth animations to almost anything on your website while maintaining great performance at the same time. It is a powerful and lightweight tool that can help you elevate โซ your site's user experience.

Installation

npm install gsap

In this tutorial, we will be using React, but you can use GSAP with anything that runs JavaScript.

Step 1: Setting up references

Set up the references to the element you want to animate. You can use the useRef() hook, the id or the class of the element. This reference will later be used to target the element that needs to be animated.

Step 2: Understanding the structure

The GSAP code needs to be executed whenever the site's layout is rendered or updated. Along with that, using the GSAP context we need to ensure that the animation is cleaned up properly. "Clean up" essentially means reverting the properties of the elements that were changed while animating, back to their original state.

const Environment = () => { // your component
  const myRef = useRef(null); //reference to the element to be animated
  //register the plugin
  gsap.registerPlugin(ScrollTrigger);

  useLayoutEffect(() => {
    //use gsap context for easy cleanup!
    const ctx = gsap.context(()=>{
        // your GSAP animation code here -->
        //
        //
    return () => ctx.revert(); //reverting the properties back to their original state
  }, []);

return <div ref={myRef}><div>
};

export default Environment;

If you're using React or a React-based framework like Next.js, a simpler way to do things would be to use the useGSAP() Hook. Simply install the gsap/react package and you're good to go. It automatically handles cleanup for you as well.

npm install @gsap/react

Here's the same example with the useGSAP() Hook :

const Environment = () => { // your component
  const myRef = useRef(null); //reference to the element to be animated
  //register the plugin
  gsap.registerPlugin(ScrollTrigger);

 useGSAP(() => {
     // gsap code here!! 

  }, []);

return <div ref={myRef}><div>
};

export default Environment;

Step 3: Writing the GSAP code

The first task is to register the ScrollTrigger plugin.

  gsap.registerPlugin(ScrollTrigger);

Next, inside the useGSAP() hook create a GSAP timeline. A timeline allows you to manage a sequence of animations and their timings precisely.

const tl = gsap.timeline();

Now it's time to add animations to our newly created timeline! ๐Ÿฅณ

There are different kinds of tween animations you can use like from(), fromTo() and to() depending on your needs :

  • from() accepts the starting values and animates them to the current state.

  • fromTo() accepts both starting and ending values.

  • to() accepts ending values for your animation.

In the example below, the animation is done using the from() tween.

  • The first parameter is the target of the element(s) that is to be animated. This reference can be in the form of a DOM reference, an ID or a class name.

  • The second parameter is the TweenVars, or the properties that are going to be animated.

  • Inside the TweenVars we will also specify the ScrollTrigger properties.

    • trigger denotes the element that will trigger the animation.

    • start defines the starting point of the trigger. The second value is the starting point of the viewport.

    • end defines the ending point of the trigger. The second value is the ending point of the viewport.

    • scrub property determines how smoothly an animation scrubs or moves in relation to the scroll bar position.

    • toggleActions determines the four controls for the animation, onEnter, onLeave, onEnterBack and onLeaveBack. By default, it is set to
      play none none none

  useGSAP(() => {
      //create a gsap timeline
      const tl = gsap.timeline();
      tl.from( brandRef.current, {
        //scrolltrigger settings
        scrollTrigger: {
          trigger: "#brandStory",
          start: "top 80%",
          end: "50% 20%",
          scrub: true,
          toggleActions: "play none none reverse",
          markers: true
        },
        opacity: 0,
        y: 100,
        duration: 0.5,
        ease: "power3.out"
      });
  }, []);

Another ScrollTrigger property is markers, using which you can see the start and end values for the scrolltrigger animation. This is certainly helpful in situations where the trigger needs to be controlled in a precise manner.

Yay! ๐ŸŽ‰ The ScrollTrigger animation is ready!

That's it! We've successfully made a scroll trigger animation with GSAP. Of course, this is a basic example of what GSAP can do. There are much more advanced and complex topics you can explore by trying things out for yourself while referring to their official documentation. Hope this article helped understand at least a little! ๐Ÿ˜„

Here are some links for the official documentation that I would suggest you read for a better and clearer understanding of things.


Here's the entire code for reference ๐Ÿ“„. Thanks for stopping by! โœŒ

import { useRef } from "react";
import roomPic from "../assets/boyGuitar.webp"
import gsap from "gsap";
import { ScrollTrigger } from "gsap/all";
import { useGSAP } from "@gsap/react";

const Environment = () => {
  const brandRef = useRef(null);
  //register the ScrollTrigger plugin
  gsap.registerPlugin(ScrollTrigger);

  useGSAP(() => {
      //create a gsap timeline
      const tl = gsap.timeline();
      tl.from( brandRef.current, {
        //scrolltrigger settings
        scrollTrigger: {
          trigger: "#brandStory",
          start: "top 80%",
          end: "50% 20%",
          scrub: true,
          toggleActions: "play none none reverse",
          markers: true
        },
        opacity: 0,
        y: 100,
        duration: 0.5,
        ease: "power3.out"
      });

      tl.fromTo( "#brandImg",
        //from animation
        {
          opacity: 0,
          x: -100
        }, 
        //to animation
      {
        //scrolltrigger settings
        scrollTrigger: {
          trigger: "#brandImg",
          start: "top 80%",
          end: "80% 20%",
          scrub: true,
          toggleActions: "play none none reverse"
        },
        opacity: 1,
        x: 0,
        duration: 0.5,
        ease: "power3.out"
      });

  }, []);


  return (
    <section
      id="brandStory"
      className="flex flex-col md:flex-row items-center bg-orange-200 px-10 md:px-20 
    py-10 lg:px-32 lg:py-20 gap-10"
    >
      <div ref={brandRef} className="md:w-[80%] lg:w-[40%] space-y-6">
        <h1 
        className="text-3xl md:text-5xl font-semibold flex-col flex uppercase">
          Brand Story
        </h1>
        <p className="text-xl font-medium leading-5">
          We are passionate about creating a
          serene escape through the art of lofi music. Our journey began with a
          shared love for relaxation, focus, and the subtle beauty of calming
          melodies.
        </p>
      </div>
      <div id="brandImg" className="max-w-[700px] border-b-[6px] border-r-[6px] border-black pr-4 pb-4 md:order-first w-full">
        <img src={roomPic} alt="heroPic" width={800} height={800} />
      </div>
    </section>
  );
};

export default Environment;
3
Subscribe to my newsletter

Read articles from Abhrajit Ray directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Abhrajit Ray
Abhrajit Ray

Hello! I'm a full stack developer and a computer science undergrad. I like building cool projects, making illustrations, playing games and eating good food.