Jump to content


onReverseStart - still don't understand why not?

Moderator Tag

Warning: Please note

This thread was started before GSAP 3 was released. Some information, especially the syntax, may be out of date for GSAP 3. Please see the GSAP 3 migration guide and release notes for more information about how to update the code to GSAP 3's syntax. 

Recommended Posts

Hi Guys,


Let's get the niceties out of the way... GSAP is amazing, currently migrating to it from velocity.


I've been looking through the forums regarding the topic of onReverseStart and there's a number of posts saying it's unnecessary because you'll be calling reverse() from some method anyway so why not just do what you need there.  But I don't understand how that's any different from onStart?  It seems a fairly simple use case.


In my case I'm animating the transition between an introductory page and some content.  This transition is reversible, ie: you can go from the intro to the content and back again.  As I switch from one to the other I need to make a couple of tweaks to classes etc, and enable/disable a couple of elements.


If there was an onReverseStart callback, I could keep everything clean and simple (weird psudeo code follows):

  • onStart & on ReverseStart shared method - check which way we're going and make updates.
  • onComplete & onReverseComplete shared method - check which way we went and make updates.
  • toggle method - if (inIntro) timeline.play() else timeline.reverse()

As there isn't an onReverseStart, the best I can get is:

  • onStart - must be going from intro to content - make changes.
  • onComplete & onReverseComplete shared method - check which way we went and make updates.
  • toggle method - check which way we're going, if it is from content to intro (ie: reverse) make the changes and call reverse(), else call play().

That seems a little messy to me.


Also just wanted to clarify something?  If I reverse a timeline, that means any easing is reversed as well?




Link to comment
Share on other sites

Hi and welcome to the GreenSock forums. 


I'm not entirely clear on what you are asking.

I believe most of the other conversations about firing a callback when an animation is reversed are suggesting that something fire whenever playback is reversed though  tl.reverse() or tl.reversed(true) happens. 


Are you saying that this callback should only fire when the timeline is at its complete state (fully played with a progress(1)) AND then a reverse() is invoked.

In other words, if the user calls reverse() while the animation is playing forward, a callback should not fire.


Just want to be sure, as from your description, it seems like you want this onReverseStart to sit at the end of the timeline just as onStart sits at the beginning.


As you probably read in the other threads, we are really carefully about  bloating the API for use cases that aren't all that common and that can be accommodated by the end user. It is far more likely that folks need to run some initialization code or call functions onStart than when the animation reverses from the end. 

To be clear, I'm not saying this feature wouldn't help you, its just that we have to weigh a lot of factors when changing the API.


I think seeing a very basic example (with real code) of what you are doing will help us better address the situation.

Here are some tips on making a demo: http://greensock.com/forums/topic/9002-read-this-first-how-to-create-a-codepen-demo/


As for your other question, eases do not reverse or get flipped.

An animation with a Bounce.easeOut does not become a Boune.easeIn when you reverse it

When you reverse an animation we respect all the timing that was in place while it played forwards. 


Here is a little demo: http://codepen.io/GreenSock/pen/MYwNmw


It would be quite difficult to reverse an animation and change the ease half-way through without the target doing a really awkward jump. 

Keep in mind an ease dictates what the tweened values are at any point in time. 

If your tween is at a progress of 0.5 the values will be very different if you are using a an in-ease or an out-ease

  • Like 3
Link to comment
Share on other sites

Sorry if I didn't make it clear.
Yes I'm suggesting an onReverseStart to mirror onStart, ie: when the playhead is at 1 and you call reverse()  If we take the docs on onStart into account it would be described as:


onReverseStart : Function - A function that should be called when the tween reverses from the end state (when its playhead changes from 1 to some other value which can happen more than once if the tween is reversed multiple times).



It just seems like the API is incomplete, if you take these scenarios into account:


  • Playhead at 0 - call play - onStart
  • Playhead reaches 1 - onComplete
  • Playhead at 1 - call reverse - no callback
  • playhead reaches 0 - onReverseComplete

I will put together a demo, it's a fair point, although I'll have to do it a little later this evening - today's not a good day for spare time  :?


Please feel free to leave any replies on that point until I've posted that demo!


Thanks for the answer with the easing, but again I didn't make it clear it seems.  Your demo show's exactly what I was describing; if the tween ends with a bounce, the easing is reversed (in that it performs the same easing in exactly the opposite direction) and the animation starts with a bounce when it is reversed.  ie: Bounce.easeOut does effectively become Bounce.easeIn.  The question comes from the fact that I am migrating from velocity.  With velocity, the easing applies to the "tween" the same way regardless of play direction.  If you bounce out when playing forwards, you bounce out when playing backwards.  This does seem to be a useful option to have in your API.  Reversing is perfect for moving elements in or out of some key area (usually the viewport) but I would my elements to glide to a stop in both directions for example.


