async function manipulate(videoTrack, fn) { let canvas = document.createElement("canvas"); let running = true; const ctx = canvas.getContext("2d"); let video = document.createElement("video"); video.setAttribute("autoplay", true); video.setAttribute("muted", true); video.srcObject = createStream(videoTrack); videoTrack.addEventListener("ended", () => { running = false; }); await new Promise((res) => video.addEventListener("play", res)); function animate() { const { width, height } = videoTrack.getSettings(); Object.assign(canvas, { width, height, }); ctx.drawImage(video, 0, 0, canvas.width, canvas.height); // Recursively loop const frame = ctx.getImageData(0, 0, canvas.width, canvas.height); const length = frame.data.length; let data = frame.data; for (let i = 0; i < length; i += 4) { let o = fn({ red: data[i], g: data[i + 1], green: data[i + 1], blue: data[i + 2], alpha: data[i + 3], }); data[i] = o.red; data[i + 1] = o.green; data[i + 2] = o.blue; data[i + 3] = o.alpha; } ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.putImageData(frame, 0, 0); if (running) { requestAnimationFrame(animate); } } requestAnimationFrame(animate); let track = get("video", canvas.captureStream(30)); track.addEventListener("ended", () => { running = false; }) }
Preview:
downloadDownload PNG
downloadDownload JPEG
downloadDownload SVG
Tip: You can change the style, width & colours of the snippet with the inspect tool before clicking Download!
Click to optimize width for Twitter