Stock footage sites charge $15–50 for a single looping background video.
Gradient flows. Plasma effects. Aurora animations. The kind of stuff streamers use behind their webcam, designers drop into hero sections, and indie devs layer behind title screens.
I got tired of paying for something a computer can generate from math. So I built loopkit — a single Rust binary that generates perfectly seamless looping videos from the command line.
loopkit generate --preset plasma --duration 5 -o plasma_loop.mp4
That's it. One command. Full HD. Perfectly looping. Free.
The Problem
You need a looping background video. Your options:
- Pay per clip — Shutterstock, Adobe Stock, Envato. $15–50 each. Licensing restrictions. Watermarks until you pay.
- Learn After Effects — Steep learning curve for something that should be simple.
- Use Processing/TouchDesigner — Great tools, but heavy setup and a runtime to manage.
- Find free clips on Pexels — Limited selection, everyone uses the same ones.
None of these feel right for something that is, fundamentally, math applied to pixels over time.
The Solution
loopkit ships as a single binary. No Python. No Node. No runtime. Install it, run one command, get an MP4.
# Install from source
git clone https://github.com/LakshmiSravyaVedantham/loopkit.git
cd loopkit
cargo install --path .
Prerequisites: Rust 1.70+ and ffmpeg (for encoding).
# macOS
brew install ffmpeg
# Ubuntu/Debian
sudo apt install ffmpeg
5 Built-In Presets
Every preset produces a different visual effect. All of them loop seamlessly.
Plasma
Classic sine wave interference pattern with shifting rainbow hues. Think 90s demoscene.
loopkit generate --preset plasma --duration 5 --fps 30 -o plasma.mp4
Gradient
Smooth flowing gradient that morphs between deep blues, purples, and roses. Clean and modern — perfect for hero section backgrounds.
loopkit generate --preset gradient --duration 8 --fps 24 -o gradient.mp4
Aurora
Northern lights simulation with swaying curtains of green and teal. Organic, atmospheric movement.
loopkit generate --preset aurora --duration 6 --fps 30 -o aurora.mp4
Waves
Layered ocean surface with blue/teal waves and white foam highlights. Calming and rhythmic.
loopkit generate --preset waves --duration 5 --fps 30 -o waves.mp4
Fire
Turbulent fire and lava with orange, red, yellow palette and white-hot core. High energy.
loopkit generate --preset fire --duration 4 --fps 30 -o fire.mp4
Generate All At Once
for preset in plasma gradient aurora waves fire; do
loopkit generate --preset $preset --duration 5 -o "${preset}_loop.mp4"
done
How Seamless Loops Actually Work
This is the key insight that makes loopkit possible.
Most people try to make loops by blending the last few frames into the first few frames. Cross-fading. It works, but you can usually spot the seam — there's a subtle "pulse" where the blend happens.
loopkit does something different: it never creates a seam in the first place.
Instead of parameterizing time as a linear ramp (0 to 1), we parameterize it as an angle on a circle (0 to 2pi):
cos=1
|
|
sin=-1 --+-- sin=1
|
|
cos=-1
Frame 0 starts at angle 0 (top of circle)
Frame N ends at angle 2pi (back to top)
Since sin(0) = sin(2pi) and cos(0) = cos(2pi), the first frame and last frame are mathematically identical. Not "close enough" — identical. Zero seam. Zero blend artifact.
Here's the actual code:
let phase = (frame as f64 / total_frames as f64) * 2.0 * PI;
let t1 = phase.sin(); // circular time component 1
let t2 = phase.cos(); // circular time component 2
Every preset receives t1 and t2 as its time inputs. The pattern evolves through a complete cycle on the unit circle and returns exactly to its starting state.
Each preset then combines these circular time parameters with spatial coordinates (pixel x, y) through layered sine and cosine functions to produce organic, evolving patterns.
Custom Resolution
Need vertical video for TikTok or Instagram Reels? Just flip the dimensions:
# 1080x1920 vertical video
loopkit generate --preset gradient --duration 8 --width 1080 --height 1920 -o vertical.mp4
# 4K for the big screen
loopkit generate --preset aurora --duration 10 --width 3840 --height 2160 -o aurora_4k.mp4
# Quick 720p preview
loopkit generate --preset fire --duration 3 --width 1280 --height 720 -o preview.mp4
Architecture
src/
main.rs CLI entry point (clap)
lib.rs Public API
color.rs HSL-to-RGB conversion, color interpolation
renderer.rs Frame generation + ffmpeg encoding
presets/
mod.rs Preset trait + registry
plasma.rs Sine wave interference
gradient.rs Flowing color gradients
aurora.rs Northern lights
waves.rs Ocean waves
fire.rs Fire/lava
The rendering pipeline:
- Parse CLI arguments with clap
- Look up the preset function from the registry
- For each frame: compute
t1,t2from the circular phase, render every pixel - Save frames as PNGs in a temp directory
- Shell out to ffmpeg to encode PNGs into an MP4
- Clean up the temp directory
16 tests. All passing.
cargo test
Why Rust?
I could have built this in Python with Pillow. I chose Rust for three reasons:
1. Single binary. cargo install and you're done. No virtualenv, no pip install, no "which Python version do I need?" — just a binary in your PATH.
2. Speed. A 5-second 1080p video at 30fps means 150 frames. Each frame is ~2 million pixels. That's 300 million pixel computations. Rust handles this without flinching. Try that in Python and go make coffee.
3. No runtime. The only external dependency is ffmpeg for the final encoding step. Everything else — frame generation, color math, preset logic — is compiled into the binary.
Try It
git clone https://github.com/LakshmiSravyaVedantham/loopkit.git
cd loopkit
cargo install --path .
loopkit generate --preset plasma --duration 5 -o my_first_loop.mp4
Star the repo if this is useful: github.com/LakshmiSravyaVedantham/loopkit
Ideas for contributions:
- New presets (starfield, geometric patterns, noise landscapes)
- Parallel frame rendering with rayon
- Custom color palettes via CLI
- GIF output option
- Preview mode (single frame to PNG)
Stock footage sites are charging $50 for math. Now you have the math for free.
Top comments (0)