Text-to-speech that runs entirely in your browser. No server, no API keys, no data leaves your device.
VocoLoco uses WebGPU and WebAssembly to run a 600M-parameter diffusion TTS model client-side. Type text, pick a voice, and get natural speech, all locally.
Try it now: magkino.github.io/vocoloco_tts
- 600+ languages: multilingual TTS powered by OmniVoice
- Streamed generation: long texts (up to 2000 characters) are split into sentences and start playing within seconds
- Voice design: control gender and pitch with simple toggles, lock a voice you like for reuse
- Guided voice cloning: a step-by-step wizard with curated reading scripts (the transcript fills itself in), live level meter, and instant voice testing
- Saved voices: cloned voices are analyzed once and cached locally, so generation with them starts fast
- Generation library: replay, reuse, delete, and download past generations as MP3 with AI-provenance metadata
- GPU-accelerated: WebGPU for model inference, with a custom compute shader for post-processing
- CPU fallback: works without WebGPU via WebAssembly (slower, but functional)
- 100% private: all synthesis runs in your browser; no audio or text ever leaves your device
| Requirement | Details |
|---|---|
| Browser | Chrome 113+ or Edge 113+ (WebGPU required for full speed) |
| GPU | Dedicated GPU with WebGPU support recommended |
| Storage | ~3 GB for cached models (one-time download) |
| Fallback | Firefox and non-WebGPU browsers work via WASM (significantly slower) |
VocoLoco runs OmniVoice, a diffusion-based TTS model, in the browser using ONNX Runtime Web. The full pipeline:
- Text tokenization: Qwen2 BPE tokenizer via transformers.js
- Iterative masked diffusion: 8-32 denoising steps with classifier-free guidance
- Post-processing: log-softmax + CFG fusion + argmax, offloaded to a WebGPU compute shader when available (
workers/gpu-postprocess.js) - Audio decoding: HiggsAudioV2 codec converts tokens to 24kHz PCM
- MP3 export: client-side encoding with ID3v2 metadata marking audio as AI-generated
| Component | Size | Description |
|---|---|---|
| Main model | 2.3 GB (sharded) | Qwen3-0.6B backbone, iterative diffusion transformer |
| Audio decoder | 83 MB | HiggsAudioV2, token-to-waveform |
| Audio encoder | 624 MB | HiggsAudioV2, waveform-to-token (voice cloning) |
| Tokenizer | ~2 MB | Qwen2 BPE (loaded via transformers.js) |
Models are hosted on Hugging Face and cached in the browser after first download.
vocoloco_tts/
├── index.html # Main page (Tailwind CSS, pre-built)
├── app.js # UI logic, streaming orchestration, voices, library, settings
├── player.js # StreamingPlayer: chunked playback, seek, playhead, waveform
├── text-chunker.js # Sentence-aligned chunking for streamed generation
├── ui-dialogs.js # Toasts and confirm dialogs (replaces native dialogs)
├── workers/
│ ├── tts-worker.js # ONNX inference, diffusion loop, reference encoding, cancel
│ └── gpu-postprocess.js # WebGPU compute shader for post-processing
├── duration-estimator.js # Estimates output length from input text
├── sentence-buffer.js # Abbreviation-aware sentence splitting
├── lib/
│ └── lamejs.min.js # MP3 encoder (self-hosted)
├── tailwind.css # Pre-built Tailwind CSS
├── tailwind.config.js # Tailwind config (for rebuilds)
└── build-tailwind.sh # Rebuild CSS via Docker
The project is vanilla JavaScript with no build step required. Tailwind CSS is pre-built and committed.
Serve locally:
python3 -m http.server 8080Rebuild Tailwind CSS (after changing HTML classes):
docker run --rm -v "$(pwd)":/src node:20-slim sh /src/build-tailwind.shForce CPU mode (for testing):
http://localhost:8080?cpu
VocoLoco implements transparency measures in accordance with EU AI Act Article 50:
- Machine-readable metadata: all downloaded MP3 files contain ID3v2 tags identifying the audio as AI-generated synthetic speech
- User disclosure: the app displays legal obligations for users who publish or distribute generated audio
- Provenance tracking: metadata includes software identification, creation timestamps, and an AI-generation disclaimer
See the in-app disclaimer for full details.
All synthesis runs locally, but the app fetches resources from external services on first load:
| Service | Purpose | When |
|---|---|---|
| Hugging Face | Model weights (~3 GB) | First use / after cache clear |
| jsDelivr | ONNX Runtime + transformers.js | First use / after cache clear |
| GitHub Pages | Hosting the app itself | Every visit |
Once models are cached, no network requests are made during synthesis.
- VocoLoco app: Apache License 2.0
- ONNX models: Apache 2.0, derived from OmniVoice by Xiaomi/k2-fsa
Built on OmniVoice by Xiaomi Corp (k2-fsa). Uses ONNX Runtime Web by Microsoft. MP3 encoding by lamejs.
Contributions are welcome. Please open an issue first to discuss what you'd like to change.