Explosion
A click launches 60 colored rectangular particles in all directions on canvas — gravity, friction and progressive dissipation fade them out in under 3 seconds.
You'll get access to the interactive demo with a free account.
This effect is part of Effect.Labs — 811 vanilla effects, some free, some premium. Atmosphere has 57 effects, including 10 free. Explore the category →
3 usage examples



How it works
setupCanvas('psExplosion') retrieves the canvas by id, reads the parent dimensions via getBoundingClientRect() and applies them to the canvas width/height properties — pixel-exact rendering regardless of layout. A single array n holds all live particles and one recursive requestAnimationFrame starts immediately on init.
On click, CSS coordinates are converted to canvas logical space via the w / o.width ratio, then 60 particles spawn at that point. Each receives a random direction in [0, 2π] and an initial speed in [2, 8] px/frame (6 * Math.random() + 2), a size in [2, 6] px, a rotation speed in [−5, 5] deg/frame, and a decay in [0.01 – 0.025] that sets its lifetime (40 to 100 frames).
The physics loop uses Euler integration: constant gravity vy += 0.08 per frame, isotropic friction vx *= 0.99 / vy *= 0.99. Each particle is a size × size/2 rectangle drawn after translate + rotate; globalAlpha = life directly maps the decay to opacity, from 1 to 0.
The background is not cleared with clearRect but covered each frame with a semi-transparent rgba(10,10,15,0.1) fillRect: the 10% opacity gradually accumulates a deliberate motion trail that briefly illuminates trajectories. Neither IntersectionObserver nor prefers-reduced-motion handling are present in the original implementation — the RAF runs continuously.
Accessibility
- prefers-reduced-motion absent: the code does not check
window.matchMedia('(prefers-reduced-motion:reduce)')— the RAF always runs. To disable the animation, add this check at init and skip launching the RAF when the preference is active. - The
<canvas>does not carryaria-hidden="true"in the original implementation — screen readers may announce it unnecessarily. Add the attribute at deployment. - No
role="img"oraria-labelon the container — add a static description of the effect for assistive technologies. - Interaction is click/touch only: no keyboard activation is exposed. For accessibility, wire a trigger on
keydown(Enter / Space) on the focusable parent element. - Text contrast is not managed by the effect — no scrim is provided. If you overlay text, add a semi-transparent background and verify the WCAG AA ratio (≥ 4.5:1).
Browser compatibility
Requires Canvas 2D Context and requestAnimationFrame — supported in all modern browsers since 2015.
If <code>canvas</code> is not supported, <code>setupCanvas</code> returns <code>null</code> and the rest of the IIFE exits silently — no JS errors, the page stays functional.
The code
HTML structure to paste into your page (CSS + JS available with a premium account):
<div class="demo-preview">
<div class="ps-canvas-wrap">
<canvas class="ps-canvas" id="psExplosion" width="392" height="280"
aria-hidden="true"></canvas>
<span class="ps-hint">Click to explode</span>
</div>
</div>
Full HTML + CSS + JS, copy-paste ready — with hundreds of premium effects.
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
| Color array e | 7 hex (#8b5cf6 … #06b6d4) | Replace with your brand palette — add or remove entries; each particle picks randomly from the array. |
| Constant 60 (count) | 60 particles/click | Number of particles created per click — 30 for a subtle effect, 120 for a spectacular burst. |
| 6 * Math.random() + 2 (speed) | 2 – 8 px/frame | Initial particle speed — increase the factor (e.g. 10 * Math.random() + 4) for a more energetic explosion. |
| a.vy += .08 (gravity) | 0.08 px/frame² | Gravitational acceleration — 0 = zero gravity (straight-line motion), 0.20 = fast fall like heavy confetti. |
| a.vx *= .99 / a.vy *= .99 (friction) | 0.99 (light) | Per-frame drag factor — 0.95 = strong friction (rapid slowdown), 0.999 = near frictionless. |
| 4 * Math.random() + 2 (size) | 2 – 6 px | Rectangle particle size — 8 * Math.random() + 4 gives larger, more visible confetti on big screens. |
| .015 * Math.random() + .01 (decay) | 0.01 – 0.025 /frame | Fade-out speed — fixed .005 → particles visible for ~200 frames; .04 → gone in 25 frames. |
| rgba(10,10,15,0.1) (trail) | 10% opacity | Background fill opacity per frame — 0.05 = long luminous trail, 0.30 = near-instant erase, 1.0 = no trail (pure clearRect). |
FAQ
MouseEvent on the canvas: canvas.dispatchEvent(new MouseEvent('click', { clientX: cx, clientY: cy, bubbles: true })) with your target coordinates (center = rect.left + rect.width/2). No public API is exposed in the original implementation.clearRect: each frame overlays a rgba(10,10,15,0.1) fillRect that progressively fades old traces. This is intentional — for a clean slate between explosions, replace that fill with ctx.clearRect(0, 0, w, h) before drawing particles.