Jump to content


Nuxt.JS and GSAP - Scroll Trigger Animations run immediately on load instead of their trigger points.

Moderator Tag

Recommended Posts

Banging my head a bit. I've got a few Scroll Trigger based animations on the home page of a site and it works flawlessly when in local development. It isn't until we've deployed to a production/staging environment does it break. 


Effectively what's happening is when we load the site on production/staging all animations run immediately. Not sure if its a component mounting issue (which would mean its not a GSAP issue) or if something is being compiled/computed differently in a live environment? 


Each section is setup as follows:

1. Define the animation/scroll trigger in the `mount` lifecycle hook

2. Use `$refs` to pass elements into the animation. 

    <div id="vid-container" class="h-screen w-screen bg-white">
      <video @loadeddata="loaded" class="w-full fixed inset-0 duration-500 transition-opacity opacity-0" :class="{'opacity-100': videoLoaded}" src="https://player.vimeo.com/external/611257045.hd.mp4?s=785a9d52ed5d188f762436b1bb618493f784d3f5&profile_id=174" autoplay loop muted preload></video>
        class="mask absolute w-full h-full"
        <mask id="mask">
          <rect width="100%" height="100%" fill="white"></rect>
            font-family="Bagnard, serif"
            class="origin-center "
            <tspan x="50%">Freelance</tspan>
            <tspan x="50%" dy="1em">Founders</tspan>
            <tspan style="font-size: .5rem" x="50%" dy="2em">

        <rect id="bg" width="100%" height="100%" fill="#fff"></rect>

  import { gsap } from "gsap";
  import { ScrollTrigger } from "gsap/ScrollTrigger";
  import { CSSRulePlugin } from "gsap/CSSRulePlugin";
  if (process.client) {
    gsap.registerPlugin(ScrollTrigger, CSSRulePlugin);
  export default {  
    data() {
      return {
      videoLoaded: false,  
    mounted() {
      console.log('hero mounted')
      let width = window.innerWidth
      let speed = 350 //pixels per second
      let endX = width
      let duration = endX / speed
      let ease = "sine.inOut"
      let intro = '';
      if (this.$refs.mask) {
        this.$nextTick(() => {
          intro = gsap.timeline({
            onComplete: () => {},
              trigger: this.$refs.mask,
              start: "bottom 100%",
              end: "bottom 50%",
              pin: true,
              scrub: true
          intro.to(this.$refs.mask, {
            scale: 5,
            opacity: 0,
            duration: 5,
            ease: ease
          }, 'intro')
    methods: {
      loaded() {
        this.videoLoaded = true;



Staging link example: https://freelance-founders-hgc9zjyrf-progresslabs.vercel.app/


FYI - Working on a minimal example to post here shortly. 



Link to comment
Share on other sites

Adding to this. Looks like my plugins aren't being registered even though that code is in there

Link to comment
Share on other sites

Yeah, it looks like you're not loading/registering ScrollTrigger. It's almost surely related to something in Nuxt or a timing issue with your code execution or something. I'm not familiar with Nuxt at all. Did you try verifying that the window/body/document all exist when you try registering/running ScrollTrigger? 

if (process.client) {
  console.log("register", window, document, document && document.body);
  gsap.registerPlugin(ScrollTrigger, CSSRulePlugin);

Do you see that console.log() at runtime with all 3 of those values defined? 

Link to comment
Share on other sites

Since Nuxt does SSR, ES Modules might not work unless you transpile them.



Or you can import the UMD files from the dist folder.

import { ScrollTrigger } from "gsap/dist/ScrollTrigger";
import { CSSRulePlugin } from "gsap/dist/CSSRulePlugin";


Link to comment
Share on other sites

Hmm still no luck here. 

I've tried:

1. Switching our loading to server side (thinking maybe that was the trick) but nope. 
2. Loaded in UMD modules but nope. 
3. Moving around when we register the plugin, either within the JS export or without the mounted call. 


At a loss here. 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.