<!-- GENERATED by scripts/build-llms.mjs from llms/conversation.md — do not edit this file. -->

# `lr-audio-visualizer`

- **Import** `import '@aceshooting/lyra-ui/components/lr-audio-visualizer.js';` (stable tag alias; registers the tag)
- **Class** `LyraAudioVisualizer`, also available unregistered from `@aceshooting/lyra-ui/components/conversation/audio-visualizer/audio-visualizer.class.js`
- **Family** `components/conversation/` — see `llms/index.md` for its siblings
- **Status** `stable` since `4.0.0` — see the maturity and deprecation policy in `llms/shared.md`
- **Release history** [CHANGELOG.md](../../CHANGELOG.md); family-wide breaking-change summaries: [llms-full.txt](../../llms-full.txt)
- **Deprecations** none
- **Optional peers** none
- **Themeable via** 2 parts, 4 custom properties — see this component's own `@csspart`/`@cssprop` list below
- **Library-wide behavior** (events, form association, `locale`/`strings`, tokens, TS types): `llms/shared.md`

---

## `lr-audio-visualizer`

A presentational, canvas-drawn voice-activity visualization (bars or waveform) — the
LiveKit-BarVisualizer counterpart for this library. Driven by a `MediaStream` (lazily wired to a
WebAudio `AnalyserNode`), a numeric `level` for hosts that already compute levels (e.g.
`<lr-push-to-talk>`'s `lr-level`), or `state` alone for an ambient animation when no real signal
exists. A real signal (`stream` or `level`) always drives amplitude regardless of
`prefers-reduced-motion`; only the signal-less ambient animation is throttled under reduced motion.

**Properties:** `stream: MediaStream | null = null` (attribute: false) — a live capture stream, lazily
wired to a WebAudio `AnalyserNode`; `level: number | null = null` — a pre-computed 0–1 amplitude for
hosts that already have one (e.g. `lr-push-to-talk`'s `lr-level` detail); `state: 'idle' |
'listening' | 'thinking' | 'speaking' = 'idle'` (reflected) — drives the signal-less ambient
animation and per-state coloring; `mode: AudioVisualizerMode = 'bars'` (`'bars' | 'waveform'`,
reflected); `barCount: number = 5` (attribute `bar-count`, normalized to an integer in `[1, 64]`);
`gain: number = 1` — multiplier applied to the resolved amplitude, with a non-finite value treated
as `1`; `label: string = ''` — accessible-name override. `level` is clamped to `[0, 1]`; after gain,
waveform and bar values are clamped to `[-1, 1]` and `[0, 1]` respectively. Invalid `state` or
`mode` attribute/property writes normalize to `idle` and `bars` respectively.

**Methods:** `refreshTheme()` re-reads themeable custom properties after a runtime theme change (the
canvas resolves token values at paint time and cannot inherit `var()` directly). Canvas-bound
colors are materialized through a live DOM probe, so `currentColor` and inherited expressions
resolve in the component's theme scope while invalid values fall back safely. Assigning a detached
or empty `MediaStream` tears down the prior analyser transaction immediately and draws from
`level`/ambient state; late setup from an older stream cannot replace the current source.

**Events:** none — purely presentational.

**Slots:** none.

**CSS parts:** `base` (the root wrapper) and `canvas` (the drawing surface, `aria-hidden`). The host
supplies `role="img"` only while an author has not supplied a role; an authored role is preserved,
and removing it restores `img`. If observation cannot be established, it draws eagerly; otherwise
it waits for a valid observer entry and pauses offscreen.

**Themeable custom properties:** `--lr-audio-visualizer-color` (default `var(--lr-color-brand)` —
active bar/waveform color), `--lr-audio-visualizer-quiet-color` (default
`var(--lr-color-brand-border-normal)` — inactive/idle color, chosen for WCAG 1.4.11 non-text
contrast against `--lr-color-surface`), and `--lr-audio-visualizer-height` (default
`var(--lr-size-3rem)` — the host's block size). `--lr-audio-visualizer-ambient-duration` (default
`var(--lr-duration-ambient)`) is the time-only `ms`/`s` duration of one signal-less ambient pulse
or sweep. It retimes this visualizer alone; compound transition values and invalid values fall back
to the shared duration, while reduced-motion ambient output remains static.
