EnhanceCompare
StableClean up a recording with one strength slider, and switch Before and After at the same moment.
Also known as before after, audio compare, a b compare
Install with npm install @tattva/ui (setup), or copy the code from the kit in Downloads.
Clean up an interview
Clean up sound
The original
const [strength, setStrength] = useState(60);
const [listening, setListening] = useState<"before" | "after">("after");
const [status, setStatus] = useState<EnhanceStatus>("idle");
<EnhanceCompare
title="Episode 14, interview with Noor Haddad"
duration={74}
strength={strength}
onStrengthChange={setStrength}
listening={listening}
onListeningChange={setListening}
status={status}
onProcess={cleanUp}
costNote="Free on your plan"
keepParts={[
{ id: "laugh", label: "Keep laughter", on: true },
{ id: "room", label: "Keep room sound", on: false },
{ id: "music", label: "Keep background music", on: false },
]}
onKeepPartChange={setPart}
beforePeaks={original}
afterPeaks={cleaned}
beforeSrc="/audio/ep14.mp3"
afterSrc="/audio/ep14-clean.mp3"
/>Press Clean up. While it works the original stays playable. When it is ready, play and press B or the switch: the playhead stays where it was. Move the strength or a check box and Apply appears, because the After you hear no longer matches the settings.
When to use it
Lets a person hear exactly what a clean-up changes and choose how far it goes, without losing the original.
Made of: Heading · Before and After switch · Player (AI label on After only) · Strength slider · Natural and Clean ends · Sounds to keep · Error message · Status line · Key hint · Cost · Clean up, Apply or Try again
Use it for
- Removing background noise from a podcast interview.
- Making a phone voice memo clearer while keeping some room sound.
- Any AI clean-up where people say they cannot hear a difference.
Not for
- Choosing between several generated takes: use TakePicker.
- Undoing one AI change in text: use RevertToggle.
- Just playing a recording: use AudioPlayer.
Do and avoid
Reduce noise
Listening to After, cleaned up
Voice memo, kitchen
Do
- Keep the original and let people go back to it at any time.
- Start from a middle strength. Full strength often sounds robotic.
- Offer to keep the sounds that carry meaning, such as laughter.
- Show the cost next to Clean up when there is one.
Avoid
- Don't render again every time the person wants to compare. The switch must be instant.
- Don't colour the waveform with the AI colour. Only the AI label on After and Clean up use it.
- Don't use amber for processing. Nothing needs the person yet.
On a phone
- Fills the width. The Before and After switch wraps under the heading on narrow screens and its buttons are 44px tall on touch.
- The strength slider and check boxes are 44px tall on touch screens.
- The B key hint is hidden on touch screens; the switch does the same job.
- The player follows AudioPlayer: a 44px Play button and a 44px seek area.
Seen in products
- Descript Studio Sound has a single Intensity setting.
- Adobe Podcast Enhance lets people trade speech clarity against background sound, for example keeping some café ambience.
- User reports of hearing no change suggest people need an instant A/B switch at the same position.
Properties
| Prop | Type | Default | Description |
|---|---|---|---|
| titlerequired | string | none | Name of the recording. Also names the player. |
| durationrequired | number | none | Length in seconds. |
| strengthrequired | number | none | Cleanup strength, 0 (Natural) to 100 (Clean), in steps of 5. |
| onStrengthChangerequired | (n: number) => void | none | Called as the slider moves. |
| listeningrequired | "before" | "after" | none | Which version plays once the clean-up is ready. Switching keeps the position. |
| onListeningChangerequired | (v: "before" | "after") => void | none | Called by the switch and the B key. |
| statusrequired | "idle" | "processing" | "ready" | "failed" | none | Where the clean-up is. Before ready, only the original plays. |
| onProcess | () => void | none | Starts or repeats the clean-up. Shows Clean up, Apply (after a change) or Try again. |
| costNote | string | none | Cost shown beside the button, such as "Free on your plan". |
| keepParts | { id: string; label: string; on: boolean }[] | none | Sounds the person can choose to keep, such as "Keep laughter". |
| onKeepPartChange | (id: string, on: boolean) => void | none | Called when a sound to keep is ticked or cleared. |
| beforePeaks | number[] | none | Loudness per slice of the original. |
| afterPeaks | number[] | none | Loudness per slice of the cleaned version. |
| beforeSrc | string | none | The original file. Leave both files out to simulate playback. |
| afterSrc | string | none | The cleaned file. |
| errorText | string | "The clean-up did not finish. Your recording is unchanged." | Message in the failed state. |
| heading | string | "Clean up sound" | Heading of the panel. |
| headingLevel | 2 | 3 | 4 | 5 | 6 | 3 | Level of the heading. |
| className | string | none | Extra classes on the panel. |
"Show code under the preview gives the code for the example on the stage."
In Figma
In Figma, one EnhanceCompare switches all of this from its properties panel, across 8 variants. Each property sets the React prop beside it, so design and code use the same names.
| Figma property | React | Values |
|---|---|---|
| Status | status | Idle, Processing, Ready, Failed |
| Listening | listening | Before, After |
| Title | title | Any text |
| CostNote | costNote | Any text |
States
States this part has beyond its default look. Build each one your screen can reach. States set by a property are in the Code tab.
- idle
- Not cleaned up yet. Only the original plays, and Clean up starts the work.
- processing
- The AI is cleaning up: a small AI dot and words. The original stays playable; the slider and check boxes wait.
- ready
- Before and After can be switched at the same moment. The After version has the AI label.
- settings changed
- Ready, but the strength or sounds to keep changed since the After was made: the line says so and Apply appears.
- failed
- The clean-up did not work: the reason, "Nothing was changed", and Try again.
Tokens
Change one of these and every part that uses it follows.
--lime--accent--fg--fg-muted--border--surface--surface-sunken--danger-fg--dur-fast
Built in
- The panel is a section named by its heading.
- Before and After is a radio group named "Listen to": arrow keys move and select, and only the chosen option is a tab stop.
- B switches Before and After while focus is inside the panel, but not on the slider, a check box or any text field, and never with a modifier key.
- The strength slider is a native range named "Cleanup strength", read as "60 percent, between Natural and Clean".
- The sounds to keep are native check boxes in a fieldset named "Sounds to keep". They are disabled while processing.
- One status region announces processing, ready and failed. It never reads the clock.
- The player follows AudioPlayer: Play is a toggle, the waveform is a slider with the time in words, and the After version has an AI label.
- Under reduced motion the processing dot does not pulse.
What you need to do
- Keep the original. Clean-up must never replace it without a way back.
- Name the sounds to keep in plain words, starting with Keep.
- Say in errorText what happened to the recording and whether the person was charged.
- Set status to processing as soon as the work starts, and to ready or failed when it ends.
- When onProcess costs anything, pass costNote so the cost sits beside the button.
Built toward WCAG 2.2 AA and checked automatically; no independent audit yet. Read the accessibility guide