Creating the Matrix Rain Effect with JavaScript

The Matrix movie trilogy has left a lasting impression on pop culture, particularly with its iconic “digital rain” effect. This effect, representing the flowing green code of the Matrix’s virtual reality, has been replicated countless times. Today, we’ll delve into a JavaScript code snippet that recreates this captivating visual.

The Complete Code

function loadMatrixFont() {
const link = document.createElement('link');
link.href = "https://fonts.cdnfonts.com/css/matrix-code-nfi";
link.rel = "stylesheet";
document.head.appendChild(link);
}

function isFontLoaded(fontName) {
const testString = "abcdefghijklmnopqrstuvwxyz0123456789";
const testSize = "72px";
const testElement = document.createElement("span");
testElement.style.fontSize = testSize;
testElement.style.position = "absolute";
testElement.style.left = "-9999px";
testElement.style.visibility = "hidden";
testElement.style.fontFamily = "sans-serif";
testElement.innerText = testString;
document.body.appendChild(testElement);

const defaultWidth = testElement.offsetWidth;
const defaultHeight = testElement.offsetHeight;

testElement.style.fontFamily = fontName + ", sans-serif";
const newWidth = testElement.offsetWidth;
const newHeight = testElement.offsetHeight;

document.body.removeChild(testElement);

return defaultWidth !== newWidth || defaultHeight !== newHeight;
}

function waitForFontLoad(fontName, callback) {
const interval = setInterval(() => {
if (isFontLoaded(fontName)) {
clearInterval(interval);
callback();
}
}, 100);
}

function startMatrixEffect() {
loadMatrixFont(); // Load the Matrix font dynamically

waitForFontLoad("Matrix Code NFI", () => {
const slideLayer = document.querySelector('.slide-layer.base-layer.shown');

if (!slideLayer) {
console.error("Element with class 'slide-layer base-layer shown' not found.");
return;
}

const textStrip = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm'];
const stripCount = 100; // Increased density
const stripElements = [];
const stripY = new Array(stripCount).fill(-100);
const dY = Array.from({ length: stripCount }, () => Math.floor(Math.random() * 5) + 2);
const theColors = ['#cefbe4', '#81ec72', '#5cd646', '#54d13c', '#4ccc32', '#43c728'];

for (let i = 0; i < stripCount; i++) {
const strip = document.createElement('div');
strip.style.position = 'absolute';
strip.style.left = `${Math.floor(Math.random() * (slideLayer.clientWidth - 20))}px`;

// Adjust font size range here
strip.style.fontSize = `${Math.floor(Math.random() * 20) + 16}px`;
strip.style.zIndex = 9999; // Ensure it's above everything else
strip.style.fontFamily = "'Matrix Code NFI', sans-serif"; // Use the Matrix font
strip.style.color = theColors[0];
strip.innerText = textStrip[Math.floor(Math.random() * textStrip.length)];
slideLayer.appendChild(strip);
stripElements.push(strip);
}

function draw() {
for (let j = 0; j < stripCount; j++) {
if (stripY[j] > slideLayer.clientHeight) {
stripElements[j].style.left = `${Math.floor(Math.random() * (slideLayer.clientWidth - 20))}px`;
stripY[j] = -100;
dY[j] = Math.floor(Math.random() * 5) + 2;
}

stripY[j] += dY[j];
stripElements[j].style.top = `${stripY[j]}px`;

if (Math.random() > 0.9) {
stripElements[j].innerText = textStrip[Math.floor(Math.random() * textStrip.length)];
stripElements[j].style.color = theColors[Math.floor(Math.random() * theColors.length)];
}
}

requestAnimationFrame(draw);
}

draw();
});
}

startMatrixEffect();

Understanding the Code

Let’s break down the JavaScript code step-by-step to understand how it conjures up this Matrix-inspired spectacle.

1. Loading the Matrix Font

The code kicks off by loading the distinctive Matrix font loadMatrixFont(). It dynamically adds a stylesheet link to the document’s <head>, ensuring the browser can render the text in that signature Matrix style.

2. Checking if the Font is Loaded

This function isFontLoaded(); verifies whether the specified font has been successfully loaded by the browser. It does this by comparing the dimensions of a test string rendered with a generic font against the same string rendered with the target font. If the dimensions differ, it indicates the target font is active.

3. Waiting for the Font to Load

This function waitForFontLoad(); patiently waits for the font to load before proceeding. It sets up an interval that repeatedly checks if the font is loaded using isFontLoaded. Once the font is ready, it clears the interval and executes a provided callback function.

4. Starting the Matrix Effect

This is where the magic happens. The code:

  • Loads the Matrix font.
  • Waits for the font to load.
  • Finds the target element where the effect will be displayed.
  • Creates multiple “strips” of characters that will cascade down the screen.
  • Animates these strips, giving them random positions, speeds, and characters to mimic the flowing code.
  • Uses requestAnimationFrame for smooth animation.

Key Points and Enhancements

  • The code dynamically loads the Matrix font, ensuring it’s available even if the user doesn’t have it installed locally.
  • It waits for the font to load before starting the effect, preventing visual glitches.
  • You can customize the effect by adjusting variables like stripCount (density of the rain), font size range, colors, and the characters used in the strips.
  • The code uses requestAnimationFrame for optimal performance and battery life.

Conclusion

This JavaScript snippet provides a fascinating glimpse into how to create visually engaging effects using web technologies. It showcases the power of dynamic font loading, animation techniques, and the importance of performance optimization.

Feel free to experiment with the code, tweak its parameters, and create your own unique variations of the Matrix rain effect. Happy coding!