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:
- assigned randomized x, y, z coordinates
- given a randomized velocity in all three dimensions
- colored using a small, consistent color palette
- scaled based on depth to create a perspective effect
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