Jump to content


playTo() method

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

I need a method wich description would be :



playTo() method 


public function playTo(position)


Adjust the direction (forward or reverse) and plays until the position is reached. It does nothing if the timeline is already playing in the right direction.



  position:* The time (or label for TimelineLite/TimelineMax instances) on which the animation should stop.




Is there any way to do it wit current version ? tweenTo method would be ok, but it does not work well if it is called repetitively. From a mousemove event for exemple. Also it does not set isActive() to true nor it update the reversed() value, wich I need.


Link to comment
Share on other sites

What do you mean by tweenTo does not work well? Is it not tweening to the correct time? If you could please provide a demo of this occurring we should be able to figure out a solution for you.


You won't get isActive() true using tweenTo (since the timeline is paused while it is tweening the time), but you can determine the reversed state yourself:

var currenttime = timeline.time();
var endtime = 5;

// set reversed
timeline.reversed(endtime < currenttime);

// tween to time, with correct reversed state

If you can't use tweenTo, perhaps you could just set the timeline playing/reversing, and then call a function that will pause it when the time you want is reached

var endtime = 5; // your dynamic end value
var timeline = new TimelineMax({
  onUpdate:function() {
    var t = this.time();
    if ((this.reversed() && t <= endtime) || t >= endtime) {

// your function to update the end time
function updateEndTime() {
  endtime = 10; // some new value
  var t = timeline.time();
  // set reversed and resume play if paused
  if (endtime !== t) timeline.reversed(endtime < t).resume();
  • Like 2
Link to comment
Share on other sites

Thank you jamie for your answer.


Here is a codepen that shows the problem of tweenTo when it is called repetitively.

See the Pen mFzBt by anon (@anon) on CodePen


I think it would be an improvement for GSAP.

Link to comment
Share on other sites

Thanks for the CodePen demo. Very helpful.

We may have to look into this further.


It seems the variance in the playback rate of the tweenTo() might be related to overwriting.


For now, please try setting overwrite:true in your tweenTo() tween as shown here:



Does that work better on your end?

Link to comment
Share on other sites

Thanks Carl, it works this way.

Maybe this should be handled in the tweenTo method.



But I still have several quesions :

- does it respect the original timeline speed ?

- does it fire events of nested timelines ?

- performance wise, creating a new tween each time is not the best. Isn't it better to use a TweenMax instead of TweenLitle, and dynamicaly change destinationTime ? 

Link to comment
Share on other sites

If performance is a concern, you should consider throttling how often you create tweens on mousemove. Here is an example that will limit new tweens being created every 200ms (credit: JamieJefferson)




Yes, original timeline speed is respected.


In the example above I added an onComplete callback to the timeline and you can see it fire.

  • Like 2
Link to comment
Share on other sites

The easiest fix:

Use the latest version of GSAP.


Another easy fix:

Either set overwrite:true on the tweenTo() or killTweensOf(yourTimeline) right before you create a new tweenTo() or set immediateRender:true in the tweenTo(). This is definitely related to overwriting, and it's not a bug.


The complicated explanation (you can skip this if you want):

First, let me clarify a few facts that are important here:

  1. A tween initializes its values (parses the destination values, records starting values, etc.) the first time it renders. This is a performance optimization and it also also permits complex sequencing (imagine setting up an "x" tween to start running in 2 seconds, but before that occurs another tween animates "x" to a completely different value - if the original tween recorded its starting values immediately when it was created, it would suddenly jump back to those when it starts running). 
  2. Even if a tween has no delay, it doesn't render immediately by default. Again, this is a performance optimization. Rendering immediately would be very wasteful because there'd be no change to the starting values yet, and there's a chance that the tween will get overwritten or killed before it even starts.
  3. In general, tweens render in the order they were created, except inside timelines in which case they'll render in the order they occur time-wise. If two start at the same spot, they render in the order they were added to the timeline. Caveat: when timelines run backwards, of course the rendering order gets reversed too.
  4. In GSAP, tweens are perfectly synchronized and they honor the timing you set, so if you create a tween now, and it has a delay of 0.05 but the next render doesn't actually happen until 0.2 from now, it will render as if that tween is 0.15 into its progress. This is a very important feature that many other engines don't have, causing them to have small timing and synchronizing issues. 

So let's walk through exactly what happens in your tweenTo() example: 


Every time you call tweenTo(), it creates a tween of the timeline's "time". In your example, every time the mouse moved, you were creating a new tween which is actually fine. GSAP is built for outstanding performance. The odd behavior had nothing to do with creating too many tweens or stressing the system somehow. 


So it creates the first tween (we'll call it tween1) which, as described above, renders on the very next "tick" of the engine. To make things a little easier to visualize, let's say it's going to take timeline.time from 0 to 100 over the course of 100 ticks (as if it's frame-based), so 1 increment per tick.


On the very next tick, it renders tween1, looks at the current value of timeline.time (0) and records that as the starting value, set the destination to 100, and interpolates accordingly (in this case, setting timeline.time to 1). Great. At the same time (assuming the mouse is moving), you ALSO create another tween (by calling tweenTo()), which we'll call tween2. 


Now this is where the issue comes in...


On the very next tick, it renders tween1 which sets timeline.time to 2 (correctly) and then it initializes tween2, triggering it to record its starting values based on what timeline.time currently is, but notice it is 2 now. In terms of timing, tween2 knows that 1 tick has elapsed since its start time, thus it should render accordingly. tween2 looks at the current timeline.time value (2) and says "okay, I'm going from 2 to 100 over 99 frames and I'm one frame into my animation, so I should render at 2.98. The math is correct but the problem is that between the time that tween2 was scheduled to start and when it recorded its starting values, tween1 affected the value! In other words, the previous tween is throwing things off.


By killing the previous tween, you don't give it that chance to sneak in one "extra" render before the next tween initializes and kills it. 


For the record, the overwriting is working exactly as it's supposed to, and in this case the default "auto" mode would kick in the first time the tween renders and it finds the previous tween and kills it, but not until after that previous tween fired off a render which affected the starting values. 


There's really no automatic way around this that I can think of that wouldn't have a pretty significant negative performance impact. 


I updated GSAP so that tweenTo() tweens use overwrite:true by default unless you set a delay. That should resolve things for you, but I still wanted to explain the mechanics in case you or someone else is interested. 


Again, it's not really a bug at all - it's just a somewhat complicated timing dynamic related to overwriting logic. 

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