ABeamer: a Frame-by-Frame Animation Framework

Avatar of Alexandre Bento Freire
Alexandre Bento Freire on (Updated on )

In a recent post, Zach Saucier demonstrated the awesome things that the DOM allows us to do, thanks to the <canvas> element. Taking a snapshot of an element and manipulating it to create an exploding animation is pretty slick and a perfect example of how far complex animations have come in the last few years.

ABeamer is a new animation ecosystem that takes advantage of these new concepts. At the core of the ecosystem is the web browser animation library. But, it’s not just another animation engine. ABeamer is designed to build frame-by-frame animations in the web browser and use a render server to generate a PNG file sequence, which can ultimately be used to create an animated GIF or imported into a video editor.

First, a little about what ABeamer can do

A key feature is its ability to hook into remote sources. This allows us to build an animation by using the web browser and “beam” it to the cloud to be remotely rendered—hence the name “ABeamer.”

ABeamer doesn’t only distinguish itself from other animation frameworks by its capacity to render elements in a file sequence, but it also includes a rich and extensible toolset that is still growing, avoiding the need to constantly rewrite common animations.

ABeamer’s frame-by-frame design allows it to create overlays without dropping frames. (Demo)

The purpose isn’t to be another Velocity or similar real-time web browser animation library, but to use the web technologies that have become mainstream and allow us to create pure animations, image overlays and video edits from the browser.

I have plans to create an interface for ABeamer that acts as an animation editor. This will abstract the need to write code, making the technology accessible to folks at places like ad networks and e-commerce companies who might want to provide their customers a simple tool to build rich, animated content instead of static images for ad placements. It can create titles, filter effects, transitions, and ultimately build videos directly from image slideshows without having to install any software.

In other words, taking advantage of all these effects and features will require no coding skills whatsoever, which opens this up to new use cases and a wider audience.

Create animated GIFs like this out of images. (Demo)

But if JavaScript is used, what about security? ABeamer has two modes of server rendering: one for trusted environments such as company intranets that renders the HTML/CSS/JavaScript as it was built by sending the files; and another for untrusted environments such as cloud render servers that renders teleported stories by sending them by AJAX along with the assets. Teleportation sanitizes the content both on the client side and the server side. The JavaScript that is used during interpolation process is not allowed, nor is any plug-in that isn’t on an authorization list. ABeamer supports expressions, which are safe, teleportable, and in many cases, it can replace the need of JavaScript code.

Example of an advertisement made with ABeamer (Demo)

The last key feature is decoupling. ABeamer doesn’t operate directly with the document DOM, but instead uses adapters as a middleman, allowing us to animate SVG, canvas, WebGL, or any other virtual element.

Several examples of the chart animations built into ABeamer. (Demo)

Getting started with ABeamer

Now that we’ve covered a lot of ground for what ABeamer is capable of doing, let’s dive into what it takes to get up and running with it.


The ABeamer animation library can be downloaded or cloned on GitHub, but in order to generate animated GIFs, movies, or simplify the process of getting started, you’ll want to install it with npm:

# 1. install nodejs: https://www.nodejs.org

# 2. install abeamer
$ npm install -g abeamer

# 2. learn how to configure puppeteer to use chrome instead of chromium
$ abeamer check

# 3. install a render server (requires chrome web browser) 
$ npm install -g puppeteer

# 4. install imagemagick: https://www.imagemagick.org

# 5. install ffmpeg: https://www.ffmpeg.org/

Puppeteer is installed separately, since other server renders are also supported, like PhantomJS. Still, Puppeteer running on Chrome will produce the best results.

Spinning up a new project

The best way to get started it’s to use the ABeamer CLI to create a new project:

abeamer create my-project --width 640 --height 480

This will create a project with the following files:

  • abeamer.ini – Change this file to modify the frame dimensions and recompile main.scss. This file will be used by the server render and main.scss.
$abeamer-width: 640;
$abeamer-height: 480;
  • css/main.scss – CSS can also be used instead of SCSS, but it requires to change the dimensions in two places.
@import "./../abeamer.ini";

