AE Overshoot

AE overshooting expressions
#code/js

Calculation Overshoot

Now we'll add some overshoot. In this case, since the incoming animation is generated by a linear() function, we can easily calculate the velocity coming into the overshoot. It turns out that the velocity is just the end value minus the start value, divided by the duration, which in this case would be (endVal - startVal)/dur. So we need to modify the scale-up expression so that it ramps up until it reaches endVal, then switches to the overshoot oscillation. The final expression looks like this:

freq = 3;
decay = 5;
t = time - inPoint;
startVal = [0,0];
endVal = [200,200];
dur = 0.1;
if (t < dur){
  linear(t,0,dur,startVal,endVal);
}else{
  amp = (endVal - startVal)/dur;
  w = freq*Math.PI*2;
  endVal + amp*(Math.sin((t-dur)*w)/Math.exp(decay*(t-dur))/w);
}

The trick to making the velocities of the two animations match is the mysterious variable w. Here, w represents the angular velocity of the oscillation. Without getting into a lot of detail, it turns out that dividing the incoming velocity by the angular velocity of the oscillation gives an overshoot that matches perfectly. In practical terms this means that the higher the frequency of oscillation, the lower the resulting amplitude of the overshoot. One important thing to remember with overshoot is that you don't have direct control over the overshoot amplitude (the amp variable is calculated by the expression). If you want a larger overshoot, you need to either increase the incoming velocity, or reduce the oscillation frequency. It's worthwhile playing around with the expression to see the interaction between frequency, incoming velocity, and resulting overshoot amplitude.

This is an extremely useful and versatile expression. Here's fun a variation that you can use on a text layer to get the text characters to randomly scale up from zero to 100 percent, with overshoot. To get this to work, you would add a Scale Animator to your text layer, set the Scale value to zero percent, add an Expression Selector, (you can then delete the Range Selector), and finally, replace the default expression of the Expression Selector's Amount property with this:

freq = 3;
decay = 5;
maxDelay = 1.0;
seedRandom(textIndex,true);
myDelay = random(maxDelay);
t = time - (inPoint + myDelay);
startVal = [100,100];
endVal = [0,0];
dur = 0.1;
if (t < dur){
  linear(t,0,dur,startVal,endVal);
}else{
  amp = (endVal - startVal)/dur;
  w = freq*Math.PI*2;
  endVal + amp*(Math.sin((t-dur)*w)/Math.exp(decay*(t-dur))/w);
}

You'll notice that the only real difference between this and the previous version of the expression are the lines that calculate a random delay variable (myDelay) based on the character's textIndex value. Using textIndex as the random seed ensures that each character will get a unique, random delay.

Here's another variation that you can use to get the 3D characters of text layer to sequentially swing into view with overshoot. First you need to move the anchor point of your text layer to the top of your text. You can do this with an Anchor Point Animator. Also, make sure you have enabled per-character 3D. Add a new Animator for Rotation (don't use the same one you used to adjust the Anchor Point). Set the value of X Rotation such that the text is rotated out of view (perpendicular to the screen). Add an Expression Selector and delete the Range Selector. Replace the default expression of the Expression Selector's Amount property with this:

freq = 2;
decay = 5;
delay = .15;
dur = .12;
myDelay = (textIndex-1)*delay;
t = time - (inPoint + myDelay);
startVal = 100;
endVal = 0;
if(t < dur){
  linear(t,0,dur,startVal,endVal);
}else{
  amp = (endVal - startVal)/dur;
  w = freq*Math.PI*2;
  endVal + amp*(Math.sin(t*w)/Math.exp(decay*t)/w);
}

Keyframe Overshoot

Perhaps a more common overshoot application would be adding overshoot to a keyframed animation. This is actually fairly straightforward because the expression language gives you access to a property's velocity. In this case we'll use the velocityAtTime() function to get the incoming velocity at the most recent keyframe. This is the keyframe overshoot expression:

freq = 3;
decay = 5;
n = 0;
if (numKeys > 0){
  n = nearestKey(time).index;
  if (key(n).time > time) n--;
}
if (n > 0){
  t = time - key(n).time;
  amp = velocityAtTime(key(n).time - .001);
  w = freq*Math.PI*2;
  value + amp*(Math.sin(t*w)/Math.exp(decay*t)/w);
}else
  value