Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

33 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Particlops logo

Particlops

Seamlessly looped particle videos for compositing.
CLI + GUI · OpenGL 3.3 · Deterministic seeds

Python 3.12 MIT License moderngl


Overview

Generate particle animations on a black background, designed to be layered onto other footage with additive or screen blend modes. Every video loops seamlessly via a crossfade export pipeline.


Installation

Requirements

  • Python 3.12
  • uv (recommended) or pip
  • ffmpeg on PATH
  • OpenGL 3.3+ GPU

System dependencies

Fedora
sudo dnf install ffmpeg mesa-libGL
Ubuntu / Debian
sudo apt install ffmpeg libgl1-mesa-glx libegl1
macOS
brew install ffmpeg

Setup

git clone https://github.com/Lorakszak/Particlops.git && cd Particlops
uv sync

For development tools (pytest, ruff, pyright):

uv sync --extra dev

GUI

Launch the live preview with sidebar controls:

uv run particlops preview

Load a built-in preset:

uv run particlops preview --preset stardust

Load a custom preset file:

uv run particlops preview --preset-file my_preset.json

The window has:

  • Left panel -- live OpenGL particle preview at ~60 fps
  • Right sidebar -- grouped parameter controls (Core, Spawn, Shapes, Physics, Lifecycle, Colors). Changes apply instantly.
  • Export section -- duration, crossfade, resolution, fps, CRF, output path. Click Generate to render in the background.

Presets can be loaded / saved via the buttons at the top of the sidebar.


CLI

Basic render

uv run particlops generate --preset rising_sparks --duration 30 --output sparks.mp4

Full customization

uv run particlops generate \
  --duration 15 \
  --crossfade 5 \
  --resolution 1920x1080 \
  --fps 60 \
  --crf 18 \
  --particles 3000 \
  --spawn-rate 200 \
  --lifetime 3 \
  --spawn-mode circle \
  --vortex 0.5 \
  --turbulence 0.2 \
  --colors "#ff00ff,#00ffff,#ffff00" \
  --output vortex.mp4

Quick test render

uv run particlops generate \
  --preset stardust \
  --duration 5 --crossfade 2 \
  --resolution 640x360 --fps 30 \
  --output /tmp/test_loop.mp4

mpv --loop /tmp/test_loop.mp4

Deterministic output

uv run particlops generate --preset fireflies --seed 42 --output fireflies.mp4

Presets
uv run particlops list-presets
Preset Description
gentle_snow Slow drifting white and blue particles
rising_sparks Upward embers with warm orange, red, and yellow
vortex_swirl Spiral motion with multi-color particles
stardust Gentle outward drift with white, cyan, and purple
fireflies Random slow pulsing particles in green and yellow

Save / load custom presets

# Save
uv run particlops generate --preset stardust --vortex 0.3 \
  --save-preset my_preset.json --output out.mp4

# Load
uv run particlops generate --preset-file my_preset.json --output out.mp4

How the seamless loop works

The export pipeline runs a single simulation pass rendering duration + crossfade total frames:

  1. Pre-roll -- simulation runs without recording so the screen starts populated
  2. Head frames (first crossfade seconds) -- compressed as PNGs, held in RAM
  3. Middle frames -- streamed to a lossless intermediate
  4. Tail frames (last crossfade seconds) -- alpha-blended with corresponding head frames

The blended segments are concatenated and encoded to H.264. When the video loops, the last-to-first transition is seamless.


CLI reference
particlops generate [OPTIONS]

Core:
  --duration FLOAT       Video length in seconds (default: 30)
  --crossfade FLOAT      Loop overlap in seconds (default: 10)
  --output PATH          Output file path (default: particles.mp4)
  --preset NAME          Built-in preset name
  --preset-file PATH     Path to preset JSON file
  --seed INT             Random seed for reproducibility
  --preroll FLOAT        Pre-roll seconds (default: auto)

Video:
  --resolution WxH       Output resolution (default: 1920x1080)
  --fps INT              Frames per second (default: 60)
  --crf INT              H.264 CRF quality, lower = better (default: 18)
  --codec STR            Video codec (default: libx264)

Particles:
  --particles INT        Max particles alive at once
  --size FLOAT           Base particle size in pixels
  --spawn-rate FLOAT     Particles per second
  --lifetime FLOAT       Seconds per particle
  --spread FLOAT         Spawn velocity spread
  --spawn-mode STR       point | line | circle | edges | random
  --spawn-x FLOAT        Horizontal spawn position (0-1)
  --spawn-y FLOAT        Vertical spawn position (0-1)
  --spawn-radius FLOAT   Radius for circle mode
  --gravity-x FLOAT      Horizontal gravity
  --gravity-y FLOAT      Vertical gravity
  --speed-min FLOAT      Min initial speed
  --speed-max FLOAT      Max initial speed
  --drag FLOAT           Velocity damping
  --turbulence FLOAT     Noise perturbation
  --radial-force FLOAT   Attract/repel from spawn
  --vortex FLOAT         Rotational force
  --size-over-life STR   constant | grow | shrink | pulse
  --fade-curve STR       linear | ease_out | flash
  --color-over-life      Shift through palette over lifetime
  --colors STR           Comma-separated hex colors

Other:
  --save-preset PATH     Save current settings to JSON

Development
uv run pytest tests/ -v       # run tests
uv run ruff check src/ tests/ # lint
uv run pyright src/            # type check

MIT License

About

Seamlessly looped particle video generator for compositing. CLI + GUI.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages