559 named video transitions across four render backends
Project description
cut-fx
559 named video transitions across four render backends, with GPU acceleration when available.
Built at Trollfabriken AITrix AB to make programmatic video rendering match the visual vocabulary
of consumer video editors. Five-hundred-and-fifty-nine named transitions across eleven taxonomy
buckets, mapped to thirty-four hand-written base engines and parametric variants. Four render
backends: ffmpeg filter_complex, NumPy/OpenCV procedural, HTML/CSS via web-overlay, and GLSL
shaders. GPU acceleration when available, CPU fallback when not. One API:
apply_transition(clip_a, clip_b, transition="atomic_teleport", output=...).
What it solves
Programmatic batch video rendering — AIMOS Insight municipal report videos, civic-education
explainers, pipeline-driven content — needs named, repeatable transitions. ffmpeg's xfade covers
dissolves. It does not cover 559 named effects. Writing each effect from scratch is not feasible.
| Problem | What cut-fx does |
|---|---|
Named transitions not in ffmpeg xfade |
559 catalog entries map to 34 base engines |
| Different effects need different render tech | Four backends; catalog picks the right one |
| GPU present on some machines, absent on others | Runtime detection; CPU fallback always works |
| LLMs need a machine-readable transition spec | JSON schema export via cut_fx.schema |
| Beat-aligned cuts require audio analysis | cut_fx.beats wraps audio-arrange |
| Lyric-timed transitions | Optional lyric-sync integration |
Installation
pip install cut-fx
Runtime requirement: ffmpeg >= 6.0 must be on PATH.
# Ubuntu / Debian
sudo apt-get install ffmpeg
# macOS
brew install ffmpeg
# Windows
choco install ffmpeg
Extras:
| Extra | Installs | Enables |
|---|---|---|
overlay |
web-overlay |
HTML/CSS/SVG transitions (light_fx, particle_nature, graphic_stylized) |
shader |
moderngl, moderngl-window |
GLSL shader transitions; requires OpenGL 3.3+ |
beats |
audio-arrange, librosa |
Beat-synced cut placement |
lyrics |
lyric-sync |
Lyric-timed transitions |
all |
all of the above | Full feature set |
dev |
pytest, ruff, build, pillow | Development tools |
pip install "cut-fx[overlay,shader,beats]"
pip install "cut-fx[all]"
Quick start
from cut_fx import apply_transition
apply_transition(
clip_a="intro.mp4",
clip_b="main.mp4",
transition="atomic_teleport",
output="combined.mp4",
overlap_seconds=0.8,
)
List what is available:
from cut_fx import list_transitions, list_categories
list_categories()
# ['motion', 'rotation', 'shape_mask', 'optical_blur', 'light_fx',
# 'particle_nature', 'graphic_stylized', 'digital_glitch',
# 'grid_card_layout', 'film_retro', 'general_fx']
list_transitions(category="digital_glitch")
# ['Capture Glitch 2', 'Console Buzz', 'Cyber Beehive', 'Cyber Flare',
# 'Cyber Phantom', 'Hologram Shred', ...]
Inspect a specific transition:
from cut_fx import get_transition_info
info = get_transition_info("cyber_phantom")
# TransitionInfo(
# name='Cyber Phantom',
# slug='cyber_phantom',
# category='digital_glitch',
# base_engine='glitch_scan',
# parameters={'intensity': 0.7, 'scan_lines': 12, 'color_shift': True},
# backends=['procedural', 'shader'],
# )
The catalog
The catalog (cut_fx/data/transitions_catalog.json) lists 559 transition names across 11 taxonomy
buckets. Behind those names are 34 base engine implementations. Each base engine accepts parameters:
direction, easing, intensity, colour, shape, count, duration curve.
The 559 → 34 design: a named transition is a (base_engine, parameter_set) tuple. Adding a new
named variant means adding one JSON entry — no new Python code.
| Bucket | Transitions | Base engines | Example named variants |
|---|---|---|---|
motion |
119 | 4 | 180 Wipe, Block Slides, Push Right |
light_fx |
93 | 5 | Basic Flash, Bright Flash, Crescent Sparks |
grid_card_layout |
47 | 3 | 3-block Swing, 3D Card 2, Bizarre Rubik |
rotation |
46 | 3 | 3-flap Turn, 3D Flip, Calendar Flip |
shape_mask |
44 | 4 | Circle, Comic Cutout, Blast Door |
film_retro |
35 | 3 | B&W Arrows, Black Smoke, Black Fade |
optical_blur |
31 | 3 | Auto Focus, Blur & Zoom, Blur Focus |
particle_nature |
22 | 3 | Bubble Blur, Crystal Energy, Dust Flurry |
digital_glitch |
16 | 4 | Cyber Phantom, Hologram Shred, Console Buzz |
graphic_stylized |
12 | 2 | Comic Cut, Glowing Graffiti, Light Graffiti I |
general_fx |
94 | (composed) | 3D Glass, Atomic Teleport, Acrylic Fades |
The general_fx bucket entries are composed from existing base engines. "Atomic Teleport" is a
light_fx flash + shape_mask radial + motion zoom-out, assembled in sequence.
Inspect catalog totals at runtime:
from cut_fx.catalog import catalog_summary
print(catalog_summary())
# {'total': 559, 'categories': 11, 'base_engines': 34, ...}
Render engines
Each catalog entry specifies which backend handles it. The dispatch is automatic.
| Engine | Handles | Implementation |
|---|---|---|
| ffmpeg | motion, rotation, optical_blur, simple wipes |
filter_complex with crop/scale/translate/rotate expressions; xfade for cross-dissolves |
| procedural | digital_glitch, film_retro, custom pixel math |
NumPy + OpenCV; frame-by-frame in Python |
| overlay | light_fx, particle_nature, graphic_stylized, shape_mask |
HTML/CSS/SVG via web-overlay; alpha-composited over ffmpeg base |
| shader | Premium light_fx variants, refraction, fluid sim |
GLSL via moderngl; optional; CPU fallback to procedural when absent |
The overlay engine requires pip install "cut-fx[overlay]" and a headless Chromium install
(playwright install chromium). The shader engine requires pip install "cut-fx[shader]" and
OpenGL 3.3+ context support.
Force a specific backend:
apply_transition(
clip_a="a.mp4",
clip_b="b.mp4",
transition="basic_flash",
output="out.mp4",
backend="procedural", # override automatic selection
)
Hardware acceleration
At import time, cut_fx probes for hardware encoders and GPU context.
from cut_fx.gpu import gpu_status
print(gpu_status())
# {
# 'ffmpeg_hwaccel': 'nvenc', # or 'videotoolbox', 'qsv', None
# 'opengl_available': True,
# 'opengl_renderer': 'NVIDIA GeForce RTX 3080',
# 'shader_backend': 'moderngl', # or 'procedural' (fallback)
# }
Acceleration paths:
- ffmpeg hardware encoders: NVENC (NVIDIA), VideoToolbox (Apple), QSV (Intel). Detected via
ffmpeg -hwaccels. Falls back to libx264/libx265 when none is found. - GLSL shader engine: requires a real GPU context. Falls back to the procedural (NumPy/OpenCV) implementation automatically — output is identical, speed is lower.
Print a summary from the CLI:
cut-fx gpu
No GPU is required. All 559 transitions render on CPU.
Beat-synced cuts
Requires pip install "cut-fx[beats]".
from cut_fx.beats import transitions_on_beats
transitions_on_beats(
clips=["clip1.mp4", "clip2.mp4", "clip3.mp4", "clip4.mp4"],
audio="track.mp3",
transition="cyber_phantom",
output="beat_video.mp4",
beats_per_cut=2, # place a cut every 2 beats
overlap_seconds=0.4,
)
transitions_on_beats uses audio-arrange to extract beat timestamps, then places transitions
at beat boundaries. The beats_per_cut parameter controls cut density. Fractional values are
supported: beats_per_cut=0.5 cuts on every half-beat.
For lyric-timed cuts, add pip install "cut-fx[lyrics]":
from cut_fx.beats import transitions_on_lyrics
transitions_on_lyrics(
clips=["verse.mp4", "chorus.mp4"],
lyrics_file="song.lrc",
transition="light_burst",
output="lyric_video.mp4",
)
LLM integration
cut_fx.schema exports a JSON Schema describing every valid transition call. Pass it to an LLM
as a tool definition.
from cut_fx.schema import transition_spec_schema
schema = transition_spec_schema()
# {
# "$schema": "https://json-schema.org/draft/2020-12/schema",
# "title": "TransitionSpec",
# "type": "object",
# "properties": {
# "transition": {"type": "string", "enum": ["atomic_teleport", "cyber_phantom", ...]},
# "overlap_seconds": {"type": "number", "minimum": 0.1, "maximum": 5.0},
# "backend": {"type": "string", "enum": ["auto", "ffmpeg", "procedural", "overlay", "shader"]},
# ...
# },
# "required": ["transition"]
# }
Feed the schema to an LLM as a function spec. The LLM returns a valid TransitionSpec object.
Pass it directly to apply_transition:
from cut_fx import apply_transition
from cut_fx.config import TransitionConfig
spec = TransitionConfig(**llm_response)
apply_transition(clip_a="a.mp4", clip_b="b.mp4", output="out.mp4", **spec.model_dump())
CLI
Apply a transition between two clips:
cut-fx apply intro.mp4 main.mp4 --transition atomic_teleport --output combined.mp4
List all transitions in a category:
cut-fx list --category digital_glitch
List all categories with transition counts:
cut-fx categories
Show detail for a named transition:
cut-fx info cyber_phantom
Render a short preview (3-second synthetic clips):
cut-fx preview atomic_teleport --output preview.mp4
Show GPU and hardware encoder status:
cut-fx gpu
Package structure
cut-fx/
├── src/
│ └── cut_fx/
│ ├── __init__.py # public API re-exports
│ ├── api.py # apply_transition, apply_sequence, list_*
│ ├── catalog.py # loads transitions_catalog.json
│ ├── config.py # TransitionConfig (pydantic model)
│ ├── schema.py # JSON schema export for LLM tool use
│ ├── gpu.py # hardware detection
│ ├── beats.py # beat-synced and lyric-synced cuts
│ ├── cli.py # cut-fx command-line entry point
│ ├── data/
│ │ ├── transitions_catalog.json # 559 entries
│ │ └── engine_mapping.json # slug → base_engine lookup
│ └── engines/
│ ├── base.py # abstract BaseEngine
│ ├── dispatcher.py # selects engine per catalog entry
│ ├── ffmpeg/ # filter_complex builder
│ ├── procedural/ # NumPy + OpenCV per-frame
│ ├── overlay/
│ │ └── templates/ # HTML/CSS/SVG transition templates
│ └── shader/
│ └── glsl/ # .vert / .frag shader sources
├── tests/
├── pyproject.toml
├── README.md
└── LICENSE
© Trollfabriken AITrix AB — MIT licensed
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cut_fx-0.1.2.tar.gz.
File metadata
- Download URL: cut_fx-0.1.2.tar.gz
- Upload date:
- Size: 69.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5bccbd66235e498d46d54b83ec32b567d9914312d3d772e13e14a47912075f4a
|
|
| MD5 |
78db9683c77ae78e7fca90330f183069
|
|
| BLAKE2b-256 |
faee0ff5cbb16e0c30dc80dc2fa10767d67358b98902c07bc0be9bc0805f0f5f
|
Provenance
The following attestation bundles were made for cut_fx-0.1.2.tar.gz:
Publisher:
release.yml on tomastimelock/cut-fx
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cut_fx-0.1.2.tar.gz -
Subject digest:
5bccbd66235e498d46d54b83ec32b567d9914312d3d772e13e14a47912075f4a - Sigstore transparency entry: 1615437346
- Sigstore integration time:
-
Permalink:
tomastimelock/cut-fx@3416c99da476008f2ff1484d68520ac2690ac788 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/tomastimelock
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@3416c99da476008f2ff1484d68520ac2690ac788 -
Trigger Event:
push
-
Statement type:
File details
Details for the file cut_fx-0.1.2-py3-none-any.whl.
File metadata
- Download URL: cut_fx-0.1.2-py3-none-any.whl
- Upload date:
- Size: 89.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b6ffd5f90b7e77ef1622f7e98760ab104d03e7c2c366cdea59f30a451e3d0e90
|
|
| MD5 |
786837e094863aa26f5932f7949df5f0
|
|
| BLAKE2b-256 |
4913d6f457d2e1a24ec7ed3fbf627f5804b68fc516f663fbf33c32d0801025df
|
Provenance
The following attestation bundles were made for cut_fx-0.1.2-py3-none-any.whl:
Publisher:
release.yml on tomastimelock/cut-fx
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cut_fx-0.1.2-py3-none-any.whl -
Subject digest:
b6ffd5f90b7e77ef1622f7e98760ab104d03e7c2c366cdea59f30a451e3d0e90 - Sigstore transparency entry: 1615437350
- Sigstore integration time:
-
Permalink:
tomastimelock/cut-fx@3416c99da476008f2ff1484d68520ac2690ac788 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/tomastimelock
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@3416c99da476008f2ff1484d68520ac2690ac788 -
Trigger Event:
push
-
Statement type: