Journal

Interpol

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.

Interpol

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.

  • value: 0
  • time: 0
  • progress: 0

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.

  • value: 0
  • time: 0
  • progress: 0

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:

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 chain Interpol instances
  • A Ticker instance: will allow us to suscribe to a requestAnimationFrame 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!

Next article.

I now have a journal

About

I'm Willy from France. With over 12 years of experience in design-driven front-end development, I specialize in creating design systems and interactive experiences.

Previously lead front-end developer at cher-ami.tv, I now work as a freelancer, collaborating with engineering teams and studios to balance the big picture with the finer details, ensuring that projects align perfectly with client needs and personality.

Stack

  • typescript
  • vanilla JS
  • node JS
  • PHP
  • webgl
  • preact
  • nuxt
  • vite
  • esbuild
  • ogl
  • use-gesture
  • preact signals
  • gsap
  • interpol
  • debug
  • low-router
  • docker
  • github action
  • gitlab CI

I'm Available for collaborations & projects! Feel free to reach out for any inquiries.