Claude-skill-registry 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 timing, (7) Frame rate considerations, (8) Platform-specific timing (TikTok/Shorts/Reels), (9) Readability formulas, (10) Audio-video sync tolerances. Provides: Complete time unit reference tables, optimal duration guidelines, psychology-based timing recommendations, caption readability formulas, and platform-specific timing profiles.

install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/ffmpeg-animation-timing-reference" ~/.claude/skills/majiayu000-claude-skill-registry-ffmpeg-animation-timing-reference && rm -rf "$T"
manifest: skills/data/ffmpeg-animation-timing-reference/SKILL.md
source content

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)Seconds
duration=1.5
FFmpeg zoompan
d=
parameter
Frames
d=150
(150 frames)
FFmpeg time variable
t
Seconds
enable='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.CC
0: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.CCCentiseconds
0: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
fade
duration
(d)
Seconds
fade=t=in:d=2
Floating point
fade
start_time
(st)
Seconds
fade=st=5:d=2
When fade begins
afade
duration
(d)
Seconds
afade=d=3
Audio fade
xfade
duration
Seconds
duration=1.5
Transition length
xfade
offset
Seconds
offset=4
When transition starts
acrossfade
duration
(d)
Seconds
acrossfade=d=1
Audio crossfade
drawtext
t
variable
Seconds
enable='gte(t,5)'
Time since start
drawtext
alpha
0-1 scale
alpha='min(1,t/2)'
Opacity over time
zoompan
d
Frames
d=150
Duration in frames
zoompan
t
variable
Seconds
z='1+0.1*t'
Time in expressions
fps
fps
Frames/second
fps=30
Frame rate
trim
start
,
end
Seconds
trim=start=2:end=10
Cut points
setpts
PTS
Timestamps
setpts=PTS-STARTPTS
Presentation 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 Count
d=
Parameter
Hook zoom punch600.4-0.5s24-30 frames
d=1
(use time conditional)
Hook flash600.2-0.3s12-18 frames
d=1
(use time conditional)
Continuous zoom30Entire videoN/A
d=1
(recalc per frame)
Text animations600.3-0.5s18-30 frames
d=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
\k
KaraokeCentisecondsInstant highlight (no fill)
\kf
Karaoke FillCentisecondsProgressive fill left-to-right
\ko
Karaoke OutlineCentisecondsOutline wipe effect
\K
Karaoke (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 appearing
1-exp(-t*5)
200-400ms
Element disappearing
exp(-t*5)
150-300ms
Emphasis/attention
1+0.2*sin(t*6)
Continuous
Bounce entrance
exp(-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