All skills
Skillintermediate

Timeline Editing Guide

VideoDB provides a non-destructive timeline editor for composing videos from multiple assets, adding text and image overlays, mixing audio tracks, and trimming clips — all server-side without re-encoding or local tools. Use this for trimming, combining clips, overlaying audio/music on video, adding subtitles, and layering text or images.

Claude Code Knowledge Pack7/10/2026

Overview

Timeline Editing Guide

VideoDB provides a non-destructive timeline editor for composing videos from multiple assets, adding text and image overlays, mixing audio tracks, and trimming clips — all server-side without re-encoding or local tools. Use this for trimming, combining clips, overlaying audio/music on video, adding subtitles, and layering text or images.

Prerequisites

Videos, audio, and images must be uploaded to a collection before they can be used as timeline assets. For caption overlays, the video must also be indexed for spoken words.

Core Concepts

Timeline

A Timeline is a virtual composition layer. Assets are placed on it either inline (sequentially on the main track) or as overlays (layered at a specific timestamp). Nothing modifies the original media; the final stream is compiled on demand.

from videodb.timeline import Timeline

timeline = Timeline(conn)

Assets

Every element on a timeline is an asset. VideoDB provides five asset types:

AssetImportPrimary Use
VideoAssetfrom videodb.asset import VideoAssetVideo clips (trim, sequencing)
AudioAssetfrom videodb.asset import AudioAssetMusic, SFX, narration
ImageAssetfrom videodb.asset import ImageAssetLogos, thumbnails, overlays
TextAssetfrom videodb.asset import TextAsset, TextStyleTitles, captions, lower-thirds
CaptionAssetfrom videodb.editor import CaptionAssetAuto-rendered subtitles (Editor API)

Building a Timeline

Add Video Clips Inline

Inline assets play one after another on the main video track. The add_inline method only accepts VideoAsset:

from videodb.asset import VideoAsset

video_a = coll.get_video(video_id_a)
video_b = coll.get_video(video_id_b)

timeline = Timeline(conn)
timeline.add_inline(VideoAsset(asset_id=video_a.id))
timeline.add_inline(VideoAsset(asset_id=video_b.id))

stream_url = timeline.generate_stream()

Trim / Sub-clip

Use start and end on a VideoAsset to extract a portion:

# Take only seconds 10–30 from the source video
clip = VideoAsset(asset_id=video.id, start=10, end=30)
timeline.add_inline(clip)

VideoAsset Parameters

ParameterTypeDefaultDescription
asset_idstrrequiredVideo media ID
startfloat0Trim start (seconds)
end`float\None`None

Warning: The SDK does not validate negative timestamps. Passing start=-5 is silently accepted but produces broken or unexpected output. Always ensure start >= 0, start < end, and end <= video.length before creating a VideoAsset.

Text Overlays

Add titles, lower-thirds, or captions at any point on the timeline:

from videodb.asset import TextAsset, TextStyle

title = TextAsset(
    text="Welcome to the Demo",
    duration=5,
    style=TextStyle(
        fontsize=36,
        fontcolor="white",
        boxcolor="black",
        alpha=0.8,
        font="Sans",
    ),
)

# Overlay the title at the very start (t=0)
timeline.add_overlay(0, title)

TextStyle Parameters

ParameterTypeDefaultDescription
fontsizeint24Font size in pixels
fontcolorstr"black"CSS colour name or hex
fontcolor_exprstr""Dynamic font colour expression
alphafloat1.0Text opacity (0.0–1.0)
fontstr"Sans"Font family
boxboolTrueEnable background box
boxcolorstr"white"Background box colour
boxborderwstr"10"Box border width
boxwint0Box width override
boxhint0Box height override
line_spacingint0Line spacing
text_alignstr"T"Text alignment within the box
y_alignstr"text"Vertical alignment reference
borderwint0Text border width
bordercolorstr"black"Text border colour
expansionstr"normal"Text expansion mode
basetimeint0Base time for time-based expressions
fix_boundsboolFalseFix text bounds
text_shapingboolTrueEnable text shaping
shadowcolorstr"black"Shadow colour
shadowxint0Shadow X offset
shadowyint0Shadow Y offset
tabsizeint4Tab size in spaces
xstr"(main_w-text_w)/2"Horizontal position expression
ystr"(main_h-text_h)/2"Vertical position expression

Audio Overlays

Layer background music, sound effects, or voiceover on top of the video track:

from videodb.asset import AudioAsset

music = coll.get_audio(music_id)

