Skip to content
ffmpeg-animation-timing-reference logo

FFmpeg Animation Timing Reference (2025-2026)

ffmpeg-animation-timing-reference

Definitive reference for FFmpeg and ASS/SSA animation timing units, optimal durations, and best practices. PROACTIVELY activate for: (1) Animation timing questions, (2) ASS subtitle timing, (3) Karaoke timing tags, (4) Caption duration calculation, (5) Transition duration selection, (6) Fade/zoom...

SKILL.md

Full skill instructions

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 (/).

Documentation Guidelines

NEVER create new documentation files unless explicitly requested by the user.


FFmpeg Animation Timing Reference (2025-2026)

Quick Reference Card

ContextUnitExample
FFmpeg filters (fade, xfade, drawtext)Secondsduration=1.5
FFmpeg zoompan d= parameterFramesd=150 (150 frames)
FFmpeg time variable tSecondsenable='gte(t,2)'
ASS karaoke tags (\k, \kf, \ko)Centiseconds{\k100} = 1 second
ASS animation tags (\t, \fad, \move)Milliseconds\t(0,500,...) = 0.5s
ASS dialogue timestampsH:MM:SS.CC0:00:05.50

CRITICAL: ASS Has TWO Different Time Units!

This is the most common source of confusion in subtitle animations.

ASS/​SSA Time Unit Disambiguation

Tag TypeUnitConversionExample
Karaoke tags (\k, \kf, \ko, \K)Centiseconds (1/​100s)× 100{\k50} = 0.5 seconds
Animation tags (\t)Milliseconds (1/​1000s)× 1000\t(0,200,...) = 0.2 seconds
Fade tags (\fad)Milliseconds× 1000\fad(300,0) = 0.3s fade in
Move tags (\move)Milliseconds× 1000\move(x1,y1,x2,y2,0,500) = 0.5s
Dialogue timestampsH:MM:SS.CCCentiseconds0:00:01.50 = 1.5 seconds

Example: Same Duration, Different Units

; Both animations last 0.5 seconds but use DIFFERENT UNITS:

; Karaoke: 50 CENTISECONDS = 0.5 seconds
{\k50}Word

; Animation: 500 MILLISECONDS = 0.5 seconds
{\t(0,500,\fscx120)}Word

Section 1: FFmpeg Time Units (All Filters)

Complete FFmpeg Time Unit Reference

Filter/​ContextParameterUnitExampleNotes
fadeduration (d)Secondsfade=t=in:d=2Floating point
fadestart_time (st)Secondsfade=st=5:d=2When fade begins
afadeduration (d)Secondsafade=d=3Audio fade
xfadedurationSecondsduration=1.5Transition length
xfadeoffsetSecondsoffset=4When transition starts
acrossfadeduration (d)Secondsacrossfade=d=1Audio crossfade
drawtextt variableSecondsenable='gte(t,5)'Time since start
drawtextalpha0-1 scalealpha='min(1,t/​2)'Opacity over time
zoompandFramesd=150Duration in frames
zoompant variableSecondsz='1+0.1*t'Time in expressions
fpsfpsFrames/​secondfps=30Frame rate
trimstart, endSecondstrim=start=2:end=10Cut points
setptsPTSTimestampssetpts=PTS-STARTPTSPresentation timestamps

Frame Rate Conversion

Frame Rate1 Frame Duration30 Frames60 Frames
24 fps41.67 ms1.25 s2.5 s
25 fps40 ms1.2 s2.4 s
30 fps33.33 ms1 s2 s
50 fps20 ms0.6 s1.2 s
60 fps16.67 ms0.5 s1 s

Zoompan Duration Calculation

# zoompan d= parameter is in FRAMES, not seconds!

# For 2-second zoom at 30fps:
ffmpeg -i input.mp4 -vf "zoompan=z='1.2':d=60:s=1080x1920" output.mp4
# d=60 frames ÷ 30fps = 2 seconds

# For 2-second zoom at 60fps:
ffmpeg -i input.mp4 -vf "zoompan=z='1.2':d=120:s=1080x1920" output.mp4
# d=120 frames ÷ 60fps = 2 seconds

# Formula: frames = seconds × fps

Viral Video Timing Optimizations (2025-2026)

Based on the 1.3-second attention threshold research, hook animations must be fast and dramatic:

Effect TypeFPSEffect DurationFrame Countd= Parameter
Hook zoom punch600.4-0.5s24-30 framesd=1 (use time conditional)
Hook flash600.2-0.3s12-18 framesd=1 (use time conditional)
Continuous zoom30Entire videoN/​Ad=1 (recalc per frame)
Text animations600.3-0.5s18-30 framesd=1 (use time conditional)

Important: Always use d=1 for continuous per-frame processing. Limit effect duration using time conditionals like if(lt(t,0.5),effect,1) rather than setting d= to a frame count (which would freeze the video after that many frames).

Critical Rule: Hook animations MUST complete within 0.5 seconds to fit in the 1.3-second attention window with room for text/​content.

