SWAMP UI / COMPONENTS / XYLOPHONE LIGHTS

Xylophone Lights

every bulb is a note

A string of camp bulbs where every bulb is tuned to a note. Click any one to play it. They use a pentatonic scale, which means no matter the order you press them — solo, melody, or mash all five — nothing ever sounds wrong.

Web Audio (no files)
Pentatonic = always musical
Customizable note set
Hover = preview, click = play
LIVE PREVIEW · CLICK A BULB
↑ try playing left → right, then random

When to use

A perfect "delight" element for personal sites, artist portfolios, kids sites, and product landing pages where you want one moment of joy. The pentatonic safeguard means even rapid mashing sounds intentional, never cacophonous.

Skip on anything that needs to feel serious or quiet (legal, medical, banking) and on sites where audio would break a user's flow. Web Audio is muted by default in modern browsers until first user gesture, so it won't surprise anyone — they have to click first.

Skip to

1. HTML

A container with one .bulb per note. Each bulb declares its color + note frequency via CSS variable + data attribute.

<div class="xylo">
  <div class="bulbs">

    <div class="bulb" data-freq="262" style="--bulb-color:#ff4d8d">
      <div class="bulb-body"></div>
      <span class="note-label">C</span>
    </div>

    <div class="bulb" data-freq="294" style="--bulb-color:#ff8a3d">
      <div class="bulb-body"></div>
      <span class="note-label">D</span>
    </div>

    <!-- ... E (330), G (392), A (440) ... -->
  </div>
</div>

2. CSS

Bulb shape with a teardrop radius + glow via box-shadow. The .playing class fires on click for the brighter pop.

.xylo { position: relative; padding-top: 30px; }
.xylo::before {
  content: ""; position: absolute; top: 0; left: 5%; right: 5%; height: 60px;
  border-top: 1px solid rgba(243, 238, 221, .25);
  border-radius: 50% / 100%;
}
.bulbs { display: flex; gap: 40px; justify-content: center; }

.bulb {
  position: relative; width: 30px; height: 46px;
  cursor: pointer; transition: transform .15s ease-out;
}
.bulb::before {  /* wire cap */
  content: ""; position: absolute; top: 0; left: 50%;
  transform: translateX(-50%);
  width: 8px; height: 6px; background: #2a2522; border-radius: 2px 2px 0 0;
}
.bulb-body {
  position: absolute; top: 6px; left: 0;
  width: 30px; height: 40px;
  border-radius: 50% 50% 50% 50% / 60% 60% 40% 40%;
  background: var(--bulb-color);
  box-shadow: 0 0 14px var(--bulb-color);
  transition: filter .15s;
}
.bulb:hover .bulb-body { filter: brightness(1.3); }
.bulb.playing { transform: translateY(4px) scale(1.18); }
.bulb.playing .bulb-body { filter: brightness(1.8); }

3. JavaScript

Web Audio creates each note on the fly — no audio files needed. The envelope (attack/decay) makes it sound like a soft glockenspiel hit, not a beep.

// Swamp UI — Xylophone Lights
(function () {
  let ctx = null;
  function note(freq, duration) {
    try {
      if (!ctx) ctx = new (window.AudioContext || window.webkitAudioContext)();
      const osc  = ctx.createOscillator();
      const gain = ctx.createGain();
      osc.connect(gain).connect(ctx.destination);
      osc.type = 'sine';
      osc.frequency.setValueAtTime(freq, ctx.currentTime);

      // gentle chime envelope
      gain.gain.setValueAtTime(0, ctx.currentTime);
      gain.gain.linearRampToValueAtTime(0.18, ctx.currentTime + 0.02);
      gain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + (duration || 0.6));

      osc.start();
      osc.stop(ctx.currentTime + (duration || 0.6));
    } catch (e) {}
  }

  document.querySelectorAll('.bulb').forEach(bulb => {
    const freq = parseFloat(bulb.dataset.freq);
    bulb.addEventListener('click', () => {
      note(freq);
      bulb.classList.add('playing');
      setTimeout(() => bulb.classList.remove('playing'), 300);
    });
  });
})();

4. Parameters you can tweak

WhereDefaultEffect
HTML data-freq 261.6 (C4) Frequency in Hz. Any number works. Use 1.5x for fifth, 2x for octave up.
HTML --bulb-color (CSS var) var(--neon-pink) Each bulb's color. Set inline per bulb to mix palettes.
JS osc.type sine Waveform. sine = clean. triangle = warm. sawtooth = sharp.
JS gain peak 0.18 Max loudness (0–1). Anything above 0.25 starts feeling rude.
JS duration 0.6 s How long each note rings. Shorter = pluckier; longer = chime-y.

5. Why pentatonic?

A pentatonic scale uses 5 notes spaced so no combination produces dissonance. That means random clicks always sound musical. Three scales worth knowing:

ScaleNotes (Hz)Vibe
Pentatonic C 262, 294, 330, 392, 440 Bright, happy — default. Folk / pop.
Pentatonic A minor 220, 262, 294, 330, 392 Melancholy, thoughtful. Studio Ghibli energy.
Wind chime 523, 587, 698, 784, 880 High, ethereal. Garden / temple feeling.
Liked this? Feed Mr. Knife & Ms. Ling.
And buy their owner a milk tea.
🧋 TREAT THE SWAMP
More in the garden → Firefly Tour (onboarding), Cat Wanderer, Swamp Name Generator.
Browse all →