Voice in the Browser

A cloned voice that runs entirely locally on this device. Nothing is sent anywhere.

Type something (or keep the example) and press Speak. The first time, the voice model downloads (about 160 MB); after that it starts quickly.

Please be patient: the first time, the voice model (about 160 MB) has to download, and speech is made right here on your device, so it can take a little while to start, longer on phones.

Models are saved in this browser after the first download.
Pick a model and press Speak. The first load downloads the model; after that it loads from this browser's cache.

About the “dad” voice

This is my dad's voice. He passed away on January 7, 2026. For a few years he volunteered at WDBX, the community radio station in Carbondale, Illinois, where he was on the air: playing music, sharing news items that caught his eye, and telling stories, including reading his mother's letters about the family's years in Germany after the war. Every voice on this page was trained from those radio recordings.

How the voices are made

Each voice is cloned from a short set of real recordings of one person. The model on this page, Kokoro, is the smallest of several we train per voice. It's the least accurate, but it's small enough to run entirely in your browser, on your own device: nothing is sent to a server. The larger models sound closer to the real person, but they need a graphics card (GPU) and much bigger files.

ModelSizeRuns onNotes
Kokoro-82M (this page)82M parameters, 164 MB downloadany modern browser, CPU or GPUfastest and smallest; least accurate
Qwen3-TTS 0.6B~1 GB (8-bit)a GPU; a mini PC's integrated GPU manages ~1.4× real timegood balance of quality and speed
Qwen3-TTS 1.7B~2 GB (8-bit)a GPU; about real time on the mini PCcloser to the real voice, slower
Dots.TTS (the teacher)2.2B parameters, ~9 GBa large GPU (48 GB used for training)the best sounding, 48 kHz; too big for everyday use

The recipe: a big teacher trains small students

