一键导入
final-composition
Concatenates video clips and optionally adds background music using FFmpeg.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Concatenates video clips and optionally adds background music using FFmpeg.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Align text to audio timestamps using Qwen3-ForcedAligner (~30ms precision)
Full pipeline from manga panels to animated video. Two audio modes: dialogue (Qwen3-TTS + karaoke captions) or music (ElevenLabs + rolling lyrics).
Burn karaoke captions into video using FFmpeg ASS subtitles (~20s for 16s video)
Generate multi-panel manga from character reference and story beats
Generates original background music using Google's Music Generation API. Creates soundtracks matched to scene mood and timing.
Generates anime character images from photo analysis using Nano Banana Pro (gemini-3-pro-image-preview). Creates character sheets with full body and portrait views at 2K resolution.
| name | Final Composition |
| description | Concatenates video clips and optionally adds background music using FFmpeg. |
| triggers | ["Video clips need concatenation","User wants final shareable output"] |
| keywords | ["combine","finish","export","final"] |
Concatenates video clips into final output. With Veo 3.1 native audio, this is much simpler.
Since Veo 3.1 generates audio natively, we only need:
concatenate_scenes() - Join multiple video clipscompose_video_with_music() - Add optional background music| Input | Type | Required | Default | Description |
|---|---|---|---|---|
video_path | Path | Yes | — | Path to video file |
audio_path | Path | No | None | Path to audio/music file |
output_name | str | No | Auto-generated | Output filename |
music_volume | float | No | 0.3 | Background music volume (0-1) |
| Operation | Method | Description |
|---|---|---|
add_text_overlay | execute_with_text() | Add text to video |
concatenate | concatenate_scenes() | Join multiple videos |
| Output | Type | Description |
|---|---|---|
output_path | Path | Path to final composed video |
metadata | dict | Composition metadata |
class VideoComposer:
async def execute(
self,
video_path: Path,
audio_path: Path = None,
output_name: str = None,
music_volume: float = 0.3
) -> tuple[Path, dict]:
"""
Compose video with audio.
Raises:
FileNotFoundError: If video_path doesn't exist
FFmpegError: If composition fails
"""
...
async def concatenate_scenes(
self,
scene_paths: list[Path],
output_name: str = None
) -> Path:
"""Concatenate multiple video scenes."""
...
async def add_text_overlay(
self,
video_path: Path,
text: str,
position: str = "bottom"
) -> Path:
"""Add text overlay to video."""
...
from skills.compose_final import VideoComposer
skill = VideoComposer()
# Basic: combine video + music
final_path, metadata = await skill.execute(
video_path=Path("scene.mp4"),
audio_path=Path("bgm.mp3")
)
# With custom settings
final_path, metadata = await skill.execute(
video_path=video_path,
audio_path=music_path,
output_name="my_creation",
music_volume=0.4
)
# Concatenate scenes
final_path = await skill.concatenate_scenes(
scene_paths=[scene1, scene2, scene3],
output_name="full_story"
)
# Add text
with_text = await skill.add_text_overlay(
video_path=final_path,
text="Created with Creative Universe",
position="bottom"
)
# Complete creative pipeline
pet_analysis = await understand_skill.execute(pet_photo, "pet")
world_analysis = await understand_skill.execute(scene_photo, "world")
character, _ = await character_skill.execute(pet_analysis)
video_path, _ = await video_skill.execute(
characters=[character],
world=world_analysis
)
music_path, _ = await music_skill.execute(
scene_description="Character explores world",
mood="adventurous",
duration=10
)
final_path, _ = await compose_skill.execute(
video_path=video_path,
audio_path=music_path,
output_name="my_universe"
)
# Combine video + audio (when video HAS audio track)
ffmpeg -i video.mp4 -i audio.mp3 \
-filter_complex "[1:a]volume=0.3[music];[0:a][music]amix=inputs=2:duration=first[aout]" \
-map 0:v -map "[aout]" \
-c:v copy -c:a aac \
output.mp4
# Concatenate scenes (same codec, no re-encode)
ffmpeg -f concat -safe 0 -i list.txt \
-c copy output.mp4
# Add text overlay
ffmpeg -i video.mp4 \
-vf "drawtext=text='Hello':fontsize=48:fontcolor=white:x=(w-tw)/2:y=h-th-50" \
output.mp4
# 1. Get audio duration (ffprobe)
ffprobe -v error \
-show_entries format=duration \
-of default=noprint_wrappers=1:nokey=1 \
audio.wav
# Output: 2.345 (seconds)
# 2. Pad audio to target duration (extend with silence)
ffmpeg -y -i audio.wav \
-af "apad=whole_dur=3.5" \
-c:a pcm_s16le \
padded.wav
# apad=whole_dur=X pads to exactly X seconds
# 3. Add audio to SILENT video (Veo videos have no audio track)
ffmpeg -y \
-i silent_video.mp4 \
-i audio.wav \
-c:v copy \
-c:a aac \
-map 0:v:0 \
-map 1:a:0 \
-t 3.5 \
output.mp4
# -map 0:v:0 = video from first input
# -map 1:a:0 = audio from second input
# -t X = force exact duration (cuts if longer)
# 4. Concatenate pre-synced clips
echo "file 'clip1_synced.mp4'" > concat.txt
echo "file 'clip2_synced.mp4'" >> concat.txt
echo "file 'clip3_synced.mp4'" >> concat.txt
ffmpeg -f concat -safe 0 -i concat.txt -c copy final.mp4
-map Instead of -amix?# ❌ FAILS on Veo videos (no audio track to mix)
ffmpeg -i veo_video.mp4 -i audio.wav \
-filter_complex "[0:a][1:a]amix=inputs=2" ...
# Error: Stream #0 has no audio
# ✅ WORKS - explicitly map video and audio streams
ffmpeg -i veo_video.mp4 -i audio.wav \
-map 0:v:0 -map 1:a:0 ...
CRITICAL: When combining multi-segment video with multi-segment audio, use per-clip sync.
# DON'T DO THIS - causes sync drift
video_clips = [v1, v2, v3] # 3 clips (one failed)
audio_clips = [a1, a2, a3, a4] # 4 clips
concat_video = concatenate(video_clips) # 3 clips
concat_audio = concatenate(audio_clips) # 4 clips
final = combine(concat_video, concat_audio) # MISMATCH!
# DO THIS - guarantees sync
synced_clips = []
for i, (video, audio, duration) in enumerate(zip(videos, audios, durations)):
if video is None:
continue # Skip failed clips (and their audio!)
# Pad audio if shorter than video
if get_duration(audio) < duration:
audio = pad_audio(audio, duration)
# Overlay audio onto THIS clip
synced = add_audio_to_clip(video, audio, duration)
synced_clips.append(synced)
# Now concatenate pre-synced clips
final = concatenate(synced_clips) # Perfect sync!
| Method | Purpose |
|---|---|
add_audio_to_clip() | Add audio to single video clip with padding |
pad_audio_to_duration() | Extend audio with silence using apad filter |
_get_audio_duration() | Get exact audio duration via ffprobe |
Veo 3.1 generates silent videos (no audio track). Always use add_audio_to_clip() or add_audio_to_video() - never amix filter which requires existing audio track.
| Error | Cause | Recovery |
|---|---|---|
FileNotFoundError | Input file missing | Check paths exist |
FFmpegError | FFmpeg command failed | Check FFmpeg installed, check input formats |
PermissionError | Can't write output | Check output directory permissions |
brew install ffmpeg (macOS)