JSFiddle - React, Tailwind, and code Playground

by Josh Pullen

JavaScript

class JSONVideo {
	constructor(initialData) {
  	this.frames = [];
    this.duration = 0;
    
    if (typeof initialData === "object") {
    	this.insertFrame(0, initialData);
    }
  }

  insertFrame(time, data) {
  	if (time < 0) throw new Error("Cannot insert frame at time < 0");
    if (this.frames.some(frame => frame.time === time)) {
    	throw new Error("Frame at time already exists");
    }
    if (typeof data !== "object") {
    	throw new Error("Data must be JSON-serializable object");
    }

  	this.frames.push({ time, data });
    this.duration = Math.max(time, this.duration);
  }

  exportToString() {
  	const frames = this.frames.sort((a, b) => a.time - b.time);
    const metadata = {
    	version: "0.1.0",
      duration: this.duration
    }
    
    let str = `M ${JSON.stringify(metadata)}\n`;

		for (let i = 0; i < frames.length; i++) {
      let mode = this.frames[i].time === 0 ? "K" : "S";
      str += JSONVideo.encode(this.frames[i], this.frames[i - 1] || null, mode);
    	str += "\n";
    }

    return str;
  }

  static encode(frame, previousFrame, mode) {
  	switch (mode) {
    	case "K": {
      	// Keyframe
        return `K ${frame.time} ${JSON.stringify(frame.data)}`;
      }

      case "S": {
      	// Set
        let patchObj = {};
        for (const [key, value] of Object.entries(frame.data)) {
        	if (key in previousFrame.data) {
          	if (JSON.stringify(value) !== JSON.stringify(previousFrame.data[key])) {
            	patchObj[key] = value;
            }
          } else {
          	patchObj[key] = value;
          }
        }
        return `P ${frame.time} ${JSON.stringify(patchObj)}`;
      }

      case "P": {
        // TODO: Patch
        // Deeper diffing than replacing top-level values
        // Good for small changes deep in a tree
      }
    }
  }
  
  static encodeFrameGroup(frames) {
  	for ()
  }
}

const video = new JSONVideo({ a: 2, b: ["x", "y"] });
video.insertFrame(500, { a: 4, b: ["x", "y"]...