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]}:

1 2 3 |
function noEasing (t, b, c, d) { return c * t / d + b; } |

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

1 2 |
var factor = yourEasingFunction(currentTime, 0, 1, totalTime); target.property = original.value + (destination.value - original.value) * factor; |

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:

1 |
return Math.pow(t / d, <power>); |

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:

1 2 3 |
function easeIn(t, d){ return Math.pow(t / d, 5); } |

easeOut is pretty similar:

1 |
return 1 - Math.pow(1 - (t / d), <power>); |

So Strong.easeOut would look like:

1 2 3 |
function strongEaseOut(t, d){ return 1 - Math.pow(1 - (t / d), 5); } |

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

1 2 3 4 5 |
function easeOut(v){ return function(t, b, c, d){ return 1 - Math.pow(1 - (t / d), v); } } |

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:

1 |
SomeTween.performTween(target, duration, props, easeOut(4.5)); |

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

1 2 3 4 5 6 |
function easeBack(v){ if(typeof v == 'undefined') v = 1.70158; return function(t, b, c, d) { return c * ((t = t / d - 1) * t * ((v + 1) * t + v) + 1) + b; } } |

^{[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.

AnonymousJanuary 26, 2014 at 3:30 amVery nice post, good explenation!

moagriusJanuary 26, 2014 at 11:59 amThanks

AhsanOctober 19, 2013 at 12:02 pmWow, thats some excellent explanation, indeed its really helpful…Math is power!!

moagriusOctober 19, 2013 at 12:43 pmHTH!

FilleOctober 10, 2013 at 3:31 pmWell explained. I am looking for a way to do custom easings using Apples new SpriteKit. They only support the most basic ones right now. I want to learn how to tweak ease-calculations and this was a great way to start. Thx!

moagriusOctober 10, 2013 at 4:08 pmHTH!

BeratoSeptember 10, 2013 at 3:32 pmIm trying to make an object follow the mouse while easing to the mouse position everytime it moves. How would I do that?

moagriusSeptember 11, 2013 at 8:17 amJust cancel and re-invoke your tween function each time. You can also throttle the mousemove event, like so: http://upshots.org/javascript/javascript-throttle-debounce-functions

HTH

JanimatorJune 13, 2013 at 2:25 pmYup – great post ! – thanks a lot, it made a lot of things clear to me (especially since my math-level is really quite bad…) I am translating this into python3 and it works pretty well :)

only part I am not 100% sure is:

quote: ” 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.”

moagriusJune 13, 2013 at 4:16 pmthat quote means that the entire “control” of the tween is the float produced by the math. the penner methods take the beginning value, the change in value, and apply the float to the change and add it to the beginning value. this isn’t always exactly necessary. that float is the crux – with that number you can do whatever you want, and sometimes you actually don’t want to pre-determine the destination value (for example, you might want to “tween” the order of appearance of display objects – so you’d want just the float value, not applied to start or change values.

you can get that float by passing 0 and 1 for @b and @c – this number can be used directly, as in:

target.property = original.value + (original.value – destination.value) * float;

… or more indirectly, perhaps applied to a number of different transforms, or applied to a non-standard effect like timing the appearance of words on a page (you could use ease out to have the words appear one-at-a-time, quickly at first, then more slowly as the page fills… that’s just an example, and probably a poor one at that, but my point (as emphasized heavily in the post) is that the calculations performed on “t/d” is really the heart of the tween, and to use inertia in effects outside of straight property tweens, it can be a good idea to separate that bit out entirely, which can be done with 0 and 1 for b and c.

Hope that makes sense.

Mike GordonMarch 7, 2013 at 12:14 pmI’m really grateful man, I have been looking everywhere for this.

moagriusMarch 7, 2013 at 1:06 pmGlad it helped!

MarianneFebruary 1, 2013 at 12:01 pmCommon-ness = commonality

moagriusFebruary 1, 2013 at 12:37 pmTYVM!

gabrielNovember 13, 2012 at 6:55 pmWhat is “value” on the very last line of code example?

moagriusNovember 13, 2012 at 8:36 pmThat should be “v” (the amount of “backness”). I’ve corrected it in the sample. Good catch, thanks.

Namanyay GoelOctober 15, 2012 at 5:09 amI know this post is a bit old, but how can I figure out ‘d’, the total time required? I’m using setInterval to animate things, there is not any way that I know to get d.

Also, do you have any working examples of the above?

Btw, great post. Really easy to follow, I’ve learnt a lot from it.

moagriusOctober 15, 2012 at 11:40 am“d” is equal to “duration”, so that’ll always be available from whatever duration you passed to the animation routine (as opposed to the easing routine). generally you’ll want the factor returned from an easy function, so it can be passed to the calculation to determine the position… while i wouldn’t recommend doing so, i suppose you could return an object with properties (including the factor, duration, or anything else you wanted) and use the appropriate property… like so:

As far as examples… This post is more about understanding existing easing methods, and how you an adapt them. Most folks nowadays use frameworks (all the big JS frameworks include animation methods, including jQuery, MooTooos, Prototype, dojo, YUI, etc), and in ActionScript folks use classes like TweenLite, GTween, Tweeny, Tweensy, etc), but assuming you wanted to build it from scratch, it’s pretty simple. Here’s a quick sample animating a div 500px over 1 second, using the easeIn function outlined above: http://jsfiddle.net/moagrius/gRCkW/

HTH

TomFebruary 17, 2012 at 5:57 amI am trying to adapt Penner’s equations to robotic motion. So thanks for explaining. Two things that are not clear to me. I can’t wrap my head around easeinout. In and out by themselves are simple, but I can’t seem to combine them. Also, Penner’s calculations use the /= operator, and while I understand the concept, I can’t rewrite his equations in a language that doesn’t have this operator. I feel like a dolt to be stumbling on something this simple.

moagriusFebruary 17, 2012 at 11:14 amHey Tom,

“a /= b” is the same as “a = a / b”, which should be supported in every language.

easeInOut is basically just easeIn for the first half and easeOut for the second half – it’s even expressed that way in the penner equation:

[as3]// if current time divided by total time divided by 2 is less than 1, easeIn…

if ((t/=d/2) < 1) return c/2*t*t + b;

// otherwise, easeout

return -c/2 * ((–t)*(t-2) – 1) + b;[/as3]

while the straight math of the penner equation is always going to be faster, you could write it a little more simply like so:

[as3]// if ellapsed time is greater than half of the duration, easeOut

if(t > (d / 2)) return easeOut(t, b, c, d);

// otherwise, easein

return easeIn(t, b, c, d);[/as3]

i haven’t tested the above but it should at least get you going in the right direction.

hth

AnonymousFebruary 17, 2012 at 5:19 amPenner very helpfully includes one of his book chapters on his web site, which is very generous. But I’m doing something rather different with them, and after reading specific parts repeatedly, I wasn’t able to adapt them. Your explanations are a big help.

RossieJanuary 25, 2012 at 5:29 amGreat post, thank you. :)

Gergely Rossel

moagriusJanuary 25, 2012 at 7:18 amGlad you found it helpful. Thanks for your comment

detjSeptember 18, 2011 at 4:28 amThanks for this helpful post! Every one is aware of easing but, till now no-one did actually explained what goes on in it. I’m trying to smooth rotate a sprite and this would help immensely to understand the process.

moagriusSeptember 18, 2011 at 9:50 amHey Detj,

I’m glad you found it helpful – thanks for your comment.