Skip to content

Instantly share code, notes, and snippets.

@Cdaprod
Created June 11, 2025 17:44
Show Gist options
  • Save Cdaprod/f8c9d0e0ec5857ad7124e71c6e0a36e2 to your computer and use it in GitHub Desktop.
Save Cdaprod/f8c9d0e0ec5857ad7124e71c6e0a36e2 to your computer and use it in GitHub Desktop.

🎬 CDAProd — NodeVideo Expressions Guide

⚙️ Built by David Cannan — DevOps Engineer & AI Solutions Architect
💡 Self-made | #devopsdad | #tripletdad | #hacktheplanet

GitHub - Cdaprod Blog LinkedIn Twitter YouTube MinIO Blog


Overview

NodeVideo’s Expression system allows you to create dynamic animations using MiniScript code to control any property (position, opacity, scale, blur, etc.) without manual keyframes. This guide covers cinematic text animations, 3D camera movements, and coordinated layer effects.

Table of Contents

  1. Basic Concepts
  2. Cinematic Text Animations
  3. 3D Camera and Object Animation
  4. Advanced Coordinated Effects
  5. Best Practices

Basic Concepts

Time and Progress

// Basic time calculation
t = time - thisLayer.startTime
progress = clamp(t / duration, 0, 1)
easeT = ease(progress, 0, 1)

Layer Indexing

Use index to create staggered animations across multiple layers:

delay = (index - 1) * 0.2
t = time - (thisLayer.startTime + delay)

Cinematic Text Animations

Basic Fade and Scale Animation

Create smooth, professional text reveals with combined opacity and scale effects:

// Configuration
fadeInDuration = 1.5
delay = (index - 1) * 0.2
t = time - (thisLayer.startTime + delay)

progress = clamp(t / fadeInDuration, 0, 1)
easeT = ease(progress, 0, 1)

// Opacity
opacity = easeT

// Scale (subtle zoom-in effect)
startScale = 85
endScale = 100
scale = linear(easeT, startScale, endScale)

// Apply to properties:
// Scale: [scale, scale]
// Opacity: [opacity]

Advanced Text with Position and Drift

Add vertical movement and subtle drift for dynamic text:

// Position animation
startY = 0.3 + index * 0.05
endY = 0.0
y = linear(easeT, startY, endY)
z = -0.1 * index  // Layer depth

// Subtle drift after fade-in
driftT = max(0, t - fadeInDuration)
driftAmt = clamp(driftT / 8.0, 0, 1)
y += driftAmt * -0.02
x = driftAmt * 0.015

// Apply to Position: [x, y, z]

Layer Setup for Cinematic Text

  1. Main Text Layer: Primary text (white, bold, centered)
  2. Glow Layer: Duplicate with Gaussian blur/glow effect
  3. Group: Combine for synchronized animation

Glow Layer Opacity

fadeDuration = 0.7
t = clamp((time - thisLayer.startTime)/fadeDuration, 0, 1)
ease(t, 0, 0.6) // Max 60% opacity for subtlety

Fade In/Out Animation

Complete lifecycle animation with entrance and exit:

fadeInDuration = 0.5
fadeOutDuration = 0.5
startFadeOut = thisLayer.outPoint - fadeOutDuration

if (time < thisLayer.startTime) then
    0
else if (time < thisLayer.startTime + fadeInDuration) then
    t = (time - thisLayer.startTime) / fadeInDuration
    ease(t, 0, 1)
else if (time > startFadeOut) then
    t = (time - startFadeOut) / fadeOutDuration
    ease(1-t, 0, 1)
else
    1
end if

3D Camera and Object Animation

Shared Time Base System

Create synchronized animations across multiple properties:

// Shared time base (use in all related expressions)
panDuration = 15.0
loop = true
t0 = thisLayer.startTime
t = time - t0
progress = (t / panDuration)

if loop then
    progress = (t % panDuration) / panDuration
