DEV Community

Cover image for Learning GSAP with a Day-to-Night Scroll Animation 🌞🌜
ifrah for Toru

Posted on

Learning GSAP with a Day-to-Night Scroll Animation 🌞🌜

We’ve been exploring GSAP (GreenSock Animation Platform) lately and wanted to share a breakdown of a recent project. If you’re new to GSAP, this project is a great way to get started with scroll-based animations!

What We’re Building

We’ll create a scroll-driven day-to-night transition using SVG elements. The animation will include:

  • Sun and Moon following a curved path as you scroll.
  • Sky changing colours to simulate day and night.
  • Stars appearing as the night sets in.
  • Text changes that animate based on the time of day.

1. Setting Up the HTML and CSS
First, let’s set up a basic HTML structure. We’ll include SVG elements for the sun, moon, and a path they’ll follow. We’ll also add a sky background and some stars.

<section class="container">
  <!-- Background sky div that changes color to simulate day and night -->
  <div class="sky"></div>

  <!-- SVG containing the sun, moon, and the path they will follow -->
  <svg class="circle-svg" viewBox="0 0 550 300">
    <!-- A path that defines the trajectory for the sun and moon animations -->
    <path class="circle-path" d="M 550 300 a 10 10 0 0 0 -550 0" fill="transparent"/>
    <!-- The sun element, initially positioned at (40, 40) -->
    <circle fill="#FDCA48" class="sun" cx="40" cy="40" r="40"></circle>
    <!-- The moon element, also initially positioned at (40, 40) -->
    <circle fill="#FFEFC4" class="moon" r="40" cx="40" cy="40"></circle>
  </svg>

  <!-- Container for stars that appear during the night -->
  <div class="stars">
    <!-- Individual star elements that are hidden initially -->
    <div class="star"></div>
    <div class="star"></div>
    <div class="star"></div>
    <div class="star"></div>
    <div class="star"></div>
  </div>

  <!-- "HELLO WORLD!" text displayed during the day -->
  <h1 class="hello-world"><span>HELLO WORLD!</span></h1>

  <!-- "BYE WORLD!" text displayed during the night -->
  <h1 class="bye-world"><span>BYE WORLD!</span></h1>

  <!-- Grass element that stays at the bottom of the screen -->
  <div class="grass"></div>
</section>
Enter fullscreen mode Exit fullscreen mode

Next, some basic CSS to style our elements. We position the sky, stars, sun, and moon and set up classes for our text.

html, body, * {
  margin: 0;
  padding: 0;
}

.container {
  height: 100vh;

  .sky {
    background-color: #B7F2FF;
    height: 100vh;
    width: 100%;
    position: fixed;
    top: 0;
  }

  .sun, .moon {
    opacity: 0;
  }

  .stars {
    position: fixed;
    top: 0;
    height: 80vh;
    width: 100%;

    .star {
      background-color: #FFEFC4;
      border-radius: 100px;
      display: none;
      height: 15px;
      width: 15px;
      position: absolute;
      z-index: 10;
      animation: pulsate 2s linear infinite;

      &:nth-child(1) {
        top: 20%;
        left: 5%;
        transform: translate(-5%, -20%);
      }

      &:nth-child(2) {
        display: none;
        top: 67%;
        left: 20%;
        transform: translate(-20%, -67%);
      }

      &:nth-child(3) {
        display: none;
        top: 35%;
        left: 37%;
        transform: translate(-37%, -35%);
      }

      &:nth-child(4) {
        display: none;
        top: 75%;
        left: 70%;
        transform: translate(-70%, -75%);
      }

      &:nth-child(5) {
        display: none;
        top: 30%;
        left: 90%;
        transform: translate(-30%, -90%);
      }
    }
  }

  h1 {
    display: inline-block;
    font-family: "Inter", sans-serif;
    font-size: 0;
    font-weight: 400;
    position: fixed;
    top: 68%;
    left: 50%;
    transform: translate(-50%, -68%);
    opacity: 0;
    white-space: nowrap;

    span {
      font-size: 50px;
    }

    &.hello-world {
      color: #000;
    }

    &.bye-world {
      color: #fff;
    }
  }

  .grass {
    background-color: #065C19;
    height: 20vh;
    width: 100%;
    position: fixed;
    bottom: 0;
  }
}

