Upload a static profile picture and walk away with an animated Matrix-style avatar that drips green glyphs. A live demo is here.
Quick start
- Pick a square photo—round crops look better.
- If the falling characters look off, tweak the tint until they match the vibe.
- Happy with the preview? Right-click → "Save image as…" or hit the download button.
gif.js in a nutshell
gif.js is a zero-dependency browser library that builds animated GIFs from canvas frames. It off-loads heavy pixel work to Web Workers so the UI stays snappy.
// bare-bones setup
const encoder = new GIF({
workers: 4,
quality: 20,
workerScript: './gif.worker.js' // mandatory for worker mode
});
// grab a frame
encoder.addFrame(canvas, { delay: 100 });
// repeat for every frame
for (let i = 0; i < totalFrames; i++) {
drawFrame(i);
encoder.addFrame(canvas, { delay: 100 });
}
encoder.on('finished', blob => {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'matrix-avatar.gif';
a.click();
});
encoder.render();
Matrix-rain logic
The glyph shower is a classic column drop. Each column has:
- a
headthat moves downward, - a
tailLengththat fades behind it, - a random chance too spawn a new head at the top.
const COLS = 32;
const ROWS = 32;
const FONT_SIZE = 12;
const glyphs = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
const columns = Array.from({ length: COLS }, () => ({
y: Math.random() * -ROWS,
speed: 1 + Math.random() * 3,
tail: 8 + Math.floor(Math.random() * 10)
}));
function drawFrame() {
ctx.fillStyle = 'rgba(0, 0, 0, 0.05)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.font = `${FONT_SIZE}px monospace`;
ctx.fillStyle = '#00ff41';
for (let x = 0; x < COLS; x++) {
const col = columns[x];
for (let i = 0; i < col.tail; i++) {
const y = col.y - i;
if (y >= 0 && y < ROWS) {
const char = glyphs[Math.floor(Math.random() * glyphs.length)];
ctx.fillText(char, x * FONT_SIZE, y * FONT_SIZE);
}
}
col.y += col.speed;
if (col.y - col.tail > ROWS) {
col.y = Math.random() * -col.tail;
col.speed = 1 + Math.random() * 3;
}
}
}
Overlaying the avatar
After each rain pass, compostie the user’s image on top with a soft-light blend so the face remains recognizable.
ctx.globalCompositeOperation = 'soft-light';
ctx.drawImage(userImage, 0, 0, canvas.width, canvas.height);
ctx.globalCompositeOperation = 'source-over';
Full source is on GitHub; open DevTools on the demo page for instant tinkering.