> blender-vse-pipeline
Automate video editing in Blender's Video Sequence Editor with Python. Use when the user wants to add video, image, or audio strips, create transitions, apply effects, build edit timelines, batch assemble footage, estimate render times, or script any VSE workflow from the command line.
curl "https://skillshub.wtf/TerminalSkills/skills/blender-vse-pipeline?format=md"Blender VSE Pipeline
Overview
Automate video editing with Blender's Video Sequence Editor (VSE) using Python. Add and arrange strips (video, image, audio), create transitions, apply effects, assemble edits from file lists, and render final video — all headlessly from the terminal.
Instructions
1. Initialize the sequence editor
import bpy
scene = bpy.context.scene
if not scene.sequence_editor:
scene.sequence_editor_create()
sequences = scene.sequence_editor.sequences
scene.frame_start = 1
scene.frame_end = 250
scene.render.fps = 24
2. Add strips
# Video strip
strip = sequences.new_movie(name="Clip_A", filepath="/path/to/video.mp4", channel=1, frame_start=1)
strip.frame_offset_start = 24 # trim start (skip 1 sec)
strip.frame_offset_end = 48 # trim end
# Image strip (hold for duration)
img = sequences.new_image(name="Title_Card", filepath="/path/to/title.png", channel=2, frame_start=1, fit_method='FIT')
img.frame_final_duration = 72 # 3 seconds at 24fps
# Image sequence
import glob
img_files = sorted(glob.glob("/path/to/frames/frame_*.png"))
img_seq = sequences.new_image(name="Render", filepath=img_files[0], channel=1, frame_start=1)
for f in img_files[1:]:
img_seq.elements.append(f.split("/")[-1])
# Audio strip with fade in/out
audio = sequences.new_sound(name="Music", filepath="/path/to/music.mp3", channel=3, frame_start=1)
audio.volume = 0.0
audio.keyframe_insert(data_path="volume", frame=1)
audio.volume = 0.6
audio.keyframe_insert(data_path="volume", frame=24)
audio.volume = 0.6
audio.keyframe_insert(data_path="volume", frame=audio.frame_final_end - 48)
audio.volume = 0.0
audio.keyframe_insert(data_path="volume", frame=audio.frame_final_end)
3. Transitions and effects
# Cross dissolve (strips must overlap and be on different channels)
cross = sequences.new_effect(
name="CrossDissolve", type='GAMMA_CROSS', channel=3,
frame_start=clip_a.frame_final_end - 24,
frame_end=clip_b.frame_final_start + 24,
seq1=clip_a, seq2=clip_b
)
# Color strip (solid background)
color = sequences.new_effect(name="BlackBG", type='COLOR', channel=1, frame_start=1, frame_end=48)
color.color = (0, 0, 0)
# Text overlay
text = sequences.new_effect(name="Title", type='TEXT', channel=4, frame_start=1, frame_end=72)
text.text = "My Video Title"
text.font_size = 80
text.color = (1, 1, 1, 1)
text.location = (0.5, 0.5)
text.align_x = 'CENTER'
text.align_y = 'CENTER'
text.use_shadow = True
# Speed control
speed = sequences.new_effect(name="SlowMo", type='SPEED', channel=5,
frame_start=clip_a.frame_final_start, frame_end=clip_a.frame_final_end, seq1=clip_a)
speed.speed_factor = 0.5
# Transform (position, scale, rotation)
transform = sequences.new_effect(name="Transform", type='TRANSFORM', channel=5, frame_start=1, frame_end=100, seq1=clip_a)
transform.scale_start_x = 1.2
transform.scale_start_y = 1.2
4. Strip modifiers for color correction
strip = sequences["Clip_A"]
bc = strip.modifiers.new(name="BrightContrast", type='BRIGHT_CONTRAST')
bc.bright = 0.1
bc.contrast = 0.15
cb = strip.modifiers.new(name="ColorBalance", type='COLOR_BALANCE')
cb.color_balance.lift = (0.95, 0.95, 1.0)
cb.color_balance.gain = (1.1, 1.05, 0.95)
5. Render the final video
scene = bpy.context.scene
scene.render.filepath = "/tmp/final_edit.mp4"
scene.render.image_settings.file_format = 'FFMPEG'
scene.render.ffmpeg.format = 'MPEG4'
scene.render.ffmpeg.codec = 'H264'
scene.render.ffmpeg.audio_codec = 'AAC'
scene.render.ffmpeg.audio_bitrate = 192
scene.render.resolution_x = 1920
scene.render.resolution_y = 1080
# Auto-set frame range from strips
all_strips = scene.sequence_editor.sequences_all
if all_strips:
scene.frame_start = min(s.frame_final_start for s in all_strips)
scene.frame_end = max(s.frame_final_end for s in all_strips)
bpy.ops.render.render(animation=True)
Examples
Example 1: Assemble an edit from a shot list
User request: "Build a timeline from video clips with crossfades between them"
import bpy, os
clips = ["/path/to/shot_01.mp4", "/path/to/shot_02.mp4", "/path/to/shot_03.mp4", "/path/to/shot_04.mp4"]
crossfade_frames = 12
scene = bpy.context.scene
scene.render.fps = 24
if not scene.sequence_editor:
scene.sequence_editor_create()
sequences = scene.sequence_editor.sequences
current_frame = 1
prev_strip = None
for i, clip_path in enumerate(clips):
if prev_strip and crossfade_frames > 0:
current_frame -= crossfade_frames
strip = sequences.new_movie(
name=os.path.splitext(os.path.basename(clip_path))[0],
filepath=clip_path, channel=1 + (i % 2), frame_start=current_frame
)
if prev_strip and crossfade_frames > 0:
sequences.new_effect(name=f"Fade_{i}", type='GAMMA_CROSS', channel=3,
frame_start=current_frame, frame_end=current_frame + crossfade_frames,
seq1=prev_strip, seq2=strip)
current_frame += strip.frame_final_duration
prev_strip = strip
scene.frame_start = 1
scene.frame_end = current_frame
Example 2: Batch add text overlays from data
User request: "Add text titles at specific timecodes"
import bpy
titles = [("Introduction", 0, 3), ("Chapter 1", 15, 4), ("Chapter 2", 120, 4), ("Conclusion", 300, 5)]
fps = bpy.context.scene.render.fps
sequences = bpy.context.scene.sequence_editor.sequences
for text_content, start_sec, dur_sec in titles:
start_frame = int(start_sec * fps) + 1
text = sequences.new_effect(name=text_content[:20], type='TEXT', channel=5,
frame_start=start_frame, frame_end=start_frame + int(dur_sec * fps))
text.text = text_content
text.font_size = 60
text.color = (1, 1, 1, 1)
text.location = (0.5, 0.15)
text.align_x = 'CENTER'
text.use_shadow = True
Guidelines
- Always call
scene.sequence_editor_create()ifscene.sequence_editorisNone. - Use
sequences.new_movie(),new_image(),new_sound(),new_effect(). Avoidbpy.ops.sequencer.*in background mode. - Cross dissolves need strips on different channels with overlapping frames. Alternate channels (1, 2, 1, 2).
frame_offset_start/endtrims content without moving the strip.frame_startmoves it on the timeline.- For audio fades, keyframe
strip.volume— no built-in fade effect in VSE. - Render long edits as image sequences first, then assemble with ffmpeg.
- Set resolution to match source footage to avoid scaling artifacts.
- VSE processes channels bottom-to-top — higher channels layer on top.
> related_skills --same-repo
> zustand
You are an expert in Zustand, the small, fast, and scalable state management library for React. You help developers manage global state without boilerplate using Zustand's hook-based stores, selectors for performance, middleware (persist, devtools, immer), computed values, and async actions — replacing Redux complexity with a simple, un-opinionated API in under 1KB.
> zoho
Integrate and automate Zoho products. Use when a user asks to work with Zoho CRM, Zoho Books, Zoho Desk, Zoho Projects, Zoho Mail, or Zoho Creator, build custom integrations via Zoho APIs, automate workflows with Deluge scripting, sync data between Zoho apps and external systems, manage leads and deals, automate invoicing, build custom Zoho Creator apps, set up webhooks, or manage Zoho organization settings. Covers Zoho CRM, Books, Desk, Projects, Creator, and cross-product integrations.
> zod
You are an expert in Zod, the TypeScript-first schema declaration and validation library. You help developers define schemas that validate data at runtime AND infer TypeScript types at compile time — eliminating the need to write types and validators separately. Used for API input validation, form validation, environment variables, config files, and any data boundary.
> zipkin
Deploy and configure Zipkin for distributed tracing and request flow visualization. Use when a user needs to set up trace collection, instrument Java/Spring or other services with Zipkin, analyze service dependencies, or configure storage backends for trace data.