Introduction to Popmotion: Tween

Popmotion is a functional JavaScript animation library. Compared to other libraries like GreenSock or Anime.js, Popmotion is low-level and unopinionated.

It packs a ton of features, like spring physics and pointer tracking, into a very small filesize (11.5kb).

It allows developers to write their own features using simple functions, rather than waiting for the library author to add them.

It also means it's just as easy to animate 3D objects, charts or React components as it is to animate DOM or SVG elements.

This flexibility can make the initial learning curve steeper than for other libraries. So, in this tutorial series, we'll learn the basics of Popmotion's powerful animations. We'll start with the workhorse of the animation world, the tween.

Install

Popmotion supports a variety of installation methods. In production, I recommend installing via npm, as this allows you to import only the bits you need, saving space even further.

However, for this tutorial, you can follow along with this CodePen, which has been set up with the latest version of Popmotion.

Tween

For those unfamiliar, a tween transitions between one number and another over a predetermined length of time. If you've used a CSS transition, Popmotion's tween function works exactly the same.

We can import tween like so:

const { tween } = popmotion;

By default, tween animates between 0 and 1 over a duration of 300 milliseconds. If you open your console, you can test this yourself:

Understands default value types, so you can set translateX (for instance) without appending 'px'.

You're also not limited to using it inside an animation. You could manually set an element's style while others are animating, and the change will be automatically scheduled and batched along with the others.

So let's import it:

const { tween, styler } = popmotion;

Create the ball styler:

const ballStyler = styler(ball);

Now we can use ballStyler to set and animate any of the ball's properties. ballStyler.set is flexible. It can set a single property:

ballStyler.set('background', '#f00');

Or multiple properties:

ballStyler.set({
x: 100,
y: 100
});

We want to animate opacity for now, so let's change our animation:

tween().start(v => ballStyler.set('opacity', v));

set can also be curried. By providing it just a property name, it will return a setter function for that prop. So we can neaten the above by writing:

tween().start(ballStyler.set('opacity'));

So far, we've only animated the ball using the default tween properties. Let's take a look at how versatile a tween can be.

Tween Props

tween accepts one optional argument, an object of tween properties. Let's take a look at some of the more commonly used props:

from/to

A tween can be between any two states. We define these with from and to.

Let's animate translateX by rewriting 'opacity' to 'x'. Then, pass from and to props:

tween({ from: 0, to: 300 })

Your ball now moves from left to right by 300px.

However, I said that a tween can be between two states, not just numbers. If we provide from and to objects of numbers and/or colors, we can animate multiple properties at once.

Easing

Easing functions are used in tweening to change the rate of movement throughout the animation.

In real life, objects don't start or stop at their target velocity. Depending on the object, they gradually speed up, or gradually slow down, or both.

An easing function simply works by taking the tween's progress, defined as a number between 0 and 1, and returning a new one.

You don't need to know how to make these functions because Popmotion provides a bunch for you.

Import them:

const { easing, tween, styler } = popmotion;

By default, ease is set to easing.easeOut. When a function eases out, it means it starts fast and ends slow.

This was chosen as default because it's my belief that most animation in user interfaces should initiate as a result of a user's action. By starting fast and ending slow, the user will feel as if they imparted their energy, via their tap or click, directly into the interface. It feels snappy, alive, and responsive.

For many animations away from the user's input, or on their own, it can feel a little less jarring to use an animation that eases in, like easing.easeInOut or easing.anticipate, which does a playful tug before animating.

Finally, there's the easing.cubicBezier function, which creates a new easing function based on an easing curve, just like CSS transitions. This provides a massive degree of control and flexibility over your motion.

Try applying some of these to your animation while playing around with duration to see how it affects the feel and character of it.

Repeating

Animations can be repeated in three different ways: loop, yoyo, and flip.

Loop starts the animation from the start. Yoyo mirrors the tween by running it backwards. And flip runs it backwards andflips the easing function.

One of these can be set per tween, and each is set as a number that denotes the number of times to repeat the animation. To repeat forever, simply pass Infinity:

With this, we can create a scrubbable animation! In a later tutorial, we'll explore how to use Popmotion's pointer function to create a scrub bar, but for now you can scrub one tween with a second tween, to see this in action:

Because keyframes is just a tween, we can adjust its overall playback with all the same properties like ease and loop, and control it with all the same methods that we learned earlier.

Conclusion

The tween and keyframes functions allow you to create both simple and complex animations.

styler brings its own benefits, like usage outside of animations, standardisation of CSS and SVG transform models, and render batching for high animation performance.

In this tutorial, we've covered just a couple of the animations that Popmotion offers. In the next installment, we're going to explore pointer tracking and velocity-based animations like physics and spring.

Velocity-based animations can be used to create natural-feeling UIs that react realistically to a user's input. See you there!