One of the first form to capture images that could display motion were the ‘Zoöpraxiscopes’ invented by the photographic pioneer William Ensign Lincoln in 1865. This invention would strap a series of slightly altering images (e.g. a walk-cycle of a horse) to the inside of a cylinder with viewing slids above them.


W.E. Lincoln’s U.S. Patent No. 64,117 of Apr. 23, 1867, Source: https://docs.google.com/viewer?url=patentimages.storage.googleapis.com/pdfs/US64117.pdf

A glance through the openings would reveal the image on the opposing side of the contraption, and, if rotated, it appeared as if the image were moving. This gave way to a commercially successful product that established the concept of selling moving images and, eventually, films and cinemas.

Why do we talk about this? Well, in my recent browsings on CodePen, I stumbled upon the work by Tamino Martinius, who uses a interpretation of this technique to create small, user-delighting animations like this one.

To create a sense of movement, he uses a pre-rendered set of images that are displayed in rapid succession.

Here is how you do it yourself.

The how


At first you need your source material. I turned to Adobe After Effects, but really any series of images will work. I’d suggest to keep the duration of the animation under one second in order to retain a small file size, also its easier if this source material is square. This method should be used for small, specific animations.

In the AE renderlist klick on “export module” to export your animation with the following settings:

  • Format: PNG Sequence
  • Channels: RGB + Alpha

The rendered images are the frames for the animation. I then used Photoshop to align them all in one really wide image, starting with the first frame on the left. Its height should be the equal to the final height of our animation on the webpage.


See, how we’re mimicking figure 4 of W.E. Lincoln’s original patent shown above? Now we just need to build our own ‘Zoöpraxiscope’ within the browser.

As always we have a really forgettable markup structure.

<div class="wrapper">
  <span class="icon"></span>

The wrapper’s only job is to align the icon in the center of the screen like so:

.wrapper {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
  width: 100vw;
  background-color: #31f7d6;

To make our code just a tiny bit more flexible, we introduce two css variables.

:root {
  --size: 100px;
  --frames: 60;

These two values, size and frames, are the height/width and the amount of images/frames of the animation respectively. If your animation isn’t square, you should have a separate value for the width.

The <span class="icon"></span> is the interesting bit. It resembles the “viewing slid” that only shows us one frame of the animation at the time.

.icon {
  width: var(--size);
  height: var(--size);
  background-image: url("/link/to/your/imagefile");
  background-size: calc(var(--size) * var(--frames)) var(--size);
  background-repeat: no-repeat;
  background-position-x: 0px;
  background-position-y: 0;

First, we are setting the width and height of our viewing slid to the size of our animation. We then set the background-image source to our prepared image and stretch it to its original size. We supply the background-size attribute with to values: the first one calc(var(--size) * var(--frames)) is the total width, calculated from the size of a single frame, multiplied by the total amount of frames. The second var(--size) simply resembles the total hight of our animation.

We set the background-repeat to no-repeat and display the first, most left frame of our animation with background-position-x: 0px. The top position is taken care of with background-position-y: 0;.

We then need some keyframes to move this background (or, if we’re staying with Lincoln, rotate the wheel).

@keyframes moveit {
  0% {
    background-position-x: 0;
  100% {
    background-position-x: calc(var(--size) * (var(--frames) * -1 + 1));

We start out on left side of our background-plane with again background-position-x: 0; at 0%. At 100% we should have moved the image-strip all the way to the left, showing the right most image. We calculate this position with background-position-x: calc(var(--size) * (var(--frames) * -1 + 1)); . How does this work? With var(--size) * (var(--frames) we get the total width of the background (like in the .icon class), we denn multiply it by - 1 because we’re moving the background to the left, into the negative values of the x-axis, thus we need a negative number. The + 1 is needed, because we will set the animation to play forwards, to have it end on the last frame. If we wouldn’t do this, we’d get a blank image.

Are you still keeping up? We’re close!

At last, we have to put the animation to work as we add it to the DOM-element.

.icon {
  animation: moveit 1s steps(calc(var(--frames) - 1)) forwards;

Our animation attribute is equipped with the following: the name of the keyframes, the time it takes to play the animation (you can play around with this one, the browser will sort out the frames), and finally the two important ones: the timing-function and the fill-mode.

For the first we choose the steps-function because we don’t want the browser to interpolate the animation, we’re supplying the steps that the animations is jumping to (i.e. the frames on our background image). We calculate this with our total amount of frames - 1, the offset from the keyframes 100%-step.

To animate it onClick, you can bind this animation to a class and apply it via JS. Visit my CodePen on how to do this.

And there you have it!

The benefits

With this kind of animation the possibilities and style-opportunities are endless. What you can come up with, you can depict. Draw up some oldshool-animations like Disney and use them, animate a comic strip or bring your After Effects prowess to the web! This kind of animation can really enhance the User-Experience on your site!

The downsides

Should you use this for all of your animations? No. There are way more sophisticated ways of animation on the web out there and for page-filling, center-piece animations you should make use of Lottie or other tools. After all, with this technique your user has to download a every frame of the animation without even starting it. Depending on the image size and length of the animation, the download-size can skyrocket.

Additionally, the scalability of the animation isn’t great as we deal with rasterized images.

The end

As with everything in webdev, this is only one tool of many that you can use when applicable.

Thanks again to Tamino Martinius for doing all the work, especially the hard part (i.e. the math)!

You can find the code at CodePen and fork your own copy of it! Hit me up with your own work on twitter.com/eliasguenther, I’d love to see what you come up with! Have a good one!

CodePen Embed

Klick below to show the CodePen as an embed. CodePen will set set several Cookies in your Browser.

CodePen.io Privacy Policy

The creation of this post was made possible by coffee.
Buy me a coffee