Optimal Zoom Parameters by Platform

PlatformHook ZoomHook DurationContinuous ZoomRecommended FPS
TikTok1.5x (50%)0.4-0.5s+0.2%/​sec60fps for hooks
YouTube Shorts1.5x (50%)0.5-0.6s+0.15%/​sec60fps throughout
Instagram Reels1.4x (40%)0.5-0.6s+0.18%/​sec60fps for hooks

Optimized Hook Effect Formulas

# 1.5x zoom punch over 0.5s at 60fps (RECOMMENDED):
# Always use d=1 for continuous processing; time conditional limits effect duration
fps=60,zoompan=z='if(lt(t,0.5),1.5-t,1)':d=1:s=1080x1920

# 8% zoom pulse at ~2Hz for 1.5s (sin(t*12) = 12 rad/​s = 1.91 Hz):
fps=60,zoompan=z='if(lt(t,1.5),1+0.08*sin(t*12),1)':d=1:s=1080x1920

# Subtle continuous zoom for TikTok (0.2%/​sec - minimum perceptible):
zoompan=z='1+0.002*t':d=1:s=1080x1920

# Subtle continuous zoom for YouTube Shorts (0.15%/​sec - larger screens):
zoompan=z='1+0.0015*t':d=1:s=1080x1920

Section 2: ASS/​SSA Subtitle Timing

Karaoke Tags (Centiseconds)

TagNameUnitEffect
\kKaraokeCentisecondsInstant highlight (no fill)
\kfKaraoke FillCentisecondsProgressive fill left-to-right
\koKaraoke OutlineCentisecondsOutline wipe effect
\KKaraoke (alt)CentisecondsSame as \k

Karaoke Timing Examples

; Each word highlights for the specified duration
; Values are in CENTISECONDS (100 = 1 second)

; 0.5 second per word:
{\k50}This {\k50}is {\k50}a {\k50}test

; Variable timing matching speech:
{\k30}The {\k25}quick {\k40}brown {\k35}fox

; Karaoke fill (progressive highlight):
{\kf100}Slowly {\kf150}highlighting {\kf80}each {\kf120}word

Conversion Table: Centiseconds

CentisecondsSecondsCommon Use
100.1sVery fast syllable
250.25sQuick word
500.5sNormal word
1001.0sLong word/​pause
1501.5sExtended emphasis
2002.0sDramatic pause

Animation Tags (Milliseconds)

TagFormatUnitEffect
\t\t(t1,t2,tags)MillisecondsAnimate between t1 and t2
\fad\fad(in,out)MillisecondsFade in/​out duration
\move\move(x1,y1,x2,y2,t1,t2)MillisecondsMove from t1 to t2

Animation Timing Examples

; Animation over 300 milliseconds (0.3 seconds):
{\t(0,300,\fscx120\fscy120)}Pop effect

; Scale animation: 0-200ms scale up, 200-400ms scale down
{\fscx80\fscy80\t(0,200,\fscx110\fscy110)\t(200,400,\fscx100\fscy100)}Bounce

; Fade in over 500ms, no fade out:
{\fad(500,0)}Fade in text

; Move over 800ms:
{\move(0,1920,540,960,0,800)}Slide in from bottom

Conversion Table: Milliseconds

MillisecondsSecondsCommon Use
500.05sInstant flash
1000.1sVery fast animation
2000.2sQuick pop/​snap
3000.3sStandard UI animation
5000.5sSmooth transition
8000.8sNoticeable movement
10001.0sSlow, deliberate
20002.0sVery slow, dramatic

Dialogue Timestamps (H:MM:SS.CC)

; Format: Hours:Minutes:Seconds.Centiseconds
; Dialogue line from 1.5s to 5.0s:
Dialogue: 0,0:00:01.50,0:00:05.00,Default,,0,0,0,,Your text here

; Examples:
0:00:00.00  = 0 seconds (start)
0:00:01.50  = 1.5 seconds
0:00:10.00  = 10 seconds
0:01:00.00  = 60 seconds (1 minute)
0:05:30.25  = 5 minutes, 30.25 seconds

Section 3: Optimal Animation Durations

Human Perception Thresholds

TimingBrain ResponseApplication
<16msSub-perceptualCannot perceive (below 60fps frame)
16-50msPreattentiveFlash effects, subliminal
50-100msMotion detectionPattern interrupts, glitches
100-200msConscious recognitionQuick animations, snappy UI
200-400msAttention captureStandard animations
400-800msProcessing timeComplex transitions
800ms-2sContemplationDramatic, emotional effects
>2sExtended focusDeliberate, artistic pacing

Recommended Durations by Effect Type

Text Animations

EffectFastStandardSlowNotes
Word pop (scale)100-150ms150-250ms250-400msMaterial Design: 200ms
Fade in200-300ms300-500ms500-800msSmooth appearance
Fade out150-250ms200-400ms400-600msSlightly faster than fade in
Slide in200-300ms300-500ms500-800msDistance affects perception
Bounce300-400ms400-600ms600-800msNeeds overshoot time
Typewriter30-50ms/​char50-80ms/​char80-120ms/​charPer character

