generate-voiceover
Generate voiceover audio using Gemini TTS. Use for narration, voiceovers, podcasts, multi-speaker dialogue.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Generate voiceover audio using Gemini TTS. Use for narration, voiceovers, podcasts, multi-speaker dialogue.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
MANDATORY pre-flight check that runs BEFORE any content plan or generation. Classifies the topic, verifies project/brand/product context, resolves the required reusable assets (characters, products, logos, voices) from the asset registry, and provides/generates whatever is missing — saving paths for reuse. Use whenever the user asks to plan a campaign, make a marketing plan, or create/generate any image, video, voiceover, or music.
Generate music using Gemini Lyria. Use for background music, jingles, intros, soundtracks, and complete songs WITH sung vocals — Lyria 3 sings your exact lyrics (8 languages, rap/sung delivery).
Generate images using Gemini 3 Image (Nano Banana). Use for thumbnails, carousels, infographics, social graphics, product photos.
Generate video content using Gemini Veo. Use when user asks to create video, TikTok ad, Instagram Reel, YouTube video, product video, explainer.
Write the words — scroll-stopping hooks, framework-driven scripts, and platform-ready captions with hashtags. Use when the user needs hook ideas, a video/ad script, ad copy, post captions, or says "what should I post", "write a script", "give me hooks", "write the caption".
Analyze a reference video (YouTube URL or local file) into a scene-by-scene breakdown — timecodes, shot types, camera moves, on-screen text, spoken lines — plus a recreation blueprint with per-scene video prompts and VO script. Use when the user says "analyze this video", "I want to create something like that", "recreate this video", "break down this YouTube video", or pastes a video link they want to emulate.
| name | generate-voiceover |
| description | Generate voiceover audio using Gemini TTS. Use for narration, voiceovers, podcasts, multi-speaker dialogue. |
| allowed-tools | Bash Read Write Edit |
Voiceover is for NARRATION ONLY — a narrator speaking over visuals, with no on-screen speaker.
Do NOT generate a voiceover for a scene where a character speaks on camera.
Those clips (Omni text_to_video / image_to_video / reference_to_video, Veo
and Seedance speaking clips) generate their own dialogue audio and lip-sync. The
lines belong in the video prompt (says: <exact words>), not in a TTS file.
Layering TTS on top double-stacks two performances and muddies the mix.
| Scene | Audio source |
|---|---|
| Character speaks on camera | The clip's own audio — quote the dialogue in the video prompt |
| Narrator over visuals | This skill |
| Silent / ambient b-roll | Music bed + clip ambience |
See workflows/VIDEO-PROMPT-GUIDE.md §4e-vo.
Do NOT create a projects/{name}/scripts/*.ts file. Run the workflow command:
node workflows/cli.cjs generateVoiceover \
'{"text":"...","outputPath":"projects/{name}/output-contents/vo.wav","voice":"..."}'
For dialogue between voices use generateMultiSpeakerVoiceover. For long scripts, put the
args in a file and pass @args.json. The CLI loads .env and prints the JSON result
(path + cost). Argument shapes are in workflows/WORKFLOWS.md.
Free option — Microsoft Edge TTS (generateEdgeTTSVoiceover, $0, no API key): use
when the user wants free narration or a different voice. Same output shape, not
budget-gated. Burmese voices my-male/my-female; rate/volume/pitch control but no
styles/emotion. Needs the edge-tts lib once: python3 -c "import edge_tts" || python3 -m pip install edge-tts (doctor reports it). Full args: WORKFLOWS.md § generateEdgeTTSVoiceover.
node workflows/cli.cjs generateEdgeTTSVoiceover '{"script":"...","voice":"my-female","outputPath":"projects/{name}/output-contents/vo.wav"}'
Trade-off: Gemini generateVoiceover = styled/emotive voices (paid ~$0.001/req); Edge =
free but plain. For the user's OWN cloned voice, use their WAVs + infiniteTalkLipsync, not TTS.
Output Location: projects/{name}/output-contents/
Does projects/{project-name}/ exist?
YES → Read these files for context:
NO → Ask user for the script directly
If project exists, READ and USE:
From projects/{name}/templates/project.md:
product.name → What to mentionoffer.headline → What to promotecta.primary → Call to action to sayFrom projects/{name}/templates/brand.md:
tone.voice → How character speaks (professional, casual, energetic)tone.energy → Pacing and intensityrestrictions.never_say → Words to AVOID in scriptFrom projects/{name}/content-plans/:
Ask: "What text do you want to convert to speech?" (Or use script from video plan)
Always ask first — don't assume. A piece may want: a voiceover (off-screen narrator), an on-screen character speaking (handled by the video skill, not here), music only, or silence.
"Do you want a voiceover (off-screen narration) on this? Or character-speaks / music-only / silent?"
If no voiceover → stop here. If yes → go to Step 2.
A project (or a specific character) may already have a locked voice identity so narration stays consistent across pieces.
# Check the locked voice's files on disk. Pass the project name — the CLI loads the
# registry itself. id = "voice-main" (or a character's linked_voice id).
node workflows/cli.cjs resolveAsset '["{name}","voice-main"]'
# → { ok, existing[], missing[] }
linked_voice so voice matches the face.registerAsset('{name}', 'voices', {...}).Read brand.md tone, then propose a value for every parameter and say why — the
user adjusts, you don't decide alone.
Voice (suggest 1, offer 2 alternatives):
| Voice | Gender | Best For | Matches brand tone |
|---|---|---|---|
| Zephyr | Male | Professional, calm narration | "professional", "calm" |
| Puck | Male | Energetic, casual, youthful | "energetic", "casual" |
| Charon | Male | Deep, authoritative | "authoritative", "serious" |
| Kore | Female | Professional, clear | "professional", "clear" |
| Aoede | Female | Warm, friendly, approachable | "friendly", "warm" |
| Fenrir | Male | Strong, dramatic | "bold", "dramatic" |
| Leda | Female | Soft, gentle | "gentle", "calm" |
| Orus | Male | Mature, wise | "wise", "trustworthy" |
Other parameters to propose:
voiceStyle.audioProfileaudioProfile line describing that delivery — and check
assets/style/copy-examples.md for past scripts whose phrasing the new script
should match. Save the description to the registered voice so future VOs reuse it.Present everything back as one summary and wait for explicit go — let the user change any single field:
🎙️ VOICEOVER SETUP — confirm or adjust each line
Voice: Kore (suggested — matches your "professional, warm" brand tone)
alt: Aoede (friendlier) · Charon (deeper male)
Style: professional
Pace: natural
Accent: american_general
Audio profile: (none) — add a custom description?
Script: "…" (~38 words ≈ 15s at natural pace ✓)
Pronunciation: "Acme" → AK-mee?
Music under VO: no (or: yes @ 30%)
Output: projects/{name}/output-contents/voiceover.wav
Proceed, or change a field? (proceed / change voice / slower / edit script / add music …)
Only after the user confirms → Step 4. If the user says "just do it", still show this summary once and state the assumed defaults before running.
Use the pre-built workflow function — do NOT re-implement file saving, retry, or cost handling.
It validates input, retries on transient errors, writes the .wav, and returns the cost.
Only run after the user confirmed the setup in Step 3. Use the exact values they approved:
# voiceName = the CONFIRMED voice; voiceStyle fields all confirmed in Step 3;
# audioProfile is optional free-text, only if the user added one.
node workflows/cli.cjs generateVoiceover '{"script":"The confirmed script text","outputPath":"projects/{name}/output-contents/voiceover.wav","voiceName":"Kore","voiceStyle":{"style":"professional","pace":"natural","accent":"american_general","audioProfile":""}}'
# → { success:true, data:{ audioPath, cost:{ totalCost } } } | { success:false, error:{ code, message } }
If it succeeded, save the voice identity so future narration stays consistent (ask the user first if it should become the project's locked voice):
node workflows/cli.cjs registerAsset '["{name}","voices",{"id":"voice-main","label":"Main narrator","voice_name":"Kore","style":"professional","pace":"natural","accent":"american_general"},{"date":"<today ISO>"}]'
Ask user to format script with speaker labels:
Host: Welcome to the show!
Guest: Thanks for having me.
Host: Let's dive right in...
Then generate with the pre-built workflow function:
node workflows/cli.cjs generateMultiSpeakerVoiceover '{"script":"<speaker-labeled script>","speakers":[{"speaker":"Host","voiceName":"Zephyr"},{"speaker":"Guest","voiceName":"Aoede"}],"outputPath":"projects/{name}/output-contents/podcast.wav"}'
# → { success:true, data:{ audioPath } }
If this voiceover is for a video:
ffmpeg -i video.mp4 -i voiceover.wav -c:v copy -c:a aac -map 0:v:0 -map 1:a:0 output.mp4
Save to: projects/{name}/output-contents/ or current directory
voiceover.wavscript.txt (keep the script)<content-id>.pipeline.json IN the content folder BEFORE generating
(nodes = CLI commands, {{node.data.field}} refs), then
node workflows/cli.cjs runPipeline @<file> — see workflows/pipelines/README.md.prompts.txt with the VO script (including audio tags)
and voice/style params; update it on every retry with a one-line RESULT note.createGenerationManifest / addManifestEntry
CLI commands (AGENT-GUIDE Step 5).~$0.001 per sentence (very cheap)
Example: 100-word script = ~$0.01
The TTS model reads the script as formatted. Whitespace, punctuation, and line breaks all change the output audio — write the script for the ear, not the eye.
Punctuation → pause mapping (use deliberately):
| You write | The model does |
|---|---|
, comma | short beat |
. period | full stop + breath |
… ellipsis | hesitation / trailing off |
— em-dash | dramatic beat mid-sentence |
? / ! | rising / emphatic intonation |
| blank line (paragraph break) | longer pause, topic shift |
[short pause] / [long pause] tag | explicit pause where punctuation isn't enough |
Normalization — spell out what TTS mangles (fix in the script, don't hope):
| Written | Script should say |
|---|---|
$50 | "fifty dollars" |
24/7 | "twenty-four seven" |
2026-07-09 | "July ninth" (or as the brand says dates) |
50% | "fifty percent" |
AI, FAQ | keep if spelled letter-by-letter is wanted; else write it out ("A-I") |
URLs (acme.com/shop) | "acme dot com slash shop" — or cut it; URLs rarely belong in VO |
| Brand/foreign names | phonetic respelling confirmed in Step 2 ("Acme" → "AK-mee") |
Tips:
Voiceovers now use gemini-3.1-flash-tts-preview: embed inline audio tags IN the
script — "[excited] …", "[short pause]", "[long pause]", "[whispers]",
"[dry chuckle]" (200+ tags; documented set in gemini/types.ts TTSAudioTag) —
plus audioProfile as director's notes. Never ship a flat read: every script
should carry 2-4 tags placed where the emotion turns. Old model available via
ttsModel:"gemini-2.5-flash-preview-tts". ffprobe the duration — expressive reads
run longer.