Audio Wave Visualizer
A bouncing equalizer bar animation for audio/podcast/music UI.
- Category
- Assets
- Added
- 2026-08-23
- Deps
- 1
- Updated
- 2026-09-01
Props
"use client";
import { useEffect, useState } from "react";
import { motion } from "framer-motion";
const BAR_COUNT = 24;
function seededBars() {
return Array.from({ length: BAR_COUNT }, (_, i) => ({
base: 45 + ((i * 37) % 40),
duration: 0.7,
delay: (i % 6) * 0.06,
}));
}
export function AudioWaveVisualizer({
playing = true,
color = "#ff2d2d",
}: {
playing?: boolean;
color?: string;
}) {
const [bars, setBars] = useState(seededBars);
useEffect(() => {
setBars(
Array.from({ length: BAR_COUNT }, () => ({
base: 20 + Math.random() * 60,
duration: 0.5 + Math.random() * 0.6,
delay: Math.random() * 0.4,
})),
);
}, []);
return (
<div className="flex h-24 items-center justify-center gap-[3px] rounded-2xl border border-neutral-200 px-4">
{bars.map((bar, i) => (
<motion.span
key={i}
className="w-[3px] rounded-full"
style={{ background: color }}
animate={
playing
? { height: [`${bar.base * 0.3}%`, `${bar.base}%`, `${bar.base * 0.5}%`, `${bar.base * 0.85}%`] }
: { height: "10%" }
}
transition={
playing
? { duration: bar.duration, delay: bar.delay, repeat: Infinity, repeatType: "mirror", ease: "easeInOut" }
: { duration: 0.3 }
}
/>
))}
</div>
);
}
About this asset
A single shared animation across all the equalizer bars looks like a pulsing block rather than a real waveform; the illusion of audio activity depends on every bar moving on its own independent schedule. Each of the 24 bars here gets its own randomized base height, duration, and delay, animated through an array of height keyframes with repeat: Infinity and repeatType: mirror. The part that matters for correctness rather than looks: that randomization has to be generated inside a useEffect that runs after mount, not inside a useState initializer, because an initializer runs during render, including any server render, and Math.random() there produces different values server-side versus the first client paint, which React flags as a hydration mismatch. Reach for this over a static waveform SVG when the playing prop needs to actually toggle motion on and off, wired to a real audio element's play state; for a purely decorative header graphic that never changes, a static image is cheaper to render. It has no real audio analysis behind it; the bars are randomized, not FFT-driven, so it will never sync to actual sound.
Curator’s note
The per-bar randomization is generated in a post-mount effect, not a useState initializer — Math.random() inside an initializer runs during any server render too, and differing server/client values there is a real hydration mismatch, not just a style choice.
Pairs well with
Matched on shared tags and category — the entries most likely to be used alongside this one.
Confetti Burst Button
componentsA button that scatters a quick burst of confetti particles on click.
CRT Scanline Overlay
backgroundsScanlines, aperture grille, rolling refresh and vignette over any content.
ASCII Halftone Canvas
assetsTurns any canvas drawing into live ASCII art, sampled one pixel per glyph.