DEV Community

Cover image for How to Create a Matrix Rain Effect with JavaScript
Mohammad Sarabi
Mohammad Sarabi

Posted on

How to Create a Matrix Rain Effect with JavaScript

We all remember the iconic raining code from The Matrix. If you have ever wanted to create a similar effect in your own project, this tutorial will show you step by step how to create it.

This tutorial is an oversimplified version of my rain-fall library, which is fully customizable with fonts, colors, size, and more, and is fully responsive. Here is a link to the GitHub repository where you can find the complete source code, examples, and a demo.

A matrix-style effect interface with options for font, character size, character range, background, foreground, speed, density factor, and resizing the effect screen.

The rain-char library demo is available in m-sarabi.ir/rain-char

Getting Started

First, let's set up our environment.
We will create an HTML file where we'll include a canvas element for rendering the rain effect:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>RainChar Effect</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }

        canvas {
            display: block;
            background-color: black;
        }
    </style>
</head>
<body>
<canvas id="rain-effect"></canvas>
<script src="script.js"></script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

In this HTML setup, we have a full-screen canvas where our rain effect will be rendered.

The RainChar Class

Let's now walk through the core functionality of our RainChar class.

1. Constructor

In the constructor, we first define the parameters of our rain effect: font, size, characters, background color, and font color.

We then set up the canvas determining the size and filling the background color.

Then we create the particle array that will store each character's position and size.

class RainChar {
    constructor(font, charSize, chars, bg, fg) {
        // Defining the parameters
        this.font = font;
        this.charSize = charSize;
        this.chars = chars;
        this.bg = bg;
        this.fg = fg;

        // Setting up the canvas
        const canvas = document.getElementById('rain-effect');
        this.context = canvas.getContext('2d');
        this.size = [canvas.offsetWidth, canvas.offsetHeight];
        canvas.width = this.size[0];
        canvas.height = this.size[1];

        this.context.fillStyle = this.bg;
        this.context.fillRect(0, 0, ...this.size);

        // Creating the particles array
        this.particles = [];
        const particleCount = this.size[0] * this.size[1] / (this.charSize ** 2) / 10;

        for (let i = 0; i < particleCount; i++) {
            // We will create an array of particles using the newParticle method that we define later in the code.
            this.particles.push(this.newParticle());
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

The number of characters is roughly one-tenth of the area of the canvas divided by the size of the character.

2. Creating New Particles

We represent each particle as an object with a random position and size.

    newParticle() {
        return {
            x: Math.random() * this.size[0],
            y: -Math.random() * this.size[1] * 2,
            size: Math.floor(Math.random() * (this.charSize * 2 - this.charSize / 2) + this.charSize / 2),
        };
    }
Enter fullscreen mode Exit fullscreen mode

Particle size is a random value between half and double the character size.

Each particle will be positioned somewhere outside the canvas at the top, later we animate them downward.

3. Drawing Particles

Now that we have an array of particles (we created the array of particles in the constructor using the newParticle method), We have to render each one on the canvas. We define the drawParticles method to handle the rendering:

    drawParticles() {
        this.context.fillStyle = this.fg;
        this.particles.forEach(particle => {
            this.context.font = `${particle.size}px ${this.font}`;
            const randomChar = this.chars[Math.floor(Math.random() * this.chars.length)];
            this.context.fillText(randomChar, particle.x, particle.y);
        });
    }
Enter fullscreen mode Exit fullscreen mode
  1. We set the fill style to the font color.
  2. For each particle, we set the font size and get a random character from the chars.
  3. Lastly, we render the particle on the canvas with the fillText method.

4. Updating Particles

For each particle, after we draw it on the canvas, we need to move it downward by the particle size, simulating the falling effect.

    updateParticles() {
        this.particles.forEach(particle => {
            if (particle.y > this.size[1]) {
                Object.assign(particle, this.newParticle());
            } else {
                particle.y += particle.size;
            }
        });
    }
Enter fullscreen mode Exit fullscreen mode

We check if the particle has reached the bottom of the canvas. If it has, we reset it by assigning it a new particle using the newParticle() method.

5. Clearing the Canvas

Before redrawing the particles, we need to clear the canvas. We do this by partially erasing the previous frame, creating a smooth trail effect.

    clearCanvas() {
        this.context.globalAlpha = 0.25;
        this.context.fillStyle = this.bg;
        this.context.fillRect(0, 0, ...this.size);
        this.context.globalAlpha = 1;
    }
Enter fullscreen mode Exit fullscreen mode

With the globalAlpha property we control how strong the erasing is. It can control the length of the trail.

6. The Play Method

Finally, we need to create the animation by continuously clearing the canvas, drawing particles, and updating their positions.

    play() {
        this.clearCanvas();
        this.drawParticles();
        this.updateParticles();
        setTimeout(() => {
            this.play();
        }, 50);
    }
Enter fullscreen mode Exit fullscreen mode

The play method calls the clearCanvas, drawParticles, and updateParticles methods in a loop, using the setTimeout to call the play method every 50 milliseconds for roughly 20 frames per second, with higher frame rates resulting in faster animation.

Putting It All Together

We can now create an instance of the RainChar class and start the animation by calling the play method:

const chars = 'ABCDEFGHIJKLMNOPRSTUVWXYZ';
const rain = new RainChar('monospace', 20, chars, 'black', 'lime');
rain.play();
Enter fullscreen mode Exit fullscreen mode

We have created an instance of the RainChar class and called the play method to start the animation.

You can see the code of this tutorial in action in the Codepen below:

Conclusion

With RainChar, you can easily add a dynamic and eye-catching rain effect to your web projects. The library is fully customizable, allowing you to experiment with different fonts, colors, and character sets, and is responsive to resizing. Try it out, and see what stunning visuals you can create!

Feel free to explore the GitHub repository for more examples and customization options. If you have any questions or improvements, don’t hesitate to drop a comment below! If you liked it please share it with your friends!

Top comments (0)