ribt.

Speech in 18 milliseconds. A small English voice for a robot that has to answer while you're still in the room.

ribt is trained and run entirely in tang's tensor IR, so the same programs that drive the robot compile to your GPU. Type something. It speaks on this page, with nothing sent to a server.

349 milliseconds is a long time to stare at a robot.

Both models get the text at the same instant. ribt's real audio starts at 17.6 ms. Kokoro, the model it learned the voice from, makes its first sound at 349. Drawn to scale, in real time.

ribtstreaming
Kokorofirst segment
349 ms
0 ms
By the time Kokoro makes a sound, ribt has already said…

What just happened

Four small models turned that sentence into sound. Each figure below is what they produced for the line in the box, and they all follow the same playhead.

1

Letters become sounds

English spelling is a mess, so the first step is a dictionary and a tagger. lilt reads the sentence the way misaki does, picks the right "read" for the tense, spells out "$42.50", and guesses words it has never seen. It runs on the CPU in under a millisecond.

99.86% word parity with misaki on held-out text
2

Every sound gets a length and a pitch

The encoder reads the phonemes and decides how long to hold each one, in frames of 10.7 ms, and where the voice should rise and fall. Stressed vowels stretch. Questions climb at the end.

each block is one phoneme, as wide as it is long
3

One step of flow paints the sound

The decoder sketches a spectrogram: 100 frequency bands, one column per frame. A flow model then adds the fine detail in a single step, where its teacher needed sixteen. Low notes sit at the bottom; the bright bands are the harmonics of the voice.

4

The vocoder turns the picture into air

A spectrogram has no phase, so it can't be played. The vocoder fills that in and writes 24,000 samples a second. It is Vocos, imported weight for weight into tang.

click anywhere on a figure to play from there

The numbers

M4 Max, batch 1, warm. Kokoro's numbers use the same machine.

17.6 ms
median time to first audio
37×
faster than real time (RTF 0.027)
4.39
UTMOS, WER-50 set
54 M
parameters, all four models
ribtKokoro af_heart
First audio17.6 ms349 ms
Real-time factor0.0270.093
UTMOS, WER-504.394.52
Word error rate, WER-502.71%2.61%
Word error rate, held-out 501.73%1.73%
Speaker similarity0.9870.990

Kokoro still sounds a little better, by about 0.13 UTMOS. ribt gets close at a twentieth of the first-audio latency. Kokoro ran with KPipeline on CPU, non-streaming; MPS was slower. Word error from Whisper small.en, UTMOS from utmos22_strong, similarity is WavLM-SV cosine to 121 held af_heart clips. In the browser, ribt matches the native build to within 6e-5 on the same weights.

Where the voice comes from

ribt's voice is distilled from Kokoro-82M's af_heart voice (Apache-2.0). We rendered 135 hours of af_heart and trained our own models on it. No Kokoro weights are in ribt. Kokoro's own training data included synthetic audio from closed commercial TTS providers, so the voice inherits that lineage.

The vocoder is Vocos by Hubert Siuzdak (MIT), trained on LibriTTS. lilt is a port of hexgrad's misaki (Apache-2.0). Text for the training renders came from LibriTTS-R transcripts and templated conversational lines.

Get it

Code at muni-works/ribt. Weights at municipal-robotics/ribt. Builds for Metal, CUDA, wgpu, OpenCL, plain C, and WebGPU.

# macOS (Metal)
$ cargo build --release
# Linux: cuda, wgpu, opencl or cpu
$ cargo build --release --no-default-features --features cuda
# the browser build on this page
$ web/build.sh