Spectrogram
spectrogramVisualizersWhere the spectrum shows one instant of the FFT, this keeps the history: each frame paints a single column at the right edge and shifts the whole image one pixel left, so the display reads right-to-left from now back to a few seconds ago. Frequency runs up the vertical axis on a log scale, magnitude is colour, and six ramps are built in. The scroll is a self-blit rather than a repaint of a stored ring buffer, which is what makes a full-width spectrogram affordable at animation rate. The bin-to-pixel mapping is an exported pure function, so the data path can be asserted on in a test or reused by a WebGL renderer.
Synthetic spectrum for display only — this demo produces no audio.
Install
Copies the source into your project. Anything it depends on comes with it.
$ npx shadcn add @syntho-ui/spectrogramPulls in
First time? Add the registry to your components.json once:
{
"registries": {
"@syntho-ui": "https://engine.syntho.app/r/{name}.json"
}
}Usage
Controlled or uncontrolled, whichever suits the surrounding state.
import { Spectrogram } from "@/components/ui/spectrogram"
<Spectrogram analyser={analyserNode} height={220} colorScale="viridis" />Props
| Prop | Type | Default | Description |
|---|---|---|---|
| analyser | AnalyserNode | — | A live analyser to read frequency data from. |
| getData | (target: Float32Array) => boolean | void | — | Supply dB magnitudes yourself instead of using an analyser. |
| colorScale | "viridis" | "plasma" | "inferno" | "magma" | "cividis" | "turbo" | "grayscale" | "heat" | (value: number) => [r, g, b] | "viridis" | Built-in colour ramp, or your own magnitude → RGB function. |
| scale | "log" | "linear" | "log" | Frequency axis mapping. Linear spends most of the height above 10 kHz; log is the musically useful one. |
| minFrequency / maxFrequency | number | 20 / Nyquist | The frequency range shown, bottom to top. |
| minDecibels / maxDecibels | number | -90 / -10 | The magnitude range mapped onto the colour ramp. |
| gain | number | 1 | Magnitude multiplier applied after normalisation, before clamping. |
| scrollSpeed | number | 1 | Pixels the image scrolls per frame. Higher is faster and coarser. |
| sampleRate | number | — | Needed for the frequency axis when driving from getData. |
| showAxis | boolean | true | Draw the decade frequency labels down the left edge. |
| height | number | 200 | Display height in pixels; width defaults to 100%. |
| paused | boolean | false | Stop the animation loop and hold the last frame. |
Interaction
- Drag with pointer capture, so the gesture keeps tracking past the edge of the control.
- Shift while dragging for a fine pass; release it mid-gesture and coarse tracking resumes.
- Double-click resets to
defaultValue. - Arrow keys step normally, Shift+arrow steps finely, PageUp/PageDown jump by ten, Home/End go to the extremes.
- Proper
sliderandswitchroles with livearia-valuetext, so a screen reader announces the formatted value rather than the raw number. - The scroll wheel adjusts the value while the pointer is over the control; stepped ranges move at least one declared step per notch by default.