Atmosphere✨ Premium

Fireflies

30 canvas fireflies each blink at their own sinusoidal frequency — damped Brownian motion, yellow-green radial halo, and toroidal edge wrapping.

JSCanvasGlow

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

Hero / Landing — Outdoor evening events — Fireflies example 1

① Hero / Landing — Outdoor evening events

WhenLanding page of a nocturnal events app, nature tourism site, or stargazing service, visible on first viewport load.
WhyFireflies set a 'summer night' atmosphere with no external image — zero HTTP requests, no format to manage — and the Brownian motion is gentle enough not to compete with the headline.
Settings30 particles, low initial speed: replace the 0.5 prefactor with 0.3 (i.e. vx/vy ±0.15 px/frame). Default halo opacity is fine at full strength on a very dark background.
Product component — Nocturnal biodiversity widget — Fireflies example 2

② Product component — Nocturnal biodiversity widget

WhenDashboard of a gardening, weather, or biodiversity app: a nocturnal species presence card or 'good observation conditions' alert.
WhyThe lightweight animation (no click, no sound, halo at 15% opacity) fits inside a card without stealing attention from numeric data.
SettingsReduce to 15 particles (change 30 to 15) and base radius 1 × Math.random() + 1 for a lighter background in a small card.
Conversion micro-interaction — Night nature booking confirmation — Fireflies example 3

③ Conversion micro-interaction — Night nature booking confirmation

WhenConfirmation screen after booking a nature outing, unlocking premium nocturnal content, or subscribing to an environmental service.
WhyFireflies tie the confirmation to a summer-night memory — emotional reinforcement of the decision without aggressive animation or sound.
Settings30 particles (maximum density), pulse speed at the high end: speed: 0.04 * Math.random() + 0.02 for slightly livelier blinks at the moment of celebration.

How it works

setupCanvas("psFireflies") sizes the <canvas> to its parent container via getBoundingClientRect(), then 30 particles are created — each with a random position, an initial velocity vector (vx = vy = ±0.25 px/frame max), a starting phase in [0, 2π], and a pulse speed in [0.01 – 0.03] rad/frame.

Each rAF frame, a random impulse of ±0.025 px is added to each velocity component (Brownian noise). A ×0.98 damping factor keeps drift bounded without freezing it — the firefly moves organically. At the four edges, toroidal wrapping teleports the particle to the opposite side: it vanishes on the right and reappears on the left.

Each firefly has its own frequency: n = (sin(frame × speed + phase) + 1) / 2. This scalar oscillates between 0 and 1 and modulates simultaneously core opacity (0.30 + 0.70×n) and effective radius (size + 2×n). With 30 independent phases and speeds, the fireflies never blink in sync.

For each firefly, a createRadialGradient of radius 6×h draws the halo — color rgba(180,230,80, 0.15×n) at center to transparent. The solid core is a filled arc in rgba(200,250,100, 0.30 + 0.70×n). The effect handles neither prefers-reduced-motion, nor IntersectionObserver, nor a public API — it is a self-contained IIFE running continuously from page load.

Accessibility

  • prefers-reduced-motion absent: the effect does not detect the system preference. Animation runs unconditionally; add window.matchMedia('(prefers-reduced-motion:reduce)').matches to stop the RAF when accessibility is required.
  • The <canvas> carries no aria-hidden, role, or aria-label in the original code — add aria-hidden="true" if the effect is purely decorative.
  • Core contrast: rgba(200,250,100) on a #0a0a0f background exceeds a 7:1 luminance ratio — above the AAA threshold for graphical elements.
  • No keyboard or pointer interaction is registered — the canvas is not focusable, keyboard navigation on the page is unaffected.
  • Purely decorative effect: no textual or informational content resides in the canvas — overlay content (title, CTA) must live in the DOM, not inside the canvas.

Browser compatibility

Requires Canvas 2D and requestAnimationFrame — supported in all modern browsers. Zero external dependencies.

Chrome 88+✓ Full
Firefox 87+✓ Full
Safari 15+✓ Full
Edge 88+✓ Full
Mobile iOS✓ Full
Android Chrome✓ Full

Without <code>canvas</code> support, the parent container displays with its background — no fatal JS errors, the rest of the page stays functional.

The code

HTML structure to paste into your page (CSS + JS available with a premium account):

index.html — structure
<div class="ps-scene" role="img" aria-label="Animated fireflies in nocturnal flight">
  <div class="ps-canvas-wrap">
    <canvas class="ps-canvas" id="psFireflies" aria-hidden="true"></canvas>
  </div>

  <!-- Optional: scrim + overlay content -->
  <div class="ps-scrim" aria-hidden="true"></div>
  <div class="ps-overlay">
    <h2 class="ps-overlay-title">Your message</h2>
    <button class="ps-overlay-cta">CTA</button>
  </div>
</div>
🔒 Unlock the full code — from €2.99 the first month

Full HTML + CSS + JS, copy-paste ready — with hundreds of premium effects.

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Particle count (for e < 30) 30 Number of simultaneous fireflies. 10–15 for a subtle card background, 50–60 for a dense full-screen scene.
Initial speed (0.5 × (random − 0.5)) ±0.25 px/frame Change the 0.5 prefactor to control initial drift. 0.3 = slow, gentle flight; 0.8 = fast, nervous flight.
Brownian noise (0.05 × (random − 0.5)) ±0.025 px/frame Amplitude of the random impulse per frame. 0.02 = near-linear path; 0.10 = highly erratic, swarming motion.
Damping (vx *= 0.98) 0.98 Velocity decay factor. 0.96 = rapid deceleration (short paths); 0.995 = near-inertial glide (long, smooth trajectories).
Pulse speed range (0.02 × random + 0.01) [0.01 – 0.03] rad/frame Blink speed range. 0.04 × random + 0.02 for lively blinks; 0.008 × random + 0.004 for very slow breathing.
Base radius range (2 × random + 1.5) [1.5 – 3.5] px Core size. 1 × random + 1 = very small, discreet insects; 3 × random + 2 = larger dots, more visible on lighter backgrounds.
Halo color (rgba(180,230,80,…)) yellow-green #b4e650 Color of the radial gradient. rgba(80,180,230,…) for electric blue; rgba(255,160,40,…) for amber glow.
Halo radius (6 × h) 6× effective radius Gradient size multiplier. 4× = tight, punctual halo; 10× = wide, vaporous aura around the core.

FAQ

The code uses two color constants: the halo as rgba(180,230,80,…) and the core as rgba(200,250,100,…). Replace both with your RGB values — for example rgba(80,180,230,…) and rgba(100,210,255,…) for blue fireflies, or rgba(255,160,40,…) and rgba(255,200,80,…) for amber.
Partially: browsers automatically suspend requestAnimationFrame when the tab is inactive (zero CPU cost). However, the effect has no IntersectionObserver — it keeps running if the section is scrolled out of view but the tab stays active. Add an IntersectionObserver on the canvas to stop the RAF off-screen.
Not in its original form: the IIFE targets the fixed id psFireflies via getElementById — only one instance is possible. For multiple instances, extract the logic into a function parameterized by the canvas id and call it once per component.