<!-- Generated by scripts/gen-docs.mts from the JSDoc in registry/. Do not edit; run `pnpm run docs`. -->

# LevelMeter

A small live input level: a row of bars that light from the start edge as a microphone picks up sound, so the person can tell it hears them before anyone else does (before joining a call, in a device menu, in a "test your microphone" row). The app feeds `value`, the microphone's linear amplitude from 0 to 1, as often as about 15 times a second, and the meter maps it to its bars on a decibel scale, so ordinary speech lights about half of them. To get the amplitude, read an `AnalyserNode`'s samples with `getFloatTimeDomainData(samples)` and take their RMS: `Math.sqrt(samples.reduce((sum, sample) => sum + sample * sample, 0) / samples.length)`.

```tsx
import { LevelMeter } from "@/components/ouro/level-meter/level-meter";
```

## Example

```tsx
<LevelMeter label="Microphone level" value={rms} />
<LevelMeter label="Microphone level" hideLabel value={rms} size="sm" bars={5} />
<LevelMeter label="Microphone level" value={rms} muted={micMuted} />
```

## Usage

The bars move as an audio meter's do: they rise within about 50 ms and fall over about 350 ms, so they hold between syllables. Every bar is the row's full height: lit bars are filled in the tone and unlit ones are a quiet track with no outline. Nothing moves or scales; a bar's colours cross-fade as it lights and goes out, the same with reduced motion. With more contrast unlit bars are outlined, and under forced colours each bar keeps an edge and a lit one is Highlight.

With `muted` the lit bars dim to the muted foreground and still follow the level, so a person who speaks while muted sees that the microphone hears them and that nobody else does.

It is a `meter` named by its label, from 0 to 100, with its level in words ("Quiet", "Speaking", "Loud", or "Muted") and a value at the middle of the word's band (10, 50 or 90; 0 while muted). What it reports is the loudest level of the last 1.5 seconds, so a person who speaks and then moves to the meter hears "Speaking", and its ARIA values change only when the word does, at most twice a second, so a screen reader has nothing new to repeat while the person speaks. It is no live region: screen readers read it when the person goes to it, and it never announces the level as it changes.

A new `value` re-renders the meter once. Between values it re-renders only when a bar lights or goes out or the word changes, and the page changes only for those bars and, when the word changes, the reading. The bars that keep their state are memoised.

Its agent side, `levelMeterAx` in `level-meter-styles.ts`, declares no agent reads and no actions: audio levels stay with the person.

## Use instead when

- Use `Progress` instead to show how far along a task is, and `Spinner` for a wait you can't measure.

## Props

Type: `LevelMeterProps`.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `bars` | `number` | `8` | How many bars to draw, a whole number from 3 to 24. A number outside that, or with a fraction, draws the nearest one. |
| `className` | `string` |  | Layout only: margins, grid placement (`mt-2`, `ms-auto`). Appearance classes warn in development; use `tone` and `size`. |
| `hideLabel` | `boolean` |  | Hides the label visually; screen readers still use it. |
| `id` | `string` |  | The meter's id, for `aria-describedby` elsewhere on the page. |
| `label` (required) | `string` |  | What the meter measures: "Microphone level". It names the meter for screen readers. |
| `muted` | `boolean` |  | The microphone is muted: the lit bars dim to the muted foreground, whatever the tone, and still follow `value`, so the person can tell the microphone hears them while nobody else does. Screen readers hear "Muted" (`valueText.muted`) and a value of 0, whatever the level. |
| `ref` | `Ref<HTMLDivElement>` |  | Reaches the rendered element. |
| `size` | `"sm" \| "md" \| "lg"` | `"md"` | The meter's size: bars 12px, 16px or 24px high. `sm` fits a menu row. |
| `tone` | `"primary" \| "secondary" \| "destructive" \| "success" \| "warning"` | `"success"` | Color role from the theme for the lit bars, named after its token. Unlit bars are always a quiet track in the input colour, so a silent meter is quiet whatever its tone. `secondary` fills lit bars in the muted foreground, as `muted` does. |
| `value` (required) | `number` |  | The microphone's linear amplitude now, from 0 (silence) to 1 (full scale): the RMS of the samples an `AnalyserNode` gives, fed up to about 15 times a second. The meter maps it to its bars on a decibel scale from -60 dBFS (no bar) to 0 dBFS (every bar), so ordinary speech, around -40 to -20 dBFS, lights 3 to 5 of 8 bars. An amplitude below 0 or not a number shows as silence, and one above 1 as full scale. To get it: `analyser.getFloatTimeDomainData(samples)`, then `Math.sqrt(samples.reduce((sum, sample) => sum + sample * sample, 0) / samples.length)`. |
| `valueText` | `LevelMeterValueText` | { quiet: "Quiet", speaking: "Speaking", loud: "Loud", muted: "Muted" } | The words screen readers hear for the loudest level of the last 1.5 seconds: below -48 dBFS, up to -12 dBFS, and from there, and the word while `muted`. Translate them with the rest of your interface. |

## Don't use

These are not props. Passing one fails the type check with the fix in the error, and in development a console message names the fix.

- `color`: Not a prop. Ouro UI uses `tone`: `<LevelMeter tone="success">`.
- `level`: Not a prop. The amplitude is `value`: `<LevelMeter value={rms}>`.
- `max`: Not a prop. `value` is an amplitude from 0 to 1: `<LevelMeter value={rms}>`.
- `segments`: Not a prop. Ouro UI uses `bars`: `<LevelMeter bars={8}>`.

## `className` is for layout only

Pass margins, width and grid placement (`mt-4`, `w-full`, `col-span-2`).

Appearance comes from props, not classes. In development, a class that sets appearance logs one warning per component instance, naming the prop to use instead. A class sets appearance when, after its variants (`hover:`, `sm:`) and any `!` are removed, it starts with `bg-`, `text-`, `border-`, `rounded-`, `shadow-`, `font-`, `ring-`, `from-`, `via-`, `to-`, `fill-` or `stroke-`, or is `border`, `rounded`, `shadow` or `ring`, or has a `dark:` variant. Text wrapping, overflow and table layout classes (`text-wrap`, `text-ellipsis`, `border-collapse`) are layout and do not warn.

Alignment classes (`text-center`) warn too: set alignment on a parent element.
