Video-Erstellungs-Skill
Für animierte Motion-Graphics aus Code – animierte Typografie, Erklärvideos, Launch-Videos, animierte Diagramme, Lower Thirds mit einer Auswahl an visuellen Stilen – verwende den
motion-graphics-Skill. Dieser Skill ist für Footage, Fotos, Audio und ffmpeg-Bearbeitung.
Erstelle Videos programmatisch mit ffmpeg (Kern-Engine) und Python (Pillow für Einzelbilder/Grafiken, MoviePy für höherwertige Bearbeitung). Plane immer zuerst, baue als Zweites, überprüfe zuletzt.
1. Plane vor dem Bauen
Lege diese Punkte vor dem Schreiben eines Befehls fest:
| Entscheidung | Standard | Hinweise |
|---|---|---|
| Seitenverhältnis | 16:9 (1920x1080) | 9:16 (1080x1920) für Reels/Shorts/TikTok, 1:1 (1080x1080) für Feeds |
| Bildrate | 30 fps | 24 für Kinospielfilme, 60 für Bildschirmaufnahmen/Gameplay |
| Länge | Wie gewünscht | Reels/Shorts ≤ 60–90 s |
| Format | MP4 (H.264 + AAC) | Läuft überall; WebM nur auf Anfrage; GIF nur für kurze Loops |
| Audio | Optional | Musik, Voiceover oder stumm |
Schreibe eine kurze Shot-Liste: jede Szene → Dauer, Bild, Text, Übergang, Audio.
2. Überprüfe die Werkzeugkette
which ffmpeg ffprobe || (apt-get update && apt-get install -y ffmpeg)
python3 -c "import PIL, moviepy" 2>/dev/null || pip install pillow moviepy --break-system-packages
fc-list | head # siehe, welche Schriftarten für Text verfügbar sind
3. Standard-Codierungseinstellungen
Verwende diese für jeden finalen Render, sofern der Benutzer nichts anderes wünscht:
-c:v libx264 -preset veryfast -crf 23 -pix_fmt yuv420p -movflags +faststart \
-c:a aac -b:a 192k
-pix_fmt yuv420p– erforderlich für die Wiedergabe auf Telefonen, QuickTime und Browsern.-movflags +faststart– lässt das Video abspielen, bevor es vollständig heruntergeladen ist.-crf 18= nahezu verlustfrei (größere Datei),-crf 28= kleinere Datei, geringere Qualität.-preset veryfasthält Render schnell; verwendeslownur, wenn beste Qualität gewünscht wird.- Breite und Höhe müssen gerade Zahlen sein für H.264.
3b. Rendere schnell – die Person wartet
Ein vollständiger Render ist der langsamste Schritt, also plane einen vollständigen Render pro Anfrage:
- Sieh nach, bevor du codierst. Ziehe ein paar Frames in Endgröße – die geschäftigsten Momente, den ersten und letzten Frame – und überprüfe Bildausschnitt, Textgröße und Farben. Für Fotovideos:
scripts/slideshow.py OUT.mp4 photos… --previewerstellt in einer Sekunde ein Kontaktblatt. - Szenen, kein einziger riesiger Graph. Codiere jede Szene in ihre eigene Datei mit identischer Größe, Bildrate und Codierereinstellungen, füge sie mit dem concat-Demuxer und
-c copyzusammen und füge den Ton zuletzt mit-c:v copyhinzu. Das Beheben einer Szene später erfordert nur das Neucodieren dieser einen Szene. - Übergänge leben in einer Szenendatei (Ein-/Ausblenden an ihren Rändern). Das Überblenden (Crossfade) von zwei fertigen Dateien erzwingt eine zweite vollständige Codierung.
- Halte ein Standbild günstig. Dekodiere das Bild einmal und wiederhole es mit dem
loop-Filter, anstatt-loop 1(das das Bild für jeden Frame erneut dekodiert):ffmpeg -framerate 30 -i still.png -vf "format=yuv420p,loop=-1:1,trim=duration=4,setpts=PTS-STARTPTS" -c:v libx264 -preset veryfast -crf 20 -pix_fmt yuv420p still.mp4 - Hinterlasse niemals eine halbe Datei unter dem richtigen Namen. Schreibe in
name.part.mp4und benenne erst um, wenn ffmpeg mit 0 beendet – ein unterbrochener Render kann noch abgespielt werden, ist aber nur abgeschnitten. - Zeichne Frames in Ausgabegröße und mit 30 fps, sofern nicht anders verlangt. Wenn du eine Webseite frame für frame erfasst, speichere als JPEG (Qualität ~90), nicht PNG – viel schneller zu schreiben und zu lesen.
Gemessen bei 10 Fotos → 1080p: Der alte einzelne -loop 1 + xfade-Graph benötigte 13,2 s; slideshow.py --crossfade benötigt 6,4 s, der Szenen-Datei-Pfad 8,9 s inklusive Musik.
Ändern eines fertigen Videos:
| Änderung | Vorgehen |
|---|---|
| Inhalt einer Szene | Neurender jener Szenendatei, erneutes Zusammenfügen mit -c copy |
| Neue Musik / Ende kürzen | -c:v copy (neue Musik: -map 0:v -map 1:a) |
| Untertitel einbrennen, kleinere Kopie erstellen | Einmaliges Neucodieren der fertigen Datei |
| Etwas, das sich in jedem Frame ändert | Ein vollständiger Render ist unvermeidlich |
4. Rezepte
4.0 Foto-Diashow in einem Befehl
python3 scripts/slideshow.py out.mp4 photos/*.jpg --seconds 3 --fade 0.5 --music song.mp3 # schnell, Blendung über Schwarz
python3 scripts/slideshow.py out.mp4 photos/*.jpg --crossfade # echte Überblendungen
python3 scripts/slideshow.py out.mp4 photos/*.jpg --zoom --size 1080x1920 # Ken Burns, vertikal
4.1 Diashow aus Bildern (mit Überblendungen), von Hand
# Jedes Bild 3 s lang angezeigt, 0,5 s Überblendung, skaliert/auf 1080p aufgefüllt
# jedes Standbild wird einmal dekodiert und mit dem loop-Filter wiederholt (2x schneller als -loop 1)
F="scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2,setsar=1,format=yuv420p,loop=-1:1,trim=duration=3,setpts=PTS-STARTPTS,fps=30"
ffmpeg -framerate 30 -i img1.jpg -framerate 30 -i img2.jpg -framerate 30 -i img3.jpg \
-filter_complex "\
[0]$F[a];[1]$F[b];[2]$F[c];\
[a][b]xfade=transition=fade:duration=0.5:offset=2.5[ab];\
[ab][c]xfade=transition=fade:duration=0.5:offset=5[out]" \
-map "[out]" -c:v libx264 -preset veryfast -crf 23 -pix_fmt yuv420p -movflags +faststart slideshow.mp4
Offset für Clip n = (Summe der vorherigen Dauern) − (n × Überblendungsdauer).
4.2 Ken Burns (Langsamzoom) auf einem Standbild
# d = Anzahl der Ausgabeframes (150 bei 30 fps = 5 s); kein -loop nötig, zoompan generiert die Frames
ffmpeg -i photo.jpg -vf "scale=3840:-2,zoompan=z='min(zoom+0.0008,1.2)':d=150:x='iw/2-(iw/zoom/2)':y='ih/2-(ih/zoom/2)':s=1920x1080:fps=30" \
-c:v libx264 -preset veryfast -crf 23 -pix_fmt yuv420p zoom.mp4
Hochskalieren auf 3840 zuerst vermeidet die ruckelige Bewegung, die zoompan bei kleinen Bildern zeigt.
4.3 Texteinblendung / Titelbild
ffmpeg -i input.mp4 -vf "drawtext=fontfile=/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf:\
text='Mein Titel':fontsize=72:fontcolor=white:box=1:[email protected]:boxborderw=20:\
x=(w-text_w)/2:y=h-150:enable='between(t,0,4)'" \
-c:v libx264 -preset veryfast -crf 23 -pix_fmt yuv420p -c:a copy titled.mp4
Für Text mit Apostrophen, Emojis oder nicht-lateinischen Schriftzeichen (Hindi usw.) rendere den Text mit Pillow in eine PNG-Datei mit einer Schriftart, die das Skript unterstützt, und überlagere ihn dann:
ffmpeg -i input.mp4 -i title.png -filter_complex "overlay=(W-w)/2:H-h-100:enable='between(t,0,4)'" ...
4.4 Einfarbige Titelgrafik aus dem Nichts
ffmpeg -f lavfi -i color=c=0x111827:s=1920x1080:d=3:r=30 \
-vf "drawtext=fontfile=/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf:text='Kapitel 1':fontsize=96:fontcolor=white:x=(w-text_w)/2:y=(h-text_h)/2" \
-c:v libx264 -preset veryfast -crf 23 -pix_fmt yuv420p card.mp4
4.5 Einen Clip trimmen
# Präzises Trimmen (codiert neu): ab 00:00:05 für 10 Sekunden
ffmpeg -ss 00:00:05 -i input.mp4 -t 10 -c:v libx264 -preset veryfast -crf 23 -pix_fmt yuv420p -c:a aac trimmed.mp4
# Schnelles Trimmen (keine Neucodierung, schneidet auf nächstgelegenen Keyframe)
ffmpeg -ss 00:00:05 -i input.mp4 -t 10 -c copy trimmed_fast.mp4
4.6 Clips zusammenfügen
Gleicher Codec/Auflösung/Bildrate → concat-Demuxer (keine Neucodierung):
printf "file 'a.mp4'\nfile 'b.mp4'\nfile 'c.mp4'\n" > list.txt
ffmpeg -f concat -safe 0 -i list.txt -c copy joined.mp4
Verschiedene Quellen → zuerst normalisieren (Skalierung, Bildrate, Audiorate) oder den concat-Filter verwenden:
ffmpeg -i a.mp4 -i b.mp4 -filter_complex \
"[0:v]scale=1920:1080,setsar=1,fps=30[v0];[1:v]scale=1920:1080,setsar=1,fps=30[v1];\
[v0][0:a][v1][1:a]concat=n=2:v=1:a=1[v][a]" \
-map "[v]" -map "[a]" -c:v libx264 -preset veryfast -crf 23 -pix_fmt yuv420p -c:a aac joined.mp4
(Wenn ein Clip keine Audiospur hat, füge Stille hinzu: -f lavfi -i anullsrc=r=48000:cl=stereo und verwende -shortest.)
4.7 Hintergrundmusik hinzufügen
# Musik unter Video, am Ende ausblenden, stoppen, wenn Video endet
# st = Videolänge minus Überblendlänge (hier 30 s Video, 3 s Überblend) – ermittle die Länge mit ffprobe
ffmpeg -i video.mp4 -i music.mp3 -filter_complex \
"[1:a]volume=0.3,afade=t=out:st=27:d=3[m]" \
-map 0:v -map "[m]" -c:v copy -c:a aac -shortest with_music.mp4
# Mische Musik unter vorhandene Sprache
ffmpeg -i video.mp4 -i music.mp3 -filter_complex \
"[1:a]volume=0.15[m];[0:a][m]amix=inputs=2:duration=first[a]" \
-map 0:v -map "[a]" -c:v copy -c:a aac mixed.mp4
4.8 Untertitel / Bildunterschriften
Schreibe eine .srt-Datei:
1
00:00:00,000 --> 00:00:03,000
Willkommen zum Video.
2
00:00:03,000 --> 00:00:06,500
Hier ist, was wir behandeln werden.
Brenne sie ein:
ffmpeg -i input.mp4 -vf "subtitles=subs.srt:force_style='FontSize=24,PrimaryColour=&HFFFFFF,OutlineColour=&H000000,BorderStyle=1,Outline=2'" \
-c:v libx264 -preset veryfast -crf 23 -pix_fmt yuv420p -c:a copy captioned.mp4
4.9 Größenänderung für soziale Medien (vertikal 9:16)
# Unscharfer Hintergrund anstelle von schwarzen Balken
ffmpeg -i landscape.mp4 -filter_complex \
"[0]scale=1080:1920:force_original_aspect_ratio=increase,crop=1080:1920,boxblur=20[bg];\
[0]scale=1080:-2[fg];[bg][fg]overlay=(W-w)/2:(H-h)/2" \
-c:v libx264 -preset veryfast -crf 23 -pix_fmt yuv420p -c:a copy vertical.mp4
4.10 Beschleunigen / Verlangsamen
# 2x Geschwindigkeit (Video + Audio)
ffmpeg -i in.mp4 -filter_complex "[0:v]setpts=0.5*PTS[v];[0:a]atempo=2.0[a]" -map "[v]" -map "[a]" fast.mp4
4.11 Video zu GIF (hohe Qualität)
ffmpeg -i in.mp4 -vf "fps=15,scale=640:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" -loop 0 out.gif
4.12 Frames aus Code rendern (Animationen, Diagramme, Motion Graphics)
Wenn ffmpeg-Filter nicht ausreichen, zeichne jeden Frame mit Python und füge sie zusammen:
from PIL import Image, ImageDraw, ImageFont
import os, subprocess
W, H, FPS, SECONDS = 1920, 1080, 30, 4
os.makedirs("frames", exist_ok=True)
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 96)
for i in range(FPS * SECONDS):
t = i / (FPS * SECONDS)
img = Image.new("RGB", (W, H), (17, 24, 39))
d = ImageDraw.Draw(img)
x = int(-600 + t * (W + 600)) # Text gleitet über das Bild
d.text((x, H // 2 - 48), "Hallo!", font=font, fill=(255, 255, 255))
img.save(f"frames/{i:05d}.png")
subprocess.run(["ffmpeg", "-y", "-framerate", str(FPS), "-i", "frames/%05d.png",
"-c:v", "libx264", "-preset", "veryfast", "-crf", "23",
"-pix_fmt", "yuv420p", "-movflags", "+faststart", "animation.mp4"], check=True)
Verwende Easing (z. B. t*t*(3-2*t)) für flüssigere Bewegungen.
4.13 MoviePy (schnelle high-level Bearbeitungen)
from moviepy import VideoFileClip, TextClip, CompositeVideoClip, concatenate_videoclips, AudioFileClip
clip1 = VideoFileClip("a.mp4").subclipped(0, 5)
clip2 = VideoFileClip("b.mp4").subclipped(2, 8)
video = concatenate_videoclips([clip1, clip2], method="compose")
music = AudioFileClip("music.mp3")
video = video.with_audio(music.subclipped(0, min(video.duration, music.duration))) # Musik kann kürzer sein
video.write_videofile("out.mp4", fps=30, codec="libx264", audio_codec="aac", preset="veryfast")
(MoviePy 2.x API gezeigt; 1.x verwendet subclip/set_audio. Überprüfe mit pip show moviepy.)
5. Überprüfen vor der Auslieferung
Übergebe niemals ein Video, ohne es zu überprüfen:
# Dauer, Auflösung, Codecs, Bildrate
ffprobe -v error -show_entries format=duration:stream=codec_name,width,height,r_frame_rate -of default=nw=1 out.mp4
# Ziehe Standbilder zu Schlüsselmomenten und betrachte sie
ffmpeg -ss 1 -i out.mp4 -frames:v 1 check_1s.png
ffmpeg -i out.mp4 -vf "fps=1/3,scale=480:-1,tile=4x2" -frames:v 1 contact_sheet.png
Checkliste:
- Dauer entspricht dem Plan
- Auflösung und Seitenverhältnis sind korrekt; keine unerwünschten schwarzen Balken oder Verzerrungen
- Text ist lesbar, innerhalb der Sicherheitsränder (ca. 5% von den Rändern; bei 9:16 den unteren Bereich von ca. 15% vermeiden, wo die App-UI sitzt)
- Übergänge landen wie beabsichtigt
- Audio vorhanden (falls erwartet), nicht übersteuert, endet sauber
- Läuft auf Telefonen: H.264,
yuv420p, gerade Abmessungen
6. Häufige Fallstricke
| Problem | Lösung |
|---|---|
| Video wird auf iPhone/QuickTime nicht abgespielt | Füge -pix_fmt yuv420p hinzu |
| "Breite nicht durch 2 teilbar" | Verwende scale=1280:-2 anstelle von -1 |
Schwarze Frames am Anfang nach -c copy Trimmen | Neucodieren oder -ss vor -i setzen und neu codieren |
| Audio nach concat nicht synchron | Normalisiere fps und Audio-Samplerate (-ar 48000) vor dem Zusammenfügen |
| xfade-Fehler "Eingaben unterscheiden sich" | Alle Eingaben benötigen gleiche Größe, fps, setsar=1 und Pixelformat |
drawtext bricht bei ' oder : ab | Escapen oder verwende textfile= / mit Pillow gerenderte PNG-Überlagerung |
| Nicht-englischer Text zeigt Kästchen | Verwende eine Schriftart, die das Skript unterstützt (z. B. Noto Sans Devanagari) |
| Riesige Dateigröße | Erhöhe CRF (26–28), senke Bildrate oder Auflösung |
| Render zu langsam | Verwende -preset veryfast oder ultrafast; reduziere Auflösung während des Entwurfs |
7. Arbeitsablauf-Zusammenfassung
- Planen — Seitenverhältnis, Bildrate, Länge, Shot-Liste, Audio.
- Assets sammeln — Bilder, Clips, Musik, Schriftarten; mit
ffprobeüberprüfen. - Schnell entwerfen — niedrige Auflösung /
ultrafast-Voreinstellung, um das Timing zu überprüfen. - Final bauen — Standard-Codierungseinstellungen (Abschnitt 3).
- Verifizieren — ffprobe + Kontaktblatt + Checkliste (Abschnitt 5).
- Ausliefern — sende die endgültige Datei mit einer einzeiligen Zusammenfassung (Dauer, Auflösung, was drin ist).