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

I suppose an easy way to remember the variable is:

t: time

b: begin

c: change

d: duration

Hi there. First off, great post, but I just wanted to know a small error at the beginning that may have just been an innocent mistake. The error is in this passage:

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.

I think you mean EaseOut instead of EaseIn here. An EaseIn would start out slow and speed up near the end; it “eases” in to the movement, so to speak. EaseOut, on the other hand starts out fast and then slows down at the end. Otherwise, great page and explanation!

Yep, just a slip, as you can tell from later in the line where it contrasts with easeIn.

It’s corrected now, thanks for pointing it out

I am looking at backEaseInOut (C++) which looks strange, let me explain.

float Back::easeInOut(float t,float b , float c, float d) {

float s = 1.70158f;

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

float postFix = t-=2;

return c/2*((postFix)*t*(((s*=(1.525f))+1)*t + s) + 2) + b;

}

"float postFix = t-=2;" is the same as

"t = t – 2; postFix = t;" hence the last two lines might as well be written:

t-=2;

return c/2*(t*t*(((s*=(1.525f))+1)*t + s) + 2) + b;

Did you mean something else? Perhaps you meant:

t-=2;

return c/2*(t*(t+2)*(((s*=(1.525f))+1)*t + s) + 2) + b;

Regards

Søren

Also, in the same function there is:

float s = 1.70158f;

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

which looks very suspicious. Why do you have "s*=(1.525f)" in the middle? You re-assign 's', so which value of 's' do expect to use later in the line? 1.70158f or 1.70158f*1.525f?

++, –, *=, /= should be avoided inside expressions as result will depend on the evaluation order.

Søren

I’m not exactly sure what you mean, or where the code samples you pasted is from. I did not write the easing equations described here, they were originally written by Robert Penner (although a lot of people have ported, translated or otherwise borrowed from that original group of easing equations).

I have a library that moves a sprite along a bezier curve.

http://en.wikipedia.org/wiki/B%C3%A9zier_curve

Can I use this easing functions just to determine the value of t?

I’m not sure what you mean. The easing function will provide a weighted value between 1 and 0 (or beyond that in the case of bounce and elastic type functions), which can be applied to the total change in property value between a starting value and a destination value. It would not tell the position along a bezier of a display object, although if the easing function were used to set the position, I supposed it could be extrapolated.

When reading I was under the impression that an easing function could return any value, which is why this sentence was confusing:

“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″

It certainly *can* return any number, but in this case the number returned would be a weighted progress – 0 being the very start and 1 being the very end – and even that isn’t entirely consistent, as Back, Bounce and Elastic easing might exceed 1… for example, when Back overshoots by say 15%, that’d be a easing value of either 1.15 (if the easing function is returning a straight weighted progress), or change * 1.15 (if the new value was computed in the easing function)

Thank you for the great explanation. Sharing make every science go forward!!

Thanks!

u rock !

thx!

Very nice post, good explenation!

Thanks

Wow, thats some excellent explanation, indeed its really helpful…Math is power!!

HTH!

Well 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!

HTH!

Im trying to make an object follow the mouse while easing to the mouse position everytime it moves. How would I do that?

Just 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

Yup – 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.”

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

I’m really grateful man, I have been looking everywhere for this.

Glad it helped!

Common-ness = commonality

TYVM!

What is “value” on the very last line of code example?

That should be “v” (the amount of “backness”). I’ve corrected it in the sample. Good catch, thanks.

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

“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

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

Hey 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

You pointed out something that always bothered me with Penner’s calculations (that have been copied everywhere) for easeInOut. To figure out whether it’s easing In or easing Out we do:

if (t / (d / 2) < 1) then easeIn

and then test to see if the result is greater/less than 1. Why not test to see if t is half of d directly?

if (t < (d / 2) ) then easeIn

This removes a divide operation and is much more intuitive (has half the duration elapsed?).

Or am I missing something?

-smb

I don’t see anything that looks exactly like what you’ve described, but IIUC then I’d agree with you – multiple tests on the same value do seem redundant. FWIW, the easing functions I keep handy (Penner’s) do see to test appropriately, e.g.,

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

Great post, thank you. :)

Gergely Rossel

Glad you found it helpful. Thanks for your comment

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

Hey Detj,

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