Video Transitions (xfade)

TransitionFastStandardSlowBest For
Fade/​Dissolve0.3-0.5s0.8-1.2s1.5-2.5sUniversal
Wipe0.2-0.4s0.5-0.8s1.0-1.5sDirectional energy
Slide0.3-0.5s0.6-1.0s1.2-2.0sDynamic movement
Circle/​Iris0.5-0.8s1.0-1.5s2.0-3.0sDramatic reveal
Zoom0.4-0.6s0.8-1.2s1.5-2.5sImpact, intensity
Pixelize0.3-0.5s0.5-0.8s1.0-1.5sGlitch aesthetic

Hook Effects (First 1-3 Seconds)

Hook TypeEffect DurationTotal HookTiming Pattern
Pattern Interrupt50-150ms0.5-1.5sInstant grab
Flash/​Brightness80-200ms0.3-0.8sQuick pulse
Zoom Punch200-400ms1-2sFast zoom-in, hold
Glitch100-300ms0.5-1.5sMultiple bursts
Text Slam150-250ms1-2sQuick appear, hold

Karaoke/​Caption Animations

ContentDuration FormulaExample
Single wordWord length × 50-100ms"Hello" = 250-500ms
Short phrase1-2 seconds"Check this out"
SentenceWords ÷ 3 per second9 words = 3 seconds
Reading captionsSee readability formulaBased on WPM

Section 4: Caption Readability Formula

Reading Speed Standards

AudienceWords Per Minute (WPM)Use Case
Slow readers120-140 WPMAccessibility, elderly
Average160-180 WPMRecommended default
Fast readers200-220 WPMExperienced viewers
Skim reading250-300 WPMNot recommended for video

Caption Duration Calculation

Formula

# Basic formula:
caption_duration = (word_count / words_per_minute) * 60

# With minimum duration (accessibility):
minimum_duration = 1.5  # seconds - WCAG recommendation
duration = max(minimum_duration, caption_duration)

# Conservative formula (recommended):
duration = max(1.5, (word_count / 160) * 60)

Quick Reference Table

Word Count@ 160 WPM@ 180 WPMRecommended
1-2 words0.75s0.67s1.5s (minimum)
3 words1.13s1.0s1.5s (minimum)
4 words1.5s1.33s1.5s
5 words1.88s1.67s1.9s
6 words2.25s2.0s2.3s
8 words3.0s2.67s3.0s
10 words3.75s3.33s3.8s
15 words5.63s5.0s5.6s

Python Implementation

def calculate_caption_duration(text: str, wpm: int = 160) -> float:
    """
    Calculate optimal caption display duration.

    Args:
        text: Caption text
        wpm: Words per minute (default 160 for comfortable reading)

    Returns:
        Duration in seconds
    """
    word_count = len(text.split())
    calculated = (word_count / wpm) * 60

    # WCAG minimum: 1.5 seconds for any caption
    minimum = 1.5

    # Add 0.5s buffer for cognitive processing
    buffer = 0.5

    return max(minimum, calculated + buffer)

# Examples:
print(calculate_caption_duration("Hello"))           # 1.5s (minimum)
print(calculate_caption_duration("This is a test")) # 2.0s
print(calculate_caption_duration("Check out this incredible transformation")) # 2.88s

Accessibility Guidelines (WCAG 2.2)

GuidelineRequirement
Minimum duration1.5 seconds for any caption
Maximum reading speed200 WPM (3.3 words/​second)
Character limit42 characters per line (readability)
Lines per captionMaximum 2 lines
PersistenceCaption visible for full duration

Section 5: Platform-Specific Timing

TikTok (Fast, Energetic)

ElementTimingNotes
Cut/​transition0.5-1.5s between clipsFast pacing
Text animation100-200msSnappy, punchy
Hook window1-1.5sImmediate grab
Caption duration0.8-1.5s per phraseShort, readable
Zoom effects200-400msQuick, impactful
Optimal video length15-30s (sweet spot)Completion rate focus

YouTube Shorts (Medium-Fast)

ElementTimingNotes
Cut/​transition1-2s between clipsSlightly slower than TikTok
Text animation150-300msSmooth but quick
Hook window2-3sSlightly more time
Caption duration1.2-2s per phraseMore readable
Zoom effects300-600msNoticeable but smooth
Optimal video length50-60sAlgorithm favored

Instagram Reels (Aesthetic, Polished)

ElementTimingNotes
Cut/​transition1.5-2.5s between clipsMore polished
Text animation150-250msStylish timing
Hook window2-3sVisual-first platform
Caption duration1-1.8s per phraseInstagram style
Zoom effects400-800msCinematic feel
Optimal video length15-30s (trending)Engagement focused

Professional/​Broadcast

