Particle Animation

This document explains the 3D particle animation implemented using a single <canvas> element. The effect simulates depth by assigning each particle a z-position and scaling its size and position based on distance.


1. Overview

The system renders a field of particles that move in simulated 3D space. Each particle is:

Together, these create a lightweight but visually dynamic background animation.


2. Canvas Setup

The animation begins by selecting and sizing the canvas to match the viewport:

const canvas = document.getElementById('particleCanvas');
const ctx = canvas.getContext('2d');

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

3. Particle Class

Each particle holds position, velocity, size, and color. A small color palette keeps the animation consistent.

class Particle {
  constructor(x, y, z) {
    this.x = x;
    this.y = y;
    this.z = z;
    this.size = Math.random() * 5 + 1;
    this.speedX = Math.random() * 3 - 1.5;
    this.speedY = Math.random() * 3 - 1.5;
    this.speedZ = Math.random() * 3 - 1.5;
    this.color = this.getRandomColor();
  }

  getRandomColor() {
    const colors = ['#0080ff', '#007acc', '#f7df1e', '#1e1e1e'];
    return colors[Math.floor(Math.random() * colors.length)];
  }
}

4. Updating & Rendering

The update() method moves each particle and wraps it when leaving screen boundaries. draw() applies perspective projection:

update() {
  this.x += this.speedX;
  this.y += this.speedY;
  this.z += this.speedZ;

  if (this.x > canvas.width || this.x < 0) this.x = Math.random() * canvas.width;
  if (this.y > canvas.height || this.y < 0) this.y = Math.random() * canvas.height;
  if (this.z > 1000 || this.z < -1000) this.z = Math.random() * 2000 - 1000;
}

draw() {
  const scale = 1 / (1 + Math.abs(this.z) / 500);
  const scaledSize = this.size * scale;

  const scaledX = (this.x - canvas.width / 2) * scale + canvas.width / 2;
  const scaledY = (this.y - canvas.height / 2) * scale + canvas.height / 2;

  if (scaledSize > 0.5) {
    ctx.beginPath();
    ctx.arc(scaledX, scaledY, scaledSize, 0, Math.PI * 2);
    ctx.fillStyle = this.color;
    ctx.fill();
  }
}

5. Animation Loop

function animate() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  particlesArray.forEach(p => {
    p.update();
    p.draw();
  });
  requestAnimationFrame(animate);
}

createParticles();
animate();

6. Window Resize

window.addEventListener('resize', () => {
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;

  particlesArray.length = 0;
  createParticles();
});

7. Live Demo

Last updated: December 2025