How to make a rainfall-like the one in Matrix movie?
Tags: webdev, javascript, tutorial, html
Published: 2023-06-21 23:52:37

**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:

```html
<canvas></canvas>
```

---

**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.

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

canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
```
<u></u>
**3. Define the characters**

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

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

---

**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.

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

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

---

**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.

```js
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);
```

---

**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.

```js
setInterval(draw, 30);
```

---

**Here's the complete code:**

```html
<!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>
```