.fade-in {
  animation: fadeIn 0.25s forwards;
}

.fade-out {
  animation: fadeOut 0.25s forwards;
}

@keyframes fadeIn {
  0% {
    opacity: 0;
  } 100% {
    opacity: 1;
  }
}

@keyframes fadeOut {
  0% {
    opacity: 1;
  } 100% {
    opacity: 0;
  }
}

@keyframes pulsate {
  0% {
    opacity: 100%;
  }
  50% {
    opacity: 25%;
    scale: 0.9;
  }
  100% {
    opacity: 100%
  }
}
Enter fullscreen mode Exit fullscreen mode

2. Bringing the Animation to Life with GSAP

Now that we have the structure in place, let’s animate it! We’ll use GSAP’s ScrollTrigger and MotionPathPlugin to animate the sun and moon based on scroll position.

gsap.registerPlugin(ScrollTrigger, MotionPathPlugin, DrawSVGPlugin);
Enter fullscreen mode Exit fullscreen mode

We need to register the plugins we’re using: ScrollTrigger for scroll-based animations, MotionPathPlugin for moving elements along paths, and DrawSVGPlugin to animate SVG paths.

3. Setting Up the Scroll Trigger and Timeline

The core of the animation happens in our timeline (tl2). We set up ScrollTrigger to pin the SVG element and control the animation based on scroll position.

var tl2 = gsap.timeline({
  scrollTrigger: {
    trigger: ".circle-svg",
    scrub: 1, // Smooth scrolling effect
    pin: true, // Pin the element during scroll
    start: "center center", // Start when the SVG reaches the center of the viewport
    end: "+=3000", // Animation length
  }
});

Enter fullscreen mode Exit fullscreen mode
  • trigger: The SVG that controls when the animation starts.
  • scrub: Links animation progress to the scroll position.
  • pin: Keeps the SVG in place as the user scrolls.
  • start and end: Define when the animation starts and how long it lasts.

4. Animating the Sun and Moon

Next, we move the sun along the path using the motionPath property. This makes the sun follow the curve we set in the SVG path.

tl2.from(".circle-path", {drawSVG: 0}) // Draw the path as we scroll
    .to(".sun", {
        motionPath: {
            path: ".circle-path", // The path to follow
            align: ".circle-path", // Align the element along the path
            alignOrigin: [0.5, 0.25], // Adjust alignment
            start: 0,
            end: 0.2, // Moves the sun a small distance initially
        },
        duration: 0.2
    })

Enter fullscreen mode Exit fullscreen mode

Here’s what’s happening:

  • The path is drawn with drawSVG as the user scrolls.
  • The sun moves a small distance along the path to simulate sunrise.

We then continue the animation by moving the sun further along the path, changing the sky’s color, and gradually revealing stars.

.to(".sky", { backgroundColor: "#7A3BFF" }) // Change sky color to night
.to(".star:nth-child(3)", { display: "block" }, 2) // Show stars one by one
Enter fullscreen mode Exit fullscreen mode

5. Handling the Moon and Text Animations

Once the sun sets, the moon rises following the same path, and the text changes based on scroll direction.

.to(".moon", {
  motionPath: {
    path: ".circle-path",
    align: ".circle-path",
    alignOrigin: [0.5, 0.25],
    start: 0,
    end: 0.2
  },
  duration: 0.2
})
.add(() => {
  if (tl2.scrollTrigger.direction === -1) {
    byeAnimation.reverse();
  } else {
    byeAnimation.play();
  }
}, "<");

Enter fullscreen mode Exit fullscreen mode

The moon animation is set up similarly to the sun. The timeline checks the scroll direction to determine which text message to display, playing or reversing the animation based on the scroll.

Final Touches

We tie everything together by animating additional stars, adding a grass element that rises, and fine-tuning timing and effects. It’s all about playing around with GSAP’s powerful timeline and animation controls

Wrapping Up

This project was a fun way to get familiar with GSAP’s capabilities. If you’re trying it out, start small and experiment with different properties and plugins. It’s amazing how much you can create with just a few lines of code!

Feel free to ask questions if you want to learn more about GSAP or how I set up the animations. For more industry insights and the latest updates from our agency, be sure to visit Toru Digital's Insights.

See demo here

Top comments (0)