end if

theta = ease(progress, 0.0, 1.0)

Position Expression (3D Movement)

// Pan left to right
maxPan = 0.02
x = sin(theta * pi) * maxPan

// Apply to Position: [x, 0, 0]

Rotation Expression (Camera Swing)

// Rotation swing
maxYRot = 0.6
yRot = sin(theta * pi) * maxYRot

// Apply to Rotation: [0, yRot, 0]

Field of View Animation

One-time FOV change for cinematic effect:

duration = 3.0
startTime = thisLayer.startTime
t = clamp((time - startTime) / duration, 0, 1)
easeT = ease(t, 0, 1)

startFOV = 35
endFOV = 49

linear(easeT, startFOV, endFOV)

Advanced Coordinated Effects

Combined Pan and Fall-Away Effect

Coordinate multiple layers with shared timing and individual fall animations:

Position Expression (Complete)

// === Shared pan time control ===
panDuration = 15.0
loop = true
t0 = thisLayer.startTime
t = time - t0
progress = t / panDuration

if loop then
    progress = (t % panDuration) / panDuration
end if

theta = ease(progress, 0.0, 1.0)

// === Panning range ===
xStart = -0.6
xEnd = 0.6
zStart = 0.0
zEnd = -0.3

x = ease(theta, xStart, xEnd)
z = ease(theta, zStart, zEnd)

// === Fall away Y motion (staggered by layer index) ===
fallDuration = 1.0
staggerDelay = 0.3
fallDistance = -0.5

fallT = t - (index - 1) * staggerDelay
fallProgress = clamp(fallT / fallDuration, 0, 1)
yStart = 0.6
yEnd = yStart + fallDistance

y = ease(fallProgress, yStart, yEnd)

// Apply to Position: [x, y, z]

Rotation Expression (Coordinated)

// Use same shared time base as position

startRot = 0.6
endRot = -0.6
yRot = ease(theta, startRot, endRot)

// Apply to Rotation: [0.0, yRot, 0.0]

Best Practices

Performance Optimization

  • Use clamp() to prevent values from exceeding intended ranges
  • Minimize complex calculations in expressions
  • Cache frequently used values in variables

Visual Enhancement Tips

  • Focus Pull Effect: Use Gaussian blur transitioning from 100% to 0% on text entrance
  • Letter Tracking: Animate letter spacing in sync with position easing
  • Staggered Animation: Use layer index to create cascading effects instead of simultaneous animations

Timing Considerations

  • Text fade-in: 0.5-1.5 seconds for readability
  • Scale effects: Keep subtle (85-100% range)
  • Stagger delays: 0.1-0.3 seconds between layers
  • Drift effects: Use longer durations (8+ seconds) for subtle movement

Synchronization

  • Sync text animations with camera movements using shared time variables
  • Match FOV changes with text scaling for cohesive visual flow
  • Use consistent easing functions across related animations

Expression Property Applications

Property Expression Return Format Example
Position [x, y, z] [0.5, -0.2, 0.1]
Rotation [x, y, z] [0, 0.6, 0]
Scale [x, y] [1.1, 1.1]
Opacity value 0.8
FOV value 45

Common Patterns

Looping Animation

// Continuous back-and-forth motion
progress = (time % duration) / duration
value = sin(progress * 2 * pi) * amplitude

Delayed Start

// Wait before starting animation
startDelay = 2.0
t = max(0, time - thisLayer.startTime - startDelay)

Bounce Effect

// Overshoot and settle
bounceAmount = 0.1
if (progress > 0.7) then
    bounce = sin((progress - 0.7) * 10 * pi) * bounceAmount * (1 - progress)
    value = targetValue + bounce
else
    value = ease(progress / 0.7, startValue, targetValue)
end if

This guide provides the foundation for creating professional motion graphics in NodeVideo using expressions. Experiment with these examples and combine techniques to achieve your desired cinematic effects.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment