Core

API reference

The FFTVisualizer class — constructor, getters, methods, events, and helpers.

fft-visualizer-core exports the imperative FFTVisualizer class plus a parseCssColor helper. All configuration uses the shared option set documented in Options.

Constructor

import { FFTVisualizer, type FFTVisualizerOptions } from 'fft-visualizer-core'

const viz = new FFTVisualizer(canvas, options)
ParameterTypeDescription
canvasHTMLCanvasElementThe canvas to render into. The visualizer sizes to the canvas's parent element and observes it for resizes
optionsFFTVisualizerOptions (optional)Any of the shared options

Constructing the instance initializes WebGL and connects immediately using options.mode (local capture starts, a WebSocket opens, or external mode begins rendering). If WebGL fails to initialize, an error event is emitted instead.

Getters

GetterTypeDescription
isConnectedbooleanWhether the data source is currently active
fpsnumberFrames processed in the last second
audioDevicesAudioDevice[]Known audio input devices (populated after getAudioDevices() or local capture)
activeAudioDeviceIdstring | undefinedThe device ID currently in use for local mic capture

Methods

MethodSignatureDescription
connect() => voidStart the current mode (open the WebSocket, start capture, or begin external rendering). Called automatically by the constructor
disconnect() => voidStop the data source and rendering
setOptions(patch: Partial<FFTVisualizerOptions>) => voidApply a partial options update at runtime (see below)
feedData(data: Uint8Array, left?: Uint8Array, right?: Uint8Array) => voidFeed FFT magnitudes (0–255) in external mode. The data is copied, so reusing one buffer per frame is safe. Pass left and right for stereo
refreshGradient() => voidRebuild the gradient LUT after mutating custom stops in place (not needed when you assign a new gradient)
getAudioDevices() => Promise<AudioDevice[]>Enumerate audio input devices (prompts for mic permission if needed)
destroy() => voidDisconnect, stop observing resize, remove all listeners, and free every WebGL resource

setOptions(patch)

Only keys whose value actually changed take effect. Changing mode or websocketUrl reconnects; changing bands reallocates buffers; changing background or gradient reuploads the relevant texture. To reload a gradient whose stops you mutated in place, either pass a new gradient reference or call refreshGradient().

viz.setOptions({ ledBars: true, gradient: 'sunset', bands: 20 })

Events

Subscribe with on(), which returns an unsubscribe function; or remove a handler with off().

const stop = viz.on('frame', ({ data, left, right }) => {
  // data: Uint8Array — one 0–255 magnitude per bar (length = bands)
  // left / right: per-channel arrays in stereo mode, else null
})
stop() // unsubscribe
EventPayloadFires when
connectedThe data source became active
disconnectedThe data source stopped
errorstringA WebSocket error, capture failure, or WebGL init failure
frameFrameEventOnce per processed audio frame, with the display bar magnitudes
audiostateLocal-audio state changed (capture started/stopped, or the device list updated)

The frame event is a ready-made feed for external hardware (LED strips, flip-dot displays) — it hands you exactly what the shader draws, without re-implementing any FFT. It's listener-gated, so it costs nothing when no handler is attached.

interface FrameEvent {
  data: Uint8Array          // per-bar magnitudes (in stereo, the per-bar max of both channels)
  left: Uint8Array | null   // per-channel in stereo, else null
  right: Uint8Array | null
}

parseCssColor(color)

import { parseCssColor } from 'fft-visualizer-core'

parseCssColor('rgba(10, 10, 10, 0.5)') // => [r, g, b, a] normalized 0–1

Parses any CSS color (including rgba() and 'transparent') into a normalized [r, g, b, a] tuple via a 1×1 canvas — the same routine the visualizer uses for the background option.

Types

VisualizerMode ('websocket' | 'local' | 'external'), BandCount (10 | 20 | 40 | 80), FFTVisualizerOptions, FFTVisualizerEventMap, and FrameEvent are all exported for typing your own code.

Copyright © 2026