# How to save your p5.js sketch as a GIF using CCapture.js

**URL:** <https://discourse.processing.org/t/how-to-save-your-p5-js-sketch-as-a-gif-using-ccapture-js/1264>\
**Category:** Libraries\
**Created:** [June 25, 2018, 11:57pm UTC](https://discourse.processing.org/t/how-to-save-your-p5-js-sketch-as-a-gif-using-ccapture-js/1264 "2018-06-25T23:57:57Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![okliis](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/okliis/32/459_2.png) [@okliis](https://discourse.processing.org/u/okliis)\
**Post date:** [June 25, 2018, 11:57pm UTC](https://discourse.processing.org/t/how-to-save-your-p5-js-sketch-as-a-gif-using-ccapture-js/1264/1 "2018-06-25T23:57:57Z")

</div>

Hello everyone,

I recently figured out how to save my canvas as a GIF using Ccapture.js - something I’ve been trying to do since I started using p5.js a few months ago - so I made a video on how to get it working with a simple sketch:

[![](https://img.youtube.com/vi/xmV-JvvMFQ8/hqdefault.jpg "How to save your p5.js sketch as a GIF file using CCapture.js") ](https://www.youtube.com/watch?v=xmV-JvvMFQ8)

I got the code from [here](https://qiita.com/aa_debdeb/items/99be7a21eedba8f44981), text is in Japanese but code is pretty self explanatory - so if you’re in a hurry and more experienced, check it out.

It took me forever to find the above link so I thought I’d show other beginners like me looking to share their sketches as GIFs how to get it working and post it on the official forum for better visibility.

I’m sure I got something wrong in the video, but it works.  
Please feel free to correct me or add anything else in the comments for I am but a n00b.

P.S. If you’re watching the video from in here, here a note I left in the YouTube comments:

"\*\* For clarity:  
One draw() loop counts as 1 frame so -

In our IF statement:  
we are essentially capturing a frame of canvas at the end of every loop of draw() until we have reached the amount of frames we set in ‘var gifLength’, in our case 180 frames. When 180 frames have passed (aka 3 seconds @ 60 fps), stop capturing and save as a .gif file.﻿"

Hope this helps!

Cheers,  
Mike

---

<div class="post-metadata">

**Author:** ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)\
**Post date:** [June 26, 2018, 8:50am UTC](https://discourse.processing.org/t/how-to-save-your-p5-js-sketch-as-a-gif-using-ccapture-js/1264/2 "2018-06-26T08:50:48Z")

</div>

I’ve managed to host a CCapture demo sketch online: 🤩  
[https://ThimbleProjects.org/gotoloop/509340](https://ThimbleProjects.org/gotoloop/509340)  
[https://ThimbleProjects.org/gotoloop/509340/sketch.js](https://ThimbleProjects.org/gotoloop/509340/sketch.js)

Important note: the CCapture library demands the file “gif.worker.js” in order to save all of the **capture()** canvas frames as a “.gif” file! You can grab 1 at the link below: 🤖  
[http://cdn.JsDelivr.net/npm/gif.js/dist/gif.worker.js](http://cdn.JsDelivr.net/npm/gif.js/dist/gif.worker.js)

## “index.html”:

```auto
<!DOCTYPE html>

<meta charset=utf-8>
<meta name=viewport content=width=device-width,initial-scale=1>

<script defer src=https://cdn.JsDelivr.net/npm/ccapture.js></script>

<script defer src=https://cdn.JsDelivr.net/npm/p5></script>
<!--<script defer src=https://cdn.JsDelivr.net/npm/p5/lib/addons/p5.dom.min.js></script>-->
<!--<script defer src=https://cdn.JsDelivr.net/npm/p5/lib/addons/p5.sound.min.js></script>-->

<script defer src=sketch.js></script>

```

## “sketch.js”:

```auto
/**
 * CCapture Bouncing Colorful Balls Demo (v1.0)
 * GoToLoop (2018-Jun-26)
 *
 * https://Discourse.Processing.org/t/
 * how-to-save-your-p5-js-sketch-as-a-gif-using-ccapture-js/1264/2
 *
 * https://ThimbleProjects.org/gotoloop/509340
 * http://CodePen.io/GoSubRoutine/pen/KaerGb/right/?editors=101
 *
 * Get the "gif.worker.js" file from:
 * http://cdn.JsDelivr.net/npm/gif.js/dist/gif.worker.js
 */

"use strict";

const NUM = 15, balls = Array(NUM),

      FORMAT = 'gif', WORKERSFOLDER = './',
      VERBOSE = false, DISPLAY = true,
      FPS = 60, FRAMERATE = FPS, FRAMELIMIT = 5 * FPS,

      capturer = new CCapture({
        format: FORMAT, workersPath: WORKERSFOLDER,
        verbose: VERBOSE, display: DISPLAY,
        framerate: FRAMERATE, frameLimit: FRAMELIMIT
      });

let bg;

function setup() {
  createCanvas(400, 400).mousePressed(restart);
  frameRate(FPS).noStroke();

  bg = color(random(0xd0, 0x100), random(0xd0, 0x100), random(0xd0, 0x100));
  for (let i = 0; i < NUM; balls[i++] = new Ball);

  capturer.start();
  console.table(capturer);
}

function draw() {
  background(bg);
  for (const b of balls) b.display().update();
  capturer.capture(canvas);
}

function restart() {
  bg = color(random(0xd0, 0o400), random(0xd0, 0o400), random(0xd0, 0o400));
  for (const b of balls) b.initBall();
}

class Ball {
  static get VEL() { delete this.VEL; return this.VEL = 2; }
  static get MIN_RAD() { delete this.MIN_RAD; return this.MIN_RAD = 5; }
  static get MAX_RAD() { delete this.MAX_RAD; return this.MAX_RAD = 30; }

  constructor() {
    this.pos = createVector(), this.vel = createVector();
    this.initBall();
  }

  initBall() {
    const r = this.rad = random(Ball.MIN_RAD, Ball.MAX_RAD), v = Ball.VEL;
    this.pos.set(random(r, width - r), random(r, height - r));
    this.vel.set(random(-v, v), random(-v, v));
    this.c = color('#' + hex(~~random(0x1000), 3));
    return this;
  }

  update() {
    const { pos, rad } = this;
    pos.add(this.vel);
    pos.x > width - rad | pos.x < rad && (this.vel.x *= -1);
    pos.y > height - rad | pos.y < rad && (this.vel.y *= -1);
    return this;
  }

  display() {
    fill(this.c).ellipse(this.pos.x, this.pos.y, this.rad<<1);
    return this;
  }
}

```

---

<div class="post-metadata">

**Author:** ![kfrajer](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/kfrajer/32/196_2.png) [@kfrajer](https://discourse.processing.org/u/kfrajer)\
**Post date:** [June 26, 2018, 6:26pm UTC](https://discourse.processing.org/t/how-to-save-your-p5-js-sketch-as-a-gif-using-ccapture-js/1264/3 "2018-06-26T18:26:10Z")

</div>

> [@GoToLoop](#):
>
> the CCapture library demands the file “gif.worker.js” in order to save all of the **capture()** canvas

@GoToLoop How do you use this `gif.worker.js`. I didn’t see it in your sketch.js. How do you make it available in your code?

Kf

---

<div class="post-metadata">

**Author:** ![okliis](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/okliis/32/459_2.png) [@okliis](https://discourse.processing.org/u/okliis)\
**Post date:** [June 26, 2018, 6:54pm UTC](https://discourse.processing.org/t/how-to-save-your-p5-js-sketch-as-a-gif-using-ccapture-js/1264/5 "2018-06-26T18:54:25Z")

</div>

Put the gif.worker.js in a folder within your project folder and then refer to that folder in the CCapture constructor.  
i.e.  
Lets say the folder you put the gif.worker.js in is called ‘worker’ - in that case the constructor should look like this at the workersPath parameter: (its all in my video 🙂 )

```auto
      capturer = new CCapture({
        format: 'gif', 
        workersPath: './worker',
        verbose: true,
        framerate: 60 

      });

```

---

<div class="post-metadata">

**Author:** ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)\
**Post date:** [June 26, 2018, 7:10pm UTC](https://discourse.processing.org/t/how-to-save-your-p5-js-sketch-as-a-gif-using-ccapture-js/1264/6 "2018-06-26T19:10:07Z")

</div>

> [@kfrajer](#):
>
> How do you use this “gif.worker.js”? I didn’t see it in your “sketch.js”.

There are 3 files I’ve hosted at [https://ThimbleProjects.org/gotoloop/509340:](https://ThimbleProjects.org/gotoloop/509340:) 😸

1. [https://ThimbleProjects.org/gotoloop/509340/index.html](https://ThimbleProjects.org/gotoloop/509340/index.html)
2. [https://ThimbleProjects.org/gotoloop/509340/sketch.js](https://ThimbleProjects.org/gotoloop/509340/sketch.js)
3. [https://ThimbleProjects.org/gotoloop/509340/gif.worker.js](https://ThimbleProjects.org/gotoloop/509340/gif.worker.js)

All 3 inside the root folder “509340/”. 🕶

---

<div class="post-metadata">

**Author:** ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)\
**Post date:** [October 19, 2019, 8:37pm UTC](https://discourse.processing.org/t/how-to-save-your-p5-js-sketch-as-a-gif-using-ccapture-js/1264/7 "2019-10-19T20:37:43Z")

</div>

> **[Thimble by Mozilla - An online code editor for learners & educators.](https://thimble.mozilla.org/en-US/)**
>
> Thimble is an online code editor that makes it easy to create and publish your own web pages while learning HTML, CSS & JavaScript.

Thimble site is retiring on 2019/Dec/16. So all links won’t work after that! 😞

All my sketches from Thimble are hosted at Glitch now: 🐟

> **[Thimble](https://glitch.com/@GoSubRoutine/thimble)**
>
> https://Thimble.Mozilla.org 🎏 A collection of apps by @GoSubRoutine

And my CCapture.js demo sketch is more precisely here: 📹

> **[ccapture-bouncing-colorful-balls-demo](https://Glitch.com/~ccapture-bouncing-colorful-balls-demo)**
>
> Check out ~ccapture-bouncing-colorful-balls-demo on Glitch, the friendly community where everyone can discover & create the best apps on the web.

---

<div class="post-metadata">

**Author:** ![adda](https://avatars.discourse-cdn.com/v4/letter/a/f17d59/32.png) [@adda](https://discourse.processing.org/u/adda)\
**Post date:** [January 13, 2022, 6:58pm UTC](https://discourse.processing.org/t/how-to-save-your-p5-js-sketch-as-a-gif-using-ccapture-js/1264/8 "2022-01-13T18:58:15Z")

</div>

Hi, Thanks for the tutorial.  
I am using CCapture, but I’m putting my draw code in a module so I have to instantiate p5 object

I used the versbous option, so I know the capturere starts, but once it’s called, my draw function won’t be invoked any more.

var canvas

// capturer.start();

let sketch = new p5(function(p5){

```
let p0, p1, p2;

p5.setup = function() {

        p5.capturer = new CCapture( { format: 'gif', workersPath: './js/', verbose: true } );

        capturer.start()
```

---

<div class="post-metadata">

**Author:** ![Metamoar](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/metamoar/32/15778_2.png) [@Metamoar](https://discourse.processing.org/u/Metamoar)\
**Post date:** [January 15, 2022, 11:26pm UTC](https://discourse.processing.org/t/how-to-save-your-p5-js-sketch-as-a-gif-using-ccapture-js/1264/10 "2022-01-15T23:26:51Z")

</div>

Whoops I deleted my post 😅 The way I’ve always done it was to put my capturer.start() in my draw:

```auto
function draw () {
  // Start recording
  if (!capturer.__isRecording) {
    capturer.__isRecording = true
    capturer.start()
  }

  // Draw things

  // Capture the frame
  capturer.capture(canvas)
}

```
