Say, if I'm doing the Ease-Out and then Ease-In animation of an object's movement from X1 coordinate to X2 coordinate over S steps at equal time intervals. Can some suggest the formula to calculate this movement's X coordinates?
6 Answers
Personally, I'd rather use a function that gets a time in [0; 1] and output a value in [0; 1], so that we can apply the result to any type (2D vector, 3D vector, ...).
Solution 1
For the quadratic easing in/out, the curve is separated in two distinct functions depending on the value of t
:
- when
t
<= 0.5:f(x) = 2 * x * x
with x in [0;0.5] (graph) - when
t
> 0.5:f(x) = 2 * x * (1 - x) + 0.5
with x in [0;0.5] (graph)
Here are the graphs:
Since the second function is also in [0;0.5], but t
> 0.5 when we start to use it, we need to reduce t
by 0.5.
This is the result, in C:
float InOutQuadBlend(float t)
{
if(t <= 0.5f)
return 2.0f * t * t;
t -= 0.5f;
return 2.0f * t * (1.0f - t) + 0.5f;
}
Solution 2 (Bézier)
Another interesting blend curve is the one given by Bézier, which have the advantage to be quite optimized (no if). Here is the curve from Wolfram:
And here is the C code:
float BezierBlend(float t)
{
return t * t * (3.0f - 2.0f * t);
}
Solution 3 (parametric function)
Another method proposed by @DannyYaroslavski is the simple formula proposed here.
It is parametric and gets a nice in/out acceleration and deceleration.
With alpha = 2, you get this function:
Which translates in C like this:
float ParametricBlend(float t)
{
float sqt = t * t;
return sqt / (2.0f * (sqt - t) + 1.0f);
}
-
In the last function I suppose that X is actually a T parameter of the funcrion, right ? – Coldsteel48 May 17 '17 at 18:05
-
In case anyone else in looking here are all 3 functions, in **JavaScript** and compressed . . . . . . . . . `function InOutQuad(n){return n<=.5?2*n*n:2*(n-=.5)*(1-n)+.5}` `function Bezier(t){return t*t*(3-2*t)}` `function Parametric(t){return t*t/(2*(t*t-t)+1)}` (Give 'em a number between 0 and +1 and they'll return a number between 0 and +1.) – ashleedawg Feb 02 '22 at 03:33
Quadratic ease out where:
t = current time
b = start value
c = change in value
d = duration
function (float time, float startValue, float change, float duration) {
time /= duration / 2;
if (time < 1) {
return change / 2 * time * time + startValue;
}
time--;
return -change / 2 * (time * (time - 2) - 1) + startValue;
};
source: http://gizma.com/easing/

- 25,694
- 7
- 76
- 115

- 15,593
- 16
- 82
- 128
-
Toad, when you say `t = time` do you mean time from start of animation or time from previous frame ? – Sir Oct 23 '15 at 02:07
-
t goes from 0 - 1 where 0 is the beginning of the animation, and 1 is the end. For every keyframe, you should change the values and let t again go from 0 to 1 – Toad Oct 23 '15 at 14:17
-
2What is the change in value? I don't understand where that comes from. – starbeamrainbowlabs Nov 20 '15 at 14:53
-
1You first use the formula to go from keyframe1 to keyframe 2. (So b is keyframe1 value and c is keyframe 2 value). Then you let the t go from 0.0 to 1.0. By the time you are at 1.0 you repeat these steps, only now you use keyframe2 and keyframe 3 – Toad Nov 25 '15 at 13:42
-
This answer should get 1M thumbs ups. I looked 10 sources, found the same formula, but none of them mentioned what the hell t, b, c and d where. Thanks man – Milad.Nozari Feb 15 '16 at 10:38
-
ok, I kind of understand, this, but what do you do with the returned value? – Myke Dev Apr 19 '17 at 19:00
-
say you ease from the value b=8 to c=17. Then given the current t (time) in respect to the total duration(d) it returns the adjusted value which eases the motion instead of that it interpolates linearly – Toad Apr 21 '17 at 06:23
-
1Say the startvalue = 3 and you want to ease to the value 5. Then the change in value is 2. So the change in value is the endvalue - the start value. – Toad Nov 12 '17 at 20:30
-
I was confused because I thought the return value was by how much the initial value (what the startValue is based on) should change, but instead it's what that initial value should become. "return change" threw me off. – TimSim Dec 19 '17 at 06:45
All the above solutions lack examples of usage.
Found good solution here:
function animate({timing, draw, duration}) {
let start = performance.now();
requestAnimationFrame(function animate(time) {
// timeFraction goes from 0 to 1
let timeFraction = (time - start) / duration;
if (timeFraction > 1) timeFraction = 1;
// calculate the current animation state
let progress = timing(timeFraction)
draw(progress); // draw it
if (timeFraction < 1) {
requestAnimationFrame(animate);
}
});
}
Example of usage:
animate({
duration: 1000,
timing(timeFraction) { // here you can put other functions
return timeFraction;
},
draw(progress) {
elem.style.width = progress * 100 + '%';
}
});
Other function:
function quad(timeFraction) {
return Math.pow(timeFraction, 2)
}
More here

- 29,388
- 11
- 94
- 103

- 2,062
- 15
- 18
I got same problem: wanted to animate my chart (Ease in-out)
.
Brainstorm gave me two ways:
1) Trygonometric formula. Firstly, I wrote y=(sin(x/π*10-π/2)+1)/2
,which analog is sin^2((5*x)/π)
float TrygoEase (float x) {
float y=(float)Math.pow(Math.sin(5*x/Math.PI),2);
return y;
}
2) Two parabolas. It was not hard. I just used y=2*x*x
on [0;0.5]
, and y=-2(x-1)^2+1
on [0.5;1]
float ParabolEase(float x) {
float y=2*x*x;
if(x>0.5f){
x-=1;
y=-2*x*x+1;
}
return y;
}
Use this ways for x=[0;1]
, what returns also y=[0;1]
.
Now You can compare this graphs:

- 279
- 5
- 21
Here is a version with the amount of curvature as an argument, following this general solution linked to by Creak.
/*
* applyCurve: apply an S-curve to an input value.
* The highest positive curvature will result in a step from 0 to 1,
* the most negative curvature will result in a constant of 0.5.
*
* progress: the input value between 0 and 1,
* curvature: the amount of curvature between -1 and 1.
* Negative values curve the other way, 0 applies no curvature.
*/
double applyCurve(double progress, double curvature) {
assert(progress >= 0.0 && progress <= 1.0);
assert(curvature >= -1.0 && curvature <= 1.0);
if (curvature >= 0.0) {
if (curvature > 0.99999) return progress > 0.5 ? 1.0 : 0.0;
float exp = 1.0 / (1.0 - curvature); // find s-curve exponent
return pow(progress, exp) / (pow(progress, exp) + pow(1.0 - progress, exp)); // apply s-curve
} else {
if (curvature < -0.99999) return 0.5;
float exp = 1.0 + curvature; // find s-curve exponent
return pow(progress, exp) / (pow(progress, exp) + pow(1.0 - progress, exp)); // apply s-curve
}
}

- 1,909
- 3
- 19
- 28
This version allows you to use any ease in and ease out functions (EaseIn and EaseOut). Both functions must take a time value parameter from between 0 and 1, and return an eased time value between 0 and 1.
float EaseInOut(float t)
{
if (t <= 0.5f)
{
return EaseIn(t * 2) * 0.5f;
}
else
{
t -= 0.5f;
return (EaseOut(t * 2) * 0.5f) + 0.5f;
}
}