Skip to content
explainroo

Docs

Voices and languages

How to choose a local voice, use ElevenLabs, record your own narration or make a video in another language.

Which voice source should I use?

Kokoro reads your script on your computer. It costs nothing and needs no key. ElevenLabs gives you its premium voices and your cloned voices, paid on your ElevenLabs account. A recording is your own voice reading the script. All three work with word cues, markers and captions.

How do I choose a Kokoro voice?

node bin/explainroo.js voices
node bin/explainroo.js say "Hello there" --voice am_michael

The first lists the voices and their languages. The second saves a sample you can listen to. There are 28 English voices with American and British accents. English uses af_heart by default.

Set "voice": "am_michael" in video.json. The object { "provider": "kokoro", "id": "am_michael" } means the same thing. speed defaults to 0.9 for Kokoro. It changes only the voice, while pace changes the whole video.

How do I use ElevenLabs?

Get an API key from ElevenLabs. Set ELEVENLABS_API_KEY in your environment, or put it in a .env file in the project folder or explainroo folder:

ELEVENLABS_API_KEY=your-key-here

The environment takes priority, then the project file, then the explainroo folder’s file. Keep .env out of git. Keep the key out of scripts, scenes and logs.

List the voices available to your key:

node bin/explainroo.js voices videos/dns --elevenlabs

Copy an id from the list into video.json:

"voice": {
  "provider": "elevenlabs",
  "id": "JBFqnCBsd6RMkjVDRZzb",
  "model": "eleven_multilingual_v2"
}

model is optional. It defaults to eleven_multilingual_v2. You can use premium or cloned voices already available to your key.

ElevenLabs receives your script text and charges your account. Check your plan’s costs and terms before you use it. voice reports the characters used. Requests are recorded in build/voice/elevenlabs-usage.jsonl, without your key or script text. Unchanged scenes reuse their narration. voice --force makes new requests for all scenes.

speed defaults to 1. ElevenLabs limits speed times pace to 0.7 through 1.2. The voice command tells you when it uses that limit.

How do I use my own recording?

Read script.md aloud and put one take for the whole video in assets/. Set this in video.json:

"voice": { "provider": "recording", "src": "assets/narration.m4a" }

explainroo uses the script’s words to split the take into scenes. Each cut keeps about 0.15 seconds around the speech. Pauses inside a scene stay as recorded. The scene’s lead and hold add gaps between scenes.

For easier retakes, record one file per scene:

"voice": { "provider": "recording", "src": "assets/narration/" }

Each scene with narration needs a file named after its id, such as intro.wav or resolver.m4a. Supported formats are WAV, MP3, M4A, AAC, FLAC, OGG and Opus. Files must stay inside assets/, with no .. in the path.

Recordings become mono and their volume is brought close to Kokoro’s. Sample rates are kept up to 48 kHz. speed defaults to 1. Changing it or pace changes the tempo without changing the pitch.

How do I record well?

Use a quiet room and keep the microphone at the same distance. Make a short test and listen for room noise, loud breaths and distorted peaks. Read at a steady pace, with natural pauses. Avoid music in the recording, since explainroo adds the music later.

Read the spoken part of {shown|spoken}. Do not say markers or scene headings. If you change the words while recording, make the script match what you said. [pause], sentenceGap and paragraphGap do not add silence to a recording.

Replacing one scene’s file redoes that scene. Replacing a whole take redoes all its scenes.

Which languages can I use?

Set language in video.json. When voice is left out, Kokoro picks this default:

Language Setting Default voice
English en af_heart
Spanish es ef_dora
French fr ff_siwis
Italian it if_sara
Brazilian Portuguese pt-br pf_dora
Hindi hi hf_alpha
Japanese ja jf_alpha
Mandarin Chinese zh zf_xiaobei
node bin/explainroo.js init videos/saludo --language es
node bin/explainroo.js voices --language es

A Kokoro voice must match the video’s language. If you change the language of an existing project, change voice too, or remove it to use the default. ElevenLabs and recordings work in every supported language.

What do other languages need?

Spanish, French, Italian, Portuguese and Hindi need the espeak-ng program. Install it once:

sudo apt install espeak-ng     # Linux
brew install espeak-ng         # macOS

On Windows, use the installer from the espeak-ng releases page. If explainroo cannot find it, set EXPLAINROO_ESPEAK to its binary. English, Japanese, Chinese, ElevenLabs and recordings do not need it.

Japanese and Chinese need Python 3 with misaki instead. See Japanese and Chinese.

The first speech check in another language downloads multilingual Whisper small. doctor --fetch downloads only the English models. Hindi fonts come with the looks.

Write the script as someone would speak that language. Cues work the same, so at: "qué" matches “Qué”. Captions and subtitle files keep the written text. Use {shown|spoken} for a pronunciation change in the same language. Outside English, the check does not match spelled numbers to digits. Use digits when that helps.

The Hindi speech check confirms fewer words. Listen before changing a word. Fix it when it sounds wrong or stays unconfirmed in several scenes.

How do Japanese and Chinese work?

Kokoro’s Japanese and Mandarin voices were trained with misaki, a pronunciation library for Python. explainroo runs it through your Python 3. Install what the language needs:

python3 -m pip install "misaki[ja]"   # Japanese
python3 -m unidic download            # Japanese dictionary, about 526 MB
python3 -m pip install "misaki[zh]"   # Chinese

On Windows, write python instead of python3. If misaki is in a virtual environment, set EXPLAINROO_PYTHON to that environment’s Python. doctor shows whether it is found.

Write the script as usual, without spaces between words. explainroo finds the words itself, so at: "解析" and [#markers] work. A cue can be a phrase, but it must match whole words. Put a marker where you need a moment inside a word.

Latin words such as API or JavaScript are read in English. For a Japanese reading, write it out, as in {API|エーピーアイ}. Numbers can stay in digits, decimals included. The Japanese reader sometimes picks the wrong reading, such as ついたち for 一日. Write 1日 there, or give the reading with {shown|spoken}.

Whisper often writes a word with other characters that sound the same, so the speech check compares sounds. Japanese is compared by its kana reading, and Chinese by pinyin without tones, with Traditional and Simplified characters counted as the same. Captions and subtitles join words without spaces, with up to 18 characters per subtitle line.

The looks’ fonts have no Japanese or Chinese characters. The first run downloads Noto Sans JP or Noto Sans SC, about 33 MB, and keeps it in the cache. After that, everything works offline. A web player keeps only the characters the video shows, so it stays small.

How do I check the narration?

With any voice source, run the usual commands:

node bin/explainroo.js voice videos/dns
node bin/explainroo.js check videos/dns
node bin/explainroo.js render videos/dns
node bin/explainroo.js verify videos/dns

For a recording mismatch, make the script match the recording. For a generated voice, use a pronunciation change or reword the sentence. See writing the script and checking a video.