Search code examples
javascriptvideoprocessingp5.js

Exporting a video in p5.js


I am creating a simple animation program in p5.js. When a user clicks the save button, I want to download a video of the animation.

I have an object called frames where each key is labelled frame_1, frame_2 and so on. The value associated with each key is an array of line segments that makes up that frame.

I am trying to think of an approach to take this data and create an mp4 video. p5.js has a built in save function that I thought might be helpful but it is not a full solution on its own. I could save each frame as an individual image and then somehow stitch those images together on the client side but I have yet to find a solution to this.

Any other approaches would be great as well. The only requirement is that it is done client side.


Solution

  • Since p5.js is built on the Canvas API, in modern browsers, you can use a MediaRecorder to do this job.

    const btn = document.querySelector('button'),
      chunks = [];
    
    function record() {
      chunks.length = 0;
      let stream = document.querySelector('canvas').captureStream(30),
        recorder = new MediaRecorder(stream);
      recorder.ondataavailable = e => {
        if (e.data.size) {
          chunks.push(e.data);
        }
      };
      recorder.onstop = exportVideo;
      btn.onclick = e => {
        recorder.stop();
        btn.textContent = 'start recording';
        btn.onclick = record;
      };
      recorder.start();
      btn.textContent = 'stop recording';
    }
    
    function exportVideo(e) {
      var blob = new Blob(chunks);
      var vid = document.createElement('video');
      vid.id = 'recorded'
      vid.controls = true;
      vid.src = URL.createObjectURL(blob);
      document.body.appendChild(vid);
      vid.play();
    }
    btn.onclick = record;
    
    // taken from pr.js docs
    var x, y;
    
    function setup() {
      createCanvas(300, 200);
      // Starts in the middle
      x = width / 2;
      y = height;
    }
    
    function draw() {
      background(200);
    
      // Draw a circle
      stroke(50);
      fill(100);
      ellipse(x, y, 24, 24);
    
      // Jiggling randomly on the horizontal axis
      x = x + random(-1, 1);
      // Moving up at a constant speed
      y = y - 1;
    
      // Reset to the bottom
      if (y < 0) {
        y = height;
      }
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.7/p5.min.js"></script>
    <button>start recording</button><br>