Here is your demo (poorly) migrated to velocity (okay I did manage to squeeze this one into the time I have).

See the Pen gbaOaL by apawsey (@apawsey) on CodePen


Thanks for the feedback!




Link to comment
Share on other sites

Hi apawsey  :)


Carl explained completely but in addition : 


the codepen demo with velocity act like playing 2 different animation , not the same in reverse .

GSAP really gone in right direction with easing and this is one of great difference between GSAP and other anim libraries like velocity .

pls imagine a character jumping animations , after jumping a character when you replay in reverse really what happening to your character animation !!! yep ; every thing'll reverse on what really happened ...

if he change his direction and jump to other side (first position) , then we have another animation , not the same animation in reverse !

See the Pen ogjNOY by MAW (@MAW) on CodePen


and about onReverseStart :

when your timeline is Paused:false ( default )  your timeline'll play auto / or when you use nested timelines you need onStart to run you functions on anim start .

but if you have Paused:true , your timeline need trigger/call to firing ( tl.play() ) , and you can put your other functions in that trigger and actually you dont need onStart .

, and now When your Timeline / Tween will play in reverse direction !? 

yep , when you have tl.reverse() , so you dont need onReverseStart .


See the Pen XJbLaw by MAW (@MAW) on CodePen

  • Like 1
Link to comment
Share on other sites

Yeah, notice how in your Velocity demo you could only "reverse" the animation when it was done playing (when left = 300)?

Like Diaco explained and illustrated, Velocity's idea of "reverse" is very different than what we consider reverse to mean. 


Here is another demo in which 3 animations with 3-second durations start playing.




FIXED DEMO: http://codepen.io/GreenSock/pen/dPYPwe


After 1 second each animation is reversed.


At the time of reverse being called:

  • the top animation uses velocity("stop").velocity("reverse"), this animation takes another 3 seconds to reverse. 
  • the middle animation continues to play forward and then reverses
  • the third animation reverses properly over the course of 1 second.


GSAP's logic is that if you play an animation forward for 1 second and then reverse, it should reverse for 1 second.

We also feel that you should be able to smoothly reverse any animation at any point in time (and not have to stop it first or wait for it to finish).


As for more reasons why we don't include an onReverseStart callback, I'll let you know if the team has other reasons. 

However if you want a single tween to play differently if you try to reverse it after it is done playing, you might want to just create a new tween for that.


If you have a sequence of animations in a TimelineMax, you can get some pretty cool effects using tweenTo() with different eases:



Notice how you can do a Bounce.easeOut when playing forward and backward.

  • Like 1
Link to comment
Share on other sites

ugh, just realized that i overwrote the first demo with the second... sheesh. 

hold on...

Link to comment
Share on other sites

First off, I totally understand why it'd seem like onReverseStart is a missing piece in the API, like an illogical gap. 


It sounds like a really clean way of handling this would be to use a TimelineLite or TimelineMax because you can add a call() anywhere that'll get fired when the virtual playhead passes that point in either direction. The only caveat I'd mention is that if you place it at the VERY beginning or VERY end of the timeline it will correctly fire when the playhead arrives there, but then when you reverse in the opposite direction and it LEAVES that position, it doesn't fire (nor should it - that's the correct behavior). So in that case you can simply offset it from the very start or very end by even 0.00000001 seconds and it'll fire either way (let me know if that doesn't make sense and I'll explain it in more detail). Example:

var tl = new TimelineLite();
tl.call(yourFunction, null, null, 0.00001) //notice the position parameter of 0.000001 just to offset it from the very start so that it fires in both directions and doesn't sit on the very beginning of the timeline.
  .to(obj, 1, {x:100})
  .call(yourOtherFunction) //we don't need to offset this one because it's not at the very start or very end of the entire timeline
  .to(obj, 1, {x:200})

To add a little more clarity about why I've resisted adding onReverseStart, doing so would require adding some conditional logic inside the main render loop which is the "hottest" area of the entire engine by far - that's where it's most important to optimize because it gets called so frequently. Since the behavior you're looking for could be achieved without injecting more conditional logic into that render method, I'm inclined to keep performance maximized for everyone. See what I mean? And then there's the file size argument, API bloat, etc.


Another factor has to do with the fact that "onReverseStart" isn't the most accurate/descriptive name especially for people who are doing reversing because of the way you can reverse a child inside a reversed parent (and so on), which would actually LOOK like it's running forward, so if we were going to add a useful callback it seems to me like it might be best to do something like "onChangeDirection" but that's also somewhat costly kb-wise and I'm not convinced it's useful enough. I think the behavior you're talking about is perfectly addressed using a callback inside of a TimelineLite/Max, so hopefully that allows you to use the existing API and we can avoid having to sacrifice performance or kb by adding stuff to the core. 

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