Getting started¶
Requirements¶
- Python >= 3.12 to develop against this repo (the packaging metadata
says
>=3.10, but treat 3.12 as the supported floor — that's what CI/tests target). - FFmpeg on your
PATH— needed forexport_to_video()and for encoding animated coded visuals. - A Chrome or Chromium install — needed for
CodedVisualClip(any coded visual) and forTextCliprendering throughFFmpegVideoExporter. VisualKit never bundles or downloads a browser itself. It looks, in order: - the
VISUALKIT_CHROMEenvironment variable (a path to the executable), - your
PATH, - the usual OS install locations,
- browsers cached by Playwright/Puppeteer.
chrome-headless-shell is preferred when present (smaller, faster to
start). If nothing is found, you get BrowserNotFoundError with concrete
fix instructions in the message — that error is designed to be read.
- Optional: playwright (pip install "visualkit[render]") — only
needed to render animated coded visuals (video). Still visuals, text,
and everything else works without it.
Install¶
pip install visualkit # core
pip install "visualkit[render]" # + animated coded visuals
# with uv
# uv add visualkit
# uv add "visualkit[render]"
dev mode¶
uv sync --group dev # includes playwright + pillow so render tests run
pytest
ruff check . && ruff format --check .
Your first timeline¶
import visualkit as vk
timeline = vk.Timeline()
video = vk.MediaClip(
id="main_video",
source=vk.Source(source="footage.mp4"),
duration=vk.Time.from_seconds(10),
)
timeline.add_clip(video, track_index=0)
title = vk.TextClip(
id="title",
text="Hello, World!",
timeline_start=vk.Time.from_seconds(1),
duration=vk.Time.from_seconds(3),
)
timeline.add_clip(title, track_index=1)
# Export to a standalone MP4 (requires ffmpeg, and Chrome for the TextClip)
timeline.export_to_video("output/hello.mp4")
# ...or to a DaVinci Resolve project
timeline.export_to_resolve("output/hello_resolve.xml")
A few things worth noticing immediately, because they shape everything else:
timeline.add_clip(clip, track_index=N)routes by clip type —AudioClipalways lands on an audio track, everything else on a video track — and provisions tracks up toNif they don't exist yet. You never manually decide "is this an audio track."MediaClip.sourceaccepts either aSource(...)instance or a bare string path — both examples above are valid;Sourcealso carries an in-file trim offset (start).- Nothing here is validated against the filesystem until export time.
Building a
Timelinein memory never touches disk or ffmpeg.
Where to go next¶
Every feature area has a matching runnable script in examples/ — read the
source, then run it:
uv run python examples/01_basic_timeline.py
uv run python examples/02_coded_visuals.py
uv run python examples/03_compound_clips_and_templates.py
uv run python examples/04_asset_resolvers.py
uv run python examples/05_keyframes_and_effects.py
Then read 02-concepts.md for the model these examples all build on.