# `` — peak meter with hold + decay _(no submodules)_ ## Purpose `` is a digital-style peak meter that shows the instantaneous input level alongside a held-then-decaying peak marker. After every new sample exceeds the held maximum, the marker freezes for `holdMs` and then decays linearly at `decayPerSec` level-units per second. The default 1000 ms hold + 1.4-per-second decay matches the legibility profile common in commercial DAWs. This component intentionally does not include ballistics — for analogue VU response use ``. `` is the right choice for clip detection, true-peak indication, and any time the user must see the actual recent maximum rather than a perceptual average. ## Features - Independent `value` (filled bar) and `peak` (hold marker) channels - Configurable hold window (`holdMs`) and decay rate (`decayPerSec`) - Optional `peak` prop — when omitted, derived from `value` - `role="meter"` with `aria-valuetext` describing both level and peak - CSS-variable themed fill and hold marker - `data-level` / `data-peak` deterministic E2E hooks ## Usage: Basic ```tsx import { MeterPeak } from "@suaveplan/react-control-surface"; ; ``` ## Usage: Advanced ```tsx import { MeterPeak } from "@suaveplan/react-control-surface"; function ClipDetector({ stream }: { stream: AsyncIterable }) { const [v, setV] = useState(0); useEffect(() => { let cancelled = false; (async () => { for await (const s of stream) { if (cancelled) return; setV(s); } })(); return () => { cancelled = true; }; }, [stream]); return ( ); } ``` ## API Reference | Prop | Type | Default | Description | | ------------- | -------- | ------- | ---------------------------------------------------- | | `value` | `number` | required| Instantaneous level in `[0, 1]`. | | `peak` | `number` | derived | External peak source. Falls back to `value`. | | `holdMs` | `number` | `1000` | Hold time after each new maximum. | | `decayPerSec` | `number` | `1.4` | Linear decay rate once the hold expires. | | `width` | `number` | `160` | Root width in CSS pixels. | | `height` | `number` | `24` | Root height in CSS pixels. | | `label` | `string` | — | Visible + accessible label. | | `ariaLabel` | `string` | derived | Override the accessible label. | | `className` | `string` | — | Appended to `rcs-meter-peak`. | The exported `stepPeakHold(held, heldUntil, incoming, now, holdMs, decayPerSec, dtMs)` helper is the pure-function hold envelope used internally. It is exported for re-use and is unit-tested independently. ## Implementation Notes State is held in a `useRef` (`{ held, heldUntil, last }`) so smoothing does not require re-renders on every RAF tick — only the display value updates via `setState`. Hold deadlines are stored as absolute timestamps (`Date.now() + holdMs`) which makes the math identical between live runs and the synchronous unit tests of `stepPeakHold`. The hold marker is rendered as a 2-pixel-wide absolutely-positioned div that tracks the held value's percentage position; the fill bar tracks the instantaneous value. Both are themable via CSS variables.