Guide
Data modes
The three ways to get audio data into the visualizer — local, WebSocket, and external.
The visualizer has one job — render a spectrum — and three ways to get the data, selected
with the mode option (a prop in Vue and React, a constructor option in Core).
| Mode | How data arrives | Use when |
|---|---|---|
local | Captures mic or display audio and computes the FFT in-browser (Rust/WASM) | You want a zero-backend, client-side visualizer |
websocket (default) | Connects to websocketUrl and reads pre-computed FFT frames | A server/device already produces FFT data (e.g. a Raspberry Pi) |
external | You pass FFT magnitudes as data / dataLeft / dataRight | You have your own audio pipeline (Web Audio, another analyser, etc.) |
Local mode
Set audioSource to display to capture tab/system audio via screen sharing instead of the
microphone.
new FFTVisualizer(canvas, { mode: 'local', audioSource: 'mic', bands: 80 })
<FFTVisualizer mode="local" audio-source="mic" :bands="80" />
<FFTVisualizer mode="local" audioSource="mic" bands={80} />
WebSocket mode
The server streams a small config message then binary FFT frames — see the
WebSocket protocol. Reference servers for Python, Node.js and
Rust are in the repository's backend-examples/.
new FFTVisualizer(canvas, {
mode: 'websocket',
websocketUrl: 'wss://your-server/fft',
bands: 40,
autoReconnect: true
})
<FFTVisualizer
mode="websocket"
websocket-url="wss://your-server/fft"
:bands="40"
:auto-reconnect="true"
/>
<FFTVisualizer
mode="websocket"
websocketUrl="wss://your-server/fft"
bands={40}
autoReconnect
/>
On an HTTPS page you must use a
wss:// URL — browsers block insecure ws:// from
secure pages as mixed content.External mode
Pass a Uint8Array of magnitudes (0–255); update it and the visual follows. For stereo,
pass dataLeft and dataRight instead of data.
const viz = new FFTVisualizer(canvas, { mode: 'external', bands: 40 })
// ...each frame, feed fresh magnitudes (the data is copied):
viz.feedData(myUint8Array)
<script setup>
import { ref } from 'vue'
import { FFTVisualizer } from '@fft-visualizer/vue'
const data = ref(new Uint8Array(80))
// ...fill data.value from your own analyser each frame
</script>
<template>
<FFTVisualizer mode="external" :data="data" :bands="40" />
</template>
import { useState } from 'react'
import { FFTVisualizer } from '@fft-visualizer/react'
const [data, setData] = useState(new Uint8Array(80))
// ...set a fresh array from your own analyser each frame
<FFTVisualizer mode="external" data={data} bands={40} />
Feed data by copy for in-place buffers. Core's
feedData() copies the data, so reusing
one Uint8Array each frame is fine. In both wrappers the data prop is compared by
reference — if you mutate the same array in place, the change goes unnoticed. Either pass a
fresh array, or call feedData() on the component (Vue,
React), which copies — and in React also skips a render per
frame.