Skip to main content

A Python-native, code-first video generation framework

Project description

Version

PyMotion

Code-first video generation for Python.
Build professional motion graphics, animated explainers, social ads, and product videos — entirely in Python.

CI PyPI Python License

mypy strict Coverage Ruff Security Audit Tests


Why PyMotion?

Most video tools force you into a GUI timeline. PyMotion doesn't. You write Python, you get broadcast-quality video. No templates to fight, no drag-and-drop constraints — just code that renders frames.

It ships with a Cairo 2D backend, a ModernGL 3D pipeline, FreeType+HarfBuzz typography, a full audio DSP chain, and 15 FFmpeg export presets out of the box. One pip install, one comp.render() call, done.

from pymotion import Composition, ColorClip, TextClip, Track

comp = Composition(1920, 1080, fps=30, duration=150)

track = Track(name="main")
bg = ColorClip(color="#1a1a2e")
bg.set_duration(150)
track.add(bg)

title = TextClip("Hello, PyMotion!", font="Arial", size=72.0, color="#FFFFFF")
title.set_duration(150).set_position(480.0, 500.0)
track.add(title)

comp.add_track(track)
comp.render("output.mp4", preset="h264_1080p")

That's a full 1080p video in 12 lines.


Features

2D Rendering Color, image, shape, gradient, and text clips — Cairo backend
3D Rendering PBR materials, point/spot/directional/ambient lights, SSAO, bloom, DOF (ModernGL headless)
Animation Keyframe tracks, 30+ easing functions, spring physics, cubic bezier curves
Typography FreeType + HarfBuzz shaping, variable fonts, 9 animated text presets (Typewriter, CountUp, Scramble, ...)
Audio Mixing, EQ, compressor, limiter, reverb, delay, pitch shift, beat detection, waveform analysis
Effects 30+ visual/color/distortion/light effects (blur, grain, glow, LUT, wave warp, god rays, ...)
Keying ChromaKey, LumaKey, ColorKey, DifferenceKey — with feathering, choking, despill
Editing Split, join, subclip, repeat, freeze frame, concatenate with transitions
Speed/Time Uniform speed, speed ramp, reverse, time remap, optical flow slow-motion
Layout Picture-in-picture, grid, split screen, stack — named anchor positioning
Tracking Motion tracking, video stabilization, follow-tracker binding
Compositing Nested compositions (pre-comps), adjustment layers, clip parenting with NullObject
Masking Bezier, linear/radial gradient, track matte, text masks — boolean ops (add, intersect, subtract)
Expressions Drive any property with Python callables — wiggle, loop_in, loop_out helpers
Path Animation SVG path following, StrokeClip draw-on/off, bezier path morphing
Proxy Low-res proxy generation with disk cache for fast preview
Transitions 39 built-in (fade, slide, wipe, zoom, glitch, film burn, shatter, vortex, ...)
Particles 9 presets — fire, sparkles, confetti, rain, smoke, stars, dust, explosion, bubbles
Export 15 presets — H.264, H.265, ProRes, AV1, WebM, GIF, PNG/EXR frame sequences
Batch Template system with field validation for data-driven video generation
Color .cube LUT loading, lift/gamma/gain grading, ACES/Reinhard/Filmic tone mapping
CLI render, preview, benchmark, validate, doctor, new

Installation

Prerequisites: Python 3.12+, FFmpeg, Cairo

# macOS
brew install ffmpeg cairo pkg-config

# Ubuntu / Debian
sudo apt-get install ffmpeg libcairo2-dev pkg-config libfreetype6-dev

# Windows (via chocolatey)
choco install ffmpeg cairo

Install from PyPI:

pip install pymotion-studio

With extras:

pip install "pymotion-studio[3d-extras]"     # GLTF model loading
pip install "pymotion-studio[gpu-compute]"   # wgpu acceleration
pip install "pymotion-studio[jit]"           # Numba JIT compilation
pip install "pymotion-studio[dev]"           # Development tools

Note: The Python import name is pymotion (no hyphen):

from pymotion import Composition, ColorClip, Track

Quick Start

Animated Text with Particles

from pymotion import Composition, ColorClip, Track
from pymotion.text.animated import Typewriter
from pymotion.particle.system import sparkles
from pymotion.utils.color import Color

comp = Composition(1920, 1080, fps=30, duration=150)

# Background
bg_track = Track(name="bg")
bg = ColorClip(color="#0D1B2A")
bg.set_duration(150)
bg_track.add(bg)

# Typewriter text
text_track = Track(name="text")
tw = Typewriter(
    text="Welcome to PyMotion",
    font_size=64.0,
    color=Color(1.0, 1.0, 1.0, 1.0),
    chars_per_frame=1.5,
)
tw.set_duration(150).at(10)
text_track.add(tw)

# Sparkle particles
fx_track = Track(name="fx")
sparks = sparkles(1920, 1080).to_clip(150)
sparks.set_duration(150)
fx_track.add(sparks)

comp.add_track(bg_track)
comp.add_track(text_track)
comp.add_track(fx_track)
comp.render("intro.mp4", preset="h264_1080p")

Batch Rendering with Templates

from pymotion import Template, Composition, ColorClip, TextClip, Track

class ProductVideo(Template):
    product_name: str
    brand_color: str = "#FF5500"

    def build(self) -> Composition:
        comp = Composition(1920, 1080, fps=30, duration=90)
        track = Track(name="main")
        bg = ColorClip(color=self.brand_color)
        bg.set_duration(90)
        track.add(bg)
        label = TextClip(self.product_name, font="Arial", size=80.0, color="#FFFFFF")
        label.set_duration(90).set_position(600.0, 480.0)
        track.add(label)
        comp.add_track(track)
        return comp

for name in ["Widget Pro", "Gadget X", "Tool Kit"]:
    ProductVideo(product_name=name).render(f"{name.lower().replace(' ', '_')}.mp4")

Video Editing Operations

from pymotion import ColorClip, concatenate, CrossDissolve, pip, grid

# Split, speed, reverse
clip = ColorClip(color="#e94560")
clip.set_duration(120)
first, second = clip.split(60)
slow = first.speed(0.5)
backwards = second.reverse()

# Concatenate with transitions
final = concatenate([slow, backwards], transition=CrossDissolve(), transition_duration=15)

# Picture-in-picture
main = ColorClip(color="#1a1a2e").set_duration(90)
overlay = ColorClip(color="#e94560").set_duration(90)
comp = pip(main, overlay, position="bottom-right", size=(320, 180))

# Grid layout
clips = [ColorClip(color=c).set_duration(90) for c in ["#e94560", "#0f3460", "#533483", "#16213e"]]
comp = grid(clips, rows=2, cols=2, gap=10)

Examples

Seven production-ready scripts ship with the repo, each targeting a real-world use case:

# Script Niche What It Demonstrates
01 real_estate_tour.py Property listings ImageClip slideshow, Typewriter text, sparkle particles, 7-track composition
02 tech_review_intro.py YouTube intros CountUp stats, radial/conic gradients, fire particles
03 fitness_social_ad.py Instagram/TikTok Vertical 1080x1920, CountDown timer, confetti, LetterByLetter
04 restaurant_menu_promo.py Menu promotions WordByWord reveals, stars particles, ShapeClip polygons
05 educational_explainer.py E-learning LetterByLetter titles, CountUp counters, diagram shapes
06 video_editing_showcase.py Post-production split/join/speed/reverse, ChromaKey, grid/pip/split_screen, proxy workflow
07 motion_graphics_toolkit.py Motion graphics Nested comps, masks, expressions, wiggle, path animation, adjustment layers
python examples/download_assets.py     # grab stock images (~5 MB)
python examples/01_real_estate_tour.py  # render

CLI

pymotion render scene.py -o out.mp4 -p h264_1080p   # render a composition
pymotion export-frame scene.py -f 30 -o thumb.png    # export single frame
pymotion benchmark scene.py -n 100                    # measure frame throughput
pymotion doctor                                       # verify system dependencies
pymotion validate scene.py                            # check composition integrity
pymotion new my-project                               # scaffold a new project

Architecture

pymotion/
├── animation/     Keyframe tracks, 30+ easings, spring, bezier, interpolation
├── audio/         Mixer, DSP effects (EQ, compressor, reverb, ...), beat detection
├── clip/          ColorClip, ImageClip, ShapeClip, TextClip, VideoClip, Scene3DClip
├── composition.py Composition, Track, CompositionClip, AdjustmentLayer
├── masking.py     Bezier, gradient, track matte, text masks + boolean ops
├── expressions.py Expression system — wiggle, loop_in, loop_out
├── path_animation.py  SVG path following, StrokeClip, path morphing
├── effects/       Visual, color, distortion, light effect processors
├── export/        FFmpeg encoder, 15 output presets
├── particle/      Vectorized particle system, 9 preset generators
├── render/        Cairo 2D, ModernGL 3D, compositor, color pipeline
├── security/      Path traversal, color, asset magic-byte, text sanitization validators
├── template/      Template ABC with field validation for batch rendering
├── text/          FreeType/HarfBuzz renderer, 9 animated text presets
├── transition/    39 transition implementations
├── utils/         Color (OKLCH), Vec2/Vec3, logging (structlog)
└── cli/           Click-based CLI (render, preview, benchmark, doctor, ...)

Internal frame format: BGRA uint8 NumPy arrays (H, W, 4) — matches Cairo ARGB32 on little-endian. The compositor uses bounding-box sparse blending with uint16 fixed-point fast paths for opaque layers and alpha-info caching for transparency detection.


Performance

Benchmarked on a typical 7-layer 1080p composition:

Metric Value
Frame render throughput ~75 fps (13 ms/frame)
12s video end-to-end ~7s wall time (2.5x realtime)
Static layer caching Single render, reused across frames
Particle simulation Vectorized NumPy — no per-particle Python loops
FFmpeg encoding Multi-threaded, contiguous frame pipe, zero-copy

Development

git clone https://github.com/Ohswedd/pymotion.git
cd pymotion
pip install -e ".[dev]"

make lint      # ruff format + ruff check + mypy --strict
make test      # pytest with coverage (85% minimum)
make clean     # remove caches and build artifacts

Running Tests

pytest -v                              # full suite (1444 tests)
pytest tests/unit/ -v                  # unit tests only
pytest tests/integration/ -v           # integration tests
pytest --cov=pymotion --cov-report=html  # coverage report

Docker

docker build -t pymotion .
docker run --rm -v $(pwd)/output:/app/output pymotion render scene.py -o output/video.mp4

System Dependencies

Dependency Purpose Bundled?
FFmpeg Video/audio encoding No — install separately
Cairo 2D vector rendering No — install separately
FreeType Font rasterization Yes (via freetype-py)
HarfBuzz Text shaping Yes (via uharfbuzz)
ModernGL 3D PBR rendering Yes (via pip)

Run pymotion doctor to verify your environment.


License

PyMotion is released under the PyMotion Source Available License 1.0.

What you can do:

  • Use PyMotion in any project, including commercial products
  • Fork the repo and modify the code for your own use
  • Contribute back via pull requests

What you cannot do:

  • Redistribute, rebrand, or republish PyMotion as a standalone library
  • Sell, sublicense, or commercially exploit the library itself
  • Publish modified versions to any package registry

Read the full LICENSE for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pymotion_studio-1.3.0.tar.gz (5.9 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pymotion_studio-1.3.0-py3-none-any.whl (172.9 kB view details)

Uploaded Python 3

File details

Details for the file pymotion_studio-1.3.0.tar.gz.

File metadata

  • Download URL: pymotion_studio-1.3.0.tar.gz
  • Upload date:
  • Size: 5.9 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pymotion_studio-1.3.0.tar.gz
Algorithm Hash digest
SHA256 8bba0b52cd2f3ac76e08230ccbc5074c724efd39fb47865ca57b5c39a13770c6
MD5 b6cf34a9f3265fcd48b522c732a6bd0d
BLAKE2b-256 e3e5b2178ccc86775d65c397c89d36c5ce857ccec5b693399a4045fa522a251f

See more details on using hashes here.

Provenance

The following attestation bundles were made for pymotion_studio-1.3.0.tar.gz:

Publisher: publish.yml on Ohswedd/pymotion

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pymotion_studio-1.3.0-py3-none-any.whl.

File metadata

  • Download URL: pymotion_studio-1.3.0-py3-none-any.whl
  • Upload date:
  • Size: 172.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pymotion_studio-1.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4cb745d33564513506b4d674c7119aca32a62e626660b3bafe82642439764645
MD5 eba2a748a1a78cd148312f7295de940f
BLAKE2b-256 2550b075bbec8e4492636223cfd4a97f5d760a7f08f7b9ccb03e2b7282ac4d3a

See more details on using hashes here.

Provenance

The following attestation bundles were made for pymotion_studio-1.3.0-py3-none-any.whl:

Publisher: publish.yml on Ohswedd/pymotion

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page