ElementTimingNotes
Cut/​transition2-4s between clipsDeliberate pacing
Text animation300-500msSmooth, professional
Lower third entrance400-600msBroadcast standard
Caption duration2-4s per phraseFull readability
Zoom effects800-1500msSubtle, cinematic
Typical segment30-90sStandard TV timing

Section 6: Easing Functions and Natural Motion

Material Design Timing Standards

Animation TypeDurationEasingUse Case
Small (icon, button)100msease-outMicro-interactions
Medium (card, dialog)200-300msease-in-outStandard UI
Large (page, panel)300-500msease-outMajor transitions
Complex (multi-element)400-700msease-in-outChoreographed

FFmpeg Easing Expressions

Ease Out (Deceleration) - Elements Entering

# Ease out: fast start, slow finish
# Good for: Elements appearing, sliding in
-vf "drawtext=text='Hello':alpha='1-exp(-t*5)':fontsize=48:fontcolor=white:x=(w-tw)/​2:y=(h-th)/​2"

Ease In (Acceleration) - Elements Leaving

# Ease in: slow start, fast finish
# Good for: Elements disappearing, sliding out
-vf "drawtext=text='Goodbye':alpha='exp(-(5-t)*5)':fontsize=48:fontcolor=white:x=(w-tw)/​2:y=(h-th)/​2:enable='lt(t,5)'"

Bounce Effect

# Bounce: overshoot then settle
# Duration: 400-600ms recommended
-vf "drawtext=text='Bounce':y='h/​2-50+50*exp(-t*3)*sin(t*15)':fontsize=48:fontcolor=white:x=(w-tw)/​2"

Elastic Effect

# Elastic: spring-like oscillation
# Duration: 600-1000ms recommended
-vf "drawtext=text='Elastic':fontsize='48*(1+0.3*exp(-t*2)*sin(t*10))':fontcolor=white:x=(w-tw)/​2:y=(h-th)/​2"

Smooth Oscillation (Continuous)

# Pulse/​float effect
# Period: 2-4 seconds per cycle
-vf "drawtext=text='Float':y='h/​2+20*sin(t*2)':fontsize=48:fontcolor=white:x=(w-tw)/​2"

Recommended Easing by Context

ContextFunctionDuration
Element appearing1-exp(-t*5)200-400ms
Element disappearingexp(-t*5)150-300ms
Emphasis/​attention1+0.2*sin(t*6)Continuous
Bounce entranceexp(-t*3)*sin(t*15)400-600ms
Smooth transitionLinear (no easing)Any

Section 10: Mathematical Animation Formula Reference

Complete Easing Function Formulas

Based on standard animation libraries (CSS, anime.js, React Spring) and adapted for FFmpeg.

Linear (No Easing)

f(t) = t

FFmpeg: alpha='t' or x='t*100'

Use for: Constant speed motion, mechanical effects

Quadratic Easing

Ease In (Acceleration):

f(t) = t²

FFmpeg: alpha='t*t'

Ease Out (Deceleration):

f(t) = 1 - (1-t)²

FFmpeg: alpha='1-(1-t)*(1-t)'

Ease In-Out:

f(t) = if(t < 0.5, 2*t², 1 - 2*(1-t)²)

FFmpeg: alpha='if(lt(t,0.5),2*t*t,1-2*(1-t)*(1-t))'

Cubic Easing

Ease In:

f(t) = t³

FFmpeg: alpha='t*t*t'

Ease Out:

f(t) = 1 - (1-t)³

FFmpeg: alpha='1-(1-t)*(1-t)*(1-t)'

Ease In-Out (Material Design Default):

f(t) = if(t < 0.5, 4*t³, 1 - 4*(1-t)³)

FFmpeg: alpha='if(lt(t,0.5),4*t*t*t,1-4*(1-t)*(1-t)*(1-t))'

Exponential Easing

Ease In:

f(t) = 2^(10*(t-1))

FFmpeg: alpha='exp(10*(t-1)*0.693)' (Note: 2^x = e^(x*ln(2)) where ln(2) ≈ 0.693)

Ease Out (Recommended for text appearing):

f(t) = 1 - 2^(-10*t)

FFmpeg: alpha='1-exp(-10*t*0.693)'

Sine Easing (Smooth, Gentle)

Ease In:

f(t) = 1 - cos(t*π/​2)

FFmpeg: alpha='1-cos(t*1.571)' (Note: π/​2 ≈ 1.571)

Ease Out:

f(t) = sin(t*π/​2)

FFmpeg: alpha='sin(t*1.571)'

Ease In-Out:

f(t) = -(cos(π*t) - 1)/​2

FFmpeg: alpha='-(cos(3.1416*t)-1)/​2'

Circular Easing (Sharp Curve)

Ease In:

f(t) = 1 - sqrt(1 - t²)

FFmpeg: alpha='1-sqrt(1-t*t)'

Ease Out:

f(t) = sqrt(1 - (1-t)²)

FFmpeg: alpha='sqrt(1-(1-t)*(1-t))'

Elastic Easing (Overshoot with Oscillation)

Ease Out (Most Common):

f(t) = 2^(-10*t) * sin((t*10 - 0.75)*2π/​3) + 1

FFmpeg approximation:

alpha='exp(-10*t*0.693)*sin((t*10-0.75)*2.094)+1'

(Note: 2π/​3 ≈ 2.094)

Ease In:

f(t) = -2^(10*(t-1)) * sin((t*10 - 10.75)*2π/​3)

FFmpeg:

alpha='-exp(10*(t-1)*0.693)*sin((t*10-10.75)*2.094)'

Bounce Easing (Multiple Bounces)

Ease Out (Complex, piecewise):

For FFmpeg, simplified bounce approximation:

# Single bounce (easier implementation):
alpha='if(lt(t,0.4),
         7.5625*t*t,
         if(lt(t,0.8),
            7.5625*(t-0.6)*(t-0.6)+0.75,
            7.5625*(t-0.9)*(t-0.9)+0.9375))'

Simplified damped oscillation bounce:

# More natural, continuous bounce:
alpha='1-abs(cos(t*4.5*3.1416))*exp(-t*6)'

Back Easing (Overshoot)

Ease Out (Slight overshoot then settle):

f(t) = 1 + c3 * (t-1)³ + c1 * (t-1)²
where c1 = 1.70158, c3 = c1 + 1

FFmpeg approximation:

# Simplified overshoot (10% beyond target):
alpha='if(lt(t,0.7),t*1.3,1+(1-t)*0.3)'

Spring Physics Mathematical Reference

Standard Spring System (Mass-Spring-Damper)

Differential equation:

m * x''(t) + c * x'(t) + k * x(t) = 0

