| name | segment-video-roundup |
| description | Builds per-segment HeyGen + ElevenLabs roundup videos from research handoff, PraisonAIPPT avatar_media_3 decks (50590 pattern), align-cues/yaml/build/normalize-audio/merge, validate-all (audio_loudness), HD 1080p compositor output, and mer.vin publish. Use for megapost video walkthroughs, segment video pipeline, roundup handoff, sync-media, align-cues, gap remediation, hook montage, loudness normalisation, image audit fixes, manifest.json segments, or re-running after handoff updates. |
Segment video roundup pipeline
Per-segment production (hook + N topics + outro) โ compositor MP4 per segment โ ffmpeg concat โ Short video walkthrough on mer.vin.
Reference: examples/videos/june-2026-ai-roundup/ ยท layout index: examples/videos/README.md
Single-topic (Phase 1 B-roll): .cursor/skills/daily-single-video/SKILL.md ยท docs/daily-single-video.md โ converges here in Phase 2 (HeyGen per beat)
Deck template: examples/heygen-50590-video-audio-heygen-images.yaml
Publish: .cursor/skills/mer-vin-article-video-upload/SKILL.md
YAML QA: .cursor/skills/ppt-yaml-deck-workflow/SKILL.md
SDK: praisonaippt/segment_video/
When to use
| Scenario | Action |
|---|
| New handoff (research dir + post ID) | Phase 0 โ full pipeline |
| Scripts only refresh | Phase 2 โ stop before TTS |
| Handoff assets updated (create-news) | Phase 4 only โ do not re-run media unless user asks |
| Media exists; rebuild decks | Phases 5โ7 with correct align โ yaml โ build order |
| Image pick / sync / caption gaps | Gap audit โ downstream fixes โ rebuild affected segments |
| Uneven volume / loudness check | normalize-audio โ merge; gap-audit loudness section |
| Verify HD output | ffprobe final + segments (expect 1920ร1080); see Phase 7 |
| Replace final video on mer.vin | Phase 8 only |
Do not regenerate ElevenLabs/HeyGen when narration.mp3 and heygen.mp4 exist unless the user explicitly asks.
Handoff crawl / review-data enrichment is owned by the create-news agent. This skill fixes downstream pipeline gaps only unless the user asks you to touch handoff files.
Prerequisites
- [ ] Mac: ffprobe, ffmpeg, praisonaippt (conda: test or windsurf)
- [ ] praisonaiwp: praisonaiwp doctor --server default
- [ ] Repo .env: ELEVEN_API_KEY, HEYGEN_API_KEY, ELEVEN_VOICE_ID, AVATAR_ID
- [ ] MER_HEYGEN_VERTICAL unset โ landscape HeyGen 1280ร720, compositor 1920ร1080
- [ ] research_dir with review-data.json + review-assets/
See reference.md for env defaults and manifest schema.
Protocol stages (order matters)
Defined in scripts/config/protocol.json. Critical rule: after sync-media adds or changes cue count, always run align-cues before yaml. Running yaml alone leaves stale single-verse decks.
cd examples/videos/<project>/scripts
PROJECT=../
| Stage | Scope | Purpose |
|---|
catalogue-media | project | Index handoff images |
crawl-missing-assets | project | Emergency only โ patches create-news handoff; normal flow = create-news crawl |
sync-media | project | media_assets.json + slide_images/* |
validate-assets | project | asset_gaps_report.json |
validate-media | project | Script alignment gate |
audit-images | project | image_audit_report.json |
media | segment | ElevenLabs + HeyGen + timestamps |
align-cues | segment | cue_timings.json from Whisper + media cues |
yaml | segment | segment.yaml verses from cue_timings |
build | segment | segment.mp4, segment.srt, slide JPEGs |
normalize-audio | project | EBU R128 loudnorm each segment.mp4 โ loudness_report.json |
merge | project | merge/final-roundup.mp4 |
validate-all | project | Full validator suite (includes audio_loudness) |
Phase 0 โ Bootstrap
zsh .cursor/skills/segment-video-roundup/scripts/bootstrap-project.sh \
"my-roundup-slug" "/path/to/research/my-roundup" POST_ID
Or copy examples/videos/june-2026-ai-roundup/ โ examples/videos/<slug>-roundup/, edit manifest.json, reset segments/*/, merge/, media_assets.json.
Phase 2 โ Scripts
| Segment | Target |
|---|
| hook | ~55โ70 words: attention โ overview roll-call โ Let's get started |
| each topic | ~80โ95 words, 3 sentences when multi-cue |
| outro | June CTA (~25 words): like/share/subscribe โ no mer.vin spoken |
python3 write_scripts.py
Gate: User review before Phase 3 (TTS cost).
Phase 3 โ ElevenLabs + HeyGen
python3 run_segment_media.py --skip-existing
python3 run_segment_media.py --skip-existing 01-nvidia-nemotron-3-ultra
Outputs: narration.mp3, heygen.mp4, timestamps.json.
Phase 4 โ Media sync (image selection)
python3 pipeline.py run sync-media
python3 pipeline.py run validate-media --strict
python3 pipeline.py run validate-assets
python3 pipeline.py run audit-images
- Heroes from
review-data.json via praisonaippt.segment_video.image_selection
- Multi-cue: one sentence โ one image when pool allows (
max_cues_per_segment: 4)
- Audit-driven fixes in
scripts/sync_media_assets.py:
CUE_IMAGE_OVERRIDES โ wrong rank, file already in handoff
VISION_ENRICHMENTS โ stub handoff vision โ alignment keywords (prefer fixing handoff instead)
HERO_REUSE_ENRICHMENTS โ thin pools (1 image / 3 sentences)
- Overrides run twice (before + after
fill_missing_sentence_cues); recalc script_alignment
- Hook montage: prepend
script_fragment to vision text before alignment
- Sparse pools: hero reuse is downstream stopgap โ handoff should supply โฅ1 relevant image per sentence
- Zoom: edit
media_fit: cover in segment.yaml after yaml, before build (yaml resets to contain)
After sync-media changes cue count โ Phase 5 align-cues is mandatory.
See reference.md โ Handoff vs downstream gaps.
Phase 5 โ Align, YAML, build (mandatory order)
SEGS="01-nvidia-nemotron-3-ultra 05-aws-bedrock-gpt-5-5-codex-ga"
python3 pipeline.py run align-cues --force $SEGS
python3 pipeline.py run yaml --force $SEGS
python3 pipeline.py run build --force $SEGS
python3 pipeline.py run normalize-audio --force
python3 pipeline.py run merge --force
Footgun: normalize-audio $SEGS can write an empty loudness_report.json and skip rebuilt segments โ always run project-wide before merge.
Hook montage (00-hook)
- Montage starts after "roundup:" (~2.44 s); compositor needs a lead-in verse or MP4 truncates ~2.7 s vs HeyGen
build_segment_yaml.py prepends intro slide when first cue audio_start_sec > 0
- When
len(verses) != len(cue_timings): SRT from verses (write_verses_srt), not cue_timings alone
- Caption rules:
.cursor/skills/video-script-captions/SKILL.md
- Rebuild hook:
align-cues โ yaml โ build --force 00-hook โ normalize-audio โ merge
Multi-cue topic segments
media_assets.json cues must match cue_timings.json count and segment.yaml verse count
avatar_timeline: continuous + slide_timestamps for 2+ cues (50590 pattern within segment)
Per-segment build internals
praisonaippt hero-panel-place -i segment.yaml --force
praisonaippt -i segment.yaml -o segment.pptx --convert-video --video-output segment.mp4
Post-build: fix-jpegs, seed-golden if validate-deck golden fails.
Phase 6 โ Merge
python3 pipeline.py run normalize-audio
python3 pipeline.py run normalize-audio --force
python3 pipeline.py run merge
Outputs:
merge/final-roundup.mp4 โ 1920ร1080 @ 30fps (Full HD); verify with user before publish
merge/final-roundup.srt
merge/timeline.json
Resolution chain: HeyGen 1280ร720 โ compositor build โ segment.mp4 1920ร1080 โ merge (no rescale). Merge alone cannot fix resolution โ rebuild segments if not 1080p. See reference.md.
Phase 7 โ Validation (run after every rebuild)
python3 pipeline.py status
python3 pipeline.py validate-all
python3 pipeline.py run validate-display
python3 pipeline.py run validate-hook
Or use the gap audit script:
zsh .cursor/skills/segment-video-roundup/scripts/gap-audit.sh examples/videos/<project>
validate-all gates (downstream focus)
| Validator | Pass means |
|---|
hook_montage | 15/15 montage cues; HeyGen vs segment.mp4 drift โค ~1 s |
segment_sync | cue_timings = yaml verses = media cue count |
audio_loudness | All segment.mp4 within ยฑ1 LUFS of target (-16); spread โค 2 LUFS |
display_sync | Per-segment captionโslideโspeech (catalogue may fail on handoff) |
image_audit | Scriptโimage alignment; fix via sync-media overrides + rebuild |
merge_output | Final MP4 + SRT exist |
HD verification (ffprobe)
Expected deliverable: 1920ร1080, 30 fps, H.264 + AAC on every segment.mp4 and merge/final-roundup.mp4.
ffprobe -v error -select_streams v:0 \
-show_entries stream=width,height,r_frame_rate \
-of csv=p=0 merge/final-roundup.mp4
for f in segments/*/segment.mp4; do
echo "$f: $(ffprobe -v error -select_streams v:0 -show_entries stream=width,height -of csv=p=0 "$f")"
done
If output is 720p: set video_export.preset: high in deck/base style โ build_segment_yaml.py โ build --force โ normalize-audio โ merge. Native 1080p HeyGen (not upscaled 720p) requires changing run_segment_media.py dimensions and regenerating all heygen.mp4.
Ignore for downstream-only work: handoff_uncrawled, insufficient_pool, manual_asset_gaps (handoff agent).
Reports: validation_report.json, loudness_report.json, image_audit_report.json, display_validation_report.json, hook_validation_report.json.
Multi-agent gap audit (recommended)
When user asks to verify or find gaps, launch parallel explore agents (not handoff crawl):
- Validation report โ read
validation_report.json; list downstream failures only
- Segment sync โ compare
cue_timings.json vs yaml verses vs slide_jpegs/ vs heygen/segment duration drift
- Hook + image audit โ
hook_validation_report.json, image_audit_report.json swap recommendations
- Loudness โ read
loudness_report.json or gap-audit loudness section; spread should be โค 2 LUFS post-normalise
- HD resolution โ ffprobe final + sample segments; expect 1920ร1080 @ 30fps on all
segment.mp4
Fix order:
sync-media (if picks wrong) โ align-cues โ build_segment_yaml.py โ build --force โ normalize-audio โ merge โ validate-all
Do not block on handoff catalogue failures if per-segment display_sync passes.
Phase 8 โ Publish
Follow mer-vin-article-video-upload skill.
praisonaiwp media upload examples/videos/<project>/merge/final-roundup.mp4 \
--post-id=POST_ID --server default
Insert wp:video block before At a glance. Update manifest.json โ final_video.
Re-run cheat sheet
| Change | Commands |
|---|
| New handoff heroes only | sync-media โ align-cues โ build_segment_yaml.py โ build --force SEGS โ normalize-audio โ merge |
| Script edit | regenerate --change script --segment DIR |
| Deck/visual only | regenerate --change deck --segment DIR |
| Wrong image pick | Edit CUE_IMAGE_OVERRIDES or handoff top_picks โ sync-media โ rebuild chain |
| Hook duration drift | align-cues 00-hook โ yaml โ build --force 00-hook โ normalize-audio โ merge |
| Uneven volume across segments | normalize-audio --force โ merge โ check loudness_report.json |
| Output not 1080p | video_export.preset: high โ yaml โ build --force โ normalize-audio โ merge |
Full downstream rebuild (no TTS/HeyGen):
cd examples/videos/<project>/scripts
python3 pipeline.py run sync-media
python3 pipeline.py run align-cues --force
python3 build_segment_yaml.py $(python3 -c "import json; m=json.load(open('../manifest.json')); print(' '.join(s['dir'] for s in m['segments'] if s.get('slide_type') in ('avatar_media_3','big_number')))")
python3 pipeline.py run build --force
python3 pipeline.py run normalize-audio --force
python3 pipeline.py run merge --force
python3 pipeline.py validate-all
Studio & CLI
cd examples/videos/<project>
segment-video -p . studio
segment-video -p . regenerate --change deck --segment 01-nvidia-nemotron-3-ultra
cd scripts && python3 pipeline.py status
Additional resources