# `` — multi-band spectrum visualiser _(no submodules)_ ## Purpose `` renders a real-time bar graph of magnitude bins. Each bin is drawn as a vertical bar whose height is proportional to the bin's magnitude in `[0, 1]`. The component is deliberately tier-pure: it has no dependency on `@suaveplan/audio-analysis-spectrum` or any audio code at all. Bins are pre-computed by the caller — wire it up to whatever analyser is appropriate (web-audio `AnalyserNode`, the spectrum-analysis package, a network stream, or a synthetic generator). This separation keeps the React rendering layer free of audio processing and makes it trivial to use the same component for any 1-D magnitude signal — FFT magnitudes, wavelet bands, frequency-warped mel bins, or live envelope follower output. ## Features - Static `Float32Array` or streaming `AsyncIterable` source - Configurable `width`, `height`, and inter-bar `gap` - Per-bin `data-value` attributes for E2E and screen-reader inspection - `role="img"` with a single `aria-label` describing the visualisation - CSS-variable themed bars (`--cs-meter-spectral-bar-color`) - Out-of-range bin values are clamped to `[0, 1]` automatically ## Usage: Basic ```tsx import { MeterSpectral } from "@suaveplan/react-control-surface"; ; ``` ## Usage: Advanced ```tsx import { MeterSpectral } from "@suaveplan/react-control-surface"; async function* spectrumStream( analyser: AnalyserNode ): AsyncIterable { const buf = new Float32Array(analyser.frequencyBinCount); while (true) { analyser.getFloatFrequencyData(buf); const out = new Float32Array(buf.length); for (let i = 0; i < buf.length; i++) { out[i] = Math.max(0, Math.min(1, (buf[i] + 100) / 100)); } yield out; await new Promise((r) => requestAnimationFrame(() => r(null))); } } ; ``` ## API Reference | Prop | Type | Default | Description | | ----------- | ------------------------------------------------- | ------- | ---------------------------------------- | | `bins` | `Float32Array \| AsyncIterable` | req | Magnitude bins in `[0, 1]`. | | `width` | `number` | `240` | Total width in CSS pixels. | | `height` | `number` | `80` | Total height in CSS pixels. | | `gap` | `number` | `1` | Inter-bar gap in CSS pixels. | | `label` | `string` | — | Visible + accessible label. | | `ariaLabel` | `string` | derived | Override the accessible label. | | `className` | `string` | — | Appended to `rcs-meter-spectral`. | ## Implementation Notes When `bins` is a `Float32Array`, the component sets its frame state directly on mount and whenever the prop identity changes. When `bins` is an `AsyncIterable`, an effect subscribes via `for await … of` and calls `setFrame` for every yielded frame. The subscription is torn down via a `cancelled` flag in the cleanup function; errors thrown from the iterator are swallowed because visualisation is best-effort. Bars are absolutely-positioned `div`s aligned to the bottom of the container; bar width is `(width - totalGap) / count`. This keeps the layout pure CSS and avoids `` — every bar is independently inspectable in DOM and accessible tooling.