DEV Community

Cover image for Matrix raining code effect using JavaScript
Adam Nagy
Adam Nagy

Posted on • Updated on

Matrix raining code effect using JavaScript

Motivation

The new Matrix movie is coming this year, and I'm so hyped for it that I had to create this iconic effect with my tools. The implementation itself is really simple and I only used HTML, CSS and vanilla javascript for it.

If you prefer a video format, you can check my tutorial on it on YouTube:

Implementation

I'll use HTML canvas to create the "Digital rain" effect, and we will have all the login in javascript.

HTML

The HTML file will be really simple. In the body we will only have a <canvas>, and I also included the javascript file here at the bottom, you can also include it in the head with the defer attribute.

<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">
    <link rel="stylesheet" href="./styles.css">
    <title>Matrix digital rain</title>
</head>
<body>
    <canvas id="Matrix"></canvas>
    <script src="./index.js"></script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

CSS

This will be really short too. In CSS I just basically make the body fill the whole viewport and set a black background color for it.

html {
    background: black;
    height: 100%;
    overflow: hidden;
}

body {
    margin: 0;
    padding: 0;
    height: 100%;
}
Enter fullscreen mode Exit fullscreen mode

Javascript

This implementation will be the ๐Ÿฆ lionshare of the project.
First we have to initialise our canvas with a 2D context. I also set the canvas to take up the whole viewport by setting it's width and height:

const canvas = document.getElementById('Matrix');
const context = canvas.getContext('2d');

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

Next I create the alphabet from which we will pick our characters for the rain. I'll use katakana characters (A variation of Katakana symbols was used in the Matrix movie itself.), the latin alphabet and arabic numbers. The concatenation of these will create the alphabet.

const katakana = 'ใ‚ขใ‚กใ‚ซใ‚ตใ‚ฟใƒŠใƒใƒžใƒคใƒฃใƒฉใƒฏใ‚ฌใ‚ถใƒ€ใƒใƒ‘ใ‚คใ‚ฃใ‚ญใ‚ทใƒใƒ‹ใƒ’ใƒŸใƒชใƒฐใ‚ฎใ‚ธใƒ‚ใƒ“ใƒ”ใ‚ฆใ‚ฅใ‚ฏใ‚นใƒ„ใƒŒใƒ•ใƒ ใƒฆใƒฅใƒซใ‚ฐใ‚บใƒ–ใƒ…ใƒ—ใ‚จใ‚งใ‚ฑใ‚ปใƒ†ใƒใƒ˜ใƒกใƒฌใƒฑใ‚ฒใ‚ผใƒ‡ใƒ™ใƒšใ‚ชใ‚ฉใ‚ณใ‚ฝใƒˆใƒŽใƒ›ใƒขใƒจใƒงใƒญใƒฒใ‚ดใ‚พใƒ‰ใƒœใƒใƒดใƒƒใƒณ';
const latin = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
const nums = '0123456789';

const alphabet = katakana + latin + nums;
Enter fullscreen mode Exit fullscreen mode

We have to calculate how many "rain columns" will fit on the screen and to do that I'll set a fixed fontsize and divide the width on the window's innerWidth to get the exact column count.

const fontSize = 16;
const columns = canvas.width/fontSize;
Enter fullscreen mode Exit fullscreen mode

I'll use an array to store and render the raindrops. The index of a given element will be the coordinate of the raindrop on the X axis, and the value of a given element will hold it's coordinate on the Y axis. This way we don't need a 2D array. To initialise the array I fill it up with with ones, so aftert the initialization we will have the same exact height for every column: 1.

const rainDrops = [];

for( let x = 0; x < columns; x++ ) {
    rainDrops[x] = 1;
}
Enter fullscreen mode Exit fullscreen mode

Now it's time to implement the hearth of our effect the draw function. First we will paint the whole canvas with a transparent black color. This will give us the trail effect on the raindrops, when the drop falls the already drown characters will slowly fade out. Next I'll set the fontsize and the color (of course it is green ๐Ÿ˜Ž). And now comes the ๐Ÿ”‘ key. I'll loop through the raindrop array, and for every element I'll pick a random character from our alphabet and render that in the next position of the column. The important thing here is that you have to multiply the coordinates (elemnt value and index) with the font size to get the perfect spacing. Lastly we have to move our raindrops which dropped below the viewport height, to the top of that column. To get the raining effect I don't put it to the top right away, but add a little randomness by adding a random chance to do that.

const draw = () => {
    context.fillStyle = 'rgba(0, 0, 0, 0.05)';
    context.fillRect(0, 0, canvas.width, canvas.height);

    context.fillStyle = '#0F0';
    context.font = fontSize + 'px monospace';

    for(let i = 0; i < rainDrops.length; i++)
    {
        const text = alphabet.charAt(Math.floor(Math.random() * alphabet.length));
        context.fillText(text, i*fontSize, rainDrops[i]*fontSize);

        if(rainDrops[i]*fontSize > canvas.height && Math.random() > 0.975){
            rainDrops[i] = 0;
        }
        rainDrops[i]++;
    }
};
Enter fullscreen mode Exit fullscreen mode

