SWAMP UI / COMPONENTS / FIREFLY CURSOR

Firefly Cursor

the cursor leaves a swarm

Move your mouse anywhere on this page. A trail of glowing fireflies follows, drifts slightly upward, then fades. It's one of those tiny choices that turns a site from finished into alive.

No dependencies
~0.8 KB CSS + 1 KB JS
Respects reduced-motion
Auto-cleans DOM
LIVE PREVIEW · MOVE YOUR MOUSE ANYWHERE
↑ Try it. The whole page is the demo.

Pick a color and the fireflies on the entire page change instantly.

When to use

Reach for it on personal sites, portfolios, landing pages, or any site where the visitor's attention is the product. It's a 2-second wow that costs nothing in performance. Pairs beautifully with dark backgrounds and high-contrast typography.

Skip it on data-heavy interfaces (dashboards, spreadsheets) or anywhere the cursor needs to read as precise (e.g., design tools). The component auto-disables for users with prefers-reduced-motion, so accessibility is handled.

Skip to

1. HTML

No HTML changes. Just drop the CSS + JS in any page. The whole document becomes the firefly canvas.

<!-- That's it. No markup needed.
     Just paste the CSS + JS below into any page. -->

2. CSS

One element style + one keyframe. The CSS variable --firefly-color lets you swap palette globally without rewriting.

:root {
  --firefly-color: #ffd23f;   /* swap to any color */
}

.firefly-trail {
  position: absolute;
  border-radius: 50%;
  background: var(--firefly-color);
  box-shadow:
    0 0 10px var(--firefly-color),
    0 0 22px rgba(255, 210, 63, .4);
  pointer-events: none;
  transform: translate(-50%, -50%);
  animation: firefly-fade 2.2s ease-out forwards;
  z-index: 5000;
}

@keyframes firefly-fade {
  0%   { opacity: .95; transform: translate(-50%, -50%) scale(1); }
  100% { opacity: 0;
         transform: translate(calc(-50% + var(--dx)), calc(-50% + var(--dy))) scale(.4); }
}

3. JavaScript

Throttles the mousemove event so it spawns ~30 fireflies/sec max. Each firefly randomizes size + drift direction, then removes itself when it fades. Respects prefers-reduced-motion.

// Swamp UI — Firefly Cursor
(function () {
  // Respect accessibility preference
  if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;

  const RATE      = 35;     // ms between spawns (lower = denser trail)
  const SIZE_MIN  = 3;      // px
  const SIZE_MAX  = 7;
  const LIFE_MS   = 2200;   // must match CSS animation duration
  const DRIFT_UP  = 40;     // px upward drift
  const DRIFT_X   = 24;     // px horizontal wobble

  let last = 0;
  document.addEventListener('mousemove', e => {
    const now = Date.now();
    if (now - last < RATE) return;
    last = now;

    const f    = document.createElement('span');
    const size = SIZE_MIN + Math.random() * (SIZE_MAX - SIZE_MIN);
    const dx   = (Math.random() - .5) * DRIFT_X;
    const dy   = -DRIFT_UP * (.5 + Math.random() * .6);

    f.className = 'firefly-trail';
    f.style.cssText =
      'left:' + (e.clientX + window.scrollX) + 'px;' +
      'top:'  + (e.clientY + window.scrollY) + 'px;' +
      'width:'  + size + 'px;' +
      'height:' + size + 'px;' +
      '--dx:' + dx + 'px;' +
      '--dy:' + dy + 'px;';
    document.body.appendChild(f);
    setTimeout(() => f.remove(), LIFE_MS);
  });

  // Optional: also spawn on touchmove for mobile
  document.addEventListener('touchmove', e => {
    if (e.touches.length === 0) return;
    const t = e.touches[0];
    document.dispatchEvent(new MouseEvent('mousemove', { clientX: t.clientX, clientY: t.clientY }));
  });
})();

4. Parameters you can tweak

ConstantDefaultEffect
RATE 35 ms Time between spawns. Lower = denser swarm; higher = sparser trail.
SIZE_MIN / SIZE_MAX 3 / 7 px Firefly diameter range. Bigger = more dragon-fly-ish.
LIFE_MS 2200 ms How long each firefly lives. Must match CSS animation duration.
DRIFT_UP 40 px Upward drift distance during fade. Higher = floatier.
DRIFT_X 24 px Horizontal wobble. Higher = more chaotic, like real fireflies.
--firefly-color (CSS var) #ffd23f Color of every firefly. Change in one place to swap palette globally.

Pro tip: set --firefly-color on a section instead of :root to give different page sections their own firefly color.

Liked this? Feed Mr. Knife & Ms. Ling.
And buy their owner a milk tea.
🧋 TREAT THE SWAMP
More in the garden → Firefly Tour (onboarding), Xylophone Lights, Cat Wanderer, Swamp Name Generator.
Browse all →