AgentSkillsCN

ffmpeg-karaoke-animated-text

完整版卡拉OK字幕系统与高级动画文字特效。主动启用此技能,可用于:(1) 卡拉OK风格的歌词高亮显示;(2) ASS/SSA的高级字幕样式设计;(3) 滚动字幕(横向/纵向);(4) 打字机文字动画;(5) 文字弹跳与移动;(6) 文字的淡入淡出效果;(7) 逐字揭示文字;(8) 动态文字排版;(9) 下三分之一区域的动画效果;(10) 倒计时与动态文字。提供ASS卡拉OK计时格式、带有时间表达式的drawtext、滚动文字模式、文字动画公式、动态文字排版技巧、字幕样式参考以及多行动画文字。

SKILL.md
--- frontmatter
name: ffmpeg-karaoke-animated-text
description: Complete karaoke subtitle system and advanced animated text effects. PROACTIVELY activate for: (1) Karaoke-style highlighted lyrics, (2) ASS/SSA advanced subtitle styling, (3) Scrolling credits (horizontal/vertical), (4) Typewriter text animation, (5) Bouncing/moving text, (6) Text fade in/out effects, (7) Word-by-word text reveal, (8) Kinetic typography, (9) Lower thirds animation, (10) Countdown timers and dynamic text. Provides: ASS karaoke timing format, drawtext with time expressions, scrolling text patterns, text animation formulas, kinetic typography techniques, subtitle styling reference, multi-line animated text.

CRITICAL GUIDELINES

Windows File Path Requirements

MANDATORY: Always Use Backslashes on Windows for File Paths

When using Edit or Write tools on Windows, you MUST use backslashes (\) in file paths, NOT forward slashes (/).


Quick Reference

EffectCommand
Scrolling credits-vf "drawtext=textfile=credits.txt:y=h-80*t"
Typewriter-vf "drawtext=text='Hello':enable='gte(t,n*0.1)'"
Fade in text-vf "drawtext=text='Title':alpha='min(1,t/2)'"
Bouncing text-vf "drawtext=text='Bounce':y='h/2+50*sin(t*5)'"
Karaoke ASSUse ASS format with \k timing tags
Moving text-vf "drawtext=text='Move':x='w-mod(t*100,w+tw)'"

When to Use This Skill

Use for animated text and karaoke:

  • Music video lyrics with karaoke highlighting
  • Movie-style scrolling credits
  • Animated titles and lower thirds
  • Typewriter text reveal
  • Kinetic typography
  • Countdown timers

FFmpeg Karaoke & Animated Text (2025)

Complete guide to karaoke subtitles, kinetic typography, scrolling credits, and advanced text animation with FFmpeg.

Karaoke Subtitles (ASS/SSA Format)

ASS Karaoke Basics

ASS (Advanced SubStation Alpha) supports karaoke timing with \k tags.

ass
[Script Info]
Title: Karaoke Example
ScriptType: v4.00+
PlayResX: 1920
PlayResY: 1080

[V4+ Styles]
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
Style: Karaoke,Arial,72,&H00FFFFFF,&H000000FF,&H00000000,&H80000000,1,0,0,0,100,100,0,0,1,3,2,2,10,10,50,1

[Events]
Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
Dialogue: 0,0:00:01.00,0:00:05.00,Karaoke,,0,0,0,,{\k50}Twinkle {\k50}twinkle {\k50}little {\k50}star
Dialogue: 0,0:00:05.00,0:00:09.00,Karaoke,,0,0,0,,{\k50}How {\k50}I {\k50}wonder {\k50}what {\k50}you {\k50}are

Karaoke Timing Tags

TagEffectExample
\kFill from left{\k100}Word = 1 second fill
\kf or \KSmooth fill (fade){\kf100}Word
\koOutline highlight{\ko100}Word

Duration is in centiseconds (100 = 1 second).


CRITICAL: ASS Time Unit Reference

ASS uses TWO DIFFERENT time unit systems - this is a common source of bugs!

Karaoke Tags = CENTISECONDS (1/100 second)

TagUnitExampleDuration
\kcentiseconds{\k50}0.5 seconds
\kfcentiseconds{\kf100}1.0 second
\kocentiseconds{\ko25}0.25 seconds

Conversion: seconds × 100 = centiseconds

Animation Tags = MILLISECONDS (1/1000 second)

