Klick-Feuerwerk-Generator
Create click fireworks, confetti and particle bursts for your site, then copy the JavaScript
100 % kostenlos. Läuft vollständig in deinem Browser: deine Dateien und Daten verlassen dein Gerät nie, und es wird nichts auf einen Server hochgeladen.
local_fire_department Click canvas
Click anywhere to spawn the effect.
code Export
/* Click fireworks - generated by 500 Toolbox
* Attach to the whole page (window):
* document.addEventListener('click', handler)
* Attach to one element:
* document.querySelector('.ugfw-btn').addEventListener('click', handler)
*
* Rendering notes: glow uses cached radial-gradient sprites and additive
* blending instead of ctx.shadowBlur, which is what keeps a 900-particle
* sky at 60fps.
*/
(function () {
var CFG = {"kind":"fireworks","count":90,"size":2.6,"speed":6.2,"gravity":0.11,"spread":360,"colors":["#fbbf24","#ef4444","#ffffff"],"glow":true,"duration":1500,"direction":"out","randomness":0.7,"emoji":"✨","attach":"window","launch":true,"trails":true,"autoShow":true,"max":900};
var canvas = document.getElementById('ugfw-canvas');
if (!canvas) {
canvas = document.createElement('canvas');
canvas.id = 'ugfw-canvas';
document.body.appendChild(canvas);
}
var ctx = canvas.getContext('2d');
if (!ctx) return;
var ps = [];
var last = 0;
var W = window.innerWidth, H = window.innerHeight;
var sprites = {};
function fit() {
var dpr = Math.min(2, window.devicePixelRatio || 1);
W = window.innerWidth;
H = window.innerHeight;
canvas.width = W * dpr;
canvas.height = H * dpr;
canvas.style.width = '100%';
canvas.style.height = '100%';
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
}
fit();
window.addEventListener('resize', fit);
function pick() { return CFG.colors[Math.floor(Math.random() * CFG.colors.length)]; }
function sprite(color) {
if (sprites[color]) return sprites[color];
var c = document.createElement('canvas');
c.width = 64; c.height = 64;
var g = c.getContext('2d');
var grd = g.createRadialGradient(32, 32, 0, 32, 32, 32);
grd.addColorStop(0, '#ffffff');
grd.addColorStop(0.22, color);
grd.addColorStop(0.55, color);
grd.addColorStop(1, 'rgba(0,0,0,0)');
g.fillStyle = grd;
g.beginPath(); g.arc(32, 32, 32, 0, Math.PI * 2); g.fill();
sprites[color] = c;
return c;
}
function star(r) {
ctx.beginPath();
for (var i = 0; i < 10; i++) {
var a = (i * Math.PI) / 5 - Math.PI / 2;
var rad = i % 2 ? r * 0.38 : r;
var x = Math.cos(a) * rad, y = Math.sin(a) * rad;
if (i) ctx.lineTo(x, y); else ctx.moveTo(x, y);
}
ctx.closePath();
}
function heart(sz) {
ctx.beginPath();
ctx.moveTo(0, sz * 0.35);
ctx.bezierCurveTo(0, -sz * 0.3, -sz, -sz * 0.3, -sz, sz * 0.12);
ctx.bezierCurveTo(-sz, sz * 0.62, 0, sz, 0, sz);
ctx.bezierCurveTo(0, sz, sz, sz * 0.62, sz, sz * 0.12);
ctx.bezierCurveTo(sz, -sz * 0.3, 0, -sz * 0.3, 0, sz * 0.35);
}
function trailKind(k) {
return k === 'fireworks' || k === 'spark' || k === 'neon' || k === 'glow' || k === 'magic' || k === 'stars';
}
function lightning(x, y) {
var dir = (Math.random() - 0.5) * (CFG.spread * Math.PI / 180);
var len = 80 + Math.random() * 140;
var pts = [{ x: x, y: y }];
var cx = x, cy = y, segs = 8 + Math.floor(Math.random() * 6);
for (var i = 0; i < segs; i++) {
cx += Math.sin(dir) * (len / segs) + (Math.random() - 0.5) * 28;
cy += Math.cos(dir) * (len / segs) + Math.random() * 10;
pts.push({ x: cx, y: cy });
}
return { role: 'spark', kind: 'lightning', x: x, y: y, vx: 0, vy: 0, life: CFG.duration * 0.5, maxLife: CFG.duration * 0.6, size: CFG.size, color: pick(), rot: 0, vr: 0, points: pts, emoji: '' };
}
function shell(x, targetY) {
var startY = H + 8;
var rise = Math.max(60, startY - targetY);
var frames = Math.max(22, Math.min(90, rise / 7));
var g = Math.max(0.02, CFG.gravity) * 0.55;
var v0 = ((targetY - startY) - 0.5 * g * frames * frames) / frames;
var lifeMs = frames * 16 + 400;
return { role: 'shell', kind: CFG.kind, x: x, y: startY, vx: (Math.random() - 0.5) * 1.1, vy: v0,
life: lifeMs, maxLife: lifeMs, size: Math.max(1.6, CFG.size * 0.8), color: pick(),
rot: 0, vr: 0, emoji: CFG.emoji, targetY: targetY, trail: [x, startY], seed: Math.random() * 6.28 };
}
function one(x, y, i, n, shellColor) {
var spreadRad = CFG.spread * Math.PI / 180;
var round = CFG.direction === 'out' && CFG.spread >= 340;
var angle;
if (round) angle = Math.random() * Math.PI * 2;
else if (CFG.direction === 'out') angle = (i / n) * Math.PI * 2 + (Math.random() - 0.5) * spreadRad * CFG.randomness;
else if (CFG.direction === 'up') angle = -Math.PI / 2 + (Math.random() - 0.5) * spreadRad;
else if (CFG.direction === 'down') angle = Math.PI / 2 + (Math.random() - 0.5) * spreadRad;
else angle = Math.random() * Math.PI * 2;
var bias = round ? 0.45 + 0.55 * Math.sqrt(Math.random()) : 0.55 + Math.random() * 0.7;
var sp = CFG.speed * bias * (1 - 0.35 * CFG.randomness + 0.35 * CFG.randomness * (0.6 + Math.random() * 0.8));
var vx = Math.cos(angle) * sp, vy = Math.sin(angle) * sp;
if (CFG.kind === 'bubbles' || CFG.kind === 'smoke') { vy = -Math.abs(vy) * (CFG.kind === 'smoke' ? 0.45 : 0.7); vx *= 0.45; }
if (CFG.kind === 'snow' || CFG.kind === 'leaves') { vy = Math.abs(vy) * 0.35 + 0.4; vx *= 0.5; }
var life = CFG.duration * (0.65 + Math.random() * 0.5);
return { role: 'spark', kind: CFG.kind, x: x, y: y, vx: vx, vy: vy, life: life, maxLife: life,
size: CFG.size * (0.6 + Math.random() * 0.9),
color: Math.random() < 0.16 ? '#fff6de' : shellColor,
rot: Math.random() * Math.PI * 2, vr: (Math.random() - 0.5) * 0.28, emoji: CFG.emoji,
seed: Math.random() * 6.28,
trail: CFG.trails && trailKind(CFG.kind) ? [x, y] : null };
}
function explode(x, y) {
var room = Math.max(0, CFG.max - ps.length);
if (room < 12) { ps.splice(0, Math.min(ps.length, CFG.count)); room = Math.max(0, CFG.max - ps.length); }
var n = Math.min(room, CFG.count);
var shellColor = pick();
if (CFG.glow) ps.push({ role: 'flash', kind: CFG.kind, x: x, y: y, vx: 0, vy: 0, life: 190, maxLife: 190, size: CFG.size * 9, color: '#ffffff', rot: 0, vr: 0, emoji: '' });
for (var i = 0; i < n; i++) ps.push(one(x, y, i, n, shellColor));
}
function burst(x, y) {
if (CFG.kind === 'lightning') {
for (var b = 0; b < 4; b++) ps.push(lightning(x, y));
return;
}
if (CFG.launch) { ps.push(shell(x, y)); return; }
explode(x, y);
}
function pushTrail(p) {
if (!p.trail) return;
p.trail.push(p.x, p.y);
if (p.trail.length > 12) p.trail.splice(0, p.trail.length - 12);
}
function tick(now) {
var dt = last ? Math.min(48, now - last) : 16;
last = now;
var f = dt / 16;
ctx.clearRect(0, 0, W, H);
var next = [];
for (var i = 0; i < ps.length; i++) {
var p = ps[i];
p.life -= dt;
if (p.role === 'shell') {
p.vy += CFG.gravity * 0.55 * f;
p.x += p.vx * f; p.y += p.vy * f;
pushTrail(p);
if (p.vy >= 0 || p.y <= p.targetY || p.life <= 0) { explode(p.x, p.y); continue; }
next.push(p);
continue;
}
if (p.life <= 0) continue;
if (p.kind === 'lightning' || p.role === 'flash') { next.push(p); continue; }
p.vy += CFG.gravity * f;
if (p.kind === 'snow' || p.kind === 'leaves') p.x += Math.sin(p.life / 90 + p.rot) * 0.6;
if (p.kind === 'bubbles') p.x += Math.sin(p.life / 70) * 0.35;
p.x += p.vx * f; p.y += p.vy * f; p.rot += p.vr * f;
var drag = p.trail ? 0.976 : 0.992;
p.vx *= drag;
if (p.trail) p.vy *= drag;
pushTrail(p);
next.push(p);
}
ps = next;
ctx.globalCompositeOperation = CFG.glow ? 'lighter' : 'source-over';
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
for (var j = 0; j < ps.length; j++) {
var q = ps[j];
var t = Math.max(0, Math.min(1, q.life / q.maxLife));
if (q.role === 'flash') {
var fr = q.size * (1 + (1 - t) * 1.6);
ctx.globalAlpha = t * t * 0.75;
ctx.drawImage(sprite(q.color), q.x - fr, q.y - fr, fr * 2, fr * 2);
continue;
}
if (q.kind === 'lightning') {
ctx.globalAlpha = t;
ctx.strokeStyle = q.color;
ctx.lineWidth = Math.max(1.2, q.size * 0.8);
ctx.beginPath();
ctx.moveTo(q.points[0].x, q.points[0].y);
for (var k = 1; k < q.points.length; k++) ctx.lineTo(q.points[k].x, q.points[k].y);
ctx.stroke();
continue;
}
var flicker = q.seed === undefined ? 1 : 0.72 + 0.28 * Math.sin(q.life * 0.045 + q.seed);
var alpha = Math.min(1, t * 1.25) * (t < 0.55 ? flicker : 1);
if (q.trail && q.trail.length >= 4) {
ctx.globalAlpha = alpha * 0.42;
ctx.strokeStyle = q.color;
ctx.lineWidth = Math.max(0.8, q.size * 0.85);
ctx.beginPath();
ctx.moveTo(q.trail[0], q.trail[1]);
for (var m = 2; m < q.trail.length; m += 2) ctx.lineTo(q.trail[m], q.trail[m + 1]);
ctx.stroke();
}
if (q.role === 'shell') {
var sr = q.size * 2.2;
ctx.globalAlpha = 0.9;
ctx.drawImage(sprite(q.color), q.x - sr, q.y - sr, sr * 2, sr * 2);
continue;
}
if (q.kind === 'confetti' || q.kind === 'pixel' || q.kind === 'stars' || q.kind === 'magic'
|| q.kind === 'hearts' || q.kind === 'emoji' || q.kind === 'leaves') {
ctx.save();
ctx.globalAlpha = alpha;
ctx.fillStyle = q.color;
ctx.translate(q.x, q.y);
ctx.rotate(q.rot);
if (q.kind === 'confetti') ctx.fillRect(-q.size, -q.size * 0.4, q.size * 2, q.size * 1.2);
else if (q.kind === 'pixel') ctx.fillRect(-q.size, -q.size, q.size * 2, q.size * 2);
else if (q.kind === 'stars' || q.kind === 'magic') { star(q.size * 1.6); ctx.fill(); }
else if (q.kind === 'hearts') { heart(q.size * 1.3); ctx.fill(); }
else if (q.kind === 'emoji') { ctx.font = (q.size * 3.2) + 'px serif'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillText(q.emoji, 0, 0); }
else { ctx.beginPath(); ctx.ellipse(0, 0, q.size * 1.6, q.size * 0.7, 0.4, 0, Math.PI * 2); ctx.fill(); }
ctx.restore();
} else if (q.kind === 'smoke') {
ctx.globalAlpha = t * 0.26; ctx.fillStyle = q.color;
ctx.beginPath(); ctx.arc(q.x, q.y, q.size * (2.2 - t), 0, Math.PI * 2); ctx.fill();
} else if (q.kind === 'bubbles') {
ctx.globalAlpha = alpha; ctx.strokeStyle = q.color; ctx.lineWidth = 1.2;
ctx.beginPath(); ctx.arc(q.x, q.y, q.size * 1.4, 0, Math.PI * 2); ctx.stroke();
} else if (q.kind === 'snow') {
ctx.globalAlpha = alpha; ctx.fillStyle = q.color;
ctx.beginPath(); ctx.arc(q.x, q.y, q.size, 0, Math.PI * 2); ctx.fill();
} else {
var rr = q.size * (q.kind === 'glow' ? 2.6 : q.kind === 'neon' ? 2.2 : 1.9);
ctx.globalAlpha = alpha;
if (CFG.glow) ctx.drawImage(sprite(q.color), q.x - rr, q.y - rr, rr * 2, rr * 2);
else { ctx.fillStyle = q.color; ctx.beginPath(); ctx.arc(q.x, q.y, q.size * 1.1, 0, Math.PI * 2); ctx.fill(); }
}
}
ctx.globalCompositeOperation = 'source-over';
ctx.globalAlpha = 1;
requestAnimationFrame(tick);
}
requestAnimationFrame(tick);
if (CFG.autoShow) {
setInterval(function () {
if (document.hidden) return;
burst(W * (0.15 + Math.random() * 0.7), H * (0.18 + Math.random() * 0.3));
}, 1100);
}
function handler(e) { burst(e.clientX, e.clientY); }
if (CFG.attach === 'button') {
var btn = document.querySelector('.ugfw-btn');
if (btn) {
btn.addEventListener('click', function (e) {
e.preventDefault();
e.stopPropagation();
var r = e.currentTarget.getBoundingClientRect();
burst(r.left + r.width / 2, r.top + r.height / 2);
});
}
} else {
document.addEventListener('click', handler);
}
})();Über dieses Tool
Klick-Feuerwerk verwandelt einen Tipp in eine Explosion aus Partikeln: Funken, Konfetti, Herzen, Emoji, Schnee, Neon. Mit diesem Generator klickst du in die Vorschau, stellst Anzahl, Schwerkraft, Streuung und Farbe ein und kopierst dann JavaScript, das sich an die ganze Seite oder an einen einzelnen Button hängt. Eine Partikelobergrenze und ein Leistungsmodus verhindern, dass schwache Handys in die Knie gehen. Effekte spielen nie automatisch Ton ab, und nichts wird hochgeladen.
So verwendest du dieses Tool
- Einen Effekt wählenFeuerwerk, Konfetti, Sterne, Herzen, Emoji, Rauch, Blasen, Schnee und mehr.
- In die Vorschau klickenJeder Klick lässt Partikel explodieren. Stell Anzahl, Größe, Geschwindigkeit, Schwerkraft und Farben ein.
- Festlegen, woran der Effekt hängtJeder Klick auf der Seite oder nur ein bestimmter Button. Dann das Skript kopieren.
Klick-Effekte, ohne die Seite auszubremsen
Verknüpfe den Effekt mit einem Button – einem Kaufen-, Anmelden- oder Feier-Moment – statt mit der ganzen Seite und halte die Partikelzahl moderat. Der Performance-Modus und die Partikelgrenze schützen ältere Handys.
Schalte Effekte für Besucher ab, die in den Systemeinstellungen reduzierte Bewegung aktiviert haben.
Warum es nutzen
- Fünfzehn Partikelstile mit Live-Test per Klick.
- Voreinstellungen für Feier, Gaming, Magie, Liebe, Neon, Minimal und Party.
- Partikelobergrenze plus Leistungsmodus für langsamere Geräte.
- Der Export hängt sich an das Fenster oder an ein einzelnes Element.
Häufige Anwendungen
- Eine Jubel-Explosion, wenn jemand ein Formular abschließt.
- Konfetti beim Klick auf ein Upgrade auf der Preisseite.
- Ein dezenter Funke in einer Spieloberfläche.
Fehler, die du vermeiden solltest
- ctx.shadowBlur für das Leuchten verwenden. Das berechnet pro Partikel und Frame einen Weichzeichner neu und ist der übliche Grund, warum eine Explosion ruckelt; zwischengespeicherte Verlaufs-Sprites kosten nur einen Bruchteil.
- Den Effekt an jeden Klick auf der Seite hängen, auch an Klicks auf Links und Formularfelder, wo er mit der eigentlichen Bedienung kollidiert.
- Hohe Partikelzahl und lange Dauer gleichzeitig einstellen. Aktive Partikel ergeben sich aus Anzahl mal Lebensdauer, nicht aus der Anzahl allein.
- Feier-Effekte auslösen, ohne prefers-reduced-motion zu prüfen – das kann Menschen mit Gleichgewichtsstörungen tatsächlich belasten.
- Die Zeichenfläche ohne pointer-events: none lassen, sodass sie unbemerkt Klicks schluckt, die für die Seite darunter gedacht sind.
Häufig gestellte Fragen
Die Engine begrenzt die aktiven Partikel (etwa 400), und der Leistungsmodus halbiert jede Explosion. Alte Partikel werden entfernt, sobald sie verblassen.
Ja. Bei Emoji und Herzen kannst du ein eigenes Symbol eintippen, das die Explosion verwendet.
Wechsle zur Element-Option, kopier das Skript und behalte den Beispiel-Selektor oder richte ihn auf die ID deines eigenen Buttons.
Nein. Der Export ist ein kleines Skript in reinem JavaScript. Kein zusätzliches Paket nötig.