Jump to content
Search Community

Scroll animation "collision" using scrolltrigger with scrub and pinning

kristoffer test
Moderator Tag

Recommended Posts



I have a video animation that I'm trying to control with ScrollTrigger. In the past I have scrolled videos through timelines, but it can become very complex, now, with scrolltrigger, it has the potential to become a lot simpler. The problem I have is when individual ScrollTriggers acting on the same element "collide" when using scrub and pinning together, and I'm not sure how to solve that. Without scrub and/or pinning the video scroll works very well.  The video scroller codepen is NOT optimized for phones or pads.

See the Pen dyGJMQa by krispen (@krispen) on CodePen

Another codepen illustrating the same problem with just scaling a ball:


The video pauses when the slides are pinned, and restarts when the pinning releases. Problem occurs when scrolling fast and the new a scrolltrigger is restarting the video before the previous scrub has finished.


Is there a way to work around this issue? I have two ideas, but struggling with how to implement them (if it's even possible): 

1) Instead of multiple scrolltriggers, use one scrolltrigger that has multiple trigger points ?

2) Somehow obtain "virtual" scroll values of the slides as they appear on the screen, i.e. scroll values pauses during the pinning and restart when pinning is released, and use that as an input to a single video-scrolltrigger ?





See the Pen PoZExRG by krispen (@krispen) on CodePen

Link to comment
Share on other sites

Yep, the problem is that you've got competing scrubs (as you know). Also, you're breaking each "section" into individual tweens so if you scroll really fast from section 2 to 3 but due to the delayed scrubbing, the one from section 2 is barely into its progress, but you're also asking #3 to start scrubbing its (separate) tween simultaneously which goes from completely different progress values. 


I'd suggest just using ONE overall linear tween, and then animate the progress of that tween in an onUpdate of the ScrollTriggers like this: 

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


let sections = gsap.utils.toArray(".step"),
    // do the entire ball tween (across all), linearly
    ballTween = gsap.fromTo(".ball", {scale: 0}, {scale: sections.length * 2, ease: "none", paused: true}),
    // we'll tween the playhead of ballTween with this separate tween. This creates the delayed scrub (2 seconds to catch up, or whatever duration you define)
    tween = gsap.to(ballTween, {duration: 2, ease: "power3", paused: true}),
    // progress incremenet
    inc = 1 / sections.length;

sections.forEach((step, i) => {
        trigger: step,
        start: "bottom bottom", 
        end: "+=1000", 
        pin: true,
        onUpdate: self => {
          tween.vars.progress = (i * inc) + self.progress * inc;

I'm reusing the same "tween" instance over and over and simply altering its vars.progress and then invalidating it solely to improve performance. A simpler (but less performant) option would be to gsap.to(ballTween, { progress: (i * inc) + self.progress * inc, duration: 2, ease: "power3", overwrite: true}) in the onUpdate but that creates a new tween instance each time (somewhat wasteful memory-wise). 


Now you get a perfectly smooth delayed scrub across everything. ?


Is that the effect you're after? 

  • Like 3
Link to comment
Share on other sites



Thanks for replying! Yes that is exactly the problem, and it's almost the solution I'm looking for. Only issue is that it should be opposite: Ball scaling should be dormant while section is pinned, and animating when sections are scrolling. Like an 'onUpdate' (or similar) when pinning is not active.




Link to comment
Share on other sites

Yes, that is exactly it! Awesome! Now I just need to figure out what you did... So instead of using a 2s scrub in the scrolltrigger, you're creating that delay by tweening the balltween with 2 sec. The progress of that tween is then updated using a separate scrolltrigger that is triggered each time the pinning scrolltrigger, st, ends. I'm not sure how the 'end: +=100%' makes that scrolltrigger end where the pinning starts. What is it 100% of?

Link to comment
Share on other sites

1 hour ago, kristoffer said:

Ok, so not related to the start value, but rather the trigger element.


Yes, the "+=" means that it's directly in relation to the starting value. In other words "take the starting value and add 100% of the height of the trigger."

  • Like 2
Link to comment
Share on other sites

2 hours ago, GreenSock said:

Yes, the "+=" means that it's directly in relation to the starting value. In other words "take the starting value and add 100% of the height of the trigger."

Ok, got it! Thanks a lot for the help!

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