TagUnitExampleDuration
\t(t1,t2,...)milliseconds\t(0,500,...)0-500ms animation
\fad(in,out)milliseconds\fad(200,300)200ms in, 300ms out
\move(x1,y1,x2,y2,t1,t2)milliseconds\move(0,0,100,100,0,1000)1 second move

Conversion: seconds × 1000 = milliseconds

FFmpeg drawtext = SECONDS (with decimals)

ExpressionUnitExample
tsecondst=2.5 means 2.5 seconds
enable='between(t,0,3)'seconds0-3 seconds
alpha='min(1,t/2)'secondsfade over 2 seconds

Quick Conversion Table

SecondsCentiseconds (karaoke)Milliseconds (animation)
0.1s10100
0.25s25250
0.5s50500
1.0s1001000
2.0s2002000

Common Mistake Example

ass
; WRONG - mixing units!
Dialogue: 0,0:00:00.00,0:00:02.00,Style,,0,0,0,,{\k100\t(0,100,...)}Word
; {\k100} = 1 second (centiseconds)
; \t(0,100,...) = 0-100ms = 0.1 seconds (milliseconds) - NOT THE SAME!

; CORRECT - consistent timing
Dialogue: 0,0:00:00.00,0:00:02.00,Style,,0,0,0,,{\k100\t(0,1000,...)}Word
; {\k100} = 1 second
; \t(0,1000,...) = 1 second - NOW THEY MATCH!

Advanced Karaoke Timing Parameters (2026 Research)

Optimal Karaoke Timing by Song Tempo

BPM RangeSyllable DurationTag ValueNotes
60-80 (Slow ballad)600-800ms\kf60-80Long, emotional
80-100 (Moderate)400-600ms\kf40-60Standard pop
100-120 (Upbeat)300-500ms\kf30-50Most common
120-140 (Fast)250-400ms\kf25-40Energetic
140+ (Rapid)200-300ms\kf20-30Rap, EDM

Karaoke Tag Selection Guide

Based on syllable/word duration and desired effect:

\k (Instant Fill) - Best For:

  • Very short syllables: <120 centiseconds (1.2s)
  • Rap/hip-hop: Fast lyric delivery
  • Staccato rhythm: Percussive, sharp delivery
ass
; Rap example (fast succession):
{\k25}Yo {\k20}this {\k15}is {\k30}rapid {\k25}fire {\k35}flow

\kf (Progressive Fill) - Best For:

  • Long syllables: >120 centiseconds (1.2s)
  • Ballads: Drawn-out emotional delivery
  • Smooth transitions: Clean visual sweep
ass
; Ballad example (sustained notes):
{\kf150}Loooooove {\kf120}yoooou {\kf180}foreeeever

Recommended: Use \kf for any syllable >100 centiseconds for smoothest visual effect.

\ko (Outline Reveal) - Best For:

  • High contrast: Text that needs to "pop"
  • Neon/glow styles: Outline-heavy fonts
  • Special emphasis: Chorus, key phrases
ass
; Neon karaoke style:
[V4+ Styles]
Style: NeonKaraoke,Arial,80,&H00000000,&H0000FF00,&H0000FF00,&H00000000,1,0,0,0,100,100,0,0,3,6,0,2,10,10,50,1

[Events]
Dialogue: 0,0:00:01.00,0:00:05.00,NeonKaraoke,,0,0,0,,{\ko50}Electric {\ko60}neon {\ko40}glow

Multi-Color Karaoke Transitions

Create dynamic color changes during karaoke fill:

ass
; Gradient karaoke: Yellow → Orange → Red
[V4+ Styles]
Style: GradientKaraoke,Impact,80,&H0000FFFF,&H000000FF,&H00000000,&H00000000,1,0,0,0,100,100,0,0,1,5,0,2,10,10,50,1
;                                   Primary^      Secondary^
;                                   Yellow(start) Red(filled)

; Add intermediate color transition with \t tags:
[Events]
Dialogue: 0,0:00:01.00,0:00:05.00,GradientKaraoke,,0,0,0,,{\kf80\t(0,400,\2c&H0000A5FF&)}Word1 {\kf100\t(0,500,\2c&H0000A5FF&)}Word2
;                                                                   ↑ Orange midpoint

Color progression formula:

code
Start: &H0000FFFF (Yellow)
Mid:   &H0000A5FF (Orange) - 50% through karaoke fill
End:   &H000000FF (Red)

Per-Character Karaoke (Fine-Grained Control)

For very precise timing (character-by-character):