.abeamer-scene {
  width: $abeamer-width + px;
  height: $abeamer-height + px;

#hello {
  position: absolute;
  color: red;
  left: 50px;
  top: 40px;

ABeamer content is defined inside a story, much like a theater play. Each story can have multiple scenes.

  • index.html – This is inside a scene where the animation happens:
<div class="abeamer-story" id=story>
  <div class="abeamer-scene" id=scene1>
    <div id=hello>Hello
      <span id=world>World</span>
$(window).on("load", () => {
  const story: ABeamer.Story = ABeamer.createStory(/*FPS:*/25);
  const scene1 = story.scenes[0];
    selector: '#hello',
    duration: '2s',
    props: [{
      // pixel property animation.
      // uses CSS property `left` to determine the start value.
      prop: 'left',
      // this is the end value. it must be numeric.
      value: 100,
      // formatted numerical property animation.
      prop: 'transform',
      valueFormat: 'rotate(%fdeg)',
      // this is the start value,
      // it must be always defined for the property `transform`.
      valueStart: 10,
      // this is the end value. it must be numeric.
      value: 100,
  }, {
    selector: '#world',
    duration: '2s',
    props: [{
      // textual property animation.
      prop: 'text',
      valueText: ['World', 'Mars', 'Jupiter'],

Live Demo

You may notice some differences between ABeamer and other web animation libraries:

  • ABeamer uses load instead of a ready event. This is due the fact that the app was designed to generate frame files, and unlike real-time animation, it requires all assets to be loaded before the process begins.
  • It sets FPS. Every state change in the CSS or DOM will fall into a specific frame. Think of it the way movie editors operate on a frame-by-frame basis. This way, when it renders to a file sequence, it guarantees that each file will represent a frame and that it is independent from the time it takes to render.
  • addAnimations doesn’t trigger an animation like other web animation libraries. Instead it builds the animation pipeline for each frame. This method is more verbose than other libraries but it benefits from allowing the same infrastructure to animate CSS/DOM elements, SVG, canvas and WebGL.
  • addAnimations can also animate text, colors and images — not only position, but rotation and scale as well.
  • render will start the rendering process. In case there is client rendering, it will simulate run-time. But if it’s server rendering, ABeamer will render at full-speed.

To test this animation, go ahead and open the index.html in your web browser.

Server Rendering

Now that we have an animation project created, we want to generate PNG file sequences, animated GIFs, and movies without frame drops. The process couldn’t be more simpler:

# 1. generate PNG file sequence
# assuming that you are in the parent directory
$ abeamer render my-project

# 2. generate animated gif (requires the PNG file sequence)
$ abeamer gif my-project

# 3. generate movie (requires the PNG file sequence)
$ abeamer movie my-project

The previous commands will place the resulting files in the project/story-frames.

Handling CORS

In the previous example, the project didn’t require loading any JSON, so it can be executed as a local file. But due CORS, if it required to load a JSON, it needs a live server.

To solve this, ABeamer has included a live server. Spin it up with this:

# 1. runs a live server on port 9000
$ abeamer serve

This will assign your project to: http://localhost:9000/my-project/

The render command then becomes:

$ abeamer render my-project --url http://localhost:9000/my-project/

Cloud Rendering

At the moment, there is no third-party cloud rendering. But as the project gains traction, I’m hoping that cloud companies see the potential and provide it as a service in the same manner as Google provides computation of Big Data that server farms can use as cloud render servers.

The benefits of cloud rendering would be huge:

  • It wouldn’t require any software installation on the client machine. Instead, it can all be done on the web browser. While there is currently no ABeamer UI, online code editors can be used, like CodePen.
  • Heavy render processes could be designed in a client machine and then sent to be rendered in the cloud.
  • Hybrid apps would be able to use ABeamer to build animations and then send them to the cloud to generate movies or animated GIFs on demand.

That said, cloud rendering is more restrictive than the server render since it doesn’t send the files, but rather a sanitized version of the story:

  • Interactive JavaScript code isn’t allowed, so case expressions are required
  • All animations are sanitized.
  • The animation can only use plugins that are allowed by the cloud server provider.

Setting up a cloud render server

If you are working in an environment where installing software locally isn’t allowed, or you have multiple users building animations, then it might be worth setting your own cloud render server.

Due to CORS, an animation must either be in a remote URL or have a live server in order to be sent to the cloud server.

The process of preparing, sending, and rebuilding on remote server side it is called teleportation. Animations requires changes to be teleported:

$(window).on("load", () => {
  const story: ABeamer.Story = ABeamer.createStory(/*FPS:*/25, { toTeleport: true });
  // the rest of the animation code
  // ....

  const storyToTeleport = story.getStoryToTeleportAsConfig();
  // render is no longer needed
  // story.render(story.bestPlaySpeed());

By setting toTeleport=true, ABeamer starts recording every animation in a way that it can be sent to the server. The storyToTeleport method will hold an object containing the animations, CSS, HTML and metadata. You need to send this by AJAX along with the required assets to the cloud.

On the server side, a web server will receive the data and the assets and it will execute ABeamer to generate the resulting files.

To prepare the server:

  • Create a simple project named remote-server using the command abeamer create remote-server.
  • Download the latest remote server code, extract the files, and override them with the ones existing in remote-server.
  • Save the received object from AJAX as remote-server/story.json and save all assets in the project.
  • Start a live server as you normally would using the abeamer serve command.
  • Render the teleported story:
abeamer render \
--url http://localhost:9000/remote-server/ \
--allowed-plugins remote-server/.allowed-plugins.json \
--inject-page remote-server/index.html \
--config remote-server/story.json

This will generate the PNG file sequence of the teleported story. For GIFs and movies you can run the same commands as before:

$ abeamer gif remote-server
$ abeamer movie remote-server

For more details, here’s the full documentation for the ABeamer teleporter.

Happy animating!

Hopefully this post gives you a good understanding of ABeamer, what it can do, and how to use it. The ability to use new animation techniques and render the results as images opens up a lot of possibilities, from commercial uses to making your own GIF generator and lots of things in between.

If you have any questions at all or have trouble setting up, leave a comment. In the meantime, enjoy exploring! I’d love to see how you put ABeamer to use.