Capture the colors and spirit of a movie — as a vinyl-like disk poster.
Every frame of a film becomes one concentric ring. Play a whole movie in a single image.
How it works · Install · Usage · Configuration · Contributing
Movinyl turns a movie into a poster: it samples thousands of frames across the runtime and paints each one as a single 1-pixel-wide concentric ring. The outermost ring is the opening shot, the innermost is the final frame — so the whole film's color journey is captured in one vibrant, vinyl-like disk. Pages add the title, year, director, runtime and an extracted color palette.
Movinyl runs natively on Linux, macOS and Windows (and in Docker). A small,
pure-Python front-end drives optimized C++ renderers and ffmpeg, with live
progress bars and an interactive dashboard. Rendering is deterministic — the
same input yields a bit-identical disk on every machine.
video ──▶ ffmpeg ──▶ 2000 frames ──▶ disk renderer ──▶ 4000×4000 disk ──▶ page
(extract) (capped 1080p) (C++ · OpenMP) PNG (title · palette · info)
| Stage | Tool | What happens |
|---|---|---|
| Extract | ffmpeg |
Pulls ~2000 evenly-spaced frames in a single pass, capped to 1080p (each frame only colors a 1px ring, so full 4K detail is wasted I/O). |
| Disk | C++ + OpenCV | Each frame → one concentric ring, filled in parallel with integer-only geometry for reproducible output. |
| Palette | Pillow | Extracts the dominant colors straight from the finished disk. |
| Info | TMDB | Looks up the official title, director and runtime (optional; degrades gracefully offline). |
| Page | C++ + Pillow | Composes the final poster: centered disk, text layers and palette. |
| Planche | Pillow | Optional printable contact sheets (grids of disks). |
Movinyl needs Python 3.8+, plus CMake, a C++ compiler, OpenCV and ffmpeg. The setup scripts handle the Python side and compile the renderers.
# Linux / macOS
./scripts/setup.sh
# add --install-system to also install opencv/ffmpeg/cmake via your package manager
# Windows (PowerShell)
./scripts/setup.ps1Check your environment at any time:
python3 -m movinyl doctorSystem libraries per platform (only if doctor reports them missing)
| OS | Command |
|---|---|
| Debian / Ubuntu | sudo apt-get install -y build-essential cmake libopencv-dev ffmpeg |
| Fedora | sudo dnf install -y gcc-c++ cmake opencv-devel ffmpeg |
| Arch | sudo pacman -S base-devel cmake opencv ffmpeg |
| macOS | brew install opencv libomp ffmpeg cmake |
| Windows | vcpkg install opencv4 ffmpeg (set VCPKG_ROOT), plus CMake + MSVC |
Tip
setup.sh / setup.ps1 create a local .venv. Activate it before running Movinyl:
source .venv/bin/activate — on Windows: .venv\Scripts\activate.
python3 -m movinyl tuiDrop videos in PROCESSING_ZONE, then use the on-screen buttons or shortcuts:
| Key | Action |
|---|---|
| d | Generate disks from the videos |
| p | Build pages from the disks |
| a | Assemble contact sheets (planche) |
| s | Setup / build the C++ renderers |
| c | Cancel the running job |
| q | Quit |
Live progress bars, a file list and clean cancellation are built in.
Name your videos Title_Year.ext (e.g. Inception_2010.mp4) and drop them in PROCESSING_ZONE:
python3 -m movinyl disk # → 4000×4000 PNG disks
python3 -m movinyl page PAGE_ZONE # → movie pages (title / year / director / palette)
python3 -m movinyl planche # → printable contact sheets
python3 -m movinyl doctor # → environment checkNo local toolchain required — everything builds inside the image:
docker build -t movinyl .
docker run --rm -v "$(pwd)/PROCESSING_ZONE:/app/PROCESSING_ZONE" movinyl diskOr with Compose (point MOVIES_DIR at your video folder):
docker compose run --rm movinyl diskTuning is done via command-line flags (not env vars):
| Flag | Command | Default | Description |
|---|---|---|---|
--n |
disk |
2000 |
Frames per video (= rings on the disk). |
--max-height |
disk |
1080 |
Cap frame resolution. Sources are never upscaled; each frame only paints a 1px ring, so this trades wasted decode/I-O for speed. Use 0 to keep full resolution. |
--overwrite |
disk |
off | Re-render disks that already exist. |
--keep-frames |
disk |
off | Keep the extracted frames instead of cleaning them up. |
--jobs |
page |
CPU count | Number of parallel page workers. |
--leave-cores |
page |
0 |
Keep N cores free so the machine stays responsive. |
--tmdb-key |
page |
bundled | Override the TMDB API key. |
The optional TMDB API key (for title/director/runtime) can also be set via the
TMDB_API_KEY environment variable — see env.example. A working
default is bundled, so it's optional.
See the open issues for proposed features and known bugs — contributions welcome!
- QR code on pages
- More page layout options
- Planche (contact sheet) rework
- Faster, resolution-aware extraction
- Cross-platform Python front-end + TUI
Made a disk you're proud of? Add it to the community album, or send us your creations by mail — it saves us re-processing movies and helps others discover new ones. Sharing is greatly appreciated.
📀 Community album · ✉️ project.movinyl@gmail.com (4000×4000 PNG files)
For code contributions:
- Fork the project
- Create your feature branch —
git checkout -b feature/AmazingFeature - Commit your changes —
git commit -m 'Add some AmazingFeature' - Push to the branch —
git push origin feature/AmazingFeature - Open a Pull Request
Distributed under the MIT License. See LICENSE for details.
Movinyl — project.movinyl@gmail.com Project link: https://github.com/Pataclop/Movinyl