ass
; Each character gets individual timing (manual, tedious)
{\k10}H{\k8}e{\k12}l{\k10}l{\k15}o {\k20}w{\k18}o{\k15}r{\k12}l{\k10}d

; Best practice: Use tools like Aegisub Karaoke Timer
; Manual character timing only for special effects

When to use character-level karaoke:

  • Slow-motion word reveal
  • Dramatic emphasis
  • Non-linear character highlighting (e.g., every other letter)

Advanced Text Animation Formulas (FFmpeg Drawtext)

Spring Physics Implementation

Create natural bounce effects with exponential decay:

bash
# Vertical spring bounce (decaying oscillation)
# Formula: y_offset = amplitude * e^(-decay*t) * sin(frequency*t)
-vf "drawtext=text='BOUNCE':fontsize=80:fontcolor=white:\
     x=(w-tw)/2:\
     y='(h-th)/2-30*exp(-t*2.5)*sin(t*15)'"

# Breakdown:
# -30*exp(-t*2.5) = amplitude decays from 30px to 0
# sin(t*15) = oscillates at 15 rad/s (≈2.4 Hz)
# Combines: bounces 2-3 times over ~1 second, settling at center

Parameter tuning:

  • Decay rate (2.5): Higher = faster settling (3-4 for quick, 1-2 for slow)
  • Frequency (15): Higher = more bounces (10-12 slow, 15-20 fast)
  • Amplitude (30): Bounce height in pixels

Elastic Overshoot Effect

Simulate elastic material with multiple overshoots:

bash
# Elastic scale effect (rubber band)
# Overshoots target size multiple times before settling
-vf "drawtext=text='ELASTIC':fontsize='72*(1+0.4*exp(-t*3)*sin(t*20))':\
     fontcolor=yellow:x=(w-tw)/2:y=(h-th)/2"

# Scale oscillates: 72px → 101px → 65px → 80px → 70px → 72px (settled)
# Mathematical basis: e^(-3t) * sin(20t) creates damped oscillation

Elastic parameters:

  • Base fontsize: 72 (target)
  • Overshoot: 0.4 (40% maximum deviation) → 72 * 1.4 = 101px peak
  • Decay: 3 (settles in ~1.5 seconds)
  • Frequency: 20 (multiple small bounces)

Bezier Curve Approximation (Ease-In-Out)

FFmpeg doesn't support bezier directly, but we can approximate with piecewise functions:

bash
# Ease-out approximation (fast start, slow end)
# Cubic bezier (0, 0, 0.2, 1) approximation
-vf "drawtext=text='EASE OUT':\
     alpha='if(lt(t,0.5),1-exp(-t*6),1)':\
     fontsize=80:fontcolor=white:x=(w-tw)/2:y=(h-th)/2:\
     enable='lt(t,1)'"

# Ease-in approximation (slow start, fast end)
# Cubic bezier (0.8, 0, 1, 1) approximation
-vf "drawtext=text='EASE IN':\
     alpha='if(lt(t,0.5),exp(-(1-t)*6),0)':\
     fontsize=80:fontcolor=white:x=(w-tw)/2:y=(h-th)/2:\
     enable='between(t,1,2)'"

# Ease-in-out (S-curve) using sigmoid approximation
-vf "drawtext=text='SMOOTH':\
     alpha='1/(1+exp(-10*(t-0.5)))':\
     fontsize=80:fontcolor=white:x=(w-tw)/2:y=(h-th)/2:\
     enable='lt(t,1)'"

Mathematical reasoning:

  • Exponential ease: 1 - e^(-kt) creates natural deceleration
  • Sigmoid curve: 1/(1+e^(-k(t-0.5))) creates smooth S-curve (ease-in-out)
  • k parameter: Controls transition sharpness (6-10 for subtle, 15-20 for pronounced)

Wobble/Wiggle Effects

Create organic, unpredictable motion:

bash
# Dual-frequency wobble (complex motion)
# Combines two sine waves at different frequencies for organic feel
-vf "drawtext=text='WOBBLE':fontsize=80:fontcolor=white:\
     x='(w-tw)/2+8*sin(t*7)+4*sin(t*17)':\
     y='(h-th)/2+6*cos(t*7)+3*cos(t*13)'"

# Breakdown:
# Primary wobble: 8*sin(t*7) = 8px amplitude, 7 rad/s (1.1 Hz)
# Secondary wobble: 4*sin(t*17) = 4px amplitude, 17 rad/s (2.7 Hz)
# Result: Complex, organic motion pattern

# Drunk/unstable effect (low frequency, large amplitude)
-vf "drawtext=text='UNSTABLE':fontsize=80:fontcolor=white:\
     x='(w-tw)/2+20*sin(t*2.5)+10*sin(t*6.3)':\
     y='(h-th)/2+15*cos(t*3.1)+8*cos(t*7.2)'"

Wobble design principles:

  • Use two frequencies (primary + secondary) for natural randomness
  • Prime number ratios (e.g., 7 and 17) prevent pattern repetition
  • Amplitude ratio 2:1 (primary twice the secondary) for balanced motion

Pulse with Variable Intensity

Create heartbeat or alarm-style pulsing:

bash
# Heartbeat pulse (two quick beats, pause)
# Pattern: THUMP-thump ... pause ... THUMP-thump
-vf "drawtext=text='♥ HEARTBEAT ♥':\
     fontsize='80+25*max(0,sin(t*15)*exp(-mod(t,1.2)*10))':\
     fontcolor=red:x=(w-tw)/2:y=(h-th)/2"

# Breakdown:
# sin(t*15) = rapid oscillation
# exp(-mod(t,1.2)*10) = decay envelope every 1.2 seconds
# max(0, ...) = only positive pulses
# Result: Pulse decays quickly, resets every 1.2s

# Alarm pulse (constant urgent rhythm)
-vf "drawtext=text='⚠ ALERT ⚠':\
     fontsize='80+20*abs(sin(t*8))':\
     fontcolor=yellow:x=(w-tw)/2:y=(h-th)/2"

# abs(sin(t*8)) creates continuous pulsing at 8 rad/s (1.3 Hz)

Text Reveal Animations (Wipe Effects)

Horizontal Wipe (Left to Right)

bash
# Clip text progressively from left
# Uses drawbox mask to reveal text over time
-filter_complex "\
  [0:v]drawtext=text='REVEALED':fontsize=100:fontcolor=white:\
       x=(w-tw)/2:y=(h-th)/2[txt];\
  [txt]drawbox=x=0:y=0:w='min(w,t*500)':h=h:c=black@0:t=fill:replace=1[v]" \
  -map "[v]"

# Breakdown:
# w='min(w,t*500)' = width grows at 500 pixels/second
# Creates left-to-right reveal effect

Vertical Wipe (Bottom to Top)

bash
# Text rises from bottom
-vf "drawtext=text='RISING':fontsize=100:fontcolor=white:\
     x=(w-tw)/2:\
     y='if(lt(t,1),h-t*h,0)'"

# y position: starts at h (bottom), moves to 0 (top) over 1 second

Countdown Timer Variations

Animated Countdown with Anticipation

bash
# Countdown that pulses on each second change
-vf "drawtext=text='%{eif\\:10-floor(t)\\:d}':\
     fontsize='200+50*abs(sin(floor(t)*50))*exp(-(t-floor(t))*8)':\
     fontcolor=white:x=(w-tw)/2:y=(h-th)/2"

# Breakdown:
# %{eif\\:10-floor(t)\\:d} = countdown number (10, 9, 8, ...)
# abs(sin(floor(t)*50)) = trigger pulse on integer seconds
# exp(-(t-floor(t))*8) = decay within each second
# Result: Number "pops" at each second change

Split-Flap Display (Mechanical)

bash
# Simulates old-school flip counter with vertical offset
-vf "drawtext=text='%{eif\\:10-floor(t)\\:d}':\
     fontsize=200:fontcolor=white:\
     x=(w-tw)/2:\
     y='(h-th)/2-(t-floor(t))*100*step(t-floor(t))'"

# y offset creates "flipping" motion at second boundaries

Optimal Animation Timing by Content Type

Music Video Karaoke

GenreSyllable TimingAnimation StyleColor Scheme
Ballad100-200 centiseconds\kf smooth fillWhite → Soft Blue
Pop40-80 centiseconds\kf with bounceWhite → Bright Pink
Rap15-40 centiseconds\k instantWhite → Red
Rock50-100 centiseconds\k with shakeWhite → Orange
EDM30-60 centiseconds\ko outlineNeon colors

Educational Content

bash
# Slow, clear typewriter for learning
# 80ms per character = comfortable reading pace
-vf "drawtext=textfile=lesson.txt:\
     fontsize=48:fontcolor=white:\
     x=50:y=100:\
     enable='gte(n,eif(n/24,80))'"
