Animated GIFs From p5.js

After my first few days getting into creative coding / compform, I reached a point where I wanted to share some animations I created. The problem was that I didn’t know how to get an animated gif.

The sketches on p5.js (editor) are all rendered in an HTML canvas element. It’s easy enough to get a static image (just right click and save), but there’s no out-of-the-box way to save an animation.

Searching lead me to CCapture.js, but I wasn’t able to get this to work. One of the open issues suggests that this library no longer works with current versions of the p5.js library/editor.

CCapture.js actually uses gif.js under the hood. This was a lot simpler to use. Here’s what you need to do.

Guide

These steps assume you’re using the default layout given from editor.p5js.org. Specifically, we’re updating index.html and sketch.js.

Also, make sure you’re working from a saved sketch. You want your url to be something like https://editor.p5js.org/vple/sketches/gTK85f8He, not https://editor.p5js.org/. This matters since we’re going to be using a relative path later.

Configure Resources

There are two main files we’ll need: gif.js and gif.worker.js.

gif.js

The first one we can add via jsDelivr. In index.html, add this somewhere in your head:

<script src="https://cdn.jsdelivr.net/gh/jnordberg/gif.js/dist/gif.js"></script>

This defines GIF, which is what our code will use to build and render its animated gif.

gif.worker.js

gif.js needs gif.worker.js, so we’ll have to provide that. This looks like it’s fetched dynamically, so CORS blocks us from using jsDelivr again.

First, download gif.worker.js.

Then upload this file into the p5 editor. There’s a dropdown in the directory, next to “Sketch Files”, that you can use to upload a file. Or, create an empty file and copy/paste.

Once you’ve done this, you should see gif.worker.js in your sketch files.

Configure Encoder

Now that the encoder’s available to us, let’s set it up.

Constants

I recommend setting up a few constants to make later steps slightly easier. These aren’t necessary, but are probably helpful if you’re just creating simple/short gifs.

If you don’t already have a variable that defines the frame rate, create one! This should be the same value that you use to configure p5’s frame rate.

const FPS = 30;

function setup() {
  frameRate(FPS);
  // ...
}

Next, some constants to control the encoder itself:

const
  CREATE_GIF = true,
  RECORD_FRAMES = FPS * 5;

CREATE_GIF allows us to toggle whether or not we want to generate a gif. RECORD_FRAMES is the number of frames that we want to capture in our gif. In this example, we’re going to get a 5 second gif.

Encoder

Next, we define the encoder. I added this snippet somewhere before setup():

if (CREATE_GIF) {
  var gif = new GIF({
    debug: true,
    quality: 0,
    workerScript: "./gif.worker.js"
  });
  gif.on('finished', function(blob) {
    window.open(URL.createObjectURL(blob));
  });
}

You can find a full list of options here.

Make sure the workerScript path is correct—this is relative to the top level “Sketch Files” directory.

The second part of this snippet (gif.on) describes what to do once we’re done rendering our gif. In this case, we open it up in a new window.

GIF Creation

We now have our encoder ready! Add this snippet to the bottom of draw():

if (CREATE_GIF) {
  if (frameCount <= RECORD_FRAMES) {
    gif.addFrame(canvas, {
      delay: 1000 / FPS,
      copy: true
    });
  }

  if (frameCount == RECORD_FRAMES) {
    gif.render();
  }
}

gif.addFrame adds a frame to the gif we’re going to create. Conveniently, it takes our canvas element.

The options affect how the encoder adds the frame to the final gif. Empirically, using copy seems to be faster.

delay specifies how many milliseconds the frame should show for. Setting it to 1000 / FPS will have our final gif animate at the same rate as the animation in p5.js.

You can tweak this to do some neat stuff—you can scale the delay up/down to slow down/speed up your animation. Especially helpful if it takes a while for you to draw each frame—you can use this to speed up the final gif.

Run It!

We’re all set, so now you just need to run your code. If it’s working, you should see a new window pop up with your gif! You can then right click and save it.