framevideo-voiceover-ssml
Create narration from project subtitles or AI analysis output, then author SSML-style voice scripts with phoneme, break, and ttnumber markup for FrameVideo voiceovers. Use when the user wants subtitles linked to voice generation, automatic narration from transcript/content, pronunciation fixes, pause insertion, or text normalization before TTS.
How do I install this agent skill?
npx skills add https://github.com/chanjing-ai/framevideo --skill framevideo-voiceover-ssmlIs this agent skill safe to install?
- Gen Agent Trust Hubpass
The skill is safe. It provides tools for creating voiceover scripts with SSML-style markup from project subtitles or transcripts, and integrating the resulting audio back into the project workflow.
- Socketpass
No alerts
- Snykwarn
Risk: MEDIUM · 1 issue
What does this agent skill do?
FrameVideo Voiceover SSML
Generate narration scripts from existing project content (subtitles, transcripts, AI analysis) and enhance them with SSML-style markup for pronunciation fixes, pauses, and number reading control.
When To Use
- User wants narration generated from project subtitles or transcript
- Need to fix pronunciation of brand names, technical terms, or foreign words
- Need to control pause timing for dramatic effect or pacing
- Need to normalize how numbers, dates, or prices are spoken
- Expanding terse subtitles into natural narration
- Creating voiceover that stays aligned with visible text
Do NOT Use
- For simple text-to-speech without markup → use
framevideo-media(tts) directly - For digital human video synthesis → use
chanjing-digital-human - For choosing TTS voices or providers → use
framevideo-media - When the user provides a complete narration script ready for TTS
Quick Start
Minimal workflow:
# 1. Find source text (subtitle file, transcript, or analysis)
cat subtitles.txt
# Output: "Visit chanjing.ai for more info"
# 2. Add SSML markup for pronunciation
echo '<phoneme alphabet="ipa" ph="tʃæn.dʒɪŋ">Chanjing</phoneme> <break time="0.3s"/> Visit chanjing dot AI for more info.' > script-marked.txt
# 3. Generate TTS with markup (if provider supports)
npx framevideo tts script-marked.txt --voice af_heart --output narration.wav
# 4. Transcribe back to get timestamps
npx framevideo transcribe narration.wav --output transcript.json
# 5. Reference in composition
# <audio src="narration.wav" data-start="0" data-duration="5.2"></audio>
Core Concepts
Source Text Priority
Find the source text in this order:
- Project subtitles/transcript — the primary source, already aligned with visible content
- AI analysis text — scene descriptions or product copy extracted during storyboard
- Existing narration draft — if the user provided one
- Manual authoring — last resort when no source exists
Why subtitles first? They're already timed to the visual beats and match what viewers see on screen.
SSML-Style Markup
Three tags for delivery control:
| Tag | Purpose | Example |
|---|---|---|
<phoneme> | Fix pronunciation | <phoneme alphabet="ipa" ph="tʃæn.dʒɪŋ">Chanjing</phoneme> |
<break> | Insert pause | <break time="0.5s"/> |
<ttnumber> | Control number reading | <ttnumber pronounce="twenty twenty-six">2026</ttnumber> |
Markup is authoring-layer only. Keep it in your script file, but strip it before sending to TTS providers that don't support SSML.
Fallback Strategy
Not all TTS providers support SSML tags:
- Kokoro (local): Does NOT support SSML — strip tags before generation
- Chanjing TTS: Supports
phoneme,break,ttnumber— pass through unchanged - ElevenLabs: Supports subset of SSML — check their docs
Always save both versions:
script-marked.txt— original with SSML tagsscript-fallback.txt— clean text for non-SSML providers
Workflow
Step 1: Locate Source Text
# Check for existing subtitles
ls subtitles.txt captions.json transcript.json
# Check AI analysis output (if using website-to-framevideo)
cat STORYBOARD.md SCRIPT.md
# Check existing narration drafts
ls narration-draft.txt script.txt
Step 2: Normalize Into Speakable Script
Expand terse subtitles:
Source: "New feature: AI search"
Narration: "Introducing our new feature: AI-powered search that understands your intent."
Keep alignment with visible text:
- If subtitle says "50% faster", narration should say "fifty percent faster" at the same timing
- If product name appears on screen as "FrameVideo", say "FrameVideo" not "frame video"
Text normalization rules:
- Convert
&to "and" - Spell out acronyms on first use: "TTS, or text to speech"
- Convert URLs: "chanjing.ai" → "chanjing dot AI"
- Convert symbols:
$99→ "ninety-nine dollars"
Step 3: Add SSML Markup
Use sparingly. Only add markup where TTS misreads or pacing is critical.
Phoneme Tag — Pronunciation Fixes
Chinese names and brands:
<phoneme alphabet="py" ph="chan1 jing4">蝉镜</phoneme>
<phoneme alphabet="py" ph="xi1">茜</phoneme> (name: "Xi", not "qi")
English technical terms:
<phoneme alphabet="ipa" ph="dʒiː.sæp">GSAP</phoneme> (not "guh-sap")
<phoneme alphabet="ipa" ph="weɪ.ˈeɪ.ˈeɪ.ˈpiː">WAAPI</phoneme> (spell it out)
Product names:
<phoneme alphabet="ipa" ph="freɪm.ˈvɪd.i.oʊ">FrameVideo</phoneme>
When to use:
- Brand names mispronounced by TTS
- Technical jargon with non-standard pronunciation
- Foreign words in English narration
- Acronyms that should be spelled vs pronounced
Alphabets:
ipa— International Phonetic Alphabet (universal)py— Pinyin for Mandarin Chinesex-sampa— Extended SAMPA (ASCII-safe IPA)
Break Tag — Pause Control
Dramatic pauses:
Introducing our new product. <break time="0.8s"/> Built for creators.
List separation:
Three reasons: speed<break time="0.4s"/>, quality<break time="0.4s"/>, and ease of use.
Transition markers:
In the past<break time="0.3s"/>, this took hours. Now? Seconds.
Timing guidelines:
0.2s— natural comma pause0.3-0.5s— sentence boundary, breath0.6-0.8s— dramatic pause, emphasis1.0s+— scene transition, major shift
When to use:
- Default TTS pacing feels rushed
- Need emphasis before key message
- Narration must sync with on-screen timing
When NOT to use:
- Every comma (let TTS handle natural pauses)
- Replacing proper sentence structure
Ttnumber Tag — Number Reading
Years:
<ttnumber pronounce="twenty twenty-six">2026</ttnumber>
<ttnumber pronounce="nineteen fifty-five">1955</ttnumber>
Product codes:
Model <ttnumber pronounce="A X dash three hundred">AX-300</ttnumber>
Prices:
Only <ttnumber pronounce="ninety-nine dollars">$99</ttnumber>
Dates:
Launch date: <ttnumber pronounce="July seventeenth">7/17</ttnumber>
When to use:
- Default TTS reads numbers awkwardly ("two thousand twenty-six" vs "twenty twenty-six")
- Product codes should be spelled ("A-X-three-hundred" not "ax three hundred")
- Currency needs natural phrasing
- Dates need cultural reading convention
Step 4: Choose TTS Provider
Decision tree:
Does user require Chanjing platform voices?
├─ YES → Use chanjing-digital-human skill (supports SSML)
└─ NO
├─ Need offline/free → Kokoro via framevideo-media (strip SSML)
└─ Need high quality → ElevenLabs (check SSML support)
Provider SSML support:
| Provider | Phoneme | Break | Ttnumber | Invoke via |
|---|---|---|---|---|
| Kokoro | ❌ | ❌ | ❌ | framevideo-media |
| Chanjing TTS | ✅ | ✅ | ✅ | chanjing-digital-human |
| ElevenLabs | ✅ | ✅ | ⚠️ | External API |
Step 5: Generate Audio
With SSML support (Chanjing):
# Pass marked script directly
npx framevideo chanjing tts script-marked.txt \
--voice-id <voice-id> \
--output narration.wav
Without SSML support (Kokoro):
# Strip tags first
sed 's/<[^>]*>//g' script-marked.txt > script-fallback.txt
# Generate clean
npx framevideo tts script-fallback.txt \
--voice af_heart \
--output narration.wav
Stripping SSML tags:
# Simple regex (removes all XML-like tags)
sed 's/<[^>]*>//g' input.txt > output.txt
# Or Python for precise control
python3 << 'EOF'
import re
with open('script-marked.txt') as f:
text = f.read()
# Remove SSML tags but keep inner text
text = re.sub(r'<phoneme[^>]*>(.*?)</phoneme>', r'\1', text)
text = re.sub(r'<break[^>]*/?>', ' ', text)
text = re.sub(r'<ttnumber[^>]*>(.*?)</ttnumber>', r'\1', text)
with open('script-fallback.txt', 'w') as f:
f.write(text)
EOF
Step 6: Save Both Versions
File structure:
project/
├── script-marked.txt # Original with SSML
├── script-fallback.txt # Stripped for non-SSML TTS
├── narration.wav # Generated audio
└── transcript.json # Re-transcribed with timestamps
Why save both?
- Marked version preserves authoring intent
- Fallback version for re-generation with different TTS
- Future TTS providers may add SSML support
Step 7: Writeback to Project
Generate transcript from audio:
npx framevideo transcribe narration.wav --output transcript.json
Use in composition:
<audio
src="narration.wav"
data-start="0"
data-duration="12.4"
data-track-index="10"
data-volume="1.0">
</audio>
Sync captions (see framevideo skill for caption patterns):
// transcript.json → caption timing
const WORDS = [
{ text: "Introducing", start: 0.2, end: 0.8 },
{ text: "FrameVideo", start: 0.9, end: 1.4 },
// ...
];
Patterns
Pattern 1: Subtitle Expansion
Input subtitles.txt:
🚀 New: AI Search
50% faster
Try it now
Output script-marked.txt:
Introducing our newest feature:<break time="0.4s"/> AI-powered search.
<break time="0.3s"/>
It's fifty percent faster than traditional search.
<break time="0.5s"/>
Try it now at <phoneme alphabet="ipa" ph="tʃæn.dʒɪŋ">chanjing</phoneme> dot AI.
Pattern 2: Brand Name Consistency
DESIGN.md snippet:
## Brand Voice
- Company: "Chanjing" (IPA: tʃæn.dʒɪŋ, NOT "chan-jing")
- Product: "FrameVideo" (one word, capital F, capital V)
Apply in script:
Welcome to <phoneme alphabet="ipa" ph="tʃæn.dʒɪŋ">Chanjing</phoneme>.
<phoneme alphabet="ipa" ph="freɪm.ˈvɪd.i.oʊ">FrameVideo</phoneme> makes video simple.
Pattern 3: Technical Demo Narration
For product walkthroughs:
First, click the Timeline button.<break time="0.6s"/>
Then drag the <phoneme alphabet="ipa" ph="dʒiː.sæp">GSAP</phoneme> animation track.<break time="0.5s"/>
Notice the seek time updates in real-time.
Pattern 4: Multilingual Product Names
English narration with Chinese brand:
This is <phoneme alphabet="py" ph="chan1 jing4">蝉镜</phoneme><break time="0.3s"/>, the AI video platform from China.
Pattern 5: Number-Heavy Content
Pricing and metrics:
Available in three tiers:<break time="0.4s"/>
Starter at <ttnumber pronounce="forty-nine dollars">$49</ttnumber>,<break time="0.3s"/>
Pro at <ttnumber pronounce="ninety-nine dollars">$99</ttnumber>,<break time="0.3s"/>
and Enterprise at <ttnumber pronounce="four ninety-nine">$499</ttnumber>.
Rules (Non-Negotiable)
- Always save the marked script — even if TTS doesn't support SSML today
- Fallback text must be natural — stripping tags shouldn't break grammar
- Transcribe generated audio — don't assume timing matches script
- Source text takes priority — expand subtitles, don't replace them
- Markup is sparse — only where TTS fails or timing is critical
Avoid
- ❌ Adding SSML to every sentence — only fix actual problems
- ❌ Using
<break>instead of rewriting awkward phrasing - ❌ Assuming Kokoro supports SSML — it doesn't, strip tags first
- ❌ Hard-coding phonemes without testing TTS output — verify it helps
- ❌ Ignoring provider limitations — check what tags are supported
- ❌ Discarding the marked script after generation — keep for iteration
Integration
With framevideo-media
# This skill: create marked script
echo '<phoneme>...</phoneme> text' > script-marked.txt
# framevideo-media: generate TTS
npx framevideo tts script-fallback.txt --voice af_heart --output narration.wav
# framevideo-media: transcribe
npx framevideo transcribe narration.wav --output transcript.json
# framevideo skill: use in composition
With chanjing-digital-human
# This skill: create marked script with SSML
cat script-marked.txt
# chanjing-digital-human: generate with SSML support
npx framevideo chanjing tts script-marked.txt --voice-id <id> --output narration.wav
With website-to-framevideo
Step 3 (Storyboard) → produces SCRIPT.md
↓
This skill → adds SSML markup to SCRIPT.md content
↓
Step 4 (VO) → generates audio via framevideo-media or chanjing-digital-human
↓
Step 5 (Build) → uses transcript.json for caption timing
Validation
1. Check SSML syntax:
# No unclosed tags
grep -o '<[^/>]*>' script-marked.txt | sort | uniq -c
# Phoneme has alphabet attribute
grep '<phoneme' script-marked.txt | grep -v 'alphabet='
# (should return nothing)
2. Test fallback stripping:
sed 's/<[^>]*>//g' script-marked.txt > test-fallback.txt
cat test-fallback.txt
# Verify: readable, no XML artifacts, natural grammar
3. A/B test TTS output:
# Generate without markup
npx framevideo tts script-fallback.txt --voice af_heart -o no-markup.wav
# Generate with markup (if supported)
npx framevideo chanjing tts script-marked.txt --voice-id <id> -o with-markup.wav
# Compare audio quality and pronunciation
4. Verify transcript alignment:
npx framevideo transcribe narration.wav --output transcript.json
# Check: word timing matches intended beats
References
- references/workflow.md — step-by-step workflow details
- references/ssml.md — SSML tag specifications
framevideo-mediaskill — TTS generation and transcriptionchanjing-digital-humanskill — SSML-aware TTS via Chanjing platformframevideoskill — audio element conventions and caption timing- SSML W3C spec: https://www.w3.org/TR/speech-synthesis/
- IPA chart: https://www.internationalphoneticalphabet.org/ipa-charts/
How can the creator link this skill?
Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.
<a href="https://skillzs.dev/skills/chanjing-ai/framevideo/framevideo-voiceover-ssml">View framevideo-voiceover-ssml on skillZs</a>