# Live Waveform

> A canvas waveform of a live signal, as scrolling history or the current frame.

<ComponentPreview name="live-waveform-demo" />

## Installation

```npm
npx shadcn-svelte@latest add @audiocn-svelte/live-waveform
```

## Usage

```svelte
<script lang="ts">
	import { LiveWaveform } from "#lib/components/ui/live-waveform/index.js";
</script>

<LiveWaveform mode="scrolling" source={analyser.visual} class="h-16" />
```

The waveform fills its container, so size it with classes. It redraws on resize and picks up theme changes on its own.

Scrolling moves between history samples without adding samples. The source's `historyIntervalMs` option sets the minimum wait, 50 ms by default. The source takes the next sample on the first frame after that wait. With 16 ms frames, samples arrive every 64 ms, and a bar moves one step over those 64 ms.

The drawing uses a short buffer so it can follow measured sample times without guessing when the next sample will arrive. This adds twice the configured history interval as display delay, 100 ms by default. If the browser pauses or throttles frames, the built-in sources skip missed samples rather than repeat stale levels. If you use a custom source, add the [history timing fields](/docs/concepts/feeding-data#frames) to enable smooth scrolling.

When the source stops sending frames, the waveform finishes its buffered scroll and stops requesting animation frames. A new source frame wakes it again.

## Examples

### Variants

<ComponentPreview name="live-waveform-variants" />

### Idle

With `active={false}` the waveform shows a dotted line.

<ComponentPreview name="live-waveform-idle" />

### Microphone

<ComponentPreview name="live-waveform-microphone" />

## Theming

| Variable or attribute       | Meaning                                      |
| --------------------------- | -------------------------------------------- |
| `--waveform`                | Drawing color, default `currentColor`        |
| `data-mode`, `data-variant` | Current settings                             |
| `data-active`               | Drawing the signal rather than the idle line |

## Accessibility

The root has `role="img"`. Give it an `aria-label`, or `aria-hidden` when a labelled meter is next to it. With reduced motion it redraws four times a second.

## API reference

<PropsTable
	rows={[
		["source", "FrameSource<VisualFrame> | null", null, null],
		[
			"mode",
			'"scrolling" | "static"',
			'"static"',
			"scrolling shows level history; static shows the current frame.",
		],
		[
			"variant",
			'"bars" | "line" | "mirror"',
			'"bars"',
			"line draws the waveform trace in static mode.",
		],
		["barWidth", "number", "3", "Pixels."],
		["barGap", "number", "1", "Pixels."],
		["barRadius", "number", "1.5", "Pixels."],
		["minBarHeight", "number", "4", "Pixels."],
		["lineWidth", "number", "1.5", "For the line variant."],
		["fadeEdges", "boolean", "true", "Fade the left and right edges."],
		["fadeWidth", "number", "24", "Pixels."],
		["active", "boolean", "true", "false shows an idle dotted line."],
		["sensitivity", "number", "1", "Visual gain."],
	]}
/>

### Exported functions

Bind the component with `bind:this` to call them. Their type is `LiveWaveformActions`.

<PropsTable
	rows={[
		["paint", "(frame: VisualFrame) => void", null, "Paint a frame directly."],
		["clear", "() => void", null, "Clear the canvas and forget the last frame."],
	]}
/>
