REQUIRED: Load Remotion Best Practices First
This skill depends on
remotion-best-practices. You MUST invoke it before proceeding:text
Invoke the skill/tool named: remotion-best-practices
Automated pipeline for 4K Bilibili horizontal knowledge videos from a topic. Coding agent + TTS backend + Remotion + FFmpeg.
videos/{name}/ to iterate on a finished video--public-dir, namingreferences/ fileResolve SKILL_DIR to the directory containing this SKILL.md. If your agent exposes a built-in skill directory variable (e.g. ${CLAUDE_SKILL_DIR}), map it to SKILL_DIR.
bash
SKILL_DIR="${SKILL_DIR:-${CLAUDE_SKILL_DIR}}"
# 1. Update check (notify-only, throttled to 24h)
"${SKILL_DIR}/scripts/check_update.sh"
# 2. Prerequisites (CLIs + backend env vars)
python3 "${SKILL_DIR}/scripts/check_prereqs.py"
check_update.sh output:
UPDATE_AVAILABLE vX.Y.Z -> vA.B.C — tell the user the version delta and ask before running git -C "${SKILL_DIR}" pull --ff-only. Notify-only by design — never pull without consent (the skill directory belongs to the user).UP_TO_DATE / SKIPPED_RECENT_CHECK / MANUAL_INSTALL — continue silently.Prereqs failures — see README.md for setup. The check is backend-aware (resolves TTS_BACKEND env → user_prefs.json global.tts.backend → edge default), so only env vars required by the active backend are validated.
Design Learning shortcut: If the user provides a reference video/image or asks to save/list/delete style profiles, see references/design-learning.md instead of running the workflow below.
Detect at workflow start:
Full pipeline with sensible defaults. Mandatory stop at Step 9 (Studio review); Step 10 (4K render) only fires when the user says "render 4K" / "render final".
StepDecisionAuto Default3Title positiontop-center5AssetsFree sources auto-resolve; paid generation needs confirmation7Thumbnail methodRemotion-generated (16:9 + 4:3)9Outro animationPre-made MP4 (white/black by theme)12Subtitle methodRemotion-native (skip legacy FFmpeg burn)14CleanupAuto-clean temp files
Override any default in the initial request:
Prompts at each decision point.
If videos/{name}/ already exists and the user is iterating on a finished or in-progress video — "regenerate", "re-render", "rebuild", "I edited the script/prompt", "update the video", "change the BGM" — reuse that directory. Do NOT start a new project or a new videos/{newname}/; that is the Single Project rule applied to iteration, and starting fresh is the most common mistake here.
Pick the smallest re-run for what actually changed. Every command targets the same videos/{name}/, and every Remotion command keeps --public-dir videos/{name}/:
ChangedRe-runReuses (don't redo)Narration script ( podcast.txt)Step 8 ( generate_tts.py --output-dir videos/{name}) → Step 9 preview → Step 10 render (on explicit confirm) → Step 11 BGMtopic research + section designVisuals only (components, layout, colors, props)Step 9 preview → Step 10 render (on explicit confirm)podcast_audio.wav / timing.json (audio unchanged)Background music onlyStep 11 mixoutput.mp4 (no re-render)Subtitles onlyStep 12output.mp4 / video_with_bgm.mp4
Any re-run that changes what the viewer sees or hears re-enters the Step 9 gate: apply the change, let Studio hot-reload (or relaunch it), and wait for a fresh explicit "render 4K" — the confirmation that started the previous render does not carry over to the adjusted version. Only the audio-untouched post-render steps (BGM mix, subtitles) skip the gate.
A script change shifts every downstream timestamp, so always regenerate timing.json through TTS — never hand-edit it (see Audio-Master Clock). After any re-run, re-verify:
bash
python3 ${SKILL_DIR}/scripts/verify_output.py videos/{name}/
Cleanup only removes TTS temp files, never
output.mp4/video_with_bgm.mp4— so BGM/subtitle re-runs avoid a full ~8-min re-render.
Iterating on a finished video? If
videos/{name}/already exists and the user wants to regenerate after a change, do NOT start at Step 1 — see Regenerating an Existing Video for the minimal re-run.
At Step 1 start, create one task per step in your agent's tracker (Claude Code TaskCreate / Codex todo list / equivalent). Mark in_progress on start, completed on finish. Files in videos/{name}/ are the durable record — if interrupted, inspect the directory to determine where to resume.
#StepOutputPhase file1Define topic directiontopic_definition.mdworkflow-script.md2Research topictopic_research.mdworkflow-script.md3Design 5-7 sections(in-memory)workflow-script.md4Write narration scriptpodcast.txtworkflow-script.md4.5Pronunciation pre-flight (zh-CN)phonemes.jsonworkflow-script.md5Asset plan & resolveassets/manifest.jsonworkflow-assets.md6Generate publish info (Part 1)publish_info.mdworkflow-production.md7Generate thumbnails (16:9 + 4:3)thumbnail_*.pngworkflow-production.md8Generate TTS audiopodcast_audio.wav, timing.jsonworkflow-production.md9****Remotion composition + Studio preview—workflow-production.md10Render 4K video (only on user request)output.mp4workflow-production.md11Mix background musicvideo_with_bgm.mp4workflow-production.md12Finalize (optional legacy subtitle burn)final_video.mp4workflow-publish.md13Complete publish info (Part 2)chapter timestampsworkflow-publish.md14****Verify output ( scripts/verify_output.py)—workflow-publish.md15Generate vertical shorts (optional)shorts/workflow-publish.md
Mandatory stops (bold rows above):
npx remotion studio and wait for user feedback before rendering. NEVER render 4K until the user explicitly confirms ("render 4K" / "render final"). A reply containing adjustment requests is not confirmation — even if it also says "otherwise looks good": apply the changes, let Studio hot-reload, and ask again. Every round of adjustments needs its own fresh confirmation before Step 10.verify_output.py. MUST pass before declaring the video done. Exit 0 = green; exit 2 = warnings still publishable. Auto-fixes common omissions (creates final_video.mp4 if missing). For machine-readable output add --format json (auto when piped).Pre-render audit (recommended) — before Step 9:
bash
python3 ${SKILL_DIR}/scripts/audit_beat_sync.py <Video.tsx> <timing.json>
Flags beats that drift > 1.5s from narration. Especially important for kinetic-typography videos.
After StepCheck8 (TTS)podcast_audio.wav plays · timing.json covers all sections · SRT is UTF-810 (Render)output.mp4 is 3840×2160 · audio-video sync · no black frames14 (Verify)verify_output.py exits 0 (or 2 with reviewed warnings)
RuleRequirementSingle ProjectAll videos under videos/{name}/ in user's Remotion project. NEVER create a new project per video.4K Output3840×2160 (or 2160×3840 vertical), use scale(2) wrapper over 1920×1080 design spaceAudio SyncAudio ( podcast_audio.wav + podcast_audio.srt) is the master clock. timing.json MUST be generated from the real TTS output, never hand-estimated. Before rendering, final video duration must match audio within ±0.5s. See Audio-Master Clock.ThumbnailMUST generate both 16:9 (1920×1080) AND 4:3 (1200×900) — see design-guide.mdStudio Before RenderMUST launch remotion studio for review. NEVER render 4K until user explicitly confirms. Adjustment feedback ≠ confirmation — apply, hot-reload, ask again.**--public-dir**Every Remotion command uses --public-dir videos/{name}/
Visual minimums (text sizes, content width, safe zones, animation safety) live in references/design-guide.md. MUST load before Step 9.
Audio is the master clock. Every slide start, subtitle, progress-bar chapter, and animation beat is derived from podcast_audio.wav and podcast_audio.srt.
Generate timing from TTS, not from text estimates. The canonical pipeline is: text
podcast.txt (final)
→ generate_tts.py
→ podcast_audio.wav + podcast_audio.srt + timing.json
→ Remotion composition
→ render
Never hand-write timing.json before audio exists. If you already have curated slides, run align_timing_from_srt.py to anchor them to the real SRT, or add a "section" field to each slide and then run it.
Compensate TransitionSeries overlap. TransitionSeries renders sum(section.duration_frames) - (N-1) * transitionFrames frames. To keep the rendered length equal to timing.total_frames, scale every section proportionally; do not stuff all overlap frames into the first section. The corrected pattern is in templates/Video.tsx.
WhenCheckCommand / ActionAfter Step 8timing.json.total_duration matches podcast_audio.wav within ±0.5sffprobe -show_entries format=duration podcast_audio.wavBefore Step 10Video.tsx scales all sections for transition overlapInspect the compensatedSections calculationAfter Step 10/12final_video.mp4 duration matches podcast_audio.wav within ±0.5sffprobe -show_entries format=duration final_video.mp4Step 14verify_output.py exits 0 and reports green on audio/timingpython3 ${SKILL_DIR}/scripts/verify_output.py videos/<name>/
If any checkpoint fails, stop. Do not publish.
ParameterHorizontal (16:9)Vertical (9:16)Resolution3840×2160 (4K)2160×3840 (4K)Frame rate30 fps30 fpsEncodingH.264, 16MbpsH.264, 16MbpsAudioAAC, 192kbpsAAC, 192kbpsDuration1-15 min60-90s (highlight)
text
project-root/ # Remotion project root
├── src/remotion/ # Remotion source (Root.tsx, compositions, index.ts)
├── videos/{video-name}/ # Per-video assets (the agent's working dir)
│ ├── topic_definition.md # Step 1
│ ├── topic_research.md # Step 2
│ ├── podcast.txt # Step 4: narration script
│ ├── phonemes.json # Step 4.5: zh-CN pronunciation overrides
│ ├── podcast_audio.wav # Step 8: TTS audio
│ ├── podcast_audio.srt # Step 8: subtitles
│ ├── timing.json # Step 8: timeline (drives animations)
│ ├── thumbnail_*.png # Step 7
│ ├── output.mp4 # Step 10: 4K render (no BGM)
│ ├── video_with_bgm.mp4 # Step 11
│ ├── final_video.mp4 # Step 12: final output
│ └── bgm.mp3 # Background music
└── remotion.config.ts
--public-dir per video#Remotion commands MUST use --public-dir videos/{name}/ — each video's assets stay in its own directory, no copy to public/. Enables parallel renders.
bash
npx remotion studio src/remotion/index.ts --public-dir videos/{name}/
npx remotion render src/remotion/index.ts CompositionId videos/{name}/output.mp4 --public-dir videos/{name}/ --video-bitrate 16M
npx remotion still src/remotion/index.ts Thumbnail16x9 videos/{name}/thumbnail.png --public-dir videos/{name}/
{video-name}: lowercase English, hyphen-separated (e.g. reference-manager-comparison){section}: lowercase English, underscore-separated, matches [SECTION:xxx]Type16:94:3Remotionthumbnail_remotion_16x9.png``thumbnail_remotion_4x3.pngAIthumbnail_ai_16x9.png``thumbnail_ai_4x3.png
Load on demand — do NOT load all at once:
FileLoad whenreferences/workflow-script.mdSteps 1-4 (topic → script)references/natural-narration.mdLoad before Step 4 script writing — anti-slop rules for spoken narration (kill list, structural tells, checklist)references/workflow-assets.mdStep 5, or when the user supplies images/clips or wants stock/AI mediareferences/hyperframes-overlays.mdA section needs a data-chart/infographic animation beyond the component library (transparent overlay via Hyperframes)references/workflow-production.mdSteps 6-11 (publish info → TTS → Remotion → render → BGM)references/workflow-publish.mdSteps 12-15 (subtitles, publish, cleanup, shorts)references/design-guide.mdMUST load before Step 9 — visual minimums, typography, animation safetyreferences/design-learning.mdUser provides a reference video/image, or manages style profilesreferences/azure-tts-pitfalls.mdChoosing Azure voice/style, debugging hoarse/glitchy audioreferences/troubleshooting.mdOn error, or user asks about preferences/BGMtemplates/presets/kinetic-typography/Bold type-driven preset (opinion / argument / declaration videos)examples/Reference for composition structure and timing.json format
All scripts under ${SKILL_DIR}/scripts/ are reachable through one hierarchical entry point:
bash
python3 ${SKILL_DIR}/scripts/cli.py --help # list resources
python3 ${SKILL_DIR}/scripts/cli.py <resource> --help # list actions
python3 ${SKILL_DIR}/scripts/cli.py <resource> <action> --help # forwards to underlying script
python3 ${SKILL_DIR}/scripts/cli.py schema [<method>] # JSON parameter schema
Routes: tts run|validate, verify, align, audit beats, shorts gen, design list|show|delete|add, assets init|add|list|validate, prereqs, capabilities, prefs get|migrate|backend|bgm-path, schema [<method>]. Direct script invocation ( python3 scripts/<name>.py ...) keeps working — the dispatcher is additive.
Skill auto-learns and applies preferences. Full commands and learning details: references/troubleshooting.md.
user_prefs.json (auto-created from user_prefs.template.json, schema in prefs_schema.json).Root.tsx defaults < global < topic_patterns[type] < current instructions.See references/troubleshooting.md on errors, BGM options, preference learning, design-learning issues.