# Each character appears every 80/24 ≈ 3.3 frames at 24fps

Scrolling Credits Optimization

bash
# Professional credits scroll
# Speed: 60-80 pixels/second for comfortable reading
-vf "drawtext=textfile=credits.txt:\
     fontsize=42:fontcolor=white:\
     x=(w-tw)/2:\
     y='h-60*t':\
     line_spacing=25"

# Calculation:
# 60 px/s at 42px font = ~1.4 lines/second
# For 50 lines: 50/1.4 = ~36 seconds total duration

Credits readability formula:

code
scroll_speed = font_size * 1.2 to 1.5  (pixels/second)
total_duration = (line_count * line_height) / scroll_speed

Example:
font_size = 42px
line_height = 42 + 25 (spacing) = 67px
scroll_speed = 42 * 1.4 = 59 px/s
50 lines = 50 * 67 = 3350 pixels
duration = 3350 / 59 = 56.8 seconds

Sources

Enhanced with research from:


Apply Karaoke ASS to Video

bash
# Burn karaoke subtitles into video
ffmpeg -i input.mp4 \
  -vf "ass=karaoke.ass" \
  -c:v libx264 -crf 18 -c:a copy \
  output_karaoke.mp4

# With specific fonts directory
ffmpeg -i input.mp4 \
  -vf "ass=karaoke.ass:fontsdir=/path/to/fonts" \
  output.mp4

Advanced ASS Karaoke Styles

ass
[V4+ Styles]
; Gradient karaoke (yellow to red)
Style: KaraokeGradient,Impact,80,&H0000FFFF,&H000000FF,&H00000000,&H80000000,1,0,0,0,100,100,0,0,1,4,2,2,10,10,60,1

; Glow effect karaoke
Style: KaraokeGlow,Arial Black,72,&H00FFFFFF,&H00FF00FF,&H00FF00FF,&H00000000,1,0,0,0,100,100,0,0,4,0,20,2,10,10,50,1

; Outline only (neon style)
Style: KaraokeNeon,Arial,80,&H00000000,&H0000FF00,&H0000FF00,&H00000000,1,0,0,0,100,100,0,0,3,4,0,2,10,10,50,1

[Events]
; Word-by-word with effects
Dialogue: 0,0:00:01.00,0:00:05.00,KaraokeGradient,,0,0,0,,{\k50\fad(200,0)}Never {\k50}gonna {\k50}give {\k50}you {\k50}up
; With positioning
Dialogue: 0,0:00:05.00,0:00:09.00,KaraokeGlow,,0,0,0,,{\pos(960,900)\k50}Never {\k50}gonna {\k50}let {\k50}you {\k50}down

ASS Color Format

ASS uses &HAABBGGRR format (Alpha, Blue, Green, Red):

  • &H00FFFFFF = White (fully opaque)
  • &H000000FF = Red
  • &H0000FF00 = Green
  • &H00FF0000 = Blue
  • &H80000000 = 50% transparent black

Karaoke with Animation Effects

ass
[Events]
; Bounce effect per word
Dialogue: 0,0:00:01.00,0:00:05.00,Karaoke,,0,0,0,,{\k50\t(0,500,\fry360)}Word1 {\k50\t(0,500,\fry360)}Word2

; Scale pop on highlight
Dialogue: 0,0:00:01.00,0:00:05.00,Karaoke,,0,0,0,,{\k50\t(0,100,\fscx120\fscy120)\t(100,200,\fscx100\fscy100)}Pop

; Color transition
Dialogue: 0,0:00:01.00,0:00:05.00,Karaoke,,0,0,0,,{\k100\t(0,1000,\c&H0000FF&)}Red {\k100\t(0,1000,\c&H00FF00&)}Green

ASS Animation Tags Reference

TagEffect
\t(t1,t2,tags)Animate tags from t1 to t2
\move(x1,y1,x2,y2)Move text from point to point
\fad(fadein,fadeout)Fade in/out (milliseconds)
\fscx, \fscyScale X/Y percentage
\frx, \fry, \frzRotate on axis
\pos(x,y)Position text
\an1-9Alignment (numpad positions)

Scrolling Credits

Vertical Scroll (Bottom to Top)

