원클릭으로
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)