Hey devs! ๐ Today, we're going to create an awesome Matrix effect, just like in the movie. Don't worry if you're a beginner - I'll explain everything step by step. By the end of this tutorial, you'll have a Matrix effect that looks like this:
Before we start, make sure you have:
Let's start by creating a new Next.js project. Open your terminal and type:
npx create-next-app@latest matrix-effect
cd matrix-effectAnswer the questions as follows:
src/ directory? โ YesNow, let's create a new folder for our component. In your project:
components folder in src if it doesn't exist alreadyMatrixEffect.tsx in this folderHere's the code step by step, with explanations:
'use client'
// โ๏ธ This line is necessary because we're using React hooks that
// only work on the client side
import { useEffect, useRef } from 'react'
// ๐ We import the hooks we need
const MatrixEffect = () => {
// Creating a reference to our canvas
const canvasRef = useRef<HTMLCanvasElement>(null)
useEffect(() => {
// Getting the canvas and context
const canvas = canvasRef.current
if (!canvas) return
const ctx = canvas.getContext('2d')
if (!ctx) return
// ๐จ Setting up canvas size
const resizeCanvas = () => {
canvas.width = window.innerWidth
canvas.height = window.innerHeight
}
resizeCanvas()
window.addEventListener('resize', resizeCanvas)
// ๐ Characters that will fall
// We use Japanese characters for a more authentic effect
const matrix = "ใขใกใซใตใฟใใใใคใฃใฉใฏใฌใถใใใใคใฃใญใทใใใใใชใฐใฎใธใใใใฆใฅใฏในใใใใ ใฆใฅใซใฐใบใใ
ใใจใงใฑใปใใใใกใฌใฑใฒใผใใใใชใฉใณใฝใใใใขใจใงใญใฒใดใพใใใใดใใณ0123456789"
const characters = matrix.split('')
// ๐ Column configuration
const fontSize = 16 // Size of each character
const columns = canvas.width / fontSize // Number of columns based on width
// ๐ง Creating "drops" - each column has a drop
const drops: number[] = []
for (let i = 0; i < columns; i++) {
drops[i] = 1
}
// ๐ฌ Main animation function
const draw = () => {
// Creating fade effect with semi-transparent black rectangle
ctx.fillStyle = 'rgba(0, 0, 0, 0.05)'
ctx.fillRect(0, 0, canvas.width, canvas.height)
// Matrix characters style
ctx.fillStyle = '#0F0' // The famous Matrix green!
ctx.font = `${fontSize}px monospace`
// Drawing characters
for (let i = 0; i < drops.length; i++) {
// Random character selection
const char = characters[Math.floor(Math.random() * characters.length)]
// Position calculation
const x = i * fontSize
const y = drops[i] * fontSize
// Drawing the character
ctx.fillText(char, x, y)
// Reset drop when it reaches bottom
if (drops[i] * fontSize > canvas.height && Math.random() > 0.975) {
drops[i] = 0
}
drops[i]++
}
}
// โก Starting the animation
const interval = setInterval(draw, 33) // ~30 frames per second
// ๐งน Cleanup when component unmounts
return () => {
clearInterval(interval)
window.removeEventListener('resize', resizeCanvas)
}
}, []) // [] means useEffect runs only once on mount
// Canvas rendering
return (
<canvas
ref={canvasRef}
className="fixed top-0 left-0 w-full h-full bg-black"
/>
)
}
export default MatrixEffectNow, let's create a page to display our effect. In src/app/page.tsx:
import MatrixEffect from '@/components/MatrixEffect'
export default function Home() {
return (
<main className="relative min-h-screen">
<MatrixEffect />
{/* Adding content over the Matrix effect */}
<div className="relative z-10 flex items-center justify-center min-h-screen">
<h1 className="text-4xl font-bold text-green-400">
Welcome to the Matrix
</h1>
</div>
</main>
)
}Let's break down the key concepts:
The canvas is like a digital painting canvas. We use it to draw our characters quickly. It's much more performant than manipulating the DOM directly.
Each column has a "drop" that makes characters fall. It's simply a number that increases to make characters move down. When a drop reaches the bottom, it has a chance to reset to the top.
Our animation works like this:
Here are some simple modifications you can make:
// In the draw function
ctx.fillStyle = '#00ff00' // Brighter green
// or
ctx.fillStyle = '#0099ff' // Matrix blue!// Faster (20ms = ~50fps)
const interval = setInterval(draw, 20)
// Slower (50ms = ~20fps)
const interval = setInterval(draw, 50)const fontSize = 20 // Larger characters
// or
const fontSize = 12 // Smaller charactersCheck that:
Adjust the fontSize variable according to your needs. A good starting point is between 12 and 20 pixels.
Congratulations! You've created your own Matrix effect! This is an excellent exercise for understanding:
Here are some improvement ideas:
Feel free to experiment and create your own version of the Matrix effect!
Q: Why use Canvas instead of divs? A: Canvas is much more performant for this type of animation as it avoids creating hundreds of DOM elements.
Q: My animation is slow, what should I do? A: Try:
Q: Can I use different characters?
A: Absolutely! Modify the matrix variable with characters of your choice.
I hope this tutorial was helpful! Feel free to ask questions in the comments and share your creations! ๐
See you next time! ๐