audio_layer = AudioAsset(
    asset_id=music.id,
    disable_other_tracks=False,
    fade_in_duration=2,
    fade_out_duration=2,
)

# Start the music at t=0, overlaid on the video track
timeline.add_overlay(0, audio_layer)

AudioAsset Parameters

ParameterTypeDefaultDescription
asset_idstrrequiredAudio media ID
startfloat0Trim start (seconds)
end`float\None`None
disable_other_tracksboolTrueWhen True, mutes other audio tracks
fade_in_durationfloat0Fade-in seconds (max 5)
fade_out_durationfloat0Fade-out seconds (max 5)

Image Overlays

Add logos, watermarks, or generated images as overlays:

from videodb.asset import ImageAsset

logo = coll.get_image(logo_id)

logo_overlay = ImageAsset(
    asset_id=logo.id,
    duration=10,
    width=120,
    height=60,
    x=20,
    y=20,
)

timeline.add_overlay(0, logo_overlay)

ImageAsset Parameters

ParameterTypeDefaultDescription
asset_idstrrequiredImage media ID
width`int\str`100
height`int\str`100
xint80Horizontal position (px from left)
yint20Vertical position (px from top)
duration`float\None`None

Caption Overlays

There are two ways to add captions to video.

Method 1: Subtitle Workflow (simplest)

Use video.add_subtitle() to burn subtitles directly onto a video stream. This uses the videodb.timeline.Timeline internally:

from videodb import SubtitleStyle

# Video must have spoken words indexed first (force=True skips if already done)
video.index_spoken_words(force=True)

# Add subtitles with default styling
stream_url = video.add_subtitle()

# Or customise the subtitle style
stream_url = video.add_subtitle(style=SubtitleStyle(
    font_name="Arial",
    font_size=22,
    primary_colour="&H00FFFFFF",
    bold=True,
))

Method 2: Editor API (advanced)

The Editor API (videodb.editor) provides a track-based composition system with CaptionAsset, Clip, Track, and its own Timeline. This is a separate API from the videodb.timeline.Timeline used above.

from videodb.editor import (
    CaptionAsset,
    Clip,
    Track,
    Timeline as EditorTimeline,
    FontStyling,
    BorderAndShadow,
    Positioning,
    CaptionAnimation,
)

# Video must have spoken words indexed first (force=True skips if already done)
video.index_spoken_words(force=True)

# Create a caption asset
caption = CaptionAsset(
    src="auto",
    font=FontStyling(name="Clear Sans", size=30),
    primary_color="&H00FFFFFF",
    back_color="&H00000000",
    border=BorderAndShadow(outline=1),
    position=Positioning(margin_v=30),
    animation=CaptionAnimation.box_highlight,
)

# Build an editor timeline with tracks and clips
editor_tl = EditorTimeline(conn)
track = Track()
track.add_clip(start=0, clip=Clip(asset=caption, duration=video.length))
editor_tl.add_track(track)
stream_url = editor_tl.generate_stream()

CaptionAsset Parameters

ParameterTypeDefaultDescription
srcstr"auto"Caption source ("auto" or base64 ASS string)
font`FontStyling\None`FontStyling()
primary_colorstr"&H00FFFFFF"Primary text colour (ASS format)
secondary_colorstr"&H000000FF"Secondary text colour (ASS format)
back_colorstr"&H00000000"Background colour (ASS format)
border`BorderAndShadow\None`BorderAndShadow()
position`Positioning\None`Positioning()
animation`CaptionAnimation\None`None

Compiling & Streaming

After assembling a timeline, compile it into a streamable URL. Streams are generated instantly - no render wait times.

stream_url = timeline.generate_stream()
print(f"Stream: {stream_url}")

For more streaming options (segment streams, search-to-stream, audio playback), see streaming.md.

Complete Workflow Examples

Highlight Reel with Title Card


from videodb import SearchType
from videodb.exceptions import InvalidRequestError
from videodb.timeline import Timeline
from videodb.asset import VideoAsset, TextAsset, TextStyle

conn = videodb.connect()
coll = conn.get_collection()
video = coll.get_video("your-video-id")

# 1. Search for key moments
video.index_spoken_words(force=True)
try:
    results = video.search("product announcement", search_type=SearchType.semantic)
    shots = results.get_shots()
except InvalidRequestError as exc:
    if "No results found" in str(exc):
        shots = []
    else:
        raise

# 2. Build timeline
timeline = Timeline(conn)

# Title card
title = TextAsset(
    text="Product Launch Highlights",
    duration=4,
    style=TextStyle(fontsize=48, fontcolor="white", boxcolor="#1a1a2e", alpha=0.95),
)
timeline.add_overlay(0, title)