Where:
m = mass
c = damping coefficient
k = spring stiffness (Hooke's constant)
x(t) = position at time t
x'(t) = velocity
x''(t) = acceleration

Key Parameters

Natural frequency:

ω_n = sqrt(k/​m)

Damping ratio:

ζ = c / (2 * sqrt(k * m))

Damping Cases

Under-damped (0 < ζ < 1) - Bouncy, overshoots:

x(t) = e^(-ζ*ω_n*t) * [A*cos(ω_d*t) + B*sin(ω_d*t)]

Where:
ω_d = ω_n * sqrt(1 - ζ²)  (damped frequency)

Critically damped (ζ = 1) - No overshoot, fastest settle:

x(t) = (A + B*t) * e^(-ω_n*t)

Over-damped (ζ > 1) - Slow, sluggish:

x(t) = A*e^(r1*t) + B*e^(r2*t)
Where r1, r2 are real roots

Simplified Spring for UI Animation

Two-parameter approach (bounce + duration):

# Convert bounce and duration to spring parameters
mass = 1  # Normalized
stiffness = (2*π / duration)²

if bounce >= 0:
    damping = (1 - bounce) * 4*π / duration
else:
    damping = 4*π / (duration * (1 + bounce))

Bounce parameter mapping:

  • bounce = 0: Critically damped (no overshoot)
  • 0 < bounce < 1: Under-damped (1 = undamped oscillation)
  • bounce < 0: Over-damped (negative = slower settling)

FFmpeg Spring Implementation

Basic under-damped spring (stiffness=100, damping=10, mass=1):

# Calculate natural frequency and damping ratio:
# ω_n = sqrt(100/​1) = 10
# ζ = 10 / (2*sqrt(100*1)) = 10/​20 = 0.5 (under-damped)
# ω_d = 10 * sqrt(1 - 0.5²) = 10 * 0.866 = 8.66

# Position formula:
-vf "drawtext=text='SPRING':\
     y='(h-th)/​2-50*exp(-5*t)*cos(8.66*t)':\
     fontsize=80:fontcolor=white:x=(w-tw)/​2"

# Breakdown:
# -50 = initial displacement (50px below center)
# exp(-5*t) = exponential decay (damping term: ζ*ω_n = 0.5*10 = 5)
# cos(8.66*t) = oscillation at damped frequency

Tunable spring parameters for FFmpeg:

# Low bounce (ζ=0.8, quick settle):
y='(h-th)/​2+amplitude*exp(-8*t)*sin(10*t)'

# Medium bounce (ζ=0.5, balanced):
y='(h-th)/​2+amplitude*exp(-5*t)*sin(12*t)'

# High bounce (ζ=0.3, very bouncy):
y='(h-th)/​2+amplitude*exp(-3*t)*sin(14*t)'

# Critical damping (ζ=1, no overshoot):
y='(h-th)/​2+amplitude*exp(-10*t)*(1+10*t)'

Oscillation and Wave Formulas

Basic Trigonometric Functions

Sine wave (smooth oscillation):

y = A * sin(ω*t + φ)

Where:
A = amplitude (peak height)
ω = angular frequency (rad/​s)
t = time (seconds)
φ = phase offset (radians)

Frequency conversion:

ω = 2πf
where f = frequency in Hz (cycles/​second)

Examples:
1 Hz = 6.28 rad/​s (ω = 2π * 1)
2 Hz = 12.56 rad/​s (ω = 2π * 2)
3 Hz = 18.85 rad/​s (ω = 2π * 3)

FFmpeg examples:

# 2 Hz oscillation (2 cycles/​second):
y='50*sin(12.56*t)'

# 1 Hz with phase offset (starts at peak):
y='50*sin(6.28*t+1.571)'  # φ = π/​2 = 1.571

# Cosine (90° phase shifted sine):
y='50*cos(6.28*t)'  # equivalent to sin(t + π/​2)

Amplitude Modulation (AM)

Variable amplitude sine wave:

y = A(t) * sin(ω*t)

FFmpeg decaying oscillation:

# Exponential amplitude decay:
y='50*exp(-2*t)*sin(10*t)'

# Linear amplitude decay:
y='50*max(0,1-t)*sin(10*t)'

# Pulsing amplitude (low frequency modulates high frequency):
y='(30+20*sin(2*t))*sin(20*t)'
#    ↑ envelope     ↑ carrier wave

Frequency Modulation (FM)

Variable frequency sine wave:

y = A * sin(ω(t)*t)

FFmpeg examples:

# Accelerating oscillation (siren effect):
y='50*sin(5*t*t)'  # frequency increases linearly

# Decelerating oscillation:
y='50*sin(20*t-5*t*t)'  # frequency decreases

# Vibrato (musical wobble):
y='50*sin(10*t+2*sin(3*t))'
#          ↑ base  ↑ vibrato modulation

Lissajous Curves (2D Parametric Motion)

Circular motion:

x = r * cos(ω*t)
y = r * sin(ω*t)

FFmpeg circular orbit:

-vf "drawtext=text='○':\
     x='(w/​2)+200*cos(2*t)':\
     y='(h/​2)+200*sin(2*t)':\
     fontsize=40:fontcolor=white"

Elliptical motion:

# a=200 (horizontal radius), b=100 (vertical radius)
x='(w/​2)+200*cos(2*t)'
y='(h/​2)+100*sin(2*t)'

Figure-8 motion (Lissajous 1:2 ratio):

x='(w/​2)+150*sin(1*t)'
y='(h/​2)+150*sin(2*t)'

Noise and Randomness Functions

Pseudo-Random with Sine

FFmpeg doesn't have true random(), but we can approximate:

# Pseudo-random using high-frequency sine:
'10*sin(t*137.5)'  # 137.5 is irrational, appears random

# Multi-layered pseudo-random:
'5*sin(t*137.5)+3*sin(t*241.3)+2*sin(t*89.7)'

Perlin-like Noise (Smooth Random)

# Smooth noise using multiple sine waves:
noise = 'sin(t*2.3)+0.5*sin(t*5.1)+0.25*sin(t*11.7)'

# Normalized to 0-1 range:
normalized_noise = '(sin(t*2.3)+0.5*sin(t*5.1)+0.25*sin(t*11.7)+1.75)/​3.5'

Jitter/​Shake Effects

Continuous shake:

# High frequency, small amplitude:
x='(w-tw)/​2+5*sin(t*50)'
y='(h-th)/​2+5*cos(t*47)'  # Different freq for 2D randomness

Decaying shake (impact):

# Shake that settles over time:
x='(w-tw)/​2+10*exp(-t*3)*sin(t*50)'
y='(h-th)/​2+10*exp(-t*3)*cos(t*47)'

Triggered shake (specific moments):

# Shake only between t=2s and t=2.5s:
x='(w-tw)/​2+if(between(t,2,2.5),15*sin(t*60),0)'

Practical Animation Cookbook

Fade Transitions

Fade in (0 to 1 over duration):

# Linear: alpha='min(1,t/​duration)'
alpha='min(1,t/​0.5)'  # 0.5s fade in

# Ease out: alpha='1-exp(-k*t)'
alpha='1-exp(-5*t)'  # Smooth fade in

# Cubic: alpha='min(1,t/​duration)^3'
alpha='min(1,(t/​0.5)*(t/​0.5)*(t/​0.5))'

Fade out (1 to 0):

# Assuming video duration = 10s, fade out in last 2s:
alpha='if(gt(t,8),1-(t-8)/​2,1)'

# Exponential fade out:
alpha='if(gt(t,8),exp(-(t-8)*3),1)'

Fade in and out:

# Fade in 0-1s, hold 1-9s, fade out 9-10s:
alpha='if(lt(t,1),t,if(gt(t,9),10-t,1))'

Scale Animations

Pop in (scale 0 to 100%):

# FFmpeg drawtext (no scale support, use ASS instead)

# ASS:
{\fscx0\fscy0\t(0,300,\fscx100\fscy100)}Text

Pulse (continuous breathing):

# ASS:
fontsize='72+8*sin(t*6.28)'  # 1 Hz pulse, ±8px

# ASS pulse with hold:
{\t(0,300,\fscx110\fscy110)\t(300,600,\fscx100\fscy100)}

Bounce scale:

# ASS overshoot bounce:
{\fscx50\fscy50\t(0,150,\fscx115\fscy115)\t(150,300,\fscx95\fscy95)\t(300,450,\fscx100\fscy100)}

Position Animations

Slide in from right:

x='if(lt(t,1),w-(w-target_x)*t,target_x)'
# Example: target_x = (w-tw)/​2 (center)
x='if(lt(t,1),w-((w-(w-tw)/​2)*t),(w-tw)/​2)'

Slide in with ease-out:

x='if(lt(t,1),w-((w-(w-tw)/​2)*(1-exp(-5*t))),(w-tw)/​2)'

Bounce in from bottom:

# ASS:
{\move(540,1920,540,960,0,400)\t(0,150,\fscy115)\t(150,300,\fscy95)\t(300,400,\fscy100)}

Circular path:

x='(w/​2)+radius*cos(speed*t)'
y='(h/​2)+radius*sin(speed*t)'

Rotation Animations

FFmpeg drawtext doesn't support rotation. Use ASS:

; Continuous spin (360° over 2 seconds):
{\t(0,2000,\frz360)}Text

; Wobble rotation:
{\t(0,200,\frz15)\t(200,400,\frz-10)\t(400,600,\frz5)\t(600,800,\frz0)}

Timing Psychology and Perception

Human Perception Thresholds

ThresholdDurationPerceptionUse Case
Flicker fusion16-20msBelow this: perceived as continuous60fps = 16.67ms/​frame
Preattentive20-50msDetected but not consciously processedSubliminal cues
Attention capture50-100msMinimum for conscious recognitionFlash effects
Pattern interrupt100-200msBreaks expectation, grabs attentionHook effects
Comfortable transition200-400msNatural UI timingStandard animations
Deliberate motion400-800msNoticeable, purposefulDramatic emphasis
Sustained attention800ms-2sHolds focusTitle cards, captions
Cognitive processing2-5sComplex informationInfographic reveals

Animation Duration Guidelines by Distance

Relationship between distance and duration for perceived constant speed:

duration = sqrt(distance) * k

Where:
distance = pixels traveled
k = speed constant (typically 5-15)

Example:
100px move: duration = sqrt(100) * 10 = 100ms
400px move: duration = sqrt(400) * 10 = 200ms
(Appears same speed despite 4x distance)

FFmpeg implementation:

# Move text 500px in 224ms (sqrt(500)*10):
-vf "drawtext=text='MOVE':\
     x='if(lt(t,0.224),(w-500)+500*t/​0.224,w)':\
     y=(h-th)/​2:fontsize=80:fontcolor=white"

Biological Rhythms

Natural timing that feels "right":

RhythmRateUse Case
Resting heartbeat60-80 BPM (1-1.3 Hz)Calm, meditative pulse
Walking pace100-120 BPM (1.7-2 Hz)Comfortable, steady rhythm
Excited/​anxious120-160 BPM (2-2.7 Hz)Energetic, urgent feeling
Breathing12-20/​min (0.2-0.33 Hz)Slow, natural oscillation

FFmpeg examples:

# Heartbeat pulse (70 BPM = 1.17 Hz):
fontsize='72+6*max(0,sin(t*7.33))'

# Walking pace pulse (110 BPM = 1.83 Hz):
fontsize='72+4*abs(sin(t*11.5))'

# Breathing (15 breaths/​min = 0.25 Hz):
fontsize='72+10*sin(t*1.57)'

Sources

This comprehensive timing reference compiled from:


Section 7: Audio-Video Sync Tolerances

Synchronization Thresholds

Sync TypeMaximum ToleranceRecommendedNotes
Lip sync±80ms±40msHuman perception limit
Music beat sync±50ms±20msMusical precision
Karaoke lyrics±100ms±30msComfortable singing
Sound effects±30ms±10msImpact synchronization
Transition + audio±100ms±50msCross-fade sync

Practical Guidelines

Lip Sync

Tolerance: ±80ms (audio can lead or lag video by 80ms)
Recommendation: Keep within ±40ms for professional quality

Audio Leading (negative offset): Less noticeable, up to -80ms acceptable
Audio Lagging (positive offset): More noticeable, keep under +40ms

Music Sync

# Calculate beat timing:
# 120 BPM = 2 beats/​second = 500ms per beat
# 140 BPM = 2.33 beats/​second = 429ms per beat

# Align transitions to beat:
# At 120 BPM, beats fall at: 0ms, 500ms, 1000ms, 1500ms, 2000ms...

Karaoke Timing

Word highlight should START when word begins (not before)
Early highlight: Confusing, breaks immersion
Late highlight: Frustrating for singers

Recommendation: Highlight 0-50ms AFTER word starts (slight lag preferred)

Section 8: Frame Rate Considerations

Timing Precision Limits

Frame RateFrame DurationPrecision Limit
24 fps41.67ms~40ms increments
25 fps40ms40ms increments
30 fps33.33ms~33ms increments
60 fps16.67ms~17ms increments

Implications

Animation Smoothness

For smooth animation, use durations that are multiples of frame duration:

30fps:
- 100ms = 3 frames (smooth)
- 200ms = 6 frames (smooth)
- 333ms = 10 frames (smooth)
- 150ms = 4.5 frames (may stutter)

60fps:
- 100ms = 6 frames (smooth)
- 200ms = 12 frames (smooth)
- 167ms = 10 frames (smooth)

Minimum Visible Duration

Animation duration must be at least 2-3 frames to be perceived:
- 30fps minimum: ~67-100ms
- 60fps minimum: ~33-50ms

Very short effects (<50ms) may not render consistently

Frame-Safe Duration Table

Desired Duration30fps Safe60fps Safe
~100ms100ms (3f)100ms (6f)
~150ms167ms (5f)150ms (9f)
~200ms200ms (6f)200ms (12f)
~250ms233ms (7f)250ms (15f)
~300ms300ms (9f)300ms (18f)
~500ms500ms (15f)500ms (30f)

Section 9: Quick Copy-Paste Reference

FFmpeg Common Timing Patterns

# 2-second fade in:
-vf "fade=t=in:d=2"

# Text visible from 1s to 5s:
-vf "drawtext=text='Hello':enable='between(t,1,5)':..."

# 1.5s xfade starting at 4s:
-filter_complex "[0:v][1:v]xfade=duration=1.5:offset=4"

# 2-second zoom at 30fps (60 frames):
-vf "zoompan=z='1.5':d=60:s=1080x1920"

# Fade text in over 0.5s, hold, fade out over 0.3s:
-vf "drawtext=text='Hello':alpha='if(lt(t,0.5),t/​0.5,if(lt(t,4.7),1,(5-t)/​0.3))':enable='lt(t,5)':..."

ASS Common Timing Patterns

; Word karaoke (centiseconds): 0.5s + 0.4s + 0.6s + 0.5s
{\k50}This {\k40}is {\k60}the {\k50}test

; 200ms pop animation (milliseconds):
{\fscx80\fscy80\t(0,200,\fscx100\fscy100)}Pop

; 500ms slide + 300ms fade:
{\move(0,1920,540,960,0,500)\fad(300,0)}Slide in

; Bounce: 150ms up, 100ms overshoot, 150ms settle (total 400ms)
{\fscx90\fscy90\t(0,150,\fscx110\fscy110)\t(150,250,\fscx95\fscy95)\t(250,400,\fscx100\fscy100)}Bounce

Duration Cheat Sheet

DurationUse For
50-100msGlitch, flash
100-200msQuick UI feedback
200-300msStandard animation
300-500msSmooth transition
500-800msNoticeable movement
800-1500msDramatic effect
1.5-3sCaption display
3-5sLong text reading

Related Skills

  • ffmpeg-karaoke-animated-text - Karaoke subtitle creation
  • viral-video-animated-captions - CapCut-style animations
  • ffmpeg-transitions-effects - Video transitions
  • viral-video-hook-templates - Hook timing patterns
  • ffmpeg-captions-subtitles - Subtitle fundamentals

More Other skills

Delegate independent tasks to specialized agents working concurrently with isolated context.

295.4K 206.3K
View

Applies Anthropic's official brand colors and typography to any sort of artifact that may benefit from having Anthropic's look-and-feel. Use it when brand colors or style guidelines, visual formatting, or company design standards apply.

179.7K 100.1K
View

Toolkit for styling artifacts with a theme. These artifacts can be slides, docs, reportings, HTML landing pages, etc. There are 10 pre-set themes with colors/fonts that you can apply to any artifact that has been creating, or can generate a new theme on-the-fly.

179.7K 89.5K
View

A set of resources to help me write all kinds of internal communications, using the formats that my company likes to use. Claude should use this skill whenever asked to write some sort of internal communications (status reports, leadership updates, 3P updates, company newsletters, FAQs, incident reports, project updates, etc.).

179.7K 76.1K
View

Fundamental design principles for writing maintainable, testable Python code.

40.2K 21.9K
View

Modern responsive layouts using container queries, fluid typography, CSS Grid, and mobile-first strategies.

40.2K 20K
View

Generate Playwright tests from scenarios using interactive browser exploration and validation.

39.7K 18.2K
View

Modern React state management with Redux Toolkit, Zustand, Jotai, and React Query for every state category.

40.2K 14.7K
View

GDPR-compliant data handling with consent management, data subject rights, and privacy controls.

40.2K 14.3K
View

Python error handling patterns including input validation, exception hierarchies, and partial failure handling. Use when implementing validation logic, designing exception strategies, handling batch processing failures, or building robust APIs.

40.2K 13.5K
View

Detailed multi-file refactor planning with safety checks and rollback guidance.

39.7K 13K
View