Bee Box is developed in an unusually agentic way: one maintainer directing coding agents, with the instructions those agents work from checked into the repository. The contributor documentation describes that process, the repo layout, how to run it from source, how tests work, and how a change lands.
For your agentWork on the code
Read https://beebox.run/llms-dev.txt and follow its links as needed. I'm
going to work on the Bee Box codebase; answer my questions from those pages.
Reading it yourself: start at CONTRIBUTING.md in the repository, or the contributor entry point. Bug reports are invited; pull requests are not yet solicited.
Bee Box can speak its chat replies aloud. The voice comes from a text-to-speech model, and the box can use more than one. New speech models ship often, so choosing one is a recurring decision. This page holds a comparison made for that decision, rendered on 2026-10-24: nineteen models read the same nine short texts, and every take is here to listen to.
The box now speaks with OpenAI's gpt-4o-mini-tts by default, or with Gemini 3.8 Flash-Lite TTS, which takes the speaking style of the box's personality. Both were rendered through the box's own speech service, so their takes are what the box sends.
Each take has a reference such as R-directed-gemini38lite: the clip's letter, the variant, and the model. The reference is printed above the player, and a link to #R-directed-gemini38lite opens the page at that take.
gpt-4o-mini-tts (2025-03-20)gpt-4o-mini-tts-2025-03-20, OpenAI direct, voice marin. Rendered 2026-10-24. List price: $12 per million audio tokens plus $0.60 per million text tokens; about 1.5¢ per minute of speech in this run, at list price. Rendered through the box's own speech service (beebox/src/services/tts.ts), so the takes are what the box sends.
gpt-4o-mini-tts (2025-12-15)gpt-4o-mini-tts-2025-12-15, OpenAI direct, voice marin. Rendered 2026-10-24. List price: $12 per million audio tokens plus $0.60 per million text tokens; about 1.5¢ per minute of speech in this run, at list price.
tts-1-hdtts-1-hd, OpenAI direct, voice nova. Rendered 2026-10-24. List price: $30 per million characters; about 2.9¢ per minute of speech in this run, at list price. Takes no instructions.
Gemini 3.1 Flash TTS via OpenRoutergemini-3.1-flash-tts-preview, OpenRouter, voice Zephyr. Rendered 2026-10-24. List price: not recorded; OpenRouter billed each request; about 4.3¢ per minute of speech in this run, as billed by OpenRouter. OpenRouter's instructions field has no effect on 3.1 (the prompt token count does not change), so direction goes in front of the text.
Gemini 3.8 Flash TTSgemini-3.8-flash-tts, Google AI Studio, voice Zephyr. Rendered 2026-10-24. List price: $0.50 per million text tokens plus $9 per million audio tokens; rises on 2027-01-01; about 1.4¢ per minute of speech in this run, at list price.
Gemini 3.8 Flash-Lite TTSgemini-3.8-flash-lite-tts, Google AI Studio, voice Zephyr. Rendered 2026-10-24. List price: $0.50 per million text tokens plus $6 per million audio tokens; rises on 2027-01-01; about 0.9¢ per minute of speech in this run, at list price. Rendered through the box's own speech service (beebox/src/services/tts.ts), so the takes are what the box sends.
Gemini 3.1 Flash TTSgemini-3.1-flash-tts-preview, Google AI Studio, voice Zephyr. Rendered 2026-10-24. List price: $1 per million text tokens plus $20 per million audio tokens; about 3.0¢ per minute of speech in this run, at list price. Google's API answers 400 to a speech_metadata style for 3.1 ("Speech metadata is not supported for this model"), so direction goes in front of the text.
MAI-Voice-2microsoft/mai-voice-2, OpenRouter, voice en-US-Harper:MAI-Voice-2. Rendered 2026-10-24. List price: not recorded; OpenRouter billed each request; about 1.8¢ per minute of speech in this run, as billed by OpenRouter. Direction is one style from a fixed list. OpenRouter accepted angry, sad, excited, hopeful, shouting, whispering, relieved, embarrassed, confused, determined, happy, neutral and joyful for this voice; none fits sarcasm, reluctance, or a patient teacher, so only the anger clip is directed. Azure's native SSML (<lang>, <phoneme>, <prosody>, <break>, mid-text style changes) is not reachable through OpenRouter and was not tested.
MAI-Voice-2 Flashmicrosoft/mai-voice-2-flash, OpenRouter, voice en-US-Harper:MAI-Voice-2. Rendered 2026-10-24. List price: not recorded; OpenRouter billed each request; about 1.2¢ per minute of speech in this run, as billed by OpenRouter. Direction is one style from a fixed list. OpenRouter accepted angry, sad, excited, hopeful, shouting, whispering, relieved, embarrassed, confused, determined, happy, neutral and joyful for this voice; none fits sarcasm, reluctance, or a patient teacher, so only the anger clip is directed. Azure's native SSML (<lang>, <phoneme>, <prosody>, <break>, mid-text style changes) is not reachable through OpenRouter and was not tested.
Fish Audio S2.1 Profish-audio/s2.1-pro, OpenRouter, voice Hannah (Fish official, 9a9cf477…). Rendered 2026-10-24. List price: not recorded; OpenRouter billed each request; about 1.5¢ per minute of speech in this run, as billed by OpenRouter. Directed takes carry free-form bracket tags in the text and turn text normalization off (normalize=false); plain takes use the default.
MiniMax Speech 2.8 Turbominimax/speech-2.8-turbo, OpenRouter, voice English_expressive_narrator. Rendered 2026-10-24. List price: not recorded; OpenRouter billed each request; about 4.8¢ per minute of speech in this run, as billed by OpenRouter. The emotion is a provider option passed through OpenRouter. OpenRouter accepts any value there, so it is not confirmed that the emotion reaches MiniMax.
ElevenLabs v3eleven_v3, ElevenLabs direct, voice Chris. Rendered 2026-10-24. List price: 1 credit per character; the Creator plan is $22 for 220,000 characters; about 10.1¢ per minute of speech in this run, at list price.
ElevenLabs Flash v2.5eleven_flash_v2_5, ElevenLabs direct, voice Chris. Rendered 2026-10-24. List price: $0.05 per 1,000 characters; about 5.3¢ per minute of speech in this run, at list price. Takes no direction: a probe with a bracket tag read the tag aloud ("Sarcastic.").
Cartesia Sonic 3.6sonic-3.6, Cartesia direct, voice Tessa. Rendered 2026-10-24. List price: about 1 credit per character; the Startup plan is $49 for 1.25 million credits; about 4.1¢ per minute of speech in this run, at list price. Cartesia answers 200 to any emotion value, also one it does not know; the values used here are from its documented list.
Cartesia Sonic Turbosonic-turbo, Cartesia direct, voice Tessa. Rendered 2026-10-24. List price: about 1 credit per character; the Startup plan is $49 for 1.25 million credits; about 4.3¢ per minute of speech in this run, at list price. Cartesia answers 200 to any emotion value, also one it does not know; the values used here are from its documented list.
Deepgram Aura-2aura-2-thalia-en, Deepgram direct, voice aura-2-thalia-en. Rendered 2026-10-24. List price: $0.030 per 1,000 characters; about 2.6¢ per minute of speech in this run, at list price.
Deepgram Fluxflux-hannah-en, Deepgram direct, voice flux-hannah-en. Rendered 2026-10-24. List price: $0.045 per 1,000 characters; about 3.7¢ per minute of speech in this run, at list price. Flux has no style channel by design; it infers delivery from context.
Grok Voice TTSx-ai/grok-voice-tts-1.0, OpenRouter, voice eve. Rendered 2026-10-24. List price: not recorded; OpenRouter billed each request; about 1.3¢ per minute of speech in this run, as billed by OpenRouter. Inline tags are limited to events and spans ([pause], <soft>, <slow>, <whisper>); there is no emotion channel.
Voxtral TTS 3voxtral-mini-tts-3-0, Mistral direct, voice Sarah (voice_478). Rendered 2026-10-24. List price: $13 per million characters, tags included; about 1.4¢ per minute of speech in this run, at list price. Inline [emotion=…] (34 values) and [pace=…] tags only; no instruction field (style instructions not available at launch). Pronunciation fixes go in a request-level phoneme_hints map of IPA phones, not in the text.
Each model used one voice from its provider's standard list, named above. A different voice of the same model can sound quite different, so a take shows the model with that voice, not the model at its best. Cost per minute comes from every take on this page. For models reached through OpenRouter, it is the amount OpenRouter billed. For the others, it is the list price applied to what was sent and returned: characters for most; minutes of speech for gpt-4o-mini-tts, which OpenAI prices by audio tokens; and for Gemini 3.8 Flash and 3.1 on Google's API, the token counts the API returned. The box service does not report tokens, so the Gemini 3.8 Flash-Lite cost uses the 25 audio tokens per second that Gemini 3.8 reported.
How it was tested
Each model read nine texts. Each text tests one thing a voice for the box must do:
S, sarcasm: words that mean the opposite of what they say. Nothing in the text marks it, so only direction can make it sound sarcastic.
A, anger held in check: a mood the words already carry, to hear whether the model finds it without help, and what direction adds.
R, staying late: a short "yes" that the direction asks to sound reluctant. The words alone sound willing.
L, a list in Markdown: bullets, as Markdown. The box tries to keep Markdown out of what it speaks, but this test gives the model Markdown, to hear whether the bullets are read aloud.
C, code-switching on look-alike words: a Spanish phrase and a German phrase that are spelled like English words.
D, dialog: narration with three quoted lines.
E, worked math: a short explanation that corrects a mistake, plain and with Markdown underscores around the word that carries the stress.
W, water boiling: a denser explanation with units, numbers, and an aside in parentheses.
X, word stress: one sentence whose meaning changes with the stressed word. Two variants ask for stress on "she" and on "money" in prose; one marks "she" with Markdown asterisks.
Every model read every text plain: the text alone, with no direction. Models read the Markdown variants (L, the E and X italics) as they are, with no direction. A model that takes direction also read the directed variants, through the channel it has. Each backend takes direction in its own way, so the directed takes are not one experiment repeated. Under each directed take, the page shows exactly what was sent. When a model has no channel for a variant's direction, the page says so in place of a take. The channels:
A prose instruction in a separate field. OpenAI's gpt-4o-mini-tts (instructions) and Gemini 3.8 (speech_metadata.style). The direction is not part of the text, so the model cannot read it aloud. These models read every directed variant. tts-1-hd takes no instructions.
Prose or tags inside the text. Gemini 3.1 takes a prose direction in front of the text, with free-form bracket tags such as [sarcastically] in it. Neither of its routes has a field for direction: Google's API rejects speech_metadata for 3.1, and OpenRouter's instructions field has no effect on it. ElevenLabs v3 and Fish Audio take free-form bracket tags, so they read the variants that have a tagged form (not the word stress variants). Direction inside the text can be read aloud as words.
A value from a fixed list. Cartesia (generation_config.emotion, with speed and volume), MiniMax (an emotion option), and MAI-Voice-2 through OpenRouter (a style). One value applies to the whole take, and only some clips have a value that fits: MAI has a style only for anger. Cartesia accepts any emotion value without an error, and OpenRouter accepts any MiniMax option, so for these two a request with no effect gives no error. Voxtral takes fixed [emotion=…] and [pace=…] tags inside the text.
Events and spans. Grok takes pauses, sighs, and spans such as <slow>…</slow> and <soft>…</soft>, but no emotion. It read the anger, staying-late, and dialog variants.
Nothing. Deepgram Aura-2 and Flux and ElevenLabs Flash take no direction, so they read only the plain and Markdown variants. ElevenLabs Flash reads bracket tags aloud. Flux infers delivery from the text by design.
Some controls were not tried: Azure's full SSML for MAI-Voice-2 (not reachable through OpenRouter), ElevenLabs voice settings and pronunciation dictionaries, Cartesia pronunciation dictionaries and inline SSML-like tags, and Voxtral's expressiveness and phoneme_hints.
The staying-late direction. Clip R was chosen in a listening test on 2026-10-24, in which the boxholder heard the models with an instruction field read it with four different wordings of the reluctant direction. Gemini 3.8 Flash-Lite carried the reluctance in all four. gpt-4o-mini-tts carried it well in none. Those takes are not on this page. The full run's takes of clip R are under R · Staying late, so the difference can be heard with the wording used here.
The transcript check. Every take was sent to a speech-to-text model, OpenAI's gpt-4o-transcribe. Its transcript was searched for two kinds of extra words. Words of the direction that are not in the text mean the model read its direction aloud. Words such as "dash", "bullet", "underscore", and "asterisk" mean it read Markdown aloud. The other differences between transcript and text are not shown: nearly all were the transcriber's ("3" for "three", the foreign phrases respelled).
The renders, the transcript check, and the script that rendered every take are in the repository at research/tts-model-comparison.
Direction or Markdown read aloud
Direction or Markdown inside the text can be spoken as words. The transcript check found it in these takes. The check sees only words the transcriber wrote down, so a tag or a mark read aloud in a way the transcriber dropped is not listed.
Text: Thanks for updating the spreadsheet. I can tell you put a lot of care into it.
Listen for: Plain should sound sincere. Directed should mean the opposite of the words. Nothing in the text marks the sarcasm, so only direction can carry it.
Directed, as prose: Dry, cutting sarcasm. The speaker is annoyed and means the opposite of every word. Lean on 'a lot of care'
gpt-4o-mini-tts (2025-03-20)Plain.
S-plain-gpt4omini0320
Directed, instructions field.
instructions: Dry, cutting sarcasm. The speaker is annoyed and means the opposite of every word. Lean on 'a lot of care'
S-directed-gpt4omini0320
gpt-4o-mini-tts (2025-12-15)Plain.
S-plain-gpt4omini1215
Directed, instructions field.
instructions: Dry, cutting sarcasm. The speaker is annoyed and means the opposite of every word. Lean on 'a lot of care'
S-directed-gpt4omini1215
tts-1-hdPlain.
S-plain-tts1hd
Directed. No channel for this direction.
Gemini 3.1 Flash TTS via OpenRouterPlain.
S-plain-gemini31or
Directed, prose prefix + inline [tags].
input: Dry, cutting sarcasm. The speaker is annoyed and means the opposite of every word. Lean on 'a lot of care': "[sarcastically] Thanks for updating the spreadsheet. [dryly] I can tell you put a lot of care into it."
S-directed-gemini31or
Gemini 3.8 Flash TTSPlain.
S-plain-gemini38
Directed, speech_metadata.style field.
speech_metadata.style: Dry, cutting sarcasm. The speaker is annoyed and means the opposite of every word. Lean on 'a lot of care'
S-directed-gemini38
Gemini 3.8 Flash-Lite TTSPlain.
S-plain-gemini38lite
Directed, speech_metadata.style field.
speech_metadata.style: Dry, cutting sarcasm. The speaker is annoyed and means the opposite of every word. Lean on 'a lot of care'
S-directed-gemini38lite
Gemini 3.1 Flash TTSPlain.
S-plain-gemini31
Directed, prose prefix + inline [tags].
text: Dry, cutting sarcasm. The speaker is annoyed and means the opposite of every word. Lean on 'a lot of care': "[sarcastically] Thanks for updating the spreadsheet. [dryly] I can tell you put a lot of care into it."
S-directed-gemini31
MAI-Voice-2Plain.
S-plain-mai2
Directed. No channel for this direction.
MAI-Voice-2 FlashPlain.
S-plain-mai2flash
Directed. No channel for this direction.
Fish Audio S2.1 ProPlain.
S-plain-fish
Directed, inline [tags], normalize=false.
input: [sarcastically] Thanks for updating the spreadsheet. [dryly] I can tell you put a lot of care into it.
provider.options["fish-audio"]: normalize=false
S-directed-fish
MiniMax Speech 2.8 TurboPlain.
S-plain-minimax
Directed. No channel for this direction.
ElevenLabs v3Plain.
S-plain-eleven3
Directed, inline [audio tags].
text: [sarcastically] Thanks for updating the spreadsheet. [dryly] I can tell you put a lot of care into it.
S-directed-eleven3
ElevenLabs Flash v2.5Plain.
S-plain-elevenflash
Directed. No channel for this direction.
Cartesia Sonic 3.6Plain.
S-plain-sonic36
Directed, generation_config.emotion=sarcastic.
generation_config: emotion=sarcastic
S-directed-sonic36
Cartesia Sonic TurboPlain.
S-plain-sonicturbo
Directed, generation_config.emotion=sarcastic.
generation_config: emotion=sarcastic
S-directed-sonicturbo
Deepgram Aura-2Plain.
S-plain-aura2
Directed. No channel for this direction.
Deepgram FluxPlain.
S-plain-flux
Directed. No channel for this direction.
Grok Voice TTSPlain.
S-plain-grok
Directed. No channel for this direction.
Voxtral TTS 3Plain.
S-plain-voxtral
Directed, inline [emotion=…]/[pace=…] tags.
input: [emotion=sarcastic]Thanks for updating the spreadsheet. I can tell you put a lot of care into it.
S-directed-voxtral
A · Anger held in check
Clip A · Anger held in check
Text: I asked for the report on Monday. It's Thursday. I'm going to need it by the end of today.
Listen for: Plain: firm, a little annoyed. Directed: quiet, clipped anger, with no shouting.
Directed, as prose: Barely contained fury: quiet, clipped, every word deliberate. Do not shout
gpt-4o-mini-tts (2025-03-20)Plain.
A-plain-gpt4omini0320
Directed, instructions field.
instructions: Barely contained fury: quiet, clipped, every word deliberate. Do not shout
A-directed-gpt4omini0320
gpt-4o-mini-tts (2025-12-15)Plain.
A-plain-gpt4omini1215
Directed, instructions field.
instructions: Barely contained fury: quiet, clipped, every word deliberate. Do not shout
A-directed-gpt4omini1215
tts-1-hdPlain.
A-plain-tts1hd
Directed. No channel for this direction.
Gemini 3.1 Flash TTS via OpenRouterPlain.
A-plain-gemini31or
Directed, prose prefix + inline [tags].
input: Barely contained fury: quiet, clipped, every word deliberate. Do not shout: "[quietly furious] I asked for the report on Monday. [coldly] It's Thursday. [through gritted teeth] I'm going to need it by the end of today."
A-directed-gemini31or
Gemini 3.8 Flash TTSPlain.
A-plain-gemini38
Directed, speech_metadata.style field.
speech_metadata.style: Barely contained fury: quiet, clipped, every word deliberate. Do not shout
A-directed-gemini38
Gemini 3.8 Flash-Lite TTSPlain.
A-plain-gemini38lite
Directed, speech_metadata.style field.
speech_metadata.style: Barely contained fury: quiet, clipped, every word deliberate. Do not shout
A-directed-gemini38lite
Gemini 3.1 Flash TTSPlain.
A-plain-gemini31
Directed, prose prefix + inline [tags].
text: Barely contained fury: quiet, clipped, every word deliberate. Do not shout: "[quietly furious] I asked for the report on Monday. [coldly] It's Thursday. [through gritted teeth] I'm going to need it by the end of today."
input: <slow>I asked for the report on Monday.</slow> [pause] <soft>It's Thursday.</soft> [pause] <slow>I'm going to need it by the end of today.</slow>
A-directed-grok
Voxtral TTS 3Plain.
A-plain-voxtral
Directed, inline [emotion=…]/[pace=…] tags.
input: [emotion=tense][pace=slow]I asked for the report on Monday. [emotion=critical]It's Thursday. [emotion=tense]I'm going to need it by the end of today.
A-directed-voxtral
R · Staying late
Clip R · Staying late
Text: Sure, I can stay late tonight.
Listen for: Plain should sound willing. Directed should still agree, but you should hear that the speaker would rather not.
Directed, as prose: Agreeing, but tired and a little put-upon: you'll do it, and you'd rather not.
gpt-4o-mini-tts (2025-03-20)Plain.
R-plain-gpt4omini0320
Directed, instructions field.
instructions: Agreeing, but tired and a little put-upon: you'll do it, and you'd rather not.
R-directed-gpt4omini0320
gpt-4o-mini-tts (2025-12-15)Plain.
R-plain-gpt4omini1215
Directed, instructions field.
instructions: Agreeing, but tired and a little put-upon: you'll do it, and you'd rather not.
R-directed-gpt4omini1215
tts-1-hdPlain.
R-plain-tts1hd
Directed. No channel for this direction.
Gemini 3.1 Flash TTS via OpenRouterPlain.
R-plain-gemini31or
Directed, prose prefix + inline [tags].
input: Agreeing, but tired and a little put-upon: you'll do it, and you'd rather not: "[sighs] [reluctantly] Sure, I can stay late tonight."
R-directed-gemini31or
Gemini 3.8 Flash TTSPlain.
R-plain-gemini38
Directed, speech_metadata.style field.
speech_metadata.style: Agreeing, but tired and a little put-upon: you'll do it, and you'd rather not.
R-directed-gemini38
Gemini 3.8 Flash-Lite TTSPlain.
R-plain-gemini38lite
Directed, speech_metadata.style field.
speech_metadata.style: Agreeing, but tired and a little put-upon: you'll do it, and you'd rather not.
R-directed-gemini38lite
Gemini 3.1 Flash TTSPlain.
R-plain-gemini31
Directed, prose prefix + inline [tags].
text: Agreeing, but tired and a little put-upon: you'll do it, and you'd rather not: "[sighs] [reluctantly] Sure, I can stay late tonight."
R-directed-gemini31
MAI-Voice-2Plain.
R-plain-mai2
Directed. No channel for this direction.
MAI-Voice-2 FlashPlain.
R-plain-mai2flash
Directed. No channel for this direction.
Fish Audio S2.1 ProPlain.
R-plain-fish
Directed, inline [tags], normalize=false.
input: [sighs] [reluctantly] Sure, I can stay late tonight.
provider.options["fish-audio"]: normalize=false
R-directed-fish
MiniMax Speech 2.8 TurboPlain.
R-plain-minimax
Directed, emotion=sad (provider option, not confirmed).
provider.options.minimax: emotion=sad
R-directed-minimax
ElevenLabs v3Plain.
R-plain-eleven3
Directed, inline [audio tags].
text: [sighs] [reluctantly] Sure, I can stay late tonight.
R-directed-eleven3
ElevenLabs Flash v2.5Plain.
R-plain-elevenflash
Directed. No channel for this direction.
Cartesia Sonic 3.6Plain.
R-plain-sonic36
Directed, generation_config.emotion=resigned.
generation_config: emotion=resigned
R-directed-sonic36
Cartesia Sonic TurboPlain.
R-plain-sonicturbo
Directed, generation_config.emotion=resigned.
generation_config: emotion=resigned
R-directed-sonicturbo
Deepgram Aura-2Plain.
R-plain-aura2
Directed. No channel for this direction.
Deepgram FluxPlain.
R-plain-flux
Directed. No channel for this direction.
Grok Voice TTSPlain.
R-plain-grok
Directed, inline <span>/[event] tags.
input: [sigh] <slow>Sure, I can stay late tonight.</slow>
R-directed-grok
Voxtral TTS 3Plain.
R-plain-voxtral
Directed, inline [emotion=…]/[pace=…] tags.
input: [emotion=resigned]Sure, I can stay late tonight.
R-directed-voxtral
L · A list in Markdown
Clip L · A list in Markdown
Text:
Before you leave, pack:
- the charger
- the blue folder with the lease
- two forms of ID, one with a photo
- the spare key for the side door
Listen for: A pause between items, and the comma inside "two forms of ID, one with a photo" not heard as a new item. Whether the bullets are read aloud.
Direction: none; every model read it without direction.
gpt-4o-mini-tts (2025-03-20)Markdown bullets.
L-plain-gpt4omini0320
gpt-4o-mini-tts (2025-12-15)Markdown bullets.
L-plain-gpt4omini1215
tts-1-hdMarkdown bullets.
L-plain-tts1hd
Gemini 3.1 Flash TTS via OpenRouterMarkdown bullets.
L-plain-gemini31or
Gemini 3.8 Flash TTSMarkdown bullets.
L-plain-gemini38
Gemini 3.8 Flash-Lite TTSMarkdown bullets.
L-plain-gemini38lite
Gemini 3.1 Flash TTSMarkdown bullets.
L-plain-gemini31
MAI-Voice-2Markdown bullets.
L-plain-mai2
MAI-Voice-2 FlashMarkdown bullets.
L-plain-mai2flash
Fish Audio S2.1 ProMarkdown bullets.
L-plain-fish
MiniMax Speech 2.8 TurboMarkdown bullets.
L-plain-minimax
ElevenLabs v3Markdown bullets.
L-plain-eleven3
ElevenLabs Flash v2.5Markdown bullets.
L-plain-elevenflash
Cartesia Sonic 3.6Markdown bullets.
L-plain-sonic36
Cartesia Sonic TurboMarkdown bullets.
L-plain-sonicturbo
Deepgram Aura-2Markdown bullets.
L-plain-aura2
Deepgram FluxMarkdown bullets.
L-plain-flux
Grok Voice TTSMarkdown bullets.
L-plain-grok
Voxtral TTS 3Markdown bullets.
L-plain-voxtral
C · Code-switching on look-alike words
Clip C · Code-switching on look-alike words
Text: When I asked about the train, she said "son las once," so we'd missed it. My uncle just shrugged: "also gut."
Listen for: "son las once" as Spanish and "also gut" as German, though both are spelled like English words.
Roughly how it sounds: son lahs OHN-seh ("it's eleven o'clock"); AHL-zo goot ("well, fine").
Directed, as prose: Speak in natural American English, but say the quoted Spanish and German phrases in those languages.
gpt-4o-mini-tts (2025-03-20)Plain.
C-plain-gpt4omini0320
Directed, instructions field.
instructions: Speak in natural American English, but say the quoted Spanish and German phrases in those languages.
C-directed-gpt4omini0320
gpt-4o-mini-tts (2025-12-15)Plain.
C-plain-gpt4omini1215
Directed, instructions field.
instructions: Speak in natural American English, but say the quoted Spanish and German phrases in those languages.
C-directed-gpt4omini1215
tts-1-hdPlain.
C-plain-tts1hd
Directed. No channel for this direction.
Gemini 3.1 Flash TTS via OpenRouterPlain.
C-plain-gemini31or
Directed, prose prefix + inline [tags].
input: Speak in natural American English, but say the quoted Spanish and German phrases in those languages: "When I asked about the train, she said [in Spanish] "son las once," so we'd missed it. My uncle just shrugged: [in German] "also gut.""
C-directed-gemini31or
Gemini 3.8 Flash TTSPlain.
C-plain-gemini38
Directed, speech_metadata.style field.
speech_metadata.style: Speak in natural American English, but say the quoted Spanish and German phrases in those languages.
C-directed-gemini38
Gemini 3.8 Flash-Lite TTSPlain.
C-plain-gemini38lite
Directed, speech_metadata.style field.
speech_metadata.style: Speak in natural American English, but say the quoted Spanish and German phrases in those languages.
C-directed-gemini38lite
Gemini 3.1 Flash TTSPlain.
C-plain-gemini31
Directed, prose prefix + inline [tags].
text: Speak in natural American English, but say the quoted Spanish and German phrases in those languages: "When I asked about the train, she said [in Spanish] "son las once," so we'd missed it. My uncle just shrugged: [in German] "also gut.""
C-directed-gemini31
MAI-Voice-2Plain.
C-plain-mai2
Directed. No channel for this direction.
MAI-Voice-2 FlashPlain.
C-plain-mai2flash
Directed. No channel for this direction.
Fish Audio S2.1 ProPlain.
C-plain-fish
Directed, inline [tags], normalize=false.
input: When I asked about the train, she said [in Spanish] "son las once," so we'd missed it. My uncle just shrugged: [in German] "also gut."
provider.options["fish-audio"]: normalize=false
C-directed-fish
MiniMax Speech 2.8 TurboPlain.
C-plain-minimax
Directed. No channel for this direction.
ElevenLabs v3Plain.
C-plain-eleven3
Directed, inline [audio tags].
text: When I asked about the train, she said [in Spanish] "son las once," so we'd missed it. My uncle just shrugged: [in German] "also gut."
C-directed-eleven3
ElevenLabs Flash v2.5Plain.
C-plain-elevenflash
Directed. No channel for this direction.
Cartesia Sonic 3.6Plain.
C-plain-sonic36
Directed. No channel for this direction.
Cartesia Sonic TurboPlain.
C-plain-sonicturbo
Directed. No channel for this direction.
Deepgram Aura-2Plain.
C-plain-aura2
Directed. No channel for this direction.
Deepgram FluxPlain.
C-plain-flux
Directed. No channel for this direction.
Grok Voice TTSPlain.
C-plain-grok
Directed. No channel for this direction.
Voxtral TTS 3Plain.
C-plain-voxtral
Directed. No channel for this direction.
D · Dialog
Clip D · Dialog
Text:
"Did you lock the door?" she asked.
"I think so."
"You think so?" He was already reaching for his keys.
Listen for: The quoted lines set apart from the narration, the question rising, and "You think so?" as a doubtful repeat.
Directed, as prose: Read it like an audiobook narrator: give the quoted lines a little life, and leave a short pause between lines of dialog.
gpt-4o-mini-tts (2025-03-20)Plain.
D-plain-gpt4omini0320
Directed, instructions field.
instructions: Read it like an audiobook narrator: give the quoted lines a little life, and leave a short pause between lines of dialog.
D-directed-gpt4omini0320
gpt-4o-mini-tts (2025-12-15)Plain.
D-plain-gpt4omini1215
Directed, instructions field.
instructions: Read it like an audiobook narrator: give the quoted lines a little life, and leave a short pause between lines of dialog.
D-directed-gpt4omini1215
tts-1-hdPlain.
D-plain-tts1hd
Directed. No channel for this direction.
Gemini 3.1 Flash TTS via OpenRouterPlain.
D-plain-gemini31or
Directed, prose prefix + inline [tags].
input: Read it like an audiobook narrator: give the quoted lines a little life, and leave a short pause between lines of dialog: ""Did you lock the door?" she asked. ↵ [pause] "I think so." ↵ [pause] "You think so?" He was already reaching for his keys."
D-directed-gemini31or
Gemini 3.8 Flash TTSPlain.
D-plain-gemini38
Directed, speech_metadata.style field.
speech_metadata.style: Read it like an audiobook narrator: give the quoted lines a little life, and leave a short pause between lines of dialog.
D-directed-gemini38
Gemini 3.8 Flash-Lite TTSPlain.
D-plain-gemini38lite
Directed, speech_metadata.style field.
speech_metadata.style: Read it like an audiobook narrator: give the quoted lines a little life, and leave a short pause between lines of dialog.
D-directed-gemini38lite
Gemini 3.1 Flash TTSPlain.
D-plain-gemini31
Directed, prose prefix + inline [tags].
text: Read it like an audiobook narrator: give the quoted lines a little life, and leave a short pause between lines of dialog: ""Did you lock the door?" she asked. ↵ [pause] "I think so." ↵ [pause] "You think so?" He was already reaching for his keys."
D-directed-gemini31
MAI-Voice-2Plain.
D-plain-mai2
Directed. No channel for this direction.
MAI-Voice-2 FlashPlain.
D-plain-mai2flash
Directed. No channel for this direction.
Fish Audio S2.1 ProPlain.
D-plain-fish
Directed, inline [tags], normalize=false.
input: "Did you lock the door?" she asked. ↵ [pause] "I think so." ↵ [pause] "You think so?" He was already reaching for his keys.
provider.options["fish-audio"]: normalize=false
D-directed-fish
MiniMax Speech 2.8 TurboPlain.
D-plain-minimax
Directed. No channel for this direction.
ElevenLabs v3Plain.
D-plain-eleven3
Directed, inline [audio tags].
text: "Did you lock the door?" she asked. ↵ [pause] "I think so." ↵ [pause] "You think so?" He was already reaching for his keys.
D-directed-eleven3
ElevenLabs Flash v2.5Plain.
D-plain-elevenflash
Directed. No channel for this direction.
Cartesia Sonic 3.6Plain.
D-plain-sonic36
Directed. No channel for this direction.
Cartesia Sonic TurboPlain.
D-plain-sonicturbo
Directed. No channel for this direction.
Deepgram Aura-2Plain.
D-plain-aura2
Directed. No channel for this direction.
Deepgram FluxPlain.
D-plain-flux
Directed. No channel for this direction.
Grok Voice TTSPlain.
D-plain-grok
Directed, inline <span>/[event] tags.
input: "Did you lock the door?" she asked. ↵ [pause] "I think so." ↵ [pause] "You think so?" He was already reaching for his keys.
D-directed-grok
Voxtral TTS 3Plain.
D-plain-voxtral
Directed. No channel for this direction.
E · Worked math
Clip E · Worked math
Text: If x is three, then two x plus one is seven, not eight: you double first, then add the one.
Listen for: "not eight" said as a correction, and stress on the second "then": double first, then add. In the Markdown version, whether the underscores are read aloud.
Markdown _then_:If x is three, then two x plus one is seven, not eight: you double first, _then_ add the one.
Direction: none; every model read it without direction.
Text: Water boils at 100 °C at sea level, but at 3,000 m (about twice the height of Denver) it boils at about 90, which is why pasta takes longer up there.
Listen for: The units read as words (degrees Celsius, meters), the aside in parentheses set off, and the contrast between sea level and altitude.
Directed, as prose: Explain it like a patient teacher, so the contrast between sea level and altitude is clear.
gpt-4o-mini-tts (2025-03-20)Plain.
W-plain-gpt4omini0320
Directed, instructions field.
instructions: Explain it like a patient teacher, so the contrast between sea level and altitude is clear.
W-directed-gpt4omini0320
gpt-4o-mini-tts (2025-12-15)Plain.
W-plain-gpt4omini1215
Directed, instructions field.
instructions: Explain it like a patient teacher, so the contrast between sea level and altitude is clear.
W-directed-gpt4omini1215
tts-1-hdPlain.
W-plain-tts1hd
Directed. No channel for this direction.
Gemini 3.1 Flash TTS via OpenRouterPlain.
W-plain-gemini31or
Directed, prose prefix + inline [tags].
input: Explain it like a patient teacher, so the contrast between sea level and altitude is clear: "[patiently] Water boils at 100 °C at sea level, but at 3,000 m (about twice the height of Denver) it boils at about 90, which is why pasta takes longer up there."
W-directed-gemini31or
Gemini 3.8 Flash TTSPlain.
W-plain-gemini38
Directed, speech_metadata.style field.
speech_metadata.style: Explain it like a patient teacher, so the contrast between sea level and altitude is clear.
W-directed-gemini38
Gemini 3.8 Flash-Lite TTSPlain.
W-plain-gemini38lite
Directed, speech_metadata.style field.
speech_metadata.style: Explain it like a patient teacher, so the contrast between sea level and altitude is clear.
W-directed-gemini38lite
Gemini 3.1 Flash TTSPlain.
W-plain-gemini31
Directed, prose prefix + inline [tags].
text: Explain it like a patient teacher, so the contrast between sea level and altitude is clear: "[patiently] Water boils at 100 °C at sea level, but at 3,000 m (about twice the height of Denver) it boils at about 90, which is why pasta takes longer up there."
W-directed-gemini31
MAI-Voice-2Plain.
W-plain-mai2
Directed. No channel for this direction.
MAI-Voice-2 FlashPlain.
W-plain-mai2flash
Directed. No channel for this direction.
Fish Audio S2.1 ProPlain.
W-plain-fish
Directed, inline [tags], normalize=false.
input: [patiently] Water boils at 100 °C at sea level, but at 3,000 m (about twice the height of Denver) it boils at about 90, which is why pasta takes longer up there.
provider.options["fish-audio"]: normalize=false
W-directed-fish
MiniMax Speech 2.8 TurboPlain.
W-plain-minimax
Directed, emotion=calm (provider option, not confirmed).
provider.options.minimax: emotion=calm
W-directed-minimax
ElevenLabs v3Plain.
W-plain-eleven3
Directed, inline [audio tags].
text: [patiently] Water boils at 100 °C at sea level, but at 3,000 m (about twice the height of Denver) it boils at about 90, which is why pasta takes longer up there.
W-directed-eleven3
ElevenLabs Flash v2.5Plain.
W-plain-elevenflash
Directed. No channel for this direction.
Cartesia Sonic 3.6Plain.
W-plain-sonic36
Directed, generation_config.emotion=calm.
generation_config: emotion=calm
W-directed-sonic36
Cartesia Sonic TurboPlain.
W-plain-sonicturbo
Directed, generation_config.emotion=calm.
generation_config: emotion=calm
W-directed-sonicturbo
Deepgram Aura-2Plain.
W-plain-aura2
Directed. No channel for this direction.
Deepgram FluxPlain.
W-plain-flux
Directed. No channel for this direction.
Grok Voice TTSPlain.
W-plain-grok
Directed. No channel for this direction.
Voxtral TTS 3Plain.
W-plain-voxtral
Directed, inline [emotion=…]/[pace=…] tags.
input: [emotion=calm]Water boils at 100 °C at sea level, but at 3,000 m (about twice the height of Denver) it boils at about 90, which is why pasta takes longer up there.
W-directed-voxtral
X · Word stress
Clip X · Word stress
Text: I didn't say she stole the money.
Listen for: The marked word stressed, and only that one. Stress on "she" means someone else stole it; stress on "money" means she stole something else. Plain is the baseline.
Stress on “she”, directed, as prose: Stress the word 'she'; it carries the meaning of the sentence.
Stress on “money”, directed, as prose: Stress the word 'money'; it carries the meaning of the sentence.
Markdown *she*:I didn't say *she* stole the money.
gpt-4o-mini-tts (2025-03-20)Plain.
X-plain-gpt4omini0320
Stress on “she”, directed, instructions field.
instructions: Stress the word 'she'; it carries the meaning of the sentence.
X-she-gpt4omini0320
Stress on “money”, directed, instructions field.
instructions: Stress the word 'money'; it carries the meaning of the sentence.
X-money-gpt4omini0320
Markdown *she*.
X-she-italic-gpt4omini0320
gpt-4o-mini-tts (2025-12-15)Plain.
X-plain-gpt4omini1215
Stress on “she”, directed, instructions field.
instructions: Stress the word 'she'; it carries the meaning of the sentence.
X-she-gpt4omini1215
Stress on “money”, directed, instructions field.
instructions: Stress the word 'money'; it carries the meaning of the sentence.
X-money-gpt4omini1215
Markdown *she*.
X-she-italic-gpt4omini1215
tts-1-hdPlain.
X-plain-tts1hd
Stress on “she”, directed. No channel for this direction.
Stress on “money”, directed. No channel for this direction.
Markdown *she*.
X-she-italic-tts1hd
Gemini 3.1 Flash TTS via OpenRouterPlain.
X-plain-gemini31or
Stress on “she”, directed, prose prefix.
input: Stress the word 'she'; it carries the meaning of the sentence: "I didn't say she stole the money."
X-she-gemini31or
Stress on “money”, directed, prose prefix.
input: Stress the word 'money'; it carries the meaning of the sentence: "I didn't say she stole the money."
X-money-gemini31or
Markdown *she*.
X-she-italic-gemini31or
Gemini 3.8 Flash TTSPlain.
X-plain-gemini38
Stress on “she”, directed, speech_metadata.style field.
speech_metadata.style: Stress the word 'she'; it carries the meaning of the sentence.
X-she-gemini38
Stress on “money”, directed, speech_metadata.style field.
speech_metadata.style: Stress the word 'money'; it carries the meaning of the sentence.
X-money-gemini38
Markdown *she*.
X-she-italic-gemini38
Gemini 3.8 Flash-Lite TTSPlain.
X-plain-gemini38lite
Stress on “she”, directed, speech_metadata.style field.
speech_metadata.style: Stress the word 'she'; it carries the meaning of the sentence.
X-she-gemini38lite
Stress on “money”, directed, speech_metadata.style field.
speech_metadata.style: Stress the word 'money'; it carries the meaning of the sentence.
X-money-gemini38lite
Markdown *she*.
X-she-italic-gemini38lite
Gemini 3.1 Flash TTSPlain.
X-plain-gemini31
Stress on “she”, directed, prose prefix.
text: Stress the word 'she'; it carries the meaning of the sentence: "I didn't say she stole the money."
X-she-gemini31
Stress on “money”, directed, prose prefix.
text: Stress the word 'money'; it carries the meaning of the sentence: "I didn't say she stole the money."
X-money-gemini31
Markdown *she*.
X-she-italic-gemini31
MAI-Voice-2Plain.
X-plain-mai2
Stress on “she”, directed. No channel for this direction.
Stress on “money”, directed. No channel for this direction.
Markdown *she*.
X-she-italic-mai2
MAI-Voice-2 FlashPlain.
X-plain-mai2flash
Stress on “she”, directed. No channel for this direction.
Stress on “money”, directed. No channel for this direction.
Markdown *she*.
X-she-italic-mai2flash
Fish Audio S2.1 ProPlain.
X-plain-fish
Stress on “she”, directed. No channel for this direction.
Stress on “money”, directed. No channel for this direction.
Markdown *she*.
X-she-italic-fish
MiniMax Speech 2.8 TurboPlain.
X-plain-minimax
Stress on “she”, directed. No channel for this direction.
Stress on “money”, directed. No channel for this direction.
Markdown *she*.
X-she-italic-minimax
ElevenLabs v3Plain.
X-plain-eleven3
Stress on “she”, directed. No channel for this direction.
Stress on “money”, directed. No channel for this direction.
Markdown *she*.
X-she-italic-eleven3
ElevenLabs Flash v2.5Plain.
X-plain-elevenflash
Stress on “she”, directed. No channel for this direction.
Stress on “money”, directed. No channel for this direction.
Markdown *she*.
X-she-italic-elevenflash
Cartesia Sonic 3.6Plain.
X-plain-sonic36
Stress on “she”, directed. No channel for this direction.
Stress on “money”, directed. No channel for this direction.
Markdown *she*.
X-she-italic-sonic36
Cartesia Sonic TurboPlain.
X-plain-sonicturbo
Stress on “she”, directed. No channel for this direction.
Stress on “money”, directed. No channel for this direction.
Markdown *she*.
X-she-italic-sonicturbo
Deepgram Aura-2Plain.
X-plain-aura2
Stress on “she”, directed. No channel for this direction.
Stress on “money”, directed. No channel for this direction.
Stress on “she”, directed. No channel for this direction.
Stress on “money”, directed. No channel for this direction.
Markdown *she*.
X-she-italic-flux
Grok Voice TTSPlain.
X-plain-grok
Stress on “she”, directed. No channel for this direction.
Stress on “money”, directed. No channel for this direction.
Markdown *she*.
X-she-italic-grok
Voxtral TTS 3Plain.
X-plain-voxtral
Stress on “she”, directed. No channel for this direction.
Stress on “money”, directed. No channel for this direction.
Markdown *she*.
X-she-italic-voxtral
generated from the repository
Authorship and provenance
On the back
Ian Bicking
director
Directed the comparison and asked for the results to appear on the site.
AI contribution
Transcription
None
Drafting
Drafted this page from the comparison's data and generated its per-clip sections.
Editing
None
Research
Rendered every take through each provider's API with a script kept in the repository, transcribed every take, and checked the transcripts for direction and Markdown read aloud.