Blog

How to Create a Matrix Effect with Next.js and Tailwind CSS - Beginner Guide

DJ
Dery JUSLIN
November 11, 2024

Creating a Matrix Effect with Next.js and Tailwind CSS - Beginner Guide

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:

Prerequisites

Before we start, make sure you have:

  • Node.js installed on your computer
  • A code editor (like VS Code)
  • Basic JavaScript knowledge
  • A cup of coffee โ˜•

Step 1: Creating the Next.js Project

Let's start by creating a new Next.js project. Open your terminal and type:

npx create-next-app@latest matrix-effect
cd matrix-effect

Answer the questions as follows:

  • Would you like to use TypeScript? โ†’ Yes
  • Would you like to use ESLint? โ†’ Yes
  • Would you like to use Tailwind CSS? โ†’ Yes
  • Would you like to use src/ directory? โ†’ Yes
  • Would you like to use App Router? โ†’ Yes
  • Would you like to customize the default import alias? โ†’ No

Step 2: Creating the Matrix Component

Now, let's create a new folder for our component. In your project:

  1. Create a components folder in src if it doesn't exist already
  2. Create a file MatrixEffect.tsx in this folder

Here'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 MatrixEffect

Step 3: Using the Component

Now, 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>
  )
}

How Does It Work? ๐Ÿค”

Let's break down the key concepts:

1. The Canvas ๐ŸŽจ

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.

2. Matrix Drops ๐Ÿ’ง

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.

3. The Animation ๐ŸŽฌ

Our animation works like this:

  1. We slightly clear the screen with a semi-transparent black rectangle
  2. We draw new random characters
  3. We repeat this 30 times per second!

Customization ๐ŸŽจ

Here are some simple modifications you can make:

Change the Color

// In the draw function
ctx.fillStyle = '#00ff00'  // Brighter green
// or
ctx.fillStyle = '#0099ff'  // Matrix blue!

Modify the Speed

// Faster (20ms = ~50fps)
const interval = setInterval(draw, 20)
// Slower (50ms = ~20fps)
const interval = setInterval(draw, 50)

Change Character Size

const fontSize = 20  // Larger characters
// or
const fontSize = 12  // Smaller characters

Troubleshooting ๐Ÿ”ง

Common Issue #1: Black Screen

Check that:

  • Your component is properly imported
  • The canvas has a defined size
  • The character color isn't black

Common Issue #2: Characters Too Small/Large

Adjust the fontSize variable according to your needs. A good starting point is between 12 and 20 pixels.

Conclusion ๐ŸŽ‰

Congratulations! You've created your own Matrix effect! This is an excellent exercise for understanding:

  • Canvas animation
  • React hooks (useEffect, useRef)
  • DOM manipulation
  • Basic animation concepts

Going Further ๐Ÿš€

Here are some improvement ideas:

  1. Add color variations
  2. Create mouse hover effects
  3. Add sound effects
  4. Make the effect interactive

Feel free to experiment and create your own version of the Matrix effect!

Frequently Asked Questions โ“

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:

  1. Reducing character size
  2. Decreasing the number of columns
  3. Increasing the frame interval

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! ๐Ÿ‘‹