I have always wondered to understand how to develop GSAP's functionalities in custom tool. I decided to write my own GSAP library but quickly I changed my mind. Starting a new project with too many subjects to cover was not a good idea. I decided to focus first, on one subject: the interpolation.

Basic concept
From the wikipedia:
In the mathematical field of numerical analysis, interpolation is a type of estimation, a method of constructing (finding) new data points based on the range of a discrete set of known data points
In my own words, interpolation is a way to find a value between two other values. In our case, we want to interpolate numbers, so the whole library is based on this mathematical formula:
Applied to javascript, consider this example:
value
is interpolated between start
and end
.
In the following, example you can see the interpolation in action on just three frames.
We take a snapshot of the element's position every x
milliseconds and interpolate the element's position between 0
and 100
.
What we need now is to make the operation on each frame to see something moving smoothly on our screen.
This is when we need requestAnimationFrame
.
Et voilà, we have a basic "animated interpolation" in action. The element moves from 0
to 100
in 1000ms
, repainting on each frame.
Easing
But we don't always want to interpolate, over a given time, in a linear way. The coolest part of the interpolation usage, is the easing implementation. We have to calc the new value depending of an easing transformation by wrapping our third parameter "percent" with an easing function.
Here is how we are going to move with a quadIn
curve:
At the "T" time, the easing function will return a value between 0
and 1
, but not the same than with a linear function (t) => t
. If we take a snapshot on each percentage progression, as will be done with our browser's requestAnimationFrame
API, our last value result should be:
With the easing feature, it is possible to change the shape of the element's path while ensuring that it always starts and ends at the same points. You can test different ones in the following example:
For more information about easing, check easings.net.
Now that we have the basic concept of what is an interpolation, it's time to use this knowledge to build our library.
The Interpol library
The linear interpolation can be useful when we want to animate things on the web. A real world usage could be DOM element style properties for sure but also, webgl object position, audio volume, color or whatever you want.
Some really powerful animation libraries like GSAP, anime.js or motion.dev are built on this simple concept (except motion.dev use also web animations API). But each of these libraries is for the most part a high-level machine with a lot of features and options.
We will see that we can do (in some cases) the same with a very low-level library, with limitations for sure, but for a smalest size than the latter.
Bundlephobia report:
- gsap@3.12.7: 26.5kB
- motion@12.0.1: 23.6kB
- animejs@3.2.2: 6.9kB
- @wbe/interpol@0.20.1 3.4kB
The goal of this comparaison is not to discredit other libraries, their statements are multiple compared to Interpol, so it is normal that their size is higher. And also be careful not to confuse size and performance. These are two different subjects. This comparison allows to situate a lib allowing only the interpolation of values vs animation libraries. (and animejs is very close in size to interpol by embedding a dom API, congrats!).
The API specifications
Here the main specifications:
- small size: the bundle size has to be less than 3.5kB
- low-level: to be maintainable and be a development base for a custom wrapper
- multiple interpolations: need to interpolate a set of values per instance, not only one
- chaining interpolations: need to create Timelines
- close to the GSAP API: should be easy to adopt and then, close to GSAP API
What do we need to build it?
- An
Interpol
instance (class or function, but class will be easier to manipulate) - A
Timeline
instance: to chainInterpol
instances - A
Ticker
instance: will allow us to suscribe to arequestAnimationFrame
in order to interpolate our values from each Interpol instances
Basically, we want to interpolate values on each frame and access to their current value and progress on each interpolation. It's like we want to "enter" and "leave" the RAF for a duration of X milliseconds.
The API should looks like GSAP we said. Starting from the target project, check a GSAP example, and an Interpol proposal first:
Note that GSAP has a DOM API that we don't use here. Instead of passing the DOM element to animate directly, we pass an object and interpolate its values.
In Interpol
instance, we don't want to develop a DOM API, there is no element
param, only [from, to]
props values to interpolate.
The prop [number, number]
array, could be a { from: number, to: number }
or only a to: number
with an implicite from
set to 0
. But we stay voluntary soft at the beginning. Also another difference is that the duration is in second in GSAP and in milliseconds in Interpol.
Interpol instance
Now, how it's work under the hood? This is a pseudo code of the Interpol
class:
The Ticker instance is not detailed but you can concider it like a pub-sub pattern witch make enter and leave our tick()
callback in a RAF.
The highlight part of the code is where the magic append, where we interpolate values and call the onUpdate
constructor param callback. Of course, we will need much more than this code to implement all the features necessary for real use.
The API of the Interpol
class should be more complex than this pseudo code. Like GSAP, we need at least:
play
pause
resume
reverse
stop
seek
Plus we should have some others callback available like
onStart
onUpdate
onComplete
Check the final Interpol constructor
Timeline instance
The second major part of the library is the Timeline part. In a real world of motion development, we often need to chain interpolations together in order to build more complex animations. The Timeline
class is a way to manage this chaining.
The development strategy is to create a store of "add" interpolations and read them one by one.
Unfortunately, the Timeline
class is not as simple as this pseudo-code. Playing each Interpol instance one by one is not enough to be fully functional. In this example we are handled to each Interpol state (ex: at time 0ms, 1st one is playing, the second is not. At time 1000ms, we should stop the first and start the second...). The better way I found is to seek them in a RAF, depending of the current time. Each instance enter and leave the RAF, based on its duration and its current time position in adds
collection.
It will suppose that the Interpol
instance has a seek
method to go to a specific progress.
This algorithm is based on the fact that a progress lower than 0 or higher than 1 seek nothing. In this case, the Interpol
instance is not playing, and it will be the natural behavior, without any extra code. So, no need to execute play
, pause
or stop
on each Interpol
instance (youpi).
Limitations
Interpol library as some limitations and considerations, we coudn't ignore if we want to use it seriously in a project.
Numbers only
The API allows to interpolate numbers only, we can't pass string with units, colors or anything else.
but the developer is free to add or convert a value to whatever he wants in the onUpate
callback.
Explicit from value
The library is not a DOM API in the first place, it is a low-level library, so it is not possible to pass a DOM element to interpolate its values automatically, it must be handled manually as well. On this point, libraries like animejs, motion.dev and gsap are easier to use. The main reason is that Interpol has no idea about the DOM, it cannot get the value of an element's current style property and simply consider it as a from
.
With this limitation, we need to define the from
explicity. GSAP need it too but this is an internal process. It make's the usage of Interpol Timeline more complicated in some cases. In our example, we need to set the from
value of the second interpolation to the to
value of the first one.
And more complicated again, if the second interpolation starts with a negative offset, we need to calculate the from
value manually.
Instead of calculating, we can keeping a reference of the previous interpolation for example, but it's not as easy as other animation library on this point.
Conclusion
More specific features implemented in Interpol can be covered here like offset, easing API, stagger, using external ticker, changing de global duration unit to second etc. Has we have seen in this article, Interpol is not an animation library but its low level API allows to meet all specific needs of a motion development. Sometime it requires more code to write, but it is a good way to understand how the animation works behind the scenes.
Nowadays, CSS and the animation API cover many needs for creating animations on the web. We should need less such libraries like this in the future when it comes to DOM animation; which does not prevent us from understanding the mathematical mechanisms behind the concept of interpolation and apply it on everything we want!