Graphics@knitui/graphics
AudioVisualizer
A data-driven Skia audio visualizer. An external driver only ever pushes new TARGET states (a row of 0..1 levels) via the imperative ref handle (ref.push(levels)) or a target SharedValue — the easing TRANSITION between states lives inside the component, paced on the display clock (requestAnimationFrame), double-buffered, off the React render path, and self-suspending when idle. useDerivedValue worklets build the SkPaths so the per-frame paint never re-renders React. Filled with a Skia gradient and optional glow. Identical on native and web (web needs <GraphicsProvider> + CanvasKit). Reduced-motion snaps to each target. The stories below drive it with a synthetic ticker.
import { AudioVisualizer } from "@knitui/graphics";Playground
Loading playground…
<AudioVisualizer
variant="mirror"
pattern="sine"
/>Examples
Default
The default mirrored waveform, driven by a smooth travelling sine.
Loading example…
Bars
Vertical bars filled with a linear gradient.
Loading example…
Line
A stroked line tracing the level at each point.
Loading example…
Dots
A dot per bar, sized by level.
Loading example…
Wave
A filled, mirrored envelope (smooth waveform area) with a glow.
Loading example…
Radial
Spokes radiating from the centre, with a sweep gradient pivoting on the centre.
Loading example…
Bursty Ticks
The headline story: a BURSTY, irregular data source (jittery delivery + occasional stalls) — yet the on-screen motion stays smooth because the easing transition is paced on the display clock, not the data clock.
Loading example…
Smoothed
Jumpy per-bar noise, tamed by heavy smoothing — the transition does the work.
Loading example…
Glow
A soft glow behind a sweep-gradient mirror waveform.
Loading example…
Neon
A neon look: a crisp shape with a separate, brightly-tinted blurred halo (glowColor).
Loading example…
Vu Meter
VU-meter feel: a snappy attack (peaks pop) with a slow release (a gentle decay tail).
Loading example…
Horizontal Gradient
A horizontal gradient running left→right across the bars instead of top→bottom.
Loading example…
Resting Floor
A resting baseline (floor) so the visualizer always shows a lively bed of bars.
Loading example…
Gain
Boosted sensitivity (gain) — quiet input pushed up toward the ceiling and clamped.
Loading example…
Tinted
A tinted background with a translucent shape (backgroundColor + opacity).
Loading example…
Spectrum10 Hz
Loading example…
Raw Fft Input
Loading example…
Target Shared Value
Driven by a target SharedValue instead of the ref handle: write target.value = levels from any JS-thread loop and the visualizer eases toward it. While a target is set the display loop runs continuously (it can't listen to SV writes portably), so prefer the ref push() for the self-suspending path.
Loading example…
Props
| Prop | Type | Default | Description |
|---|---|---|---|
attack | number | undefined | — | Rise smoothing `0..1` override — lower = snappier peaks. Defaults to `smoothing`. |
backgroundColor | string | undefined | — | Canvas background color. Default transparent. |
color | string | undefined | — | Solid fill color (any CSS / RN / Skia color). Ignored when `gradient` is set. |
count | number | undefined | — | Number of levels (bars) to render. Default 48. |
fftScale | SpectrumInput | undefined | — | How `input="fft"` magnitudes are scaled. Default `"byte"` (`AnalyserNode` bytes). |
floor | number | undefined | — | Resting baseline `0..1`: lifts every level so the shape never fully collapses (`v → floor + (1 - floor) · v`). Default `0`. |
gain | number | undefined | — | Multiply incoming levels (sensitivity), clamped to `0..1`. Default `1`. |
gap | number | undefined | — | Gap between bars, px. Default 2. |
glow | number | boolean | undefined | — | A soft glow behind the shape (a Skia blur). `true` applies a tasteful default; a number sets the blur radius in px. Pair with `glowColor` for a tinted halo. Default off. |
glowColor | string | undefined | — | Tint for the `glow` halo. When set, the shape stays crisp and a separate blurred layer in this color sits behind it (a neon look). Requires `glow`. |
gradient system | string[] | VisualizerGradient | undefined | — | A Skia gradient fill — the real payoff of rendering with Skia. Pass an array of colors for a linear gradient, or `{ colors, type }` for control. Overrides `color`. |
gradientDirection | "vertical" | "horizontal" | undefined | — | Linear-gradient orientation. Default `"vertical"` (top→bottom). |
height | number | undefined | — | Visualizer height in px. Default 48. |
input | "levels" | "fft" | undefined | — | What the pushed data (`push()` / the `levels` prop) carries. The visualizer keeps only the data its settings need: - `"levels"` (default) — already the final per-bar values. - `"fft"` — RAW FFT magnitudes; push the whole spectrum (256/512/1024 bins) and the component reduces it to `count` log-spaced, dB-normalized bands itself (a memoized `createSpectrumMapper`). Nothing larger than `count` is ever stored or animated. The `target` SharedValue is always treated as final levels. |
label | string | undefined | — | Accessible label. |
levels | number[] | undefined | — | Declarative fallback: the component pushes this state whenever the value changes. Convenient, but re-renders the component each tick — at high tick rates prefer the ref `push()` handle (Skia Rule 1). |
maxBin | number | undefined | — | `input="fft"`: last magnitude bin to include. Default = pushed length. |
maxDb | number | undefined | — | `input="fft"`: dB mapped to `1` (ceiling). Default `-10`. Ignored for `"byte"`. |
minBin | number | undefined | — | `input="fft"`: first magnitude bin to include (skip DC). Default `1`. |
minDb | number | undefined | — | `input="fft"`: dB mapped to `0` (floor). Default `-90`. Ignored for `"byte"`. |
opacity | number | undefined | — | Overall opacity `0..1` of the shape. Default `1`. |
radius system | number | undefined | — | Shape rounding, px (default 2). Its effect is per-variant: corner radius for `bars`/`mirror` rects, and the stroke width for `line`/`radial` (min 1.5). The `dots` and `wave` variants ignore it — dot size tracks the level and the wave envelope is filled, not stroked. |
release | number | undefined | — | Fall smoothing `0..1` override — higher = a slower VU-meter tail. Defaults to `smoothing`. |
responseTime | number | undefined | — | Rise time constant in MILLISECONDS, overriding the `smoothing`→time mapping. Rate-independent: the same value glides identically whether you push at 10 Hz or 60 Hz — set it (e.g. `90`) to make a sparse/low-rate FFT feed smooth at 60 fps. Release defaults to ~3× this unless `release` is given. |
reverse | boolean | undefined | — | Reverse the level order (mirror the data left↔right / around the ring). |
smoothing | number | undefined | — | Attack/release smoothing, `0..1`. `0` snaps to each target; higher values let levels glide and decay. Default `0.3`. Forced to `0` under reduced motion. Use `attack`/`release` to tune the rise/fall halves independently. |
target | SharedValue<number[]> | undefined | — | Optional external target SharedValue. Write `target.value = levels` from your data handler instead of using the ref handle; the loop eases toward it. While a `target` is provided the display loop runs continuously (it can't listen to SV writes portably), so prefer the ref `push()` for the self-suspending path. |
variant system | string | VisualizerVariant | undefinedbars · mirror · wave · line · dots · radial | — | The visual style: a built-in name (`"bars"`, `"mirror"`, `"wave"`, `"line"`, `"dots"`, `"radial"`), a custom name registered via `registerVisualizerVariant`, or a variant function. Default `"mirror"`. |
width | number | undefined | — | Fixed width in px. Omit for a responsive `width: "100%"` canvas. |
Accessibility & DOM props (2)
| Prop | Type |
|---|---|
key | Key | null | undefined |
ref | Ref<AudioVisualizerHandle> | undefined |