Despite the commonality of the classic easing equations, largely attributed to Penner, there doesn’t seem to be the in-depth examination of “how it works” that a lot of code is subject to nowadays.

First, a quick clarification on the most popular easing Classes.

The “standard” easing classes (that provide predictable inertia), are Linear, Quad, Cubic, Quart, (Quintic or Strong)

There are almost all identical. The only difference between them is the number of times the change is multiplied by itself. If, for example, a particular point in an animation with easeIn should yield a position [1] of say 0.9 (so 90% of the way through the tween), you’d multiple that 0.9 by itself once for every “power” of the ease. So if the method had a power of 3, it’d be 0.9 * 0.9 * 0.9 = 0.729, instead of 0.9. This means it’d be more “dramatic” – for easeIn, it’d be faster in the beginning and slower at the end.

Those five standard Classes use a power of 1 – 5.

Linear = 1 (and any number to the power of 1 is itself, so at 10% of the way through the tween, the property will have added 10% of the total difference between start and end).
Quad = 2
Cubic = 3
Quart = 4
Quint and Strong = 5

And yes, Quintic and Strong are the same.

Expo uses a power of 10, but applies some other checks as well, so I don’t include it with the 5 standard classes above.

The other, more exotic easing Classes usually just apply a slightly different Math method – the Sine easing class just applies Math.cos (easeIn) and Math.sin (easeOut), and creates more variation at one end (start for easeIn, end for easeOut), and “flattens” the curve on the other end. Back, Bounce and Elastic offer some more complex algorithms that are beyond the scope of this post, so I’ll move on…

These functions are usually written with 4 arguments [2]:

@t is the current time (or position) of the tween. This can be seconds or frames, steps, seconds, ms, whatever – as long as the unit is the same as is used for the total time [3].
@b is the beginning value of the property.
@c is the change between the beginning and destination value of the property.
@d is the total time of the tween.

So let’s break this down. Let’s say you’re tweening an object horizontally across the screen. Let’s state some facts:

- It’s originally at position 50 (so in JS/DOM say it had position:absolute and left:50px… In AS, it’d have element.x = 50;).
- You want to tween it to position 200.
- You want the tween to take 1 second.

At the start of the tween, the values passed to the easing function would be:

t = 0 (we’re just starting, so 0 seconds have passed)
b = 50 (the beginning value of the property being tweened)
c = 150 (the change in value – so the destination value of 200 minus the start value of 50 equals 150)
d = 1 (total duration of 1 second)

So using the linear math from above:

c * t / d + b;

While the math is the same, I prefer to look at it this way:

c * ( t / d ) + b

The parenthesized portion is the percentage of completion… ellapsed time (t) divided by total duration (t). if 30 milliseconds have ellapsed, and the total duration is 50 milliseconds, 30 / 50 = 0.6, or 60% of the way through the tween. This number what runs your tween, and everything else can be extrapolated from that value.

Back to the example… As stated above, we know that at the start of the tween, c is 150, t is 0, d is 1 and b is 50

so 150 * 0 / 1 + 50 = 50

The element, at the start of the tween, would still be at 50px – no change.

Now let’s see what happens at halfway through the tween:

t = 0.5 (halfway through the tween, so 0.5 of 1 second)
b = 50 (the beginning value of the property being tweened)
c = 150 (the change in value – so the destination value of 200 minus the start value of 50 equals 150)
d = 1 (total duration of 1 second)

You’ll see that only the “t” parameter changed – the original value, change in value, and total duration are all unchanged. Let’s see how the change to the ellapsed time affects the return.

The formula is the same: c * t / d + b, but now the updated “t” value (ellapsed time) has changed, so

150 * 0.5 / 1 + 50 = 125

Now the easing function returns 125, positioning the element at top/x of 125. This is indeed halfway between 50 (start) and 200 (end), and shows an increase of 75 pixels from the original value.

Breaking it down a little, we’ll always want to add the beginning value (b). The tween changes the property in relation to that beginning value, so we’ll always be adding that change to “b”

b + ( the relative change )

And we know that t / d represents the percentage

so 0.5 / 1 = 0.5, or 50%

The total change in value at the end of the tween – the difference between the beginning value and the destination value – is 150 (the “c” parameter)

So 50% of 150 is 75. That’s the relative change at this point in the tween.

Add that relative change (75) to the original value “b” (50), and we get the 125 current position. Simple :)

Again, you’ll also notice that all the magic happens here (highlighted):

c *     t / d     + b

In almost all easing calculations, it’s always going to be change in property times (some float) plus beginning value. How that float (the highlighted bit above) is calculated determines the returned value for any point during the tween.

In fact, for any tween, you could really just substitute @b and @c for 0 and 1, respectively – the return of the function would be a number between 0 and 1. Multiply the difference between the start value and the end value, and add that to the start value, and the effect would be the same.

In fact, you can even omit those parameters from an easing function – the following works almost identically to any of the standard easing Class’s version of easeIn:

So the function could take just two arguments: start time and total time, where “power” is the number of referenced for each of the Classes (above). To emulate Strong.easeIn, for example, the following function would perform identically:

easeOut is pretty similar:

So Strong.easeOut would look like:

You could even write a very simple functor to have any number greater than those 5, or using floated versions…

And it’d be passed as the return of an invocation, rather than a reference. The following psuedo-code shows how to use the concept just above to creating an ease halfway between Quartic and Quintic:

You could also use the same concept to customize the easeBack function, to create more or less dramatic returns:

[1] The term “position” doesn’t necessarily refer to a dimensional position, it could be any point between the start and end of the tween.
[2] I’ll use JS notation throughout, but all sample code here would work identically in AS3, just add datatypes.
[3] The current time (“position”) and the total time can be any numbers, and just represent a percentage of change. So frame 5 of 10 is halfway through, the same as 0.5 of 1 seconds, or 3500 of 7000 seconds. As long as both are expressed in the same unit, the actual values don’t matter – any numbers greater than 0 or less than Infinity will serve.