It’s very common for animations to be specified as ease-in-out. It’s a very pleasing sensation to witness an object speed up, cruise, and slow to a halt. Most easings specify one of a small number of easing curves: easeInOutQuad, easeInOutSine, easeInOutCubic, etc. However, the sharpness of that curve is not configurable. Here I show how to create a configurable ease-in-out function that will work for animating any property you desire.

How to Use It

The easing function takes a single parameter k, that specifies the steepness of the curve. The larger k is, the steeper the curve, and the higher the velocity in the middle section relative to the beginning and ending.

The sigmoidFactory will produce a function that takes a parameter t that represents the percentage of the animation completed as a number between 0 and 1. It’s important to note that this system only produces numbers that you can use within an animation framework (that you might have to build). An example framework is included in the jsFiddle.

Here is an example of the usage:

var easing = sigmoidFactory(7); easing(0); // nearly 0 (5.551115123125783e-17)

easing(1); // 1

easing(0.5); // 0.5

easing(0.25); // 0.028453023879735584

easing(0.75); // 0.9715469761202644

You can design your easing curve visually using this OS X Grapher file. Modify k to adjust the steepness.

A demonstration of four different k values implemented in the engine of mobile game Epsilon Jump (iOS, Android) graciously provided by Rienzi Gokea.

The Theory

This section is not required for use. Read on to understand the techniques underlying the code so that you will be able to develop your own easing curves.

Firstly, we need a function that looks like easeInOut. There are two that come to mind that fit the bill: sigmoid (Fig. 1, which we will use) and arctangent [1] (which we will not use).

Figure 1. The Sigmoid Function

However, these curves both have some defects we’ll have to remedy. We want our animations to start at 0 and end at 1. Both functions begin in the middle of the animation at 0, and asymptotically approach their final values (0 and 1 in the case of sigmoid, -π/2 to π/2 in the case of arctangent).

We’ll need to apply a number of fixes to our chosen function in order to make it ready for service.

Move the center point to 0.5 along the x axis. Instrument a steepness knob. Force the function to cross 0 at 0, and 1 at 1.

I’ve selected the sigmoid curve for our fixes because it’s based on e which is generally easier to analyze than arctangent, though it’s nearly as easy to work with in this case. That exercise will be left to the reader.

Equation 1. The Sigmoid Function

Moving the sigmoid is quite easy. Using an algebraic manipulation, if our easing function is f(t), then moving the center point by 0.5 is accomplished by f(t-0.5).

Similarly, if we multiply t by a chosen knob, f(kt), we can make the function “accelerate and condense” if k > 1, or make it “slow and spread out” if k < 1.

Equation 2. Sigmoid augmented with a knob k and centered at t = 0.5.

In Eqn. 2, we move the manipulations of t into the function in order to make the function easier to use. This solves our first two problems, but take a look at the graph below where Eqn. 2 has been plotted with k = 6.

Figure 2. Eqn. 2 plotted with k = 6. Note that the ends are significantly above 0 and below 1.

This is pretty close! However, the beginning and ending of the animation is respectively above 0 and below 1. This will cause an animation to exhibit a “jump” at the ends. If k is set sufficiently high (above about 11 or 12), you won’t even notice the problem. However, this restricts our range of expression as we can’t use any shallow curves, but it might be good enough for you and you can stop here if you so choose.

While your first intuition, as it was mine, might be to find some way to make the sigmoid pass though zero by doing some trick like multiplying by t or using some crazy conditional statements or reflections, there is a simpler way that’s kind of a hack. Notice that the error at the ends of the sigmoid is symmetric — the distance from 0 is the same as the distance from 1. What if we could just scale the result so that 0 passes through 0 and 1 passes through 1?

There are several steps to get this strategy to work, but in brief, you start with a basic sigmoid centered at 0 (so the range is -1/2 to 1/2), multiply by the correction factor (0.5 / f(1)), then figure out how to translate it up (+0.5) and to the right (t-0.5). You then condense the range of the function by 2 (it reaches -0.5 at -1 and +0.5 at 1).

Equation 3. Evolved from Eqn. 2, this is our instrumented sigmoid centered at 0.