Matrix Webcam Effect
by Scott Kaye
HTML
<canvas></canvas>
<video autoplay></video>
CSS
canvas {
width: calc(532px * 1.25);
height: calc(400px * 1.25);
box-shadow: 0 0 10px -2px #0f0;
border: 1px solid #090;
}
html, body {
height: 100%;
}
body {
background: #000;
margin: 0;
display: flex;
align-items: center;
justify-content: center;
}
video {
display: none;
}
JavaScript
const CRUSH = 0; // float from 0 to 1
const SIZE = 12; // Size of falling glyphs
const canvas = document.querySelector("canvas");
const video = document.querySelector("video");
const size = canvas.getBoundingClientRect();
canvas.width = size.width;
canvas.height = size.height;
const videoCanvas = canvas.cloneNode();
videoCanvas.style.display = "none";
canvas.parentNode.insertBefore(videoCanvas, canvas);
const context = canvas.getContext("2d");
const videoContext = videoCanvas.getContext("2d");
videoContext.translate(canvas.width, 0);
videoContext.scale(-1, 1);
const points = [];
let rows = canvas.height / SIZE;
let cols = canvas.width / SIZE;
for (let x = 0; x < cols; ++x) {
let speed = rand(0.8, 1.2);
for (let y = 0; y < rows + 2; ++y) {
let char = randomChar();
points.push({
x: x * SIZE,
y: y * SIZE,
speed,
char
});
}
}
function randomChar() {
return String.fromCharCode(rand(12000, 12500));
}
context.font = SIZE + "px sans-serif";
function rand(min, max) {
return Math.random() * (max - min + 1) + min;
}
function draw() {
context.fillStyle = "#000";
context.fillRect(0, 0, canvas.width, canvas.height);
videoContext.drawImage(video, 0, 0, canvas.width, canvas.height);
let i, l;
for (i = 0, l = points.length; i < l; ++i) {
var color = videoContext.getImageData(points[i].x, points[i].y, 1, 1);
var luma = (color.data[0] * 0.2126 + color.data[1] * 0.7152 + color.data[2] * 0.0722) / 255;
luma = posterize(luma, CRUSH);
context.fillStyle = "rgba(0, 255, 0, " + luma + ")";
context.fillText(points[i].char, points[i].x, points[i].y);
points[i].y += points[i].speed;
if (points[i].y > canvas.height + SIZE) {
points[i].y = SIZE * -1;
}
if (Math.random() < 0.005) {
points[i].char = randomChar();
}
}
requestAnimationFrame(draw);
}
draw();
function posterize(src, level) {
return level ? Math.round(src / level) * level : src;
}
if...