Text-to-Speech
Voice
Synthesize speech from text on-device. Three sizes: Kokoro 82M for English, Spanish and French, Supertonic 2 for English, Korean, Spanish, Portuguese and French at 44.1 kHz, or KittenTTS nano at ~28 MB. Stream PCM as it is generated, or download a WAV.
Try Voice
Runs in this tab · nothing uploaded
What it does
Natural speech, generated locally.
- Default
smallis Kokoro 82M (StyleTTS 2): American, British, Spanish and French. Runs on Transformers.js directly, nokokoro-js. fp32 on WebGPU (fp16 gives NaN on the v4 runtime), q8 on WASM. - Pass
size: "multi"for Supertonic 2 (Supertone, 2026): one ~262 MB model for English, Korean, Spanish, Portuguese and French at 44.1 kHz, 10 preset voices (st_f1…st_m5). Passlanguageper call. - Supertonic 2 is OpenRAIL-M: open weights with use restrictions (no impersonation, no deception, no illegal use). The rest of the TTS sizes are Apache-2.0.
- Pass
size: "tiny"for KittenTTS nano (~28 MB, 8 English voices, WASM). - Audio streams sentence by sentence via
speakStream. WebGPU is several times faster onsmallandmulti; WASM works everywhere. - Pass
voiceto pick a speaker (af_heart/bella/st_f1). Kokoro Spanish and French download a local eSpeak-NG WASM (~18 MB) on first use. Nothing is uploaded.
Specifications
- Package
- runonweb/tts
- Base model
- Kokoro 82M · hexgrad
- License
- Apache-2.0
- Download
- ~326 MB / ~92 MB (small)multi ~262 MBtiny ~28 MB
- Quantization
- fp32 on WebGPUq8 on WASM (multi is fp32, tiny is WASM)
- Backend
- WebGPUWASM fallback
- Input
- Text
Get started with runonweb/tts
pnpm add runonwebimport { TextToSpeech } from 'runonweb/tts'
const tts = new TextToSpeech({ size: 'small', voice: 'af_heart' })
await tts.load()
for await (const chunk of tts.speakStream('Hello from the browser')) {
// chunk.audio is 24 kHz PCM. Play as it arrives
}
const wav = await tts.speakToBlob('Hola mundo', { voice: 'ef_dora' })
new Audio(URL.createObjectURL(wav)).play()
// Supertonic 2: one model, five languages, 44.1 kHz
const multi = new TextToSpeech({ size: 'multi', voice: 'st_f1' })
const pt = await multi.speakToBlob('Olá do navegador', { language: 'pt' })
tts.dispose()Same shape everywhere: construct, load(), run, dispose(). Pass onProgressto show download progress on first use.
Questions about Voice
Does Voice run on device?
Yes. Weights download once and stay in the browser. Nothing is sent to a server.
What does Voice cost?
Nothing. runonweb is free and MIT-licensed, with no device limits, tokens or sign-in.
Which browsers support Voice?
Chromium browsers use WebGPU. Firefox and Safari fall back to WebAssembly automatically, slower but identical output.
Can I use a different model with runonweb/tts?
Yes. See each module’s docs for the options it accepts (model, size, language…). Check the license and test both backends before shipping.