A modern Python/PyGame photo screensaver engine built to replace the sluggish, limited, and non-random Windows screensaver.
The default Windows photo screensaver is slow, non-random, handles iPhone photos poorly, and takes too long to return to the desktop.
CrystalPhoto-ScreenSaver fixes all of this with a real rendering engine:
- True randomness (deck shuffle)
- Smooth transitions
- Instant return-to-desktop
- Correct iPhone portrait scaling
- HEIC/HEIF support
- Multi-monitor stability
- Genuine random sequencing (no repeats until cycle ends)
- Smooth transitions (fade, slide, crossfade, checkerboard, blocky dissolve)
- Weighted transition system (fade = 50%)
- Instant desktop return via non-blocking event loop
- HEIC/HEIF loading via pillow_heif
- EXIF orientation correction
- Smart image scaling (landscape fill, portrait fit)
- Multi-monitor compatible rendering
- Recursive folder scanning
- Supports
/s,/p,/cWindows screensaver arguments - Packaged with PyInstaller → rename exe to .scr
- Python 3.x
- PyGame for rendering + animation
- Pillow + pillow_heif for decoding images
- PyInstaller for deployment
- Windows screensaver protocol behavior
Run fullscreen screensaver: python screensaver.py /s
Preview mode: python screensaver.py /p
Config dialog placeholder: python screensaver.py /c
-
Build with PyInstaller: pyinstaller --noconsole --onefile screensaver.py
-
Rename the output file: screensaver.exe → CrystalPhoto-ScreenSaver.scr
-
Move it into the system directory: C:\Windows\System32
-
Select it from Windows screensaver settings. Done.
- Recursive folder scan
- Filters junk files (.DS_Store, Thumbs.db, macOS "._" files)
- Accepts JPG, PNG, BMP, GIF, HEIC
- Registers HEIC opener
- Applies EXIF orientation (3/6/8)
- Converts image to RGB/A when required
- Creates PyGame surfaces via frombuffer
- Yields (surface, filename) pairs for logging
Implements a true shuffle deck:
- Build list of all images
- Shuffle once
- Pop items one by one
- When empty → reshuffle entire deck
Advantages over Windows screensaver:
- No loops or repeats
- Every image shown before repeat
- True randomness, no hidden weighting
Modular transition structure:
- fade
- slide
- crossfade
- checkerboard
- blocky dissolve
Weighted system:
- Fade used 50% of the time (best overall look)
- Others at 12.5% each
Transitions run at 30–60 FPS depending on effect.
For very large images (≥ 4K):
- Landscape: scale to fill
- Portrait: scale to fit
For normal photos:
- Scale up to 75% of screen size
- Maintains aesthetic spacing
- Prevents giant portrait dominance
Every single frame checks:
- Keyboard input
- Mouse movement
- Mouse clicks
- QUIT events
Exit sequence: pygame.mouse.set_visible(True) pygame.quit() sys.exit()
This ensures instant shutdown unlike Windows’ sluggish default screensaver.
Instead of a sleep:
- 60 FPS loop
- Each frame accumulates elapsed time
- Each frame checks for exit events
Gives:
- Instant exit
- Smooth timing
- No freeze-on-wait behavior
CrystalPhoto supports:
- /s — Start screensaver mode
- /p — Preview mode (not implemented but handled)
- /c — Config dialog
Matches native Windows .scr behavior.
- Audio disabled with SDL_AUDIODRIVER=dummy
- Single-file binary
- No console window
- Rename exe → .scr to integrate into Windows
- GPU shader transitions (moderngl)
- Ken Burns motion effect
- JSON/INI config profile
- Per-monitor tuning
- CrystalSuite unified experience integration
Created by Sapphica
Senior Firmware QA Automation Engineer • Embedded Systems • Graphics/UI Pipeline Engineer
Creator of the CrystalSuite ecosystem (CrystalLCD, CrystalPhoto, JinxLED Engine, and more)