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.
<template>
<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>
<svg
ref="mask"
class="mask absolute w-full h-full"
>
<mask id="mask">
<rect width="100%" height="100%" fill="white"></rect>
<text
font-family="Bagnard, serif"
font-weight="500"
x="50%"
y="49%"
class="origin-center "
text-anchor="middle"
transform="scale(15)"
>
<tspan x="50%">Freelance</tspan>
<tspan x="50%" dy="1em">Founders</tspan>
<tspan style="font-size: .5rem" x="50%" dy="2em">
↓
</tspan>
</text>
</mask>
<rect id="bg" width="100%" height="100%" fill="#fff"></rect>
</svg>
</div>
</template>
<script>
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: () => {},
scrollTrigger:{
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;
}
}
}
</script>
Staging link example: https://freelance-founders-hgc9zjyrf-progresslabs.vercel.app/
FYI - Working on a minimal example to post here shortly.