Files
skills/docs/ui/react/react-control-surface/src/controls/meter-peak/meter-peak.md
2026-05-29 08:20:56 +01:00

3.7 KiB

<MeterPeak> — peak meter with hold + decay

(no submodules)

Purpose

<MeterPeak> 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 <MeterVU>. <MeterPeak> 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

import { MeterPeak } from "@suaveplan/react-control-surface";

<MeterPeak value={0.4} peak={0.7} label="L" />;

Usage: Advanced

import { MeterPeak } from "@suaveplan/react-control-surface";

function ClipDetector({ stream }: { stream: AsyncIterable<number> }) {
    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 (
        <MeterPeak
            value={v}
            holdMs={2000}
            decayPerSec={0.6}
            label="Clip"
        />
    );
}

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.