DEV Community

Ali Shata
Ali Shata

Posted on

How to make a rainfall-like the one in Matrix movie?

1. Add a canvas element

The Matrix rainfall animation requires a canvas element to draw the characters. Add a canvas element to your HTML code:

<canvas></canvas>
Enter fullscreen mode Exit fullscreen mode

2. Set the canvas size

Set the width and height of the canvas to match the size of the screen. You can use the window.innerWidth and window.innerHeight properties to get the width and height of the screen, respectively.

const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");

canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
Enter fullscreen mode Exit fullscreen mode


3. Define the characters

Characters required for this animation consists of the "Katakana" letters, "Latin" letters and Numbers

const katakana = "アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲンガギグゲゴザジズゼゾダヂヅデドバビブベボパピプペポキャキュキョシャシュショチャチュチョニャニュニョヒャヒュヒョミャミュミョリャリュリョギャギュギョジャジュジョヂャヂュヂョビャビュビョピャピュピョ";
const latin = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const nums = "01234567890";
const alphabet = katakana + latin + nums;
Enter fullscreen mode Exit fullscreen mode

4. Create the matrix

Create an array that contains the position of each character in each column of the screen. For example, if there are 80 columns on the screen, you can create an array of length 80 that contains the starting position of each character in each column.

const fontSize = 26;
const columns = canvas.width / fontSize;

const drops = [];
for (let i = 0; i < columns; i++) {
  drops[i] = 1;
}
Enter fullscreen mode Exit fullscreen mode

5. Draw the characters

Draw the characters falling from the top of the screen on the canvas. To do this, you need to use the fillText() method of the canvas context object to draw each character at its position in each column.

const draw = () => {
  // Set the background color
  ctx.fillStyle = "rgba(0, 0, 0, 0.05)";
  ctx.fillRect(0, 0, canvas.width, canvas.height);

  // Set the font color and size
  ctx.fillStyle = "#0f0";
  ctx.font = fontSize + "px monospace";

  // Draw the characters
  for (let i = 0; i < drops.length; i++) {
    const txt = alphabet.charAt(Math.floor(Math.random() * alphabet.length));
    ctx.fillText(txt, i * fontSize, drops[i] * fontSize);

    if (drops[i] * fontSize > canvas.height && Math.random() > 0.975) {
      drops[i] = 0;
    }

    drops[i]++;
  }
};

setInterval(draw, 30);
Enter fullscreen mode Exit fullscreen mode

6. Adjust the animation speed

You can adjust the speed of the animation by modifying the interval time of the setInterval() function. A smaller interval time will make the animation faster, and a larger interval time will make the animation slower.

setInterval(draw, 30);
Enter fullscreen mode Exit fullscreen mode

Here's the complete code:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>matrix-rainfall-animation</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        html,
        body {
            height: 100%;
        }

        canvas {
            position: absolute;
            inset: 0;
            margin: auto;
            background: #222;
        }
    </style>
</head>

<body>
    <canvas></canvas>
    <script>
        const canvas = document.querySelector("canvas")
        const ctx = canvas.getContext("2d")

        canvas.width = window.innerWidth
        canvas.height = window.innerHeight

        const katakana = "アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲンガギグゲゴザジズゼゾダヂヅデドバビブベボパピプペポキャキュキョシャシュショチャチュチョニャニュニョヒャヒュヒョミャミュミョリャリュリョギャギュギョジャジュジョヂャヂュヂョビャビュビョピャピュピョ"
        const latin = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        const nums = "01234567890"
        const alphabet = katakana + latin + nums

        const fontSize = 26
        const columns = canvas.width / fontSize

        const drops = []
        for (let i = 0; i < columns; i++) {
            drops[i] = 1
        }

        const draw = () => {
            ctx.fillStyle = "rgba(0,0,0,.05)"
            ctx.fillRect(0, 0, canvas.width, canvas.height)
            ctx.fillStyle = "#0f0"
            ctx.font = fontSize + "px monospace"
            for (let i = 0; i < drops.length; i++) {
                const txt = alphabet.charAt(Math.floor(Math.random() * alphabet.length))
                ctx.fillText(txt, i * fontSize, drops[i] * fontSize)
                if (drops[i] * fontSize > canvas.height && Math.random() > .975) {
                    drops[i] = 0
                }
                drops[i]++
            }
        }

        setInterval(draw, 30)
    </script>
</body>

</html>
Enter fullscreen mode Exit fullscreen mode

Top comments (0)