AE Bounce

AE bounce expressions
Source #code/js

Bounce

Expression sliders:
Position - Overshoot
Position - Bounce
Position - Friction

try {
    amp = effect("Position - Overshoot")("ADBE Slider Control-0001") / 2.5, freq = effect("Position - Bounce")("ADBE Slider Control-0001") / 20, decay = effect("Position - Friction")("ADBE Slider Control-0001") / 20, n = 0, 0 < numKeys && (n = nearestKey(time) 
            .index, key(n)
            .time > time && n--), t = 0 === n ? 0 : time - key(n)
        .time, 0 < n ? (v = velocityAtTime(key(n)
            .time - thisComp.frameDuration / 10), value + v / 100 * amp * Math.sin(freq * t * 2 * Math.PI) / Math.exp(decay * t)) : value;
} catch (e$$4) {
    value = value; 
}

If you've ever animated these sorts of things manually, you'll know what I mean. Most will need to be tweaked to your specific needs, but it's just a matter of playing with the numbers a little, and understanding how they'll change your animation.

Fixed version

try {
    amp = 15/ 2.5, freq = 40 / 20, decay = 100 / 20, n = 0, 0 < numKeys && (n = nearestKey(time) 
            .index, key(n)
            .time > time && n--), t = 0 === n ? 0 : time - key(n)
        .time, 0 < n ? (v = velocityAtTime(key(n)
            .time - thisComp.frameDuration / 10), value + v / 100 * amp * Math.sin(freq * t * 2 * Math.PI) / Math.exp(decay * t)) : value;
} catch (e$$4) {
    value = value; 
}

Inertial Bounce

is like making your moves "rubbery." Layers will overextend, then settle into place on position and rotation keyframes.

// Inertial Bounce (moves settle into place after bouncing around a little)
n = 0;
if (numKeys > 0){
	n = nearestKey(time).index;
	if (key(n).time > time){
		n--;
		}
}
if (n == 0){
    t = 0;
}else{
    t = time - key(n).time;
}
if (n > 0){
    v = velocityAtTime(key(n).time - thisComp.frameDuration/10);
    amp = .05;
    freq = 4.0;
    decay = 2.0;
    value + v*amp*Math.sin(freq*t*2*Math.PI)/Math.exp(decay*t);
}else{
    value;
}

Bounce Overview

Our ultimate objective here is to end up with an expression that will simulate a bounce back at the end of a keyframed motion. To understand how a bounce simulation works though, it's useful to start with a scenario that is probably more familiar—a projectile that bounces when it hits the ground/floor. To keeps things simple, we'll limit it to two dimensions. When you launch a 2D projectile, there are a number of factors that come into play: the force of gravity, the elasticity of the object, the launch angle, the initial velocity, and sometimes friction. An expression to simulate this motion basically has to split the initial velocity into x and y components. Gravity works in the y direction. At each bounce, the object loses y velocity based on the elasticity and x velocity based on the friction. Taking all these factors into account gives you an expression for 2D bounce that looks like this:

elev = degreesToRadians(75);
v = 1900;
e = .7;
f = .5;
g = 5000;
nMax = 9;
tLaunch = 1;
vy = v*Math.sin(elev);
vx = v*Math.cos(elev);
if (time >= tLaunch){
  t = time - tLaunch;
  tCur = 0;
  segDur = 2*vy/g;
  tNext = segDur;
  d = 0; // x distance traveled
  nb = 0; // number of bounces
  while (tNext < t && nb <= nMax){
    d += vx*segDur;
    vy *= e;
    vx *= f;
    segDur *= e;
    tCur = tNext;
    tNext += segDur;
    nb++
  }
  if(nb <= nMax){
    delta = t - tCur;
    x = d + delta*vx;
    y = delta*(vy - g*delta/2);
  }else{
    x = d;
    y = 0;
  }
  value + [x,-y]
}else
  value

There are a few things to be aware of with this expression. The bounce parameters—launch angle (elev), initial velocity (v), elasticity (e), friction (f), and gravity (g)—are all defined at the top of the expression. Note that you also have to define the maximum number of bounces (nMax) to keep the expression from disappearing into an endless calculation of smaller and smaller bounces. This version of the expression also includes a variable to control the launch time (tLaunch).

Keyframe Bounce Back

Now we'll look at the expression that that is really the point of this section. This expression uses a property's velocity coming into a keyframe to calculate a bounce-back (in the direction opposite to the incoming animation) with a series of diminishing bounces. The expression uses most of the logic from the basic 2D bounce expression, except that there is no need to worry about launch angle and initial velocity (those are retrieved from the keyframe), or friction. This expression has been fashioned to work with most properties. See the sidebar movie for examples applied to the Scale, Position (2D and 3D), and Rotation properties. Here's the expression:

e = .7;
g = 5000;
nMax = 9;
n = 0;
if (numKeys > 0){
  n = nearestKey(time).index;
  if (key(n).time > time) n--;
}
if (n > 0){
  t = time - key(n).time;
  v = -velocityAtTime(key(n).time - .001)*e;
  vl = length(v);
  if (value instanceof Array){
    vu = (vl > 0) ? normalize(v) : [0,0,0];
  }else{
    vu = (v < 0) ? -1 : 1;
  }
  tCur = 0;
  segDur = 2*vl/g;
  tNext = segDur;
  nb = 1; // number of bounces
  while (tNext < t && nb <= nMax){
    vl *= e;
    segDur *= e;
    tCur = tNext;
    tNext += segDur;
    nb++
  }
  if(nb <= nMax){
    delta = t - tCur;
    value +  vu*delta*(vl - g*delta/2);
  }else{
    value
  }
}else
  value

As before, you can control the bounce characteristics by adjusting the elasticity (e) and gravity (g) variables.