Skip to content
Sign in
TemplatesTTS studio appMenu

TTS studio appPro

A complete text to speech studio on scripted fixtures: a long form script with a voice and takes per paragraph, a panel for voice, delivery, take compare and stretch fixes, the voice library with design and clone, characters spent per take, and an export that renders real WAV files.

ProAn audiobook chapter in three voices. Generate the two paragraphs that need it, redo one sentence at the caret, compare two takes in the panel or say a stretch again. Once every paragraph has a take, export renders a real WAV.

Installation

$ pnpm dlx shadcn@latest add @chatcn-pro/tts-studio-app

The template installs as a folder under components/chatcn/pro/tts-studio-app/: the app, the rail, the paragraph panel, the voice library, the export and the scripted engine, each a file you own and edit.

Usage

tsx
import { TtsStudioApp } from "@/components/chatcn/pro/tts-studio-app/tts-studio-app"

<TtsStudioApp
  projects={scripts}
  voices={library}
  characters={account.characters}
  renewal={{ amount: 100_000, at: account.renewsAt }}
/>

Give it a height: it fills its parent. Everything runs on the scripted engine in tts-engine.ts: takes are synthesized in each voice's timbre with Web Audio, voice design turns the words of a description into three timbres, and export renders every take, resamples it, evens the loudness and encodes WAV in the tab. To go live, replace renderTake, designPreviews and exportAudio with your API and keep their shapes; the editor, the panel and the export follow on their own.

Examples

Design a voice

The library has three tabs: every voice with samples and filters, Design a voice from a description, and Clone a voice from recorded or uploaded samples. A saved voice joins the library and every paragraph's voice picker at once. Voices on a higher plan offer the upgrade.

ProThe library open on voice design with three previews ready: pick, refine, save, and the voice joins every paragraph's picker.

Low on characters

Every take spends the characters it says, tags excluded. At the low line the balance and a banner say so; a take that needs more than is left is not made, and the banner says how many it needs with Buy characters and the upgrade. A paragraph with a tag the model does not read fails free of charge, with the fix in words.

Pro60 characters left and a paragraph the model refused for an unknown tag: the banner, the low balance and the fix in words.

On a phone

Below 768 px the rail moves into a drawer, the paragraph panel opens as a sheet from the sliders button, the voice sits above each paragraph and every control keeps a 44 px target. Pass layout="mobile" to force it inside a device frame.

ProThe same studio at phone width: scripts in a drawer, voice and takes in a sheet, 44 px targets.

What is inside

  • The shell is the free ChatLayout: the rail collapses to icons with Cmd+B and becomes a drawer under 768 px; the paragraph panel is its side panel.
  • TtsStudio as the editor: a voice per paragraph, inline audio tags that autocomplete on [, out of date marks after edits, one sentence redone at the caret, and a timeline of the takes in use with Play all.
  • The panel follows the caret: the paragraph's voice with a sample and Change voice into the library, SpeechSettings for its next take, the last two takes in sync on AudioAbSwitch, and a stretch of the take said again on WaveformRegionEditor, spliced into a new take.
  • VoiceLibrary, VoiceDesign and VoiceCloneFlow in the Voices view. Picking a voice for a paragraph applies it and goes back to the script.
  • Characters on CreditBalance with spend by action and the renewal, RateLimitBanner when low or short, CreditTopUp in a dialog and a plan upgrade that unlocks every voice.
  • Export with sample rate, bit depth, loudness and a file per paragraph, the size before you start, progress as each paragraph renders, and WAV files to download.

Props

PropTypeNotes
projects{ id, name, detail?, paragraphs }[]Scripts. Paragraphs are TtsStudio paragraphs with their takes
voicesSpeechVoice[]The library. A voice with plan is locked until the upgrade
charactersnumberCharacters left. A take that needs more is not made
renewal{ amount, at }The monthly allowance and when it renews
spend, lowAtCreditSpend[], numberRecent spend, and the low line. Default 1,000
upgrade{ name, price, period?, features, characters }The plan the upgrade offers
packsCreditPack[]Character packs for the top up dialog
account{ name, plan }The account menu at the foot of the rail
defaultProjectId, defaultView, defaultVoicesTabstring, "script" | "voices", "library" | "design" | "clone"Where it opens
defaultDesign, cloneSamples, defaultExportingOpen into a design, a clone with samples, or a running export
defaultPanelOpenbooleanThe paragraph panel. Default open on desktop
layout"auto" | "desktop" | "mobile"Force the phone layout inside a device frame

Keyboard

KeyAction
Cmd+Enter or Ctrl+EnterGenerate the paragraph
Alt+EnterRegenerate the sentence at the caret
[Insert an audio tag
Cmd+. or Ctrl+.Show or hide the paragraph panel
XSwitch between take A and B
Arrows, Enter, SpaceMove between voices, pick one, play its sample
Cmd+B or Ctrl+BCollapse or expand the rail
Cmd+/ or Ctrl+/Every shortcut, grouped by area

Accessibility

  • Landmarks from the layout, a skip link to the script, a named navigation for scripts and the library with aria-current, and the paragraph panel as a named complementary region.
  • Each paragraph field is named by its number and voice and described by its status, so a screen reader hears Edited since the last take or Did not generate with the text.
  • Voice changes, kept takes, new voices, purchases and finished exports are announced politely, once. Generation progress is never announced per tick.
  • Every composed part keeps its own semantics: the library is a listbox, the Voices view uses tabs, the export progress is a progressbar and its options are radio groups and a switch.

Motion

  • Each composed component keeps its own motion: a generating paragraph shimmers its status after 300 ms, a new take fades into its clip, the panel slides in on the panel curve, characters roll their digits.
  • Export progress fills from the start edge as each paragraph renders and never runs backwards. Moving between scripts and the library is instant.
  • Under reduced motion only short fades remain and the progress fill jumps.