Updated Jun 21, 2026 pipeline

Step 5 — Effects

Status: ✅ Live (Chapter XV)

Unlocks when: Episode is images_ready

Advances to: effects_applied (on explicit episode approval, after all scenes approved)

Each scene gets one motion effect applied to its background image. Effects are selected per scene (editable inline in Step 5). Studio suggests one during segmentation — Tomas can override per scene.

How It Works

  1. Scene 1 active — "Apply Effect" button visible, rest locked
  2. Select effect type from dropdown (saves immediately)
  3. Click Apply Effect → MoviePy renders .mp4 clip → video player appears
  4. Preview the effect — click Approve → next scene unlocks
  5. Or click Re-render to try a different effect type
  6. All scenes approved → "Approve Effects" → episode advances to effects_applied

Base Effects (Sprint 67)

Effect Description
slow_zoom_in Ken Burns — gradual zoom toward centre (1.0 → 1.15)
slow_zoom_out Ken Burns — gradual zoom away from centre (1.15 → 1.0)
drift_left Pan slowly left
drift_right Pan slowly right
fade_through_black Fade to black and back — scene transitions
static No movement

The 20 Effect Types

Zoom

Effect Description
slow_zoom_in Ken Burns — cosine zoom toward centre
slow_zoom_out Ken Burns — cosine zoom away from centre
slow_zoom_off_center_tl Zoom toward Top Left corner
slow_zoom_off_center_tr Zoom toward Top Right corner
slow_zoom_off_center_bl Zoom toward Bottom Left corner
slow_zoom_off_center_br Zoom toward Bottom Right corner

Pan (viewer perspective)

Effect Description
drift_left Move Right
drift_right Move Left
drift_up Move Down
drift_down Move Up
diagonal_drift_tl Move diagonally from Top Left
diagonal_drift_tr Move diagonally from Top Right
diagonal_drift_bl Move diagonally from Bottom Left
diagonal_drift_br Move diagonally from Bottom Right

Horror

Effect Description
flicker Random brightness flicker — dying fluorescent light feel
heartbeat_zoom Rhythmic double-pulse zoom at ~60bpm
shake Random micro-jitter — handheld camera feel
vignette_pulse Cosine-pulsing dark vignette — edges darken rhythmically

Neutral

Effect Description
fade_through_black Fade to black and back
static No movement

Per-Scene Controls

Field Default Description
effect_type static Primary effect
effect_type_2 '' Second effect — alternates with primary at each cosine reversal. Empty = same throughout.
effect_speed 1.0 Zoom/pan magnitude multiplier (0.5-3.0)
effect_cycle 20.0 Half-cycle duration in seconds (0 = static). Slider goes 0 to narration duration.
effect_upscale 2 In-memory upscale factor (1-4x). Higher = smoother but slower render.

Motion Model

All motion effects use cosine oscillation: progress = (1 - cos(pi x t / cycle)) / 2

  • Perfectly smooth reversals — no discontinuity at turning points
  • Source image upscaled Nx in memory before the frame loop for sub-pixel smoothness
  • 60fps output
  • Cycle=0 auto-switches effect to Static

Alternating Effects

When effect_type_2 is set, apply_effect splits the total duration into half-cycle segments and alternates between the two effect types. Each segment is rendered independently and concatenated into one .mp4. Same effect throughout = seamless cosine; different effects = clean cut at each reversal.

File Naming

Effect clips stored in the scene's own subfolder alongside narration: media/studio/{series_slug}/{book_slug}/chapters/{n}/scenes/scene_NN_effect.mp4

Service

studio/effects.py — pure Python, zero Django imports. apply_effect(image_path, effect_type, duration_seconds, output_path, effect_speed, effect_cycle, effect_upscale, effect_type_2).

studio/service.py: run_scene_effect, approve_scene_effect, regenerate_scene_effect, approve_effects.


Vega
Vega · Wiki Librarian
Ask me about this project or anything in the wiki.