Hover✨ Premium

Sound Visualizer

A Web Audio visualizer: 20 bars that follow the real audio spectrum — built-in synthesized demo sound, optional mic, or connected to your own audio player.

JSAudioVisual

Updated

This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Hover has 48 effects, including 5 free. Explore the category →

3 usage examples

Giant background bars — festival or podcast landing page — Sound Visualizer example 1

① Giant background bars — festival or podcast landing page

WhenThe hero of a music festival or podcast site: the bars span the full width behind the title and the "Listen to preview" button. They animate when the user clicks and stay reactive throughout playback.
WhyA live sound background turns a static header into a sensory experience; it instantly signals that the page is about music and invites the user to press the listen button.
SettingsRoot at position: absolute; inset: 0, transparent background (--viz-bg: transparent), bars with no width cap (max-width: none via scene CSS) to fill the full section. Bar height: 192 px. Low color #2563eb, high color #a855f7. Controls hidden via scene CSS.
Now-playing indicator — track row inside a playlist — Sound Visualizer example 2

② Now-playing indicator — track row inside a playlist

WhenIn an online audio player, the track list: the currently playing track shows a small spectrum visualizer (96 × 22 px) to the right of its name; the other rows do not. The bars animate during playback and fall back on pause. In production, connect data-fx0378-source to the player's <audio> element.
WhyA spectral indicator animates the "now playing" row without adding a static icon; it is instantly readable and takes up minimal space in the list.
SettingsRoot at 96 × 22 px, transparent background, bar height 22 px, gap between bars 2 px, overflow hidden. Controls and status hidden. Low color #6366f1, high color #a78bfa.
Level gauge — microphone check screen before a video call — Sound Visualizer example 3

③ Level gauge — microphone check screen before a video call

WhenAn intermediate "Test your equipment" screen before joining a video call: microphone selector, spectrum level gauge and a "You are heard clearly" message that appears as soon as a signal is detected. The user clicks "Check mic" to activate the real audio input. In the captures for this example, the built-in synthesized demo feeds the gauge instead of a real microphone — this behaviour is private and not presented as a product feature.
WhyA real-time spectrum meter gives immediate feedback on mic level and signal presence, far more reliable than a simple green/red indicator.
SettingsFull-width root inside the center panel. Demo button hidden via CSS (only "Check mic" is visible). Bar height: 52 px. Low color #22c55e, high color #86efac. Background #0d1a12 with a subtle green border.

How it works

The root .fx-0378-root holds three zones: .viz-bars (20 .viz-bar elements created by the script, decorative), .viz-controls (two real <button> elements) and .viz-status (state announcements for screen readers). CSS gives the bars an indigo-violet gradient (linear-gradient(to top, #6366f1, #d946ef)) and a resting height of 4 px.

The script initializes one AudioContext per root, with an AnalyserNode (256-point FFT, 128 frequency bins, smoothing 0.78). On each frame, getByteFrequencyData fills a 128-byte array. The 20 bars are mapped to frequency ranges on a logarithmic scale (20 Hz–Nyquist): low frequencies drive the first bars, highs drive the last — like a real spectrum analyzer. Bar height: value / 255 × 126 px, minimum 4 px.

The built-in demo sound is fully synthesized: a setTimeout scheduler schedules Web Audio events 280 ms ahead, looping an 8-step pattern at 120 BPM (one step = 0.25 s). The pattern combines: a kick drum (sine oscillator sweeping from 90 to 28 Hz with an amplitude envelope), a hi-hat (white noise filtered high-pass at 8 800 Hz), a clap (white noise filtered band-pass at 1 500 Hz) and a G4–G5 pentatonic melody (sawtooth oscillators at 659, 523, 784, 587 Hz, filtered low-pass at 3 200 Hz). The sawtooth harmonics drive the mid bars, percussion the low and high bars.

To connect your own player, add data-fx0378-source="#my-audio" to the root: the script listens for play on that <audio> or <video> element, creates a MediaElementAudioSourceNode (once per element), connects it to both the analyser and the destination, then starts drawing the bars. CORS note: a file hosted on another domain must send proper Access-Control-Allow-Origin headers, otherwise createMediaElementSource will fail.

The AudioContext suspends whenever the root leaves the viewport (IntersectionObserver) or the tab is hidden (visibilitychange), resuming on return. Clean shutdown: mic tracks are stopped (stream.getTracks().forEach(t => t.stop())), nodes disconnected, context suspended.

Accessibility

  • Reduced motion: under prefers-reduced-motion: reduce, the requestAnimationFrame loop is replaced by updates every 300 ms (3–4 Hz) with no CSS transition. The visualizer stays informative — bars reflect the real audio spectrum — without continuous animation. Sound and status messages work normally.
  • Accessible buttons: both buttons carry aria-pressed updated on each state change ("false" / "true"). They are reachable by Tab, activatable by Enter or Space, and styled with a :focus-visible outline. Labels toggle between « Play demo » and « Stop demo ».
  • Decorative bars: the .viz-bars container carries aria-hidden="true"; the bars carry no audio information — they are a visual reflection. The audio state is announced in .viz-status (aria-live="polite").
  • Mic and https: getUserMedia is blocked on non-secure pages (http in production). A specific error message is shown for each error type: access denied, no mic found, insecure page.
  • No forced gesture: no sound starts without an explicit user click (browser autoplay policy). The mic activates only after the browser confirms permission.

Browser compatibility

Web Audio API (AudioContext, AnalyserNode, createMediaStreamSource, createMediaElementSource, IntersectionObserver). No external dependency. Measured in Chromium 151 and Firefox 153: demo sound, spectral analysis, two independent copies in one page, 0 JS errors. WebKit supports Web Audio since Safari 14.1: not verified in a real Safari.

Chrome 55+✓ Full (measured)
Firefox 53+✓ Full (measured)
Safari 14.1+✓ Web Audio supported, not verified in real Safari
Edge 79+✓ Full (Chromium engine)
Mobile iOS 14.5+✓ AudioContext supported, not verified on real device
Android Chrome 55+✓ Full (Chromium engine)

Without JavaScript or Web Audio (very old browser), the 20 bars at 4 px are visible and the buttons are displayed but inactive. No error is thrown.

The code

HTML structure to paste into your page (the CSS + JS come with your purchase):

index.html — structure
<div class="fx-0378-root">
  <div class="viz-bars" aria-hidden="true"></div>
  <div class="viz-controls">
    <button class="viz-btn viz-btn--demo" type="button" aria-pressed="false">
      <span class="viz-btn-icon" aria-hidden="true">▶</span>
      <span class="viz-btn-label">Play demo</span>
    </button>
    <button class="viz-btn viz-btn--mic" type="button" aria-pressed="false">
      <span class="viz-btn-icon" aria-hidden="true">🎙</span>
      <span class="viz-btn-label">Microphone</span>
    </button>
  </div>
  <div class="viz-status" aria-live="polite" aria-atomic="true"></div>
</div>

One-time payment, no subscription — the code is yours forever

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Audio source (HTML — data-fx0378-source attribute on .fx-0378-root) None: only the built-in synthesized demo is available Pass the CSS selector of your <audio> or <video> element (e.g. data-fx0378-source="#my-player"). The visualizer starts automatically on play and stops on pause. CORS: if your audio file is hosted on another domain (CDN, third-party service), that domain must respond with Access-Control-Allow-Origin: * or your specific domain — otherwise createMediaElementSource will fail.
Bar low and high color (CSS — --viz-low and --viz-high on .fx-0378-root) #6366f1 (indigo) → #d946ef (violet-pink) Override both variables on the root: style="--viz-low:#f97316;--viz-high:#fbbf24".
Number of bars (JS — NUM_BARS constant) 20 Increase up to 48 for finer frequency detail. Reduce to 8 for a minimal look. Bar width (flex: 1; max-width: 14px) adapts automatically.
FFT resolution (JS — analyser.fftSize) 256 (128 bins) Set to 512 or 1024 for finer frequency resolution — most useful with more than 32 bars. Must be a power of two.
Demo tempo (JS — BPM constant) 120 Slow to 90 for a more relaxed groove, increase to 140 for a faster feel. The 8-step pattern adapts automatically.
Maximum bar height (JS — the 126 in the height calculation) 126 px Adjust to match your container. Must not exceed the .viz-bars height (height: 130px).

FAQ

Add data-fx0378-source="#your-player-id" to the .fx-0378-root element. The visualizer connects on play and disconnects on pause. CORS note: if your audio is hosted on another domain (CDN, third-party service), that domain must send the Access-Control-Allow-Origin header with your domain or * — otherwise createMediaElementSource will fail and an error message will appear.
Three common causes: (1) Page on http: getUserMedia is blocked on non-secure pages — deploy over https. (2) Permission denied: the user dismissed the browser permission dialog — they can re-allow it from the site settings. (3) No mic detected: check that a microphone is connected and recognized by the operating system.
The demo is a Web Audio scheduler embedded in the script. Find the « Demo sound synthesis » section: PAT_KICK, PAT_HAT, PAT_CLAP and PAT_MEL define the 8-step pattern; SCALE sets the melody frequencies; BPM controls the tempo. The functions schedKick, schedHat, schedClap and schedNote create the Audio nodes at each step.