bash
# Basic scrolling credits
ffmpeg -i input.mp4 \
  -vf "drawtext=textfile=credits.txt:\
       fontfile=/path/to/font.ttf:\
       fontsize=48:\
       fontcolor=white:\
       x=(w-tw)/2:\
       y=h-80*t" \
  -c:v libx264 -crf 18 output.mp4

# y=h-80*t: Start at bottom (h), move up at 80 pixels/second

credits.txt Format

code
DIRECTED BY
John Smith

PRODUCED BY
Jane Doe

STARRING
Actor One
Actor Two
Actor Three

MUSIC BY
Composer Name

SPECIAL THANKS
Everyone

Scrolling Credits with Sections

bash
# Multi-speed credits (slower for names)
ffmpeg -i input.mp4 \
  -vf "drawtext=textfile=credits.txt:\
       fontsize=48:\
       fontcolor=white:\
       x=(w-tw)/2:\
       y='h-60*t':\
       line_spacing=20" \
  output.mp4

Horizontal Scrolling (News Ticker)

bash
# Right to left scroll
ffmpeg -i input.mp4 \
  -vf "drawtext=text='BREAKING NEWS... This is a scrolling ticker message':\
       fontsize=36:\
       fontcolor=white:\
       y=h-50:\
       x='w-mod(t*150,w+tw)'" \
  ticker.mp4

# x='w-mod(t*150,w+tw)': Continuous scroll at 150 pixels/second

Looping Horizontal Scroll

bash
# Seamless looping ticker
ffmpeg -i input.mp4 \
  -vf "drawtext=text='   LIVE NEWS     BREAKING STORY     UPDATES   ':\
       fontsize=40:\
       fontcolor=yellow:\
       y=h-60:\
       x='w-mod(t*200\\,w+tw)':\
       box=1:boxcolor=red@0.8:boxborderw=10" \
  news_ticker.mp4

Typewriter Effect

Character-by-Character Reveal

bash
# Typewriter effect using enable
ffmpeg -f lavfi -i "color=c=black:s=1920x1080:d=10" \
  -vf "\
    drawtext=text='H':x=100:y=500:fontsize=72:fontcolor=white:enable='gte(t,0.0)',\
    drawtext=text='e':x=150:y=500:fontsize=72:fontcolor=white:enable='gte(t,0.1)',\
    drawtext=text='l':x=200:y=500:fontsize=72:fontcolor=white:enable='gte(t,0.2)',\
    drawtext=text='l':x=250:y=500:fontsize=72:fontcolor=white:enable='gte(t,0.3)',\
    drawtext=text='o':x=300:y=500:fontsize=72:fontcolor=white:enable='gte(t,0.4)'" \
  typewriter.mp4

Typewriter with Cursor

bash
# Blinking cursor during typing
ffmpeg -f lavfi -i "color=c=black:s=1920x1080:d=5" \
  -vf "\
    drawtext=text='Hello':fontsize=72:fontcolor=white:x=100:y=500:\
             enable='gte(t,0)':alpha='min(1,(t-0)/0.5)',\
    drawtext=text='|':fontsize=72:fontcolor=white:\
             x='100+72*min(5,floor(t/0.1))':y=500:\
             alpha='lt(mod(t,0.5),0.25)'" \
  typewriter_cursor.mp4

Text Fade Effects

Fade In

bash
# Simple fade in
ffmpeg -i input.mp4 \
  -vf "drawtext=text='Title':fontsize=100:fontcolor=white:\
       x=(w-tw)/2:y=(h-th)/2:\
       alpha='if(lt(t,2),t/2,1)'" \
  fade_in.mp4

# Explanation: alpha goes from 0 to 1 over 2 seconds

Fade Out

bash
# Fade out (assuming 10 second video)
ffmpeg -i input.mp4 \
  -vf "drawtext=text='Goodbye':fontsize=100:fontcolor=white:\
       x=(w-tw)/2:y=(h-th)/2:\
       alpha='if(gt(t,8),1-(t-8)/2,1)'" \
  fade_out.mp4

Fade In and Out

bash
# Title card with fade in/out
ffmpeg -f lavfi -i "color=c=black:s=1920x1080:d=6" \
  -vf "drawtext=text='Chapter One':fontsize=120:fontcolor=white:\
       x=(w-tw)/2:y=(h-th)/2:\
       alpha='if(lt(t,1),t,if(gt(t,5),1-(t-5),1))'" \
  title_card.mp4

Moving Text

Bouncing Text

