Turn a folder of images into a polished MP4 video — in one command.
Slideshow Studio Pro is a Python CLI tool that takes a folder of photos and renders a professional MP4 slideshow video with:
- Ken Burns animations — smooth zoom & pan on every image
- Transition effects — fade, slide, zoom, wipe, and more
- Background music — auto-looped and faded
- Custom backgrounds — your own image, sharp or blurred
- Grid layouts — show 2, 4, 6, or 9 photos at once
- Multiple formats — YouTube, TikTok, Instagram, Cinema, Classic
- Preview mode — fast 15-second test before full render
- EXIF auto-rotation — phone photos always display upright
- Setup
- Quick Start
- Organize Your Images
- Common Options
- Transitions & Animations
- Grid Layouts
- Presets — Save & Reuse Settings
- Config File
- Interactive Wizard
- Ready-to-Run Examples
- All Options Reference
- Troubleshooting
FFmpeg handles video encoding. Install it once:
# Linux / WSL
sudo apt update && sudo apt install ffmpeg -y
# macOS
brew install ffmpeg
# Windows — download from https://ffmpeg.org/download.html and add to PATHVerify:
ffmpeg -versionpip install -r slideshow_studio/requirements.txtAll commands are run from inside slideshow_studio/:
cd slideshow_studio# Simplest possible — YouTube 1080p, random transitions & animations
python slideshow.py -i ./photos -o video.mp4
# Not sure what settings to use? Use the guided wizard
python slideshow.py --interactive
# Quick 15-second test before the full render
python slideshow.py -i ./photos -o video.mp4 --previewPut all your images in one folder (no subfolders). Name them with numbers so they sort in the right order:
photos/
001.jpg
002.jpg
003.png
004.webp
Any numbering style works — photo_01.jpg, slide003.png, img_100.jpg all sort correctly.
Supported formats: JPG, JPEG, PNG, GIF, BMP, WEBP
Any resolution is fine — scaling is handled automatically. Phone photos are auto-rotated using EXIF data so they always appear upright.
Full 1080p takes time. Generate a fast 15-second test first:
python slideshow.py -i ./photos -o video.mp4 --previewCreates video_preview.mp4 at ~480p in seconds. Check your timing, transitions, and animations — then run without --preview for the real thing.
# Music loops automatically if it's shorter than the video (default)
python slideshow.py -i ./photos -o video.mp4 -a music.mp3
# Music plays once, then silence
python slideshow.py -i ./photos -o video.mp4 -a music.mp3 --audio-behavior muteSupported formats: MP3, WAV, OGG, M4A
Audio gets automatic fade-in and fade-out — no editing needed.
By default each slide uses a blurred version of itself as the background. You can replace this with any photo:
# Sharp background (default) — background image fully visible
python slideshow.py -i ./photos -o video.mp4 --background ./bg.jpg
# Blurred background — softer look, slides stand out more
python slideshow.py -i ./photos -o video.mp4 --background ./bg.jpg --background-blurKeep your background image in a separate folder from your slides folder — otherwise it will be included as a slide.
Use -r to pick the output format:
| Value | Ratio | Resolution (1080p) | Best for |
|---|---|---|---|
youtube |
16:9 | 1920×1080 | YouTube, standard video (default) |
tiktok |
9:16 | 1080×1920 | TikTok, Instagram Reels |
square |
1:1 | 1080×1080 | Instagram posts |
cinema |
21:9 | 2520×1080 | Cinematic widescreen |
classic |
4:3 | 1440×1080 | Presentations, old-school TV |
python slideshow.py -i ./photos -o tiktok.mp4 -r tiktok
python slideshow.py -i ./photos -o insta.mp4 -r squarepython slideshow.py -i ./photos -o video.mp4 -q 720p # fast, small file
python slideshow.py -i ./photos -o video.mp4 -q 1080p # default — great balance
python slideshow.py -i ./photos -o video.mp4 -q 1440p # 2K
python slideshow.py -i ./photos -o video.mp4 -q 4k # 4K — slow, large fileTip: use
-q 720pwhile testing, then switch to1080por higher for the final export.
Use -s to set how many seconds each image stays on screen (default is 3):
python slideshow.py -i ./photos -o video.mp4 -s 2.0 # faster pace
python slideshow.py -i ./photos -o video.mp4 -s 5.0 # slow, cinematic
python slideshow.py -i ./photos -o video.mp4 -s 0.5 # very fast slideshowThe effect that plays between one image and the next:
| Value | What it looks like |
|---|---|
random |
A different effect for every pair (default) |
fade |
Smooth cross-dissolve |
fade_black |
Fades to black, then into the next image |
slide_left |
Next image slides in from the right |
slide_right |
Next image slides in from the left |
slide_up |
Next image slides in from the bottom |
slide_down |
Next image slides in from the top |
zoom_in |
Next image zooms in from the center |
zoom_out |
Current image shrinks to reveal the next |
wipe_left |
A reveal line sweeps across |
python slideshow.py -i ./photos -o video.mp4 -t fade
python slideshow.py -i ./photos -o video.mp4 -t slide_leftThe Ken Burns movement applied to each image while it's on screen:
| Value | What it looks like |
|---|---|
random |
A different movement per image (default) |
zoom_in_center |
Slowly zooms toward the center |
zoom_out_center |
Starts zoomed in, slowly pulls back |
pan_left |
Camera drifts left |
pan_right |
Camera drifts right |
pan_up |
Camera drifts upward |
pan_down |
Camera drifts downward |
zoom_in_pan_left |
Zooms in while drifting left |
zoom_in_pan_right |
Zooms in while drifting right |
corner_tl_br |
Drifts from top-left to bottom-right |
corner_br_tl |
Drifts from bottom-right to top-left |
python slideshow.py -i ./photos -o video.mp4 --animation zoom_in_center
python slideshow.py -i ./photos -o video.mp4 -t fade --animation pan_leftShow multiple images on screen at once — great for large photo collections.
| Value | Images per frame | Description |
|---|---|---|
auto |
decided for you | Best grid based on your image count (default) |
single |
1 | One image per frame |
2x1 |
2 | Side by side |
1x2 |
2 | Stacked vertically |
2x2 |
4 | 2×2 grid |
3x2 |
6 | 3 columns, 2 rows |
3x3 |
9 | 3×3 grid |
# One image per frame (most common)
python slideshow.py -i ./photos -o video.mp4 -g single
# 4 images per frame
python slideshow.py -i ./photos -o video.mp4 -g 2x2
# Let the tool decide
python slideshow.py -i ./photos -o video.mp4 -g auto
autotargets ~3 seconds per frame regardless of how many images you have. If you want every photo shown individually, always use-g single.
Save your settings once and load them any time.
python slideshow.py -i ./photos -o video.mp4 \
-r tiktok -s 2.5 -t fade --animation zoom_in_center \
--save-preset my_tiktokpython slideshow.py -i ./new_photos -o new_video.mp4 --preset my_tiktok# Same preset, different images and background
python slideshow.py -i ./other_photos -o other.mp4 --preset my_tiktok --background ./bg.jpgpython slideshow.py --list-presetsBuilt-in presets: default, tiktok
Put everything in a JSON file for complex or repeatable setups:
settings.json:
{
"images": "./photos",
"output": "video.mp4",
"aspect_ratio": "youtube",
"quality": "1080p",
"seconds_per_image": 4.0,
"transition": "fade",
"animation": "zoom_in_center",
"audio": "./music.mp3",
"audio_behavior": "loop",
"background": "./bg.jpg",
"background_blur": false,
"grid": "single"
}python slideshow.py --config settings.jsonEvery key is optional — leave any setting out to use the default.
Don't want to remember flags? Run the wizard and answer prompts step by step:
python slideshow.py --interactiveIt walks you through every setting and renders the video at the end.
python slideshow.py \
-i ./holiday_photos \
-o holiday.mp4 \
-r youtube -q 1080p \
-s 4.0 -t fade \
--animation zoom_in_center \
-a background_music.mp3python slideshow.py \
-i ./product_shots \
-o reel.mp4 \
-r tiktok -q 1080p \
-s 2.5 -t slide_left \
--animation random \
-a upbeat_track.mp3 \
--background ./brand_bg.pngpython slideshow.py \
-i ./photos \
-o instagram.mp4 \
-r square -q 1080p \
-s 2.0 -t zoom_in \
-g singlepython slideshow.py \
-i ./landscape_photos \
-o cinematic.mp4 \
-r cinema -q 1440p \
-s 5.0 -t fade_black \
--animation zoom_out_center \
--background ./dark_texture.jpg --background-blur \
-a ambient.mp3# Step 1 — quick test (creates video_preview.mp4)
python slideshow.py -i ./photos -o video.mp4 -r tiktok -s 2.5 -t fade --preview
# Step 2 — happy with it? Run the full render
python slideshow.py -i ./photos -o video.mp4 -r tiktok -s 2.5 -t fadefor folder in ./event1 ./event2 ./event3; do
name=$(basename "$folder")
python slideshow.py -i "$folder" -o "output/${name}.mp4" --quiet
echo "Done: output/${name}.mp4"
done| Flag | Long form | Default | What it does |
|---|---|---|---|
-i PATH |
--images PATH |
required | Folder containing your images |
-o PATH |
--output PATH |
required | Output .mp4 file path |
-a PATH |
--audio PATH |
none | Background music file |
--audio-behavior |
loop |
loop or mute when audio ends before video |
|
--background PATH |
none | Image used as background behind all slides | |
--background-blur |
off | Blur and darken the background image | |
-r RATIO |
--aspect-ratio |
youtube |
youtube tiktok square cinema classic |
-q QUAL |
--quality |
1080p |
720p 1080p 1440p 4k |
-s SECS |
--seconds-per-image |
3.0 |
How long each image stays on screen |
-t TYPE |
--transition |
random |
Transition effect between images |
--animation |
random |
Ken Burns movement per image | |
-g GRID |
--grid |
auto |
auto single 2x1 1x2 2x2 3x2 3x3 |
-c FILE |
--config FILE |
none | Load all settings from a JSON file |
-p NAME |
--preset NAME |
none | Load a saved preset by name |
--save-preset NAME |
none | Save current settings as a named preset | |
--list-presets |
— | List all saved presets and exit | |
--preview |
— | Fast 15-second test render at ~480p | |
--interactive |
— | Step-by-step guided wizard | |
--quiet |
— | No output except the final file path (great for scripts) | |
-v |
--verbose |
— | Print per-image and per-transition debug info |
sudo apt install ffmpeg -y- Check that the path after
-iis correct - Images must be directly in the folder — no subfolders
- Supported: JPG, JPEG, PNG, GIF, BMP, WEBP
- Check the path after
--backgroundis correct and the file exists - Make sure the background file is not inside your images folder — it would be treated as a slide
The -g auto setting groups multiple images per frame. To give every image its own frame:
python slideshow.py -i ./photos -o video.mp4 -g single- Use
-q 720pduring testing — much faster - Use
--previewfor a quick 15-second check - Downscale very large images (20MP+ camera exports) before processing
- Switch to
-q 720p - Use
--preview - Process a smaller batch of images
| Code | Meaning |
|---|---|
0 |
Success |
1 |
Invalid argument or setting |
2 |
No images found |
4 |
Output path not writable |
5 |
FFmpeg not installed |
6 |
Video encoding failed |
7 |
Out of memory |
130 |
Cancelled with Ctrl+C |