Introduction
Festive special effects like confetti, fireworks and particles add a touch of magic to your interfaces. Whether celebrating a purchase, congratulating a user or simply beautifying a landing page, these visual animations create memorable moments.
In this tutorial, we will explore 5 different special effects in pure JavaScript: from explosive confetti to snowflakes, including Canvas fireworks. Each example is accompanied by the complete code, ready to copy into your project.
All the effects in this article use pure JavaScript, without any external library. They combine DOM approaches (animated HTML elements) and Canvas (pixel-by-pixel drawing) as needed.
1. Confetti Explosion
The confetti effect is perfect for celebrating successful actions: form validation, completed purchase, goal reached. We create colored DOM elements with random CSS animations.
The principle
We dynamically generate dozens of absolutely positioned <div> elements, each with a random color, direction and unique fall speed. The @keyframes CSS animation handles gravity and rotation.
function createConfetti() {
const container = document.getElementById('confettiBox');
const colors = [
'#6366f1', '#8b5cf6', '#d946ef',
'#f59e0b', '#10b981', '#ef4444'
];
for (let i = 0; i < 50; i++) {
const confetti = document.createElement('div');
const color = colors[Math.floor(Math.random() * colors.length)];
const size = Math.random() * 8 + 6;
const left = Math.random() * 100;
const delay = Math.random() * 0.5;
const duration = 2 + Math.random() * 2;
confetti.style.cssText = `
position: absolute;
width: ${size}px;
height: ${size}px;
background: ${color};
left: ${left}%;
top: 0;
border-radius: ${Math.random() > 0.5 ? '50%' : '2px'};
animation: confettiFall ${duration}s ease-out
${delay}s forwards;
`;
container.appendChild(confetti);
setTimeout(() => confetti.remove(), 4500);
}
}
The associated CSS animation
@keyframes confettiFall {
0% {
transform: translateY(0) rotate(0);
opacity: 1;
}
100% {
transform: translateY(300px) rotate(720deg);
opacity: 0;
}
}
Use border-radius: 50% for round confetti and border-radius: 2px for rectangles. Alternating shapes makes the effect more natural.
2. Floating particles
Floating particles create an immersive atmosphere for your backgrounds. This effect uses the Canvas API to draw and animate dozens of particles with connections between them.
The principle
We initialize an array of particles with random positions and speeds. At each frame, we move the particles, draw them and trace lines between those that are close to each other.
function initParticles(canvasId) {
const canvas = document.getElementById(canvasId);
const ctx = canvas.getContext('2d');
canvas.width = canvas.offsetWidth;
canvas.height = canvas.offsetHeight;
const particles = [];
const count = 40;
const maxDist = 120;
for (let i = 0; i < count; i++) {
particles.push({
x: Math.random() * canvas.width,
y: Math.random() * canvas.height,
vx: (Math.random() - 0.5) * 0.8,
vy: (Math.random() - 0.5) * 0.8,
r: Math.random() * 2 + 1
});
}
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
particles.forEach(p => {
p.x += p.vx;
p.y += p.vy;
if (p.x < 0 || p.x > canvas.width) p.vx *= -1;
if (p.y < 0 || p.y > canvas.height) p.vy *= -1;
ctx.beginPath();
ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2);
ctx.fillStyle = 'rgba(99, 102, 241, 0.6)';
ctx.fill();
});
// Lines between nearby particles
for (let i = 0; i < count; i++) {
for (let j = i + 1; j < count; j++) {
const dx = particles[i].x - particles[j].x;
const dy = particles[i].y - particles[j].y;
const dist = Math.sqrt(dx * dx + dy * dy);
if (dist < maxDist) {
ctx.strokeStyle =
`rgba(99,102,241,${1 - dist/maxDist})`;
ctx.lineWidth = 0.5;
ctx.beginPath();
ctx.moveTo(particles[i].x, particles[i].y);
ctx.lineTo(particles[j].x, particles[j].y);
ctx.stroke();
}
}
}
requestAnimationFrame(animate);
}
animate();
}
Lines between nearby particles create a mesh effect. Opacity decreases with distance for a natural result. Adjust maxDist to control the mesh density.
3. Sparkles / Sparkles
Sparkles are small luminous particles that follow the mouse cursor or appear around an element on hover. It is an elegant effect for drawing attention to a CTA or premium element.
Cursor trail
We listen to mouse movements and create mini luminous elements at each movement. Each sparkle grows then fades out.
function initSparkles() {
document.addEventListener('mousemove', (e) => {
const sparkle = document.createElement('div');
const size = Math.random() * 6 + 4;
const colors = ['#fbbf24', '#f59e0b', '#fff'];
const color = colors[
Math.floor(Math.random() * colors.length)
];
sparkle.style.cssText = `
position: fixed;
pointer-events: none;
width: ${size}px;
height: ${size}px;
background: ${color};
border-radius: 50%;
left: ${e.clientX}px;
top: ${e.clientY}px;
box-shadow: 0 0 6px ${color};
animation: sparkleFade 0.6s ease-out forwards;
z-index: 9999;
`;
document.body.appendChild(sparkle);
setTimeout(() => sparkle.remove(), 600);
});
}
// Keyframes to add in CSS:
// @keyframes sparkleFade {
// 0% { transform: scale(0); opacity: 1; }
// 50% { transform: scale(1); opacity: 0.8; }
// 100% { transform: scale(0); opacity: 0; }
// }
Creating a DOM element at each mousemove event can quickly become expensive. Use a throttle (for example a call every 50ms) to limit the number of sparkles created simultaneously.
4. Falling snow
The snow effect is ideal for winter themes, Christmas pages or simply for a soft and soothing atmosphere. We use Canvas to draw falling snowflakes with a slight horizontal movement.
Canvas implementation
Each snowflake has a random size, speed and horizontal offset. When a snowflake reaches the bottom of the canvas, it is replaced at the top for a continuous effect.
function initSnow(canvasId) {
const canvas = document.getElementById(canvasId);
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const flakes = [];
const count = 100;
for (let i = 0; i < count; i++) {
flakes.push({
x: Math.random() * canvas.width,
y: Math.random() * canvas.height,
r: Math.random() * 3 + 1,
speed: Math.random() * 1 + 0.5,
wind: Math.random() * 0.5 - 0.25,
opacity: Math.random() * 0.5 + 0.3
});
}
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
flakes.forEach(f => {
f.y += f.speed;
f.x += f.wind;
// Reset to top if out of bounds
if (f.y > canvas.height) {
f.y = -5;
f.x = Math.random() * canvas.width;
}
ctx.beginPath();
ctx.arc(f.x, f.y, f.r, 0, Math.PI * 2);
ctx.fillStyle =
`rgba(255, 255, 255, ${f.opacity})`;
ctx.fill();
});
requestAnimationFrame(animate);
}
animate();
}
Customization
- Number of snowflakes: adjust
count(50 for subtle, 200 for blizzard) - Fall speed: modify the multiplier in
speed - Wind: change the
windrange for more or less pronounced lateral movement - Opacity: vary to create a depth effect (nearby vs distant snowflakes)
5. Fireworks
The most spectacular effect: a firework that explodes from a central point with colored particles that fall back in an arc under the effect of gravity. We use Canvas with a simplified physics simulation.
Simplified physics
Each particle has an initial velocity in a random direction. At each frame, we apply gravity that pulls the particles downward, creating the natural arc of a firework.
function initFireworks(canvasId) {
const canvas = document.getElementById(canvasId);
const ctx = canvas.getContext('2d');
canvas.width = canvas.offsetWidth;
canvas.height = canvas.offsetHeight;
let particles = [];
const gravity = 0.03;
function explode(x, y) {
const count = 60;
const hue = Math.random() * 360;
for (let i = 0; i < count; i++) {
const angle = (Math.PI * 2 / count) * i;
const speed = Math.random() * 3 + 1;
particles.push({
x, y,
vx: Math.cos(angle) * speed,
vy: Math.sin(angle) * speed,
life: 1,
decay: Math.random() * 0.01 + 0.005,
color: `hsl(${hue + Math.random()*30}, 100%, 60%)`
});
}
}
function animate() {
// Semi-transparent background for trail effect
ctx.fillStyle = 'rgba(10, 10, 15, 0.15)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
particles.forEach(p => {
p.x += p.vx;
p.y += p.vy;
p.vy += gravity; // Gravite
p.life -= p.decay;
ctx.beginPath();
ctx.arc(p.x, p.y, 2, 0, Math.PI * 2);
ctx.globalAlpha = p.life;
ctx.fillStyle = p.color;
ctx.fill();
});
ctx.globalAlpha = 1;
// Clean up dead particles
particles = particles.filter(p => p.life > 0);
requestAnimationFrame(animate);
}
// Click to launch firework
canvas.addEventListener('click', (e) => {
const rect = canvas.getBoundingClientRect();
explode(e.clientX - rect.left, e.clientY - rect.top);
});
animate();
}
Instead of completely clearing the canvas with clearRect, we draw a semi-transparent rectangle (rgba(10, 10, 15, 0.15)) at each frame. This leaves a luminous trail behind each particle, a very realistic effect for fireworks.
Best practices
Before deploying these effects in production, here are some essential recommendations to ensure a smooth experience:
Performance
- Always use
requestAnimationFrameinstead ofsetIntervalfor continuous animations. The browser optimizes rendering and pauses the animation when the tab is inactive. - Limit the number of particles: 50 to 100 are sufficient for a nice effect. Beyond 200, performance drops on mobile.
- Prefer Canvas over DOM for large quantities of particles. Manipulating hundreds of DOM elements is much more expensive than drawing on a canvas.
Cleanup and memory
- Remove dead particles with
filter()or manage a pool of reusable particles to avoid memory leaks. - Clean up listeners when the component is unmounted (important in SPAs with React, Vue, etc.).
- Use
cancelAnimationFrameto stop animations when they are no longer visible.
Mobile and accessibility
// Reduce particles on mobile
const isMobile = window.innerWidth < 768;
const particleCount = isMobile ? 25 : 60;
// Respect prefers-reduced-motion
const prefersReduced = window
.matchMedia('(prefers-reduced-motion: reduce)')
.matches;
if (!prefersReduced) {
initParticles('myCanvas', particleCount);
}
Always check prefers-reduced-motion before launching automatic animations. Some users suffer from vestibular disorders and animations can cause nausea or dizziness.
Conclusion
Festive special effects are an excellent way to make your interfaces more lively and memorable. Whether celebrating a user action with confetti, creating a winter atmosphere with snow or impressing with fireworks, JavaScript provides all the power needed.
The DOM approach (confetti, sparkles) is ideal for punctual effects with few elements. The Canvas approach (particles, snow, fireworks) is preferable when the number of elements increases. In all cases, always think about performance, memory cleanup and accessibility.
Find special effects ready to use in our effects library, with one-click copyable code and real-time customization.