
The Visualizer card
Make music you can see! Bars that bounce to the beat, waveforms, a whole light show… anything that reacts to sound counts.
Turn sound into something you can see! Bars that bounce to the beat, a wobbly waveform, a blob that swells every time the bass hits, a whole light show… if it moves to the music, it counts.
What counts
A visualizer listens to audio while it plays and draws something from it. The visuals have to come from the sound itself, so an animation you timed by hand to one song doesn’t count.
The best ones work with any song you throw at them. That’s the difference from the Demoscene card, where you make a show for one track. And if the player has to press buttons on the beat, you’re making a game, which sounds more like the Rhythm card!
The easiest thing that counts
Bars! One bar for each frequency band, and the louder that band is, the taller its bar.
In the browser, the Web Audio API does the hard part for you. An AnalyserNode runs an FFT (a bit of maths that splits sound into its frequencies) on whatever’s playing, many times a second:
const ctx = new AudioContext();
const analyser = ctx.createAnalyser();
analyser.fftSize = 256;
const source = ctx.createMediaElementSource(audioElement);
source.connect(analyser);
analyser.connect(ctx.destination); // so you can still hear it!
const bins = new Uint8Array(analyser.frequencyBinCount);
function draw() {
analyser.getByteFrequencyData(bins); // 0 to 255 for every band
// draw one bar per bin here
requestAnimationFrame(draw);
}
draw();
Draw the bars on a <canvas> and you’ve got a visualizer in an evening. Want to use a microphone instead? getUserMedia and createMediaStreamSource swap right in.
Making it look good
The bars are a start, but a few tricks make a huge difference:
- Bass lives in the first few bins. The FFT spreads its bands out evenly, so most of them end up covering high notes nobody really notices. Group them on a log scale, so the low end gets more room.
- Smooth it out. Raw FFT data is jittery.
smoothingTimeConstanthelps, and easing each value towards its target (fast on the way up, slow on the way down) looks way better. - Find the beat. Keep a running average of how loud the low end is. When it suddenly jumps above that average, that’s probably a kick drum! Flash something, shake the camera, spawn particles…
- Try the waveform too.
getByteTimeDomainDatagives you the raw wave instead of the frequencies, which is perfect for an oscilloscope look.
Going further
- Shaders. Pass the FFT data into a fragment shader as a texture, and every pixel gets to react to the music. Shadertoy can hook up a microphone or one of its own tracks as an input. The Shader guide is a good place to start.
- 3D. A field of cubes that jump with the frequencies, a tunnel that pulses on the beat… three.js makes this pretty approachable.
- Milkdrop. Winamp’s legendary visualizer, with thousands of presets made by its fans. Butterchurn is a WebGL port you can study, and making your own preset system is a fantastic rabbit hole.
- Oscilloscope music. Use the left channel as X and the right channel as Y, and a carefully made sound draws actual pictures on an oscilloscope. Look up Jerobeam Fenderson’s oscilloscope music, then try drawing your own shapes with sound!
- Real lights. An LED strip, an ESP32 and a little microphone make a visualizer for your whole room. WLED has a sound reactive mode if you want to see how it’s done.
About music
Test with songs you’re allowed to use, especially in your demo. incompetech.com and the Free Music Archive have tons of Creative Commons music, and you can make your own with BeepBox. Even better, let people pick their own file or use their microphone!
Before you ship
There’s a few things every project needs before we can approve it:
- It works. It doesn’t have to be finished, but the main thing it does should actually work.
- All of your code is public, on GitHub or somewhere like it.
- Anyone can try it, even someone who doesn’t code, in under two minutes of setup.
- Someone else could rebuild it from your repo and README.
What that looks like depends on where your visualizer lives:
- On the web: a public link that stays up. GitHub Pages, Vercel, Render, Railway and Nest are all great, but please don’t use Streamlit. Don’t put it behind a login either! If it really needs an account, put a demo login in your README.
- As a desktop app: a GitHub release with something people can download and run (an
.exe, a.dmg, an.AppImage…). The source code on its own isn’t enough. - As hardware, like an LED strip that dances to your music: a parts list with the exact parts you used (“ESP32-C3 SuperMini”, not “a microcontroller”), your schematic and PCB files or a wiring diagram, your firmware, and a video of it reacting to sound.
A video is a great way to show it off, but for software it can’t be your demo. When you do share one, put it on YouTube or Vimeo, or upload an .mp4, rather than Google Drive.
Shipping one
- Demo: a web page where it starts with a song already loaded. Browsers won’t play sound until someone clicks, so start with a “click to play” button.
- Screenshot: the loudest part of a song, when everything’s going off.
- README: what it reacts to and how it works. A short video is great here, since a screenshot can’t show off the motion. Credit your music too!