As a last step I need to call the draw function in an interval and this will call the draw function in every 30ms.

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

Conclusion

This is a really fun project to create and I tried to keep the implementation as beginner friendly as I could. Hope you enjoyed it, if you seek educational content on web development follow me, I create educational YouTube videos, and Instagram posts too.

Happy Hacking!

Where can you learn more from me?

I create education content covering web-development on several platforms, feel free to ๐Ÿ‘€ check them out.

I also create a newsletter where I share the week's or 2 week's educational content that I created. No bull๐Ÿ’ฉ just educational content.

๐Ÿ”— Links:

Top comments (15)

Collapse
 
marzelin profile image
Marc Ziel

Nice, but the start of the animation is a bit ugly, imho. Here's a quick fix:

const rainDrops = Array.from({ length: columns }).fill(canvas.height);
Enter fullscreen mode Exit fullscreen mode
Collapse
 
javascriptacademy profile image
Adam Nagy

Yes, this is a nice way to start it ๐Ÿ˜Š. I left it because it is felt like a cool intro to me, something that signals that something big and awesome is coming.

Collapse
 
lpm0073 profile image
Lawrence McDaniel

likewise. i originally added Marc's fix but then changed it back to your original bc i like the flicker effect.

Collapse
 
lpm0073 profile image
Lawrence McDaniel • Edited

You're welcome to do a PR on npmjs.com/package/react-mdr with your fix :)

Collapse
 
ecfaria profile image
Emรญlio Faria

I remember trying doing this circa 2004, it was MUCH MUCH MUCH more difficult than this. Impressive how web technologies evolved in the last ~20 years.

Collapse
 
javascriptacademy profile image
Adam Nagy

Yes it is evolved a lot, and now it is evolving even rapidly. Iโ€™m really excited how it will look in ^10, ^20 years ๐Ÿ™‚

Collapse
 
linuxuserin profile image
L

Don't know but 4 years old code looks same as yours.

code.sololearn.com/WpFa2Yz9WP8g

Collapse
 
lpm0073 profile image
Lawrence McDaniel • Edited

This is awesome Adam, thanks for sharing. I liked it so much that i ported it to ReactJS and created an NPM package based on your code sample: npmjs.com/package/react-mdr

Collapse
 
oojoseph67 profile image
Obinna Okolo

hey lawrence can i also use this on my Next.JS project

Collapse
 
javascriptacademy profile image
Adam Nagy

Awesome work Lawrance!

Collapse
 
chiu profile image
SkynetYu

Sorry for being late and Thanks for your sharing Adam!
I liked it so much.
I have seen the react library but not Angular version.
It would be great if have one. So I publish the ngx-mdr for Angular package.
npmjs.com/package/ngx-mdr

Collapse
 
erickvivas415 profile image
Erick Vivas

Pretty cool!

Collapse
 
javascriptacademy profile image
Adam Nagy

Thanks for the feedback, appreciated. ๐Ÿ˜Š

Collapse
 
remaster profile image
Daniel Neuman

Very nice! ๐ŸŒŸ
I borrowed this to make a point about how the aesthetic in The Matrix 4 should have been to replace the characters in the digital rain with emojis.
There is some idea there about how emojis are a form of digital compressed communication.
neuman.fi/daniel/emoji-digital-rai...

Collapse
 
jcubic profile image
Jakub T. Jankiewicz

I've created a library for this:

GitHub logo jcubic / cmatrix

Render Matrix effect animation on Canvas in JavaScript

CMatrix - Matrix effect in JavaScript

npm version LICENSE MIT jsDelivr CDN download counter

Matrix animation effect in JavaScript using Canvas

Screenshot of a browser window with Matrix rain effect, green letters that look like Japanese on black background

Installation

npm install cmatrix

Demos

Usage

You can use CDN:

<script src="https://cdn.jsdelivr.net/npm/cmatrix"></script>
Enter fullscreen mode Exit fullscreen mode

and intialize the effect.

matrix(canvasElement, {
  chars: ['0', '1'],
  font_size: 16
}).
Enter fullscreen mode Exit fullscreen mode
matrix(canvasElement, {
  chars: matrix.range(0x30A1, 0x30F6).concat(matrix.range(0x0030, 0x0039)),
  font_size: 16
}).
Enter fullscreen mode Exit fullscreen mode

The matrix function return a Promise that is resolved when exit By default, q and ESC exit from the effect. Use exit: false to disable ending of the animation.

Repo Link

Options

  • chars - array of single character strings, by default Katagana and Hiragana (Japanese characters are used).
  • exit - by default matrixโ€ฆ