<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Fizzy Sparks</title>
<style>
/*
Fizzy Sparks
------------
This interactive canvas spawns small, glowing sparks wherever the
user moves or clicks the mouse. Each spark travels in a random
direction and fades out over time. The effect approximates the
original CodePen's fizzy sparks animation using only plain
JavaScript and the Canvas API.
*/
html, body {
margin: 0;
padding: 0;
height: 100%;
overflow: hidden;
background: #000;
cursor: crosshair;
}
canvas {
display: block;
}
</style>
</head>
<body>
<canvas id="sparks"></canvas>
<script>
(function() {
const canvas = document.getElementById('sparks');
const ctx = canvas.getContext('2d');
function resize() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
window.addEventListener('resize', resize);
resize();
// Particle class representing a single spark.
class Spark {
constructor(x, y) {
this.x = x;
this.y = y;
const angle= Math.random() * Math.PI * 2;
const speed= 2 + Math.random() * 3;
this.vx = Math.cos(angle) * speed;
this.vy = Math.sin(angle) * speed;
this.life = 40 + Math.floor(Math.random() * 20);
this.age = 0;
this.radius= 2 + Math.random() * 3;
// Choose a bright, random colour.
const hue = Math.floor(Math.random() * 360);
this.colour = `hsl(${hue}, 80%, 60%)`;
}
update() {
this.x += this.vx;
this.y += this.vy;
// Apply a small amount of friction.
this.vx *= 0.98;
this.vy *= 0.98;
// Gravity to pull sparks downwards.
this.vy += 0.05;
this.age++;
}
draw(ctx) {
const alpha = 1 - this.age / this.life;
ctx.fillStyle = this.colour;
ctx.globalAlpha = alpha;
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
ctx.fill();
ctx.globalAlpha = 1;
}
isDead() {
return this.age >= this.life;
}
}
const sparks = [];
function spawn(x, y, count) {
for (let i = 0; i < count; i++) {
sparks.push(new Spark(x, y));
}
}
// Spawn sparks on mouse movement and clicks.
let lastSpawn = 0;
document.addEventListener('mousemove', (e) => {
const now = Date.now();
if (now - lastSpawn > 50) {
spawn(e.clientX, e.clientY, 5);
lastSpawn = now;
}
});
document.addEventListener('click', (e) => {
spawn(e.clientX, e.clientY, 20);
});
function animate() {
// Draw a translucent black rectangle to create trails.
ctx.fillStyle = 'rgba(0, 0, 0, 0.2)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Update and draw each spark.
for (let i = sparks.length - 1; i >= 0; i--) {
const s = sparks[i];
s.update();
s.draw(ctx);
if (s.isDead()) {
sparks.splice(i, 1);
}
}
requestAnimationFrame(animate);
}
animate();
})();
</script>
</body>
</html>
<canvas id="sparks"></canvas>
/*
Fizzy Sparks
------------
This interactive canvas spawns small, glowing sparks wherever the
user moves or clicks the mouse. Each spark travels in a random
direction and fades out over time. The effect approximates the
original CodePen's fizzy sparks animation using only plain
JavaScript and the Canvas API.
*/
html, body {
margin: 0;
padding: 0;
height: 100%;
overflow: hidden;
background: #000;
cursor: crosshair;
}
canvas {
display: block;
}
(function() {
const canvas = document.getElementById('sparks');
const ctx = canvas.getContext('2d');
function resize() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
window.addEventListener('resize', resize);
resize();
// Particle class representing a single spark.
class Spark {
constructor(x, y) {
this.x = x;
this.y = y;
const angle= Math.random() * Math.PI * 2;
const speed= 2 + Math.random() * 3;
this.vx = Math.cos(angle) * speed;
this.vy = Math.sin(angle) * speed;
this.life = 40 + Math.floor(Math.random() * 20);
this.age = 0;
this.radius= 2 + Math.random() * 3;
// Choose a bright, random colour.
const hue = Math.floor(Math.random() * 360);
this.colour = `hsl(${hue}, 80%, 60%)`;
}
update() {
this.x += this.vx;
this.y += this.vy;
// Apply a small amount of friction.
this.vx *= 0.98;
this.vy *= 0.98;
// Gravity to pull sparks downwards.
this.vy += 0.05;
this.age++;
}
draw(ctx) {
const alpha = 1 - this.age / this.life;
ctx.fillStyle = this.colour;
ctx.globalAlpha = alpha;
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
ctx.fill();
ctx.globalAlpha = 1;
}
isDead() {
return this.age >= this.life;
}
}
const sparks = [];
function spawn(x, y, count) {
for (let i = 0; i < count; i++) {
sparks.push(new Spark(x, y));
}
}
// Spawn sparks on mouse movement and clicks.
let lastSpawn = 0;
document.addEventListener('mousemove', (e) => {
const now = Date.now();
if (now - lastSpawn > 50) {
spawn(e.clientX, e.clientY, 5);
lastSpawn = now;
}
});
document.addEventListener('click', (e) => {
spawn(e.clientX, e.clientY, 20);
});
function animate() {
// Draw a translucent black rectangle to create trails.
ctx.fillStyle = 'rgba(0, 0, 0, 0.2)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Update and draw each spark.
for (let i = sparks.length - 1; i >= 0; i--) {
const s = sparks[i];
s.update();
s.draw(ctx);
if (s.isDead()) {
sparks.splice(i, 1);
}
}
requestAnimationFrame(animate);
}
animate();
})();