Tone tuner
ProA brand voice card where two sliders (formality and detail) and Friendly, Confident and Empathetic chips rewrite a customer reply. Each changed sentence crossfades in place, new words can be highlighted against the original, and Copy takes the current version.

Hello Sofia,
Thank you for reporting the duplicate charge on your October invoice. We have refunded the extra $1,240.00, and it should reach your card within 5 to 10 business days.
Let me know if anything else looks wrong.
Best,Jordan
- A composer or help desk reply that offers AI tone controls before sending.
- Brand voice tooling where marketers compare versions of the same copy.
- Any rewrite where people want to steer with a few dials rather than write a prompt.
- Free form AI editing with a prompt box: use a chat or composer instead.
- Long documents: the card is sized for a message of a few paragraphs.
- Exact line by line code or contract diffs: use a dedicated diff view.
Installation
Pro source and install commands unlock with a Pro plan.
import { ToneTuner } from "@/components/arc/tone-tuner/tone-tuner"; export function ReplyTone({ draft }: { draft: string }) { return ( <ToneTuner text={draft} recipient={{ name: "Sofia Ramirez", subject: "Re: Duplicate charge on INV-20481" }} rewrite={async ({ text, instructions }, signal) => { const res = await fetch("/api/rewrite", { method: "POST", body: JSON.stringify({ text, instructions }), signal }); if (!res.ok) throw new Error("The model did not respond."); return (await res.json()).text; }} onRewrite={text => console.log("New version", text)} /> );}ToneTuner
A message card with voice chips and two sliders (formality and detail). Each change triggers a debounced rewrite; changed sentences crossfade in place, added words can be highlighted against the original, and Copy takes the current version. With no props it tunes a sample billing reply with simulated rewrites.
textstring–The original draft, the source of every rewrite. Used with `rewrite`. Blank lines split paragraphs; single line breaks keep lines (a sign off).rewrite(request: ToneRewriteRequest, signal: AbortSignal) => Promise<string>–Calls your model and resolves to the rewritten plain text. The request has `text`, `formality`, `detail`, `voice` and a ready made `instructions` string. Superseded requests are aborted. Without it the rewrites are simulated.valueToneSettings–Controlled tone: `{ formality: 0 | 1 | 2, detail: 0 | 1 | 2, voice: "neutral" | "friendly" | "confident" | "empathetic" }`.defaultValueToneSettings{ formality: 1, detail: 1, voice: "neutral" }Starting tone when uncontrolled.onValueChange(value: ToneSettings) => void–Runs on every slider step or chip press, before the debounce.onRewrite(text: string, value: ToneSettings) => void–Runs when a rewrite lands, with the new plain text.onCopy(text: string) => void–Runs after Copy succeeds.recipient{ name: string; avatar?: string; subject?: string }Sofia Ramirez sampleWho the message is for, shown in the header.modelstring"Claude Sonnet 5.5"The model named in the status while a rewrite runs.presetsTonePreset[]Friendly, Confident, EmpatheticVoice chips. A chip sets the voice and moves both sliders to its starting point; pressing it again returns to the neutral voice.debounceMsnumber220Quiet time after the last change before a rewrite starts.showChangesboolean–Controlled change highlighting. Pair with onShowChangesChange.defaultShowChangesbooleantrueHighlights words that differ from the original draft.onShowChangesChange(show: boolean) => void–Runs when the Changes switch flips.autoPlaybooleantrue for the uncontrolled sampleTours the presets while the card is on screen, until the first pointer press or focus inside it.classNamestring–Class on the card.- Tab
- Moves through the voice chips, both sliders, the Changes switch and Copy.
- EnterorSpace
- Presses a voice chip, flips Changes, or copies.
- LeftorRight arrow
- Steps a focused slider between its three levels.
- HomeorEnd
- Jumps a focused slider to its first or last level.
- Voice chips are toggle buttons with aria-pressed inside a group named Voice.
- Each slider is named (Formality, Detail) and speaks its level name, not a number.
- A polite live region announces each landed rewrite with its settings, says when the sample is simulated (nothing was sent), and reports failures.
- Highlighted words use a mark element and the header counts the changed words, so changes are not shown by color alone.
- Status pairs an icon with a short label: Original draft, Rewriting, Rewritten or Couldn't rewrite with a Retry button.
- Each changed sentence fades out in 100ms, swaps while invisible and fades in over 160ms; all changed sentences swap on the same frame, so the paragraph reflows once, out of sight. Unchanged sentences never animate.
- The text area reserves the height of the longest voice at the current formality and detail, so switching voice never resizes the card; a slider move eases it to the new height on a bounce free spring.
- The status flips to Rewriting on the same frame as the input, with a calm shimmer, then crossfades to Rewritten.
- The self playing tour pauses off screen and stops at the first interaction. Reduced motion swaps text instantly and skips the tour.
- The card is fluid up to 640px. Under 520px the sliders stack, the chips share one row in equal columns and the status hides its settings.
- Under 400px the chip icons and changed count drop so labels never clip. Holds at 360px without horizontal scroll.
- Sliders take touch drags; vertical pans still scroll the page.
- Rewrites are debounced and superseded requests are aborted, so dragging a slider sends at most one request after it settles.
- The word diff is an O(n×m) table over the message words, fine for a few hundred words.
- Only changed sentences animate opacity; no layout animation on text.
Notes for AI
Give your coding assistant the Markdown reference instead of screenshots.
- Use for tone and length controls on AI rewrites: support replies, sales emails, release notes, in-app copy.
- Pass `text` and `rewrite` together. Send `instructions` to the model as the system or user instruction; it already asks to keep facts, numbers and names.
- Return plain text from `rewrite` with the same paragraph breaks so sentences line up and only changed sentences animate.
- The diff is word level against the original draft; keep the original stable while the person tunes.
The full library index for assistants is at /llms.txt.