The Web Audio API's AnalyserNode exposes real-time FFT data
that you can render as bars, an oscilloscope, or a 3D frequency
landscape — all without sending audio to a server. This tutorial wires a
microphone input through the audio graph and draws several
visualizations.
1Set up the AudioContext and
AnalyserNode
const ctx = new AudioContext(); const analyser = ctx.createAnalyser();
// FFT size must be power of 2; frequencyBinCount = fftSize / 2
analyser.fftSize = 2048; // 1024 bins analyser.smoothingTimeConstant =
0.85; // 0 = no smoothing, 1 = sticky // buffers for data reads const
freqData = new Uint8Array(analyser.frequencyBinCount); // 0–255 per
bin const timeData = new Uint8Array(analyser.fftSize); // waveform //
connectthe graph: source → analyser → destination
analyser.connect(ctx.destination);
frequencyBinCount is half of fftSize.
Each bin spans sampleRate / fftSize Hz. With
fftSize = 2048 at 44100 Hz that's ~21.5 Hz per bin.
2Request microphone access
let source; document.getElementById('start').addEventListener('click',
async () => { // Must be triggered by user gesture — no autoplay await
ctx.resume(); try { const stream = await
navigator.mediaDevices.getUserMedia({ audio: true, video: false });
source = ctx.createMediaStreamSource(stream);
source.connect(analyser); // NOTE: do NOT connect analyser to
ctx.destination if you don't want audio feedback draw(); } catch (err)
{ console.error('Microphone denied:', err); } });
3Draw a 2D spectrum bar chart
const canvas = document.getElementById('spectrum'); const c2d =
canvas.getContext('2d'); const W = canvas.width, H = canvas.height;
function drawSpectrum() { analyser.getByteFrequencyData(freqData);
c2d.clearRect(0, 0, W, H); const barW = W / freqData.length; for (let
i = 0; i < freqData.length; i++) { const value = freqData[i]; //
0–255 const barH = (value / 255) * H; // Colour: low freq = blue, high
= red const hue = 240 - (value / 255) * 240; c2d.fillStyle =
`hsl(${hue},100%,50%)`; c2d.fillRect(i * barW, H - barH, barW - 1,
barH); } } function draw() { requestAnimationFrame(draw);
drawSpectrum(); }
4Draw an oscilloscope waveform
const waveCanvas = document.getElementById('waveform'); const wCtx =
waveCanvas.getContext('2d'); function drawWaveform() {
analyser.getByteTimeDomainData(timeData); wCtx.clearRect(0, 0, W, H);
wCtx.lineWidth = 2; wCtx.strokeStyle = '#22c55e'; wCtx.beginPath();
const sliceW = W / timeData.length; let x = 0; for (let i = 0; i <
timeData.length; i++) { const v = timeData[i] / 128.0; // normalise
0-2, centre at 1 const y = (v / 2) * H; if (i === 0) wCtx.moveTo(x,
y); else wCtx.lineTo(x, y); x += sliceW; } wCtx.lineTo(W, H / 2);
wCtx.stroke(); } // Call drawWaveform() inside the draw() loop
alongside drawSpectrum()
getByteTimeDomainData returns the raw sample buffer
(PCM). Values range 0–255 where 128 is silence. The oscilloscope is
the simplest way to confirm audio is flowing.
53D bars with Three.js InstancedMesh
import * as THREE from
'https://cdn.jsdelivr.net/npm/three@0.160/build/three.module.js';
const BINS = 128; // use first 128 frequency bins const geo = new
THREE.BoxGeometry(0.8, 1, 0.8); const mat = new
THREE.MeshStandardMaterial({ color: 0x22c55e }); const mesh = new
THREE.InstancedMesh(geo, mat, BINS); scene.add(mesh); const dummy =
new THREE.Object3D(); const colors = new THREE.Color(); function
update3DBars() { analyser.getByteFrequencyData(freqData); for (let i =
0; i < BINS; i++) { const v = freqData[i] / 255; // 0–1 const barH
= Math.max(0.05, v * 20); const x = (i - BINS / 2) * 1.1;
dummy.position.set(x, barH / 2, 0); dummy.scale.set(1, barH, 1);
dummy.updateMatrix(); mesh.setMatrixAt(i, dummy.matrix); // Colour
gradient by frequency colors.setHSL((1 - v) * 0.66, 1, 0.5);
mesh.setColorAt(i, colors); } mesh.instanceMatrix.needsUpdate = true;
if (mesh.instanceColor) mesh.instanceColor.needsUpdate = true; } //
Call update3DBars() in the render loop
Using InstancedMesh collapses all 128 bars into a
single draw call, keeping the GPU happy even at high frame rates.
Frequently Asked Questions
What will I learn in this tutorial?
Build a real-time audio spectrum visualizer with the Web Audio API — FFT analysis, bar chart, waveform oscilloscope, and Three.js 3D bars.
What topics are covered in this tutorial?
This tutorial covers: Set up the AudioContext and AnalyserNode, Request microphone access, Draw a 2D spectrum bar chart, Draw an oscilloscope waveform, 3D bars with Three.js InstancedMesh.
What tools and technologies does this tutorial use?
This tutorial uses Web Audio API, Canvas 2D, Three.js.
How long does this tutorial take?
This tutorial takes approximately 45 minutes to complete.
What prerequisites do I need before starting?
This is a Beginner-level tutorial — no special preparation beyond basic JavaScript is assumed.