Jump to content
Search Community

Playing a separate animation at the end of a ScrollTrigger.

dmo12 test
Moderator Tag

Go to solution Solved by GreenSock,

Recommended Posts

I'm trying to animate an image sequence using a canvas & ScrollTrigger in my CodePen. Out of the 600 frames, I have the first 200 mapped to the scroll position for 500vh. The last 400 frames can be seamlessly looped, which I've done in the loop animation.

 

What I'm ultimately trying to do, is seamlessly start playing the loop animation once the user scrolls to the bottom of the page/track element, but if the user scrolls back up enough (~10% offset), tween to the correct frame for scroll position, and re-enable the scroll based playback.

 

Currently I added some bottom margin to the track, and used onLeave and onEnterBack to start/stop the looping animation, but this requires the track element to scroll off the page first to start the animation.

 

I'm sure there's a more ideal way to do this, would appreciate some help here.

See the Pen OJEXaGg by dannymout (@dannymout) on CodePen

Link to comment
Share on other sites

Hi @dmo12 and welcome to the GreenSock forums!

 

Sorry for the delay in the response, this slipped through the cracks.

 

The main issue I see here is the fact that after the first run there is a delay when starting the loop again. The first run goes OK but after that there is always a delay. If you switch scrub: 0.5 to scrub: true, that goes away but you loose the smooth scrub effect. Of course the longer the scrub time the longer the delay on the loop instance to start, this probably because there is a clear conflict since the ScrollTrigger animation and the loop animation are targeting the same object and the same properties. On top of that shortly after creating the ScrollTrigger instance the loop instance is created as well.

 

The best alternative I can offer you is to create the loop animation on the very onLeave callback:

onLeave: function () {
  loop = gsap.to(position, {
    frame: 598,
    duration: 13,
    repeat: -1,
    snap: "frame",
    ease: "none",
    onUpdate: render
  });
},
onEnterBack: function () {
  loop.pause().kill();
}

As you can see it seems to work as you expect:

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

 

Hopefully this helps. Let us know if you have more questions.

 

Happy Tweening!

Link to comment
Share on other sites

@GreenSock Appreciate your quick response, you got it spot on! Just needed to remove the bottom margin, so the loop starts once you hit the bottom of the page, which was the intended behaviour.

 

First time I'm seeing quickTo, I have a vague understanding from reading the doc. What's the benefit you get from using that over to in this case?

 

Link to comment
Share on other sites

49 minutes ago, dmo12 said:

First time I'm seeing quickTo, I have a vague understanding from reading the doc. What's the benefit you get from using that over to in this case?

 

It's mainly about performance (and somewhat simplicity). It reuses the same instance, pipes the value directly into where it's needed in the guts, so it's easier on memory and CPU in most cases. But honestly, you'd probably never notice a real-world difference in most cases. I just obsess about performance, sometimes to an unhealthy degree. 🙃

  • Like 1
Link to comment
Share on other sites

Understood.

 

One more question, is there a way to have the loop begin around when the end marker enters the viewport from the bottom? The frames don't really change from that point to the end marker exiting to the top, so it feels static until I hit the bottom.

Link to comment
Share on other sites

3 hours ago, dmo12 said:

One more question, is there a way to have the loop begin around when the end marker enters the viewport from the bottom? The frames don't really change from that point to the end marker exiting to the top, so it feels static until I hit the bottom.

You can change the end to whatever you want, sure. You actually didn't even define and end, so it uses the default "bottom top". You had an invalid start too - "top" isn't a thing. It needs to define an intersection point with two values like "top top" to say "when the top of the trigger hits the top of the viewport". 

 

But it sounds like you actually want to have the initial frame animation stop BEFORE the ScrollTrigger ends which is an entirely different thing. In that case, I'd put stuff into a timeline so you can then pad the end of the timeline with a dummy tween that has an onStart and onReverseComplete that does the same thing as your onLeave/onEnterBack. You can use the durations to control the ratio. For example, in my fork below, I have the main 200-frame scrub take 1 second, and then the "dummy" one at the end is 0.2 seconds. If you wanted them to be half-and-half (so the loop starts halfway through the entire scrub), you'd set the dummy duration to be 1 (match the initial tween). 

See the Pen BaVQrWy?editors=0010 by GreenSock (@GreenSock) on CodePen

 

I hope that helps!

  • Like 2
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...