How the voices are made Radio recordings are transcribed by hand and by Whisper, compared and fixed, aligned word by word and cut into short clips. A large teacher model (Dots.TTS) is fine-tuned on them and the best checkpoints are picked by ear. The teacher reads hours of free-license text, a Whisper filter keeps the good takes, and that speech plus the real clips trains the students: Qwen3-TTS for a PC and Kokoro for the browser. 1 · Real recordings → clean training clips 2 · The teacher 3 · Hours of new speech 4 · The students Radio-show recordings 9 clips, about 2 min each Hand transcripts typed out by hand Whisper transcripts automatic, for checking Compare and fix the transcripts review only where hand and Whisper disagree Forced alignment match every word to its moment in the audio Cut into short clips 120 clips of 3–15 s · 9 held out for testing Fine-tune Dots.TTS (2.2B, 48 kHz) on the clips · on a rented cloud GPU Pick the best checkpoints by ear three of them, mixed 2 : 1 : 1 Free-license text public-domain books & plays, CC0 sentences The teacher reads it aloud thousands of lines · 5.7 hours of speech Whisper quality filter drop misreads and odd takes · 5.2 h kept, plus the real clips Qwen3-TTS 1.7B / 0.6B on a PC's graphics chip · the voice CLI Kokoro-82M in your browser · this page
From a few minutes of real recordings to voices that run on a PC and in the browser.
  1. Real recordings. A few minutes to half an hour of the person speaking, with checked transcripts, cut into short segments. A few segments are held back from all training, so the models can be tested on sentences they never heard.
  2. The teacher. Dots.TTS, a large open model, is fine-tuned on those recordings (minutes on a rented GPU) until it sounds like the person. We listen to several checkpoints and keep the best, sometimes a mix of them.
  3. Making more speech. The teacher reads thousands of lines in the cloned voice: everyday sentences, stage-play dialogue and story narration, taken only from sources that are free for any use (public-domain books and plays, Tatoeba's CC0 sentences, and lines written for the project).
  4. Quality filter. A speech recognizer (Whisper) transcribes every line; takes with misread words, odd speed or clipping are dropped, and everything is levelled to one volume.
  5. The students. Qwen3-TTS (0.6B and 1.7B) and Kokoro are trained on the teacher's hours of speech plus the real recordings. They learn the voice from hours of examples instead of minutes.

Listen: the real voice next to each model

Each row is one sentence. The first column is the original recording we started from (where one exists); the others are the same sentence spoken by each model. Press play on any of them.

By the numbers

What we measured while making the “dad” voice. Speed is given as seconds of work per second of speech (the “RTF” shown under the player): below 1 is faster than real time, 0.5 means a minute of speech takes 30 seconds. The mini PC is a Beelink SER5 (AMD Ryzen, integrated graphics); the rented GPU is an NVIDIA L40S (48 GB) at about $0.73 an hour.

How fast each model speaks

ModelWhereSeconds per second of speech
Dots.TTS 2.2B (teacher)rented L40S GPU, compiled, 4 copies at once~0.2 combined (6 h of speech in ~1.1 h)
rented L40S GPU, one copy, not compiled~3.2
mini PC CPU~20 (and it runs hot); for tests only
Qwen3-TTS 1.7Bmini PC graphics chip (Vulkan)~1.0 (about real time)
Qwen3-TTS 0.6Bmini PC graphics chip (Vulkan)~0.7, first audio in ~0.15 s
Kokoro-82Mmini PC CPU (Python, voice CLI)~0.3–0.4
this page, Chrome on the mini PC~0.7–0.8
this page, a Windows desktop (16 threads)~1.0
this page, iPhone 13 Pro (Safari or Messenger)~1.9 (one thread on iPhone)
this page, Android phone in Chrome (multi-threaded)~1.2
this page, Android inside Messenger~2.3 (in-app browsers allow only one thread)

Example: narrating a whole book

The Adventures of Tom Sawyer is about 70,000 words, roughly 8 hours of narration.

ModelWhereTime for ~8 h of audio
Dots.TTSrented L40S~1.5 h of generating, ~2.5–3 h of rental with setup and re-takes (a few dollars)
Qwen3-TTS 1.7Bmini PC graphics chip~8 h
Qwen3-TTS 0.6Bmini PC graphics chip~5.5 h
Kokoro-82Mmini PC CPU~2.5–3 h

Training, step by step (one rental session)

StepTime on an L40SDetails
Setup~10 mininstall the tools for all models
Fine-tune the Dots teacher~5 min (300 steps)~1.2 steps/s; uses ~45 of 48 GB of GPU memory, so it needs a 48 GB card. A longer 500-step run: ~25 min with test lines
Teacher reads the text~1.1 h2,559 lines → 5.7 h of speech (4 copies in parallel, ~6.5 min of compiling first)
Whisper quality filter~8 min5.2 h kept (about 92%)
Train Kokoro~1.5 h6 + 6 epochs at 6–8 min each; ~28 GB of GPU memory
Train Qwen 1.7B and 0.6B~1 h5 epochs each (0.6B ~3 min per epoch)
Voice every checkpoint~15 min7 test lines per checkpoint, for listening
Whole projectabout $5–8 of GPU rental in total, including earlier experiments

Data and file sizes

WhatAmount
Real recordings9 radio clips, 17.8 min → 111 training clips + 9 held out (3–15 s each)
Teacher speech5.2 h after filtering, about 17× the real recordings
Dots.TTS checkpoint9.6 GB (26 GB while training, with optimizer state)
Qwen3-TTS 1.7B / 0.6B4.3 / 2.4 GB as trained; 2.0 GB / ~1 GB as 8-bit files for the mini PC
Kokoro-82M328 MB as trained; this page downloads 164 MB (16-bit) or 325 MB (32-bit), cached after the first time

Side quest: a smaller teacher (LoRA)

The fine-tuned Dots teacher is a 9.6 GB file, and every training session on a rented GPU needs it. Most of those gigabytes are the public base model, which the GPU can download for free; only the change made by fine-tuning is ours. So we tried shipping just that change in compressed form, as a LoRA (low-rank adapter).

We didn't train a LoRA; we extracted one from the finished fine-tune. For every weight we subtracted the base model from the fine-tuned one. The 475 large matrices were compressed with an SVD, keeping only their strongest r directions (the “rank”); the 391 small weights were kept in full. Base model + adapter rebuilds an approximation of the teacher.

RankAdapter sizeShare of the change keptBy ear
32147 MB55%not voiced
64290 MB67%clearly off
128576 MB78%clearly off
2561.15 GB88%closest, but audible artifacts on longer lines
full fine-tune9.6 GB100%the reference

Same sentence, same random seed, so the only difference is the model:

Model“The causes of the earth's axis tilting…”The radio intro (15 s)
full fine-tune (step 300)
LoRA rank 256
LoRA rank 128–
LoRA rank 64–

What we did instead: fine-tuning Dots takes only about 5 minutes on the rented GPU, and with the same settings and random seed it lands on the same voice. So each session downloads the public base model and simply retrains the teacher; all we upload is a ~150 MB bundle of scripts, text and the real recordings. The LoRA route is still in the pipeline as an option, and a LoRA trained from the start (rather than extracted afterwards) might do better.

Running the bigger models: the voice CLI

The larger models run on a home PC through a small command-line tool, voice. Every voice is a folder (voices/<name>/) holding its checkpoints for each engine and a few reference clips; adding a voice means adding a folder. The tool lists what's there, speaks text with any model and narrates whole books.

$ voice list
dad
├─ qwen-tts  (24 kHz, GPU via Vulkan; size = one runnable GGUF; checkpoints are BF16, 2.4/4.3 GB)
│                                    rating  params runs as     size     direct  hybrid  note
│  ├─  0.6B-student-epoch4           ★★★☆☆   0.6B   Q8_0 GGUF   969 MB   ready   ready   good; volume swings
│  └─* 1.7B-student-lev-epoch4       ★★★★☆   1.7B   Q8_0 GGUF   2.0 GB   ready   ready   chosen 1.7B: consistent
├─ dots  (48 kHz, CPU only here, slow; the teacher)
│                                    rating  params runs as     size     direct  hybrid  note
│  ├─  retrain500-step300            ★★★★★   2.2B   FP32        9.6 GB   ready   ready   #2: best breathing/pauses
│  └─  retrain500-step500            ★★★★★   2.2B   FP32        9.6 GB   ready   ready   #1 teacher: best overall
├─ kokoro  (24 kHz, CPU, fast; the web page uses ONNX exports: FP16 164 MB / FP32 325 MB)
│                                    rating  params runs as     size     direct  hybrid  note
│  └─  b4-epoch0                     ★★★★☆   82M    FP32        328 MB   ready   -       sounds most like him
└─ refs: 10s, 2min

$ voice rate "1.7B lev" 5 "my pick"                         # ratings live next to each model (notes.json)
$ voice say -m "1.7B lev" "Good evening, and welcome back to the show."
out/voice/20261024-171200-dad-1.7B-student-lev-epoch4.wav  (3.4 s audio, RTF 1.0)

$ voice say -m "dots retrain500 step500" --seed 2 "..."     # best quality, slow on a CPU
$ voice say --ref 10s "..."                                 # hybrid: clone from a reference clip
$ voice book my-novel.txt --mp3 --tempo 0.9                 # chapters -> MP3, resumable
$ voice serve                                               # this page, on the home network

Reading the list. params is the model size; runs as is the format it runs in on the PC (Qwen is converted to 8-bit GGUF files for its graphics chip; Dots and Kokoro run at full FP32 precision on the CPU); size is what one runnable copy takes on disk; rating and note are our own listening verdicts, stored next to each model so the best ones are easy to find later.

Direct vs hybrid. A fine-tuned Qwen model can speak the voice two ways. Direct: the voice is built into the model as a named speaker, so it needs nothing else; this is the normal, fastest way. Hybrid: the same fine-tuned model is combined with Qwen's speaker encoder, a part that listens to a short reference recording and clones whatever voice it hears in it. Then you pass a clip (e.g. 10 seconds of the person) with each request, and the model imitates that clip on top of what it learned in training: useful for steering style (a calmer or livelier take), at the cost of processing the clip first. Dots can clone from a reference too; Kokoro can't (its voice is a fixed "voicepack" made from the real recordings).

Notes: making it work on iPhone

The same page that ran fine on Android, Windows and Linux needed a string of fixes for iPhone and iPad, where every browser (Safari, Chrome, Firefox) runs on Apple's WebKit engine. In the order we hit them:

What happenedWhyWhat we did
Opened from a Messenger link: nothing worked, even the recorded examples A bug of ours stopped the page script in in-app browsers; the other iPhone problems below applied there too Fixed the bug; with the fixes below it now runs inside Messenger as well, on iPhone and Android
Pressing Speak did nothing, not even a status message Safari's audio system stalls if it's set up before a tap, at a fixed sample rate Start audio on the first tap, at the phone's own rate, and never wait on it
Stuck on “Generating the first sentence…” forever The pronunciation engine (eSpeak, inside kokoro-js) unpacks its dictionary with a stream feature Safari doesn't have, so it waits forever without an error Add the missing feature (a small polyfill) before kokoro-js loads
Hangs when the engine ran on the page itself Multi-threaded WebAssembly and eSpeak wait in ways Safari's main thread can't Run the speech engine in a background worker, single-threaded on iOS (Safari can't start the extra threads' workers from inside a worker)
The tab reloaded itself as soon as the voice model ran (the official kokoro-js demo too) A WebKit bug in Safari 26.2+: kokoro-js loads ONNX Runtime's WebGPU-capable (“JSEP”) build even on the CPU, and WebKit's compiler runs away on that file until iOS kills the tab (onnxruntime #26827) On iPhone and iPad, load ONNX Runtime's plain WebAssembly build of the same version instead. It works.

We weren't the only ones: other projects using Kokoro in the browser report the same Safari stream issue, thread hangs and iPhone tab crashes; the plain WebAssembly build was the workaround that made Kokoro run on iPhone.

References

The open projects, models and data this was built on.

Voice models

Where the models are hosted

Tools

Training text (free for any use)

  • Project Gutenberg: public-domain books and plays (Twain, Jerome, O. Henry, Leacock, Conan Doyle, Wilde, Shaw)
  • Tatoeba: everyday English sentences from its CC0 export

Compute

  • Training on a rented NVIDIA L40S (48 GB) via vast.ai; everything else on a small home PC