# Append each matching clip
for shot in shots:
    asset = VideoAsset(asset_id=shot.video_id, start=shot.start, end=shot.end)
    timeline.add_inline(asset)

# 3. Generate stream
stream_url = timeline.generate_stream()
print(f"Highlight reel: {stream_url}")

Logo Overlay with Background Music


from videodb.timeline import Timeline
from videodb.asset import VideoAsset, AudioAsset, ImageAsset

conn = videodb.connect()
coll = conn.get_collection()

main_video = coll.get_video(main_video_id)
music = coll.get_audio(music_id)
logo = coll.get_image(logo_id)

timeline = Timeline(conn)

# Main video track
timeline.add_inline(VideoAsset(asset_id=main_video.id))

# Background music — disable_other_tracks=False to mix with video audio
timeline.add_overlay(
    0,
    AudioAsset(asset_id=music.id, disable_other_tracks=False, fade_in_duration=3),
)

# Logo in top-right corner for first 10 seconds
timeline.add_overlay(
    0,
    ImageAsset(asset_id=logo.id, duration=10, x=1140, y=20, width=120, height=60),
)

stream_url = timeline.generate_stream()
print(f"Final video: {stream_url}")

Multi-Clip Montage from Multiple Videos


from videodb.timeline import Timeline
from videodb.asset import VideoAsset, TextAsset, TextStyle

conn = videodb.connect()
coll = conn.get_collection()

clips = [
    {"video_id": "vid_001", "start": 5, "end": 15, "label": "Scene 1"},
    {"video_id": "vid_002", "start": 0, "end": 20, "label": "Scene 2"},
    {"video_id": "vid_003", "start": 30, "end": 45, "label": "Scene 3"},
]

timeline = Timeline(conn)
timeline_offset = 0.0

for clip in clips:
    # Add a label as an overlay on each clip
    label = TextAsset(
        text=clip["label"],
        duration=2,
        style=TextStyle(fontsize=32, fontcolor="white", boxcolor="#333333"),
    )
    timeline.add_inline(
        VideoAsset(asset_id=clip["video_id"], start=clip["start"], end=clip["end"])
    )
    timeline.add_overlay(timeline_offset, label)
    timeline_offset += clip["end"] - clip["start"]

stream_url = timeline.generate_stream()
print(f"Montage: {stream_url}")

Two Timeline APIs

VideoDB has two separate timeline systems. They are not interchangeable:

videodb.timeline.Timelinevideodb.editor.Timeline (Editor API)
Importfrom videodb.timeline import Timelinefrom videodb.editor import Timeline as EditorTimeline
AssetsVideoAsset, AudioAsset, ImageAsset, TextAssetCaptionAsset, Clip, Track
Methodsadd_inline(), add_overlay()add_track() with Track / Clip
Best forVideo composition, overlays, multi-clip editingCaption/subtitle styling with animations

Do not mix assets from one API into the other. CaptionAsset only works with the Editor API. VideoAsset / AudioAsset / ImageAsset / TextAsset only work with videodb.timeline.Timeline.

Limitations & Constraints

The timeline editor is designed for non-destructive linear composition. The following operations are not supported:

Not Possible

LimitationDetail
No transitions or effectsNo crossfades, wipes, dissolves, or transitions between clips. All cuts are hard cuts.
No video-on-video (picture-in-picture)add_inline() only accepts VideoAsset. You cannot overlay one video stream on top of another. Image overlays can approximate static PiP but not live video.
No speed or playback controlNo slow-motion, fast-forward, reverse playback, or time remapping. VideoAsset has no speed parameter.
No crop, zoom, or panCannot crop a region of a video frame, apply zoom effects, or pan across a frame. video.reframe() is for aspect-ratio conversion only.
No video filters or color gradingNo brightness, contrast, saturation, hue, or color correction adjustments.
No animated textTextAsset is static for its full duration. No fade-in/out, movement, or animation. For animated captions, use CaptionAsset with the Editor API.
No mixed text stylingA single TextAsset has one TextStyle. Cannot mix bold, italic, or colors within a single text block.
No blank or solid-color clipsCannot create a solid color frame, black screen, or standalone title card. Text and image overlays require a VideoAsset beneath them on the inline track.
No audio volume controlAudioAsset has no volume parameter. Audio is either full volume or muted via disable_other_tracks. Cannot mix at a reduced level.
No keyframe animationCannot change overlay properties over time (e.g., move an image from position A to B).

Constraints