bash
# Vertical bounce
ffmpeg -i input.mp4 \
  -vf "drawtext=text='BOUNCE':fontsize=80:fontcolor=yellow:\
       x=(w-tw)/2:\
       y='(h-th)/2+50*sin(t*5)'" \
  bounce.mp4

# Horizontal bounce
ffmpeg -i input.mp4 \
  -vf "drawtext=text='PING PONG':fontsize=60:fontcolor=cyan:\
       x='(w-tw)/2+200*sin(t*3)':\
       y=(h-th)/2" \
  horizontal_bounce.mp4

Circular Motion

bash
# Text moving in circle
ffmpeg -i input.mp4 \
  -vf "drawtext=text='ORBIT':fontsize=60:fontcolor=white:\
       x='(w/2)+200*cos(t*2)-tw/2':\
       y='(h/2)+200*sin(t*2)-th/2'" \
  orbit.mp4

Enter from Side

bash
# Slide in from right
ffmpeg -i input.mp4 \
  -vf "drawtext=text='SLIDE IN':fontsize=80:fontcolor=white:\
       x='if(lt(t,1),w-tw*(t),w-tw)':\
       y=(h-th)/2" \
  slide_in.mp4

# Slide in from left
ffmpeg -i input.mp4 \
  -vf "drawtext=text='FROM LEFT':fontsize=80:fontcolor=white:\
       x='if(lt(t,1),-tw+tw*t,0)':\
       y=(h-th)/2" \
  slide_left.mp4

Kinetic Typography

Word Pop Effect

bash
# Words appearing with scale
ffmpeg -f lavfi -i "color=c=black:s=1920x1080:d=8" \
  -vf "\
    drawtext=text='THIS':fontsize='72*(1+0.3*exp(-3*(t-1)))':fontcolor=white:\
             x=(w-tw)/2:y=h/2-100:enable='gte(t,1)',\
    drawtext=text='IS':fontsize='72*(1+0.3*exp(-3*(t-2)))':fontcolor=white:\
             x=(w-tw)/2:y=h/2:enable='gte(t,2)',\
    drawtext=text='KINETIC':fontsize='72*(1+0.3*exp(-3*(t-3)))':fontcolor=red:\
             x=(w-tw)/2:y=h/2+100:enable='gte(t,3)'" \
  kinetic_pop.mp4

Shake Effect

bash
# Shaking text (impact effect)
ffmpeg -i input.mp4 \
  -vf "drawtext=text='IMPACT':fontsize=120:fontcolor=white:\
       x='(w-tw)/2+10*sin(t*50)*exp(-t*2)':\
       y='(h-th)/2+10*cos(t*50)*exp(-t*2)'" \
  shake.mp4

Rotation Animation

bash
# Spinning text (requires recent FFmpeg)
# Note: drawtext doesn't support rotation natively
# Use ASS subtitles for rotation:

# Create spinning.ass
cat << 'EOF' > spinning.ass
[Script Info]
ScriptType: v4.00+
PlayResX: 1920
PlayResY: 1080

[V4+ Styles]
Style: Spin,Arial,72,&H00FFFFFF,&H00FFFFFF,&H00000000,&H00000000,0,0,0,0,100,100,0,0,1,2,0,5,0,0,0,1

[Events]
Dialogue: 0,0:00:00.00,0:00:05.00,Spin,,0,0,0,,{\an5\pos(960,540)\t(0,5000,\frz1080)}SPINNING
EOF

ffmpeg -i input.mp4 -vf "ass=spinning.ass" output.mp4

Lower Thirds

Basic Lower Third

bash
# Name and title lower third
ffmpeg -i input.mp4 \
  -vf "\
    drawbox=x=50:y=h-150:w=500:h=100:c=blue@0.7:t=fill,\
    drawtext=text='John Smith':fontsize=36:fontcolor=white:\
             x=70:y=h-140,\
    drawtext=text='CEO, Company Inc.':fontsize=24:fontcolor=white@0.8:\
             x=70:y=h-100" \
  lower_third.mp4

Animated Lower Third

bash
# Slide-in lower third
ffmpeg -i input.mp4 \
  -vf "\
    drawbox=x='if(lt(t,0.5),-500+1000*t,50)':\
            y=h-150:w=500:h=100:c=blue@0.7:t=fill:\
            enable='between(t,0,8)',\
    drawtext=text='John Smith':fontsize=36:fontcolor=white:\
             x='if(lt(t,0.5),-430+1000*t,70)':y=h-140:\
             alpha='min(1,(t-0.3)/0.3)':\
             enable='between(t,0.3,8)',\
    drawtext=text='CEO, Company Inc.':fontsize=24:fontcolor=white:\
             x='if(lt(t,0.5),-430+1000*t,70)':y=h-100:\
             alpha='min(1,(t-0.5)/0.3)':\
             enable='between(t,0.5,8)'" \
  animated_lower_third.mp4

Countdown Timer

Simple Countdown

bash
# 10 second countdown
ffmpeg -f lavfi -i "color=c=black:s=1920x1080:d=10" \
  -vf "drawtext=text='%{eif\\:10-t\\:d}':fontsize=200:fontcolor=white:\
       x=(w-tw)/2:y=(h-th)/2" \
  countdown.mp4

Countdown with Animation

bash
# Pulsing countdown
ffmpeg -f lavfi -i "color=c=black:s=1920x1080:d=10" \
  -vf "drawtext=text='%{eif\\:10-t\\:d}':\
       fontsize='200+30*sin(t*10)*exp(-mod(t,1)*3)':\
       fontcolor=white:\
       x=(w-tw)/2:y=(h-th)/2" \
  pulsing_countdown.mp4

Stopwatch/Timer

bash
# Count up timer (MM:SS)
ffmpeg -f lavfi -i "color=c=black:s=1920x1080:d=120" \
  -vf "drawtext=text='%{eif\\:floor(t/60)\\:d\\:2}\\:%{eif\\:mod(t,60)\\:d\\:2}':\
       fontsize=100:fontcolor=green:\
       x=(w-tw)/2:y=(h-th)/2" \
  stopwatch.mp4

Dynamic Text from Variables

Frame Number Display

bash
# Show frame number
ffmpeg -i input.mp4 \
  -vf "drawtext=text='Frame\\: %{frame_num}':\
       fontsize=24:fontcolor=white:\
       x=10:y=10" \
  frame_numbers.mp4

Timecode Display

bash
# Show timecode
ffmpeg -i input.mp4 \
  -vf "drawtext=text='%{pts\\:hms}':\
       fontsize=24:fontcolor=white:\
       x=10:y=10" \
  timecode.mp4

# With milliseconds
ffmpeg -i input.mp4 \
  -vf "drawtext=text='%{pts}':\
       fontsize=24:fontcolor=white:\
       x=10:y=10" \
  timecode_ms.mp4

File Metadata Display

bash
# Show filename
ffmpeg -i input.mp4 \
  -vf "drawtext=text='%{metadata\\:title}':\
       fontsize=24:fontcolor=white:\
       x=10:y=h-40" \
  metadata.mp4

Multi-Line Text

Centered Multi-Line

bash
# Multi-line centered text
ffmpeg -i input.mp4 \
  -vf "drawtext=text='Line One\nLine Two\nLine Three':\
       fontsize=48:fontcolor=white:\
       x=(w-tw)/2:y=(h-th)/2:\
       line_spacing=20" \
  multiline.mp4

Text File Input

bash
# Use text file for long text
ffmpeg -i input.mp4 \
  -vf "drawtext=textfile=message.txt:\
       fontsize=36:fontcolor=white:\
       x=50:y=50:\
       line_spacing=10" \
  from_file.mp4

Expression Reference

Useful Time Expressions

ExpressionResult
tCurrent time in seconds
t*100Speed factor
mod(t,5)Loop every 5 seconds
sin(t*3)Oscillate 3 times/second
exp(-t)Exponential decay
if(lt(t,2),expr1,expr2)Conditional
min(a,b) / max(a,b)Min/max
floor(t) / ceil(t)Round down/up

Useful Variables

VariableMeaning
wVideo width
hVideo height
twText width
thText height
nFrame number
frame_numSame as n

Common Patterns

bash
# Appear after 2 seconds
enable='gte(t,2)'

# Visible between 2-5 seconds
enable='between(t,2,5)'

# Fade in over 1 second
alpha='min(1,t)'

# Center horizontally
x='(w-tw)/2'

# Center vertically
y='(h-th)/2'

# Loop position
x='mod(t*100,w)'

# Smooth oscillation
y='h/2+50*sin(t*3)'

# Decay animation
fontsize='100+50*exp(-t*2)'

This guide covers FFmpeg karaoke and animated text. For basic subtitles see ffmpeg-captions-subtitles, for shapes see ffmpeg-shapes-graphics.