Jump to content
Search Community

GSAP animation (maybe) crashing homepage

Marnau test
Moderator Tag

Recommended Posts

I'm creating a website in Next.js and in the homepage I have a scrollTriggered and scrubbed timeline.

The animation consists of two parts:
1) An image sequence, which I've done with the help of the codepen at the end 

2) Simple tweens fading and zooming images

 

This is a snippet of what the animation does: 

 

The animation works. I've deployed it to Netlify and it seems ok.

The thing is, though, that every once in a while, the homepage crashes. And what it shows is a weird DOM:

 

image.thumb.png.9aeec3b177dc56cb0ee03ebd1caa9aa3.png

When I disable the animation I never get this weird DOM. Now, I'm not sure if the deployment is to blame or my gsap code is.

So I'd like to ask you if you could take a look at my code and see if I'm doing something obviously wrong. Thank you so much!

 

"use client";
 
import { useRef, useLayoutEffect, useContext } from "react";
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
gsap.registerPlugin(ScrollTrigger);
import NextImage from "next/image";
import { useRouter } from "next/navigation";
import { MenuContext } from "@/Providers/MenuProvider";
 
import styles from "./AnimatedSequence.module.css";
 
const AnimatedSequence = ({ projectImages }) => {
const router = useRouter();
const canvasRef = useRef(null);
const animation = useRef(null);
const { setHeaderAndMenuHidden } = useContext(MenuContext);
 
useLayoutEffect(() => {
setHeaderAndMenuHidden(true);

 

// Here's the canvas that will hold the image sequence

const canvas = canvasRef.current;
const context = canvas.getContext("2d");
canvas.width = 3024;
canvas.height = 1983;
const frameCount = 18;
const currentFrame = (index) => `imageSequence/frame_${index.toString().padStart(2, "0")}.jpg`;
const images = [];
const crack = {
frame: 0,
};
for (let i = 0; i < frameCount; i++) {
const img = new Image();
img.src = currentFrame(i);
images.push(img);
}
function render() {
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(images[crack.frame], 0, 0);
}
images[0].onload = render;
 
let ctx = gsap.context(() => {
 
let tl = gsap.timeline({
scrollTrigger: {
trigger: ".wrapper",
scrub: true,
pin: true,
// markers: true,
start: "top top",
end: "+=200%",
onEnter: () => {
gsap.fromTo(".bg", { autoAlpha: 1 }, { autoAlpha: 0, duration: 1, delay: 0.2 });
},
onLeave: () => {
router.push("/projects");
},
},
});

 

//Here's the tween that animates the sequence

tl.to(
crack,
{
frame: frameCount - 1,
snap: "frame",
ease: "none",
duration: 9,
onUpdate: render,
onComplete: () => setHeaderAndMenuHidden(false),
},
"crack"
);

 

//This tween fades the canvas to reveal what's underneath

tl.to(canvas, { opacity: 0, duration: 1, onReverseComplete: () => setHeaderAndMenuHidden(true) }, ">");

 

// Here's the tweens fading the images

projectImages.forEach((image, i) => {
tl.fromTo(
`.image-${i}`,
{ autoAlpha: 0, scale: 0.3 },
{
autoAlpha: 1,
scale: 1.25,
duration: 9,
},
">"
);
tl.to(`.image-${i}`, { autoAlpha: 0, duration: 1 }, ">");
});
 
tl.to(".scrollDown", { autoAlpha: 0, duration: 1 }, "crack+=1");
}, animation);
return () => ctx.revert(); // cleanup
}, [canvasRef]);
 
return (
<div ref={animation}>
<div className={`wrapper ${styles.wrapper}`}>
<div>
<NextImage
className={`scrollDown ${styles.scrollDown}`}
src="/scrollDown.svg"
width={108}
height={99}
alt=""
/>
<canvas ref={canvasRef} className={`canvas ${styles.canvas}`} />
</div>
<div className={`bg ${styles.bg}`}></div>
{projectImages.map((image, i) => (
<NextImage
key={image.file.url}
className={`${styles.image} image-${i}`}
src={image.file.url}
width={image.file.width}
height={image.file.height}
alt=""
/>
))}
</div>
</div>
);
};
 
export default AnimatedSequence;

See the Pen 2152a28cffe2c2c0cca8a3e47f7b21c6 by osublake (@osublake) on CodePen

Link to comment
Share on other sites

It's pretty tough to troubleshoot without a minimal demo - the issue could be caused by CSS, markup, a third party library, your browser, an external script that's totally unrelated to GSAP, etc. Would you please provide a very simple CodePen or Stackblitz that demonstrates the issue? 

 

Please don't include your whole project. Just some colored <div> elements and the GSAP code is best. See if you can recreate the issue with as few dependancies as possible. If not, incrementally add code bit by bit until it breaks. Usually people solve their own issues during this process! If not, then at least we have a reduced test case which greatly increases your chances of getting a relevant answer.

 

Here's a starter CodePen that loads all the plugins. Just click "fork" at the bottom right and make your minimal demo

See the Pen aYYOdN by GreenSock (@GreenSock) on CodePen

 

Using a framework/library like React, Vue, Next, etc.? 

CodePen isn't always ideal for these tools, so here are some Stackblitz starter templates that you can fork and import the gsap-trial NPM package for using any of the bonus plugins: 

 

Please share the StackBlitz link directly to the file in question (where you've put the GSAP code) so we don't need to hunt through all the files. 

 

Once we see an isolated demo, we'll do our best to jump in and help with your GSAP-specific questions. 

Link to comment
Share on other sites

Thanks a lot @GSAP Helper,

 

I think I might have been making a mistake of putting canvasRef as a dependency of my useLayoutEffect, and that might have been breaking things.

Here's my stackblitz: https://stackblitz.com/edit/nextjs-jadegt?file=components%2FAnimatedSequence%2FAnimatedSequence.js

 

I still have a doubt of how to handle one thing. My timeline should do this:

1) Animate image sequence

2) Reveal navigation

3) Animate red images

 

The problem I have is with 2). I need to tween a DOM element which is not inside the context of my timeline.

So how should I do this?

 

I hope you can understand what I mean. Otherwise I can clarify.

Link to comment
Share on other sites

Hi,

 

Yeah, refs being updated don't trigger re-renders so your effect hook won't run again. That being said if the ref is in the same component and is not conditionally rendered, you shouldn't need to check if the element is rendered or not. If the element is rendered conditionally, then you can use the same state property that causes the element to be rendered as a dependency of the effect hook.

 

As for the animation reveal, indeed is a complex scenario because we're talking about something that is in a different component (your layout component). The first thing you could try is check in the effect hook if the nav has been rendered yet, if it isn't then you'll have to use a React Context instance in order to communicate between components and know when the nav has been rendered in order to create the GSAP instances needed to animate it. Unfortunately that is more a React related problem and not a GSAP one and we need to keep these forums focused on GSAP related questions.

 

There are many resources out there for using React Context in order to communicate between components and different parts of your React/Next apps. Also you could ask in Reactiflux discord channel as well:

https://discord.gg/reactiflux

 

Hopefully this helps.

Happy Tweening!

Link to comment
Share on other sites

@Rodrigo, thanks a lot for your help,

 

I fixed it in the end. The initial problem I had (the one that crashed the site) had to do with Next.js's ISR.

And I managed to reveal the nav by using React context. I just had to be very careful because the component re-rendered midway unless I isolated the ref that was responsible for the tween. A bit tedious, but it worked out!

 

This is the website: edubarcelo.com

 

  • Like 1
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.
×
×
  • Create New...