Plays your digital remuxes at their original quality and adds a layer of real-time 35 mm projection emulation, rendered live on your GPU. Nothing is re-encoded, nothing is lost: the file decodes bit-perfect, and shaders add organic grain, gate weave, lamp flicker, halation, vignette, dust and hairs on top — like a 2000s movie-theater print.
(Icon in grainlight.ico, shortcut launcher GRAINLIGHT.lnk — if you move
the folder, run Crear acceso directo GRAINLIGHT.bat to regenerate it.
Promo material in promocion/.)
⚠️ This runs on your PC (connected to the projector over HDMI), not on a network player like a Zidoo — those can't run GLSL shaders. mpv's graphics engine (libplacebo) matches or beats dedicated players for scaling and playback quality anyway.
GRAINLIGHT is free and always will be. If it's useful to you, here's every way to help fund it — and whatever comes next: claude.ai/code/artifact/…
- Download mpv for Windows (shinchiro's build, file
mpv-x86_64-...7z) from: https://github.com/shinchiro/mpv-winbuild-cmake/releases - Extract mpv.exe into this project's
mpv\folder (you should end up withmpv\mpv.exe, next tompv\portable_config). - Done. Double-click 35MM Player.bat.
- Double-click
35MM Player.bat→ a file picker opens to choose a movie. - You can also drag an .mkv onto the .bat.
- Starts in fullscreen with Preset 2 (2000s Cinema) active.
| Key | Function |
|---|---|
| 0 | CLEAN SLATE — removes 35mm image, analog audio, ambient and any adjustments: 100% pure remux |
| 1 | Preset 1 · Subtle — fine Vision3-style grain, imperceptible weave |
| 2 | Preset 2 · 2000s Cinema — print with contrast, halation, occasional dust |
| 3 | Preset 3 · Worn Print — coarse grain, flicker, dust and hairs |
| 4 | Preset 4 · Balanced — preset 2's warm print colors with preset 3's coarse grain, hairs and weave |
| 7 | Audio · Clean — original remux track |
| 8 | Audio · 35mm Optical — theater optical band: cinema compression, rounded highs |
| 9 | Audio · Vinyl — 33rpm wow, harmonic warmth |
| + / - | Volume up / down |
| m / right-click | Menu — presets, audio/subtitle tracks, ambient, open file |
| b | Cycle ambient modes (off, ambilight, blurred, subtle) |
| M | Mute |
| a | Cycle audio track |
| s / S | Cycle / hide subtitles |
| n | Cinema-style subtitles — theater typeface, printed into the film (with grain on top) |
| t / T | Raise / lower subtitles (useful if the film has baked-in bars) |
| Space | Pause |
| ← → | Seek ±10 s · ↑ ↓ ±60 s |
| f | Fullscreen |
| i | Technical stats (bitrate, fps, codec…) |
| r | Reset image (if you bumped brightness/contrast/gamma by accident) |
| q | Quit, saving position |
| Layer | What it does |
|---|---|
| Grain | v2 grain: integer PCG hashing (no banding, no repeating patterns) + 3 octaves of interpolated noise approximating the Gaussian distribution of real silver-halide crystals, plus a fine per-pixel sparkle. Denser in midtones, with a touch of per-channel color variation. Applied after scaling so it stays crisp at your display resolution. |
| Gate weave | Slow drift plus per-frame micro-jitter, like a projector's mechanical pull-down. |
| Flicker | Subtle lamp-brightness fluctuation. |
| S-curve + saturation | A photochemical print's contrast response: solid blacks, livelier color, slight lamp warmth. |
| Halation | A warm halo around highlights (light bouncing off the film base). |
| Vignette | Soft light falloff in the corners, from the projection lens. |
| Dust & hairs | Specks and fibers that last 1–2 frames, like debris on the print or in the gate. |
| Cue marks | Reel-change marks in the top-right corner, just like real theaters: a warning dot and, 8 s later, a change dot, 4 frames each. Every 15 min on preset 2, every 12 on preset 3 (tunable via CUE_PERIOD, in seconds). |
Same principle as the video: the track decodes intact and filters apply in
real time (scripts/audio-presets.lua). Works with 5.1.
- 8 · 35mm Optical — the band response of a theater optical track (55 Hz–9.5 kHz), a presence lift at 2.2 kHz for dialogue clarity, and gentle cinema-style compression.
- 9 · Vinyl — low-end warmth (90 Hz), a subtle 0.55 Hz wow (like a 33rpm turntable), and a light touch of harmonic sheen.
- 7 · Clean — back to the original track instantly.
Both presets get their character from shaped EQ, not saturation — there's a
transparent limiter (alimiter) at the end that only catches peaks, adding
no distortion of its own.
Parameters (frequencies, wow depth…) live in
mpv\portable_config\scripts\audio-presets.lua.
Two things at once: a theater typeface (warm ivory with a thin dark outline,
like subtitles burned into a print) and blending the subtitles into the
frame before the shaders run — grain, dust, even cue marks fall on the
letters too, as if they were printed into the film. To pull that off it
switches temporarily to the classic renderer (vo=gpu, the only one that
supports it; the screen flashes once on toggle) and restores the modern one
on exit. Colors live in mpv\portable_config\scripts\sub-style-35mm.lua.
Size (menu → Subtitles → Size): Small (~4%) / Normal (~5%) / Large (~6.3%) / XL (~7.8%) / XXL (~9.5%) — approximate capital-letter height relative to the height of the actual picture (Normal ≈ theater standard). Always applied (with or without cinema mode, combined with content-anchoring) and remembered.
In every submenu the active choice is marked with <<, and picking an
option doesn't close the menu — try presets/ambient/sizes and see the
result instantly; it only closes with Esc, m, or backing out from the top
level. ("Open movie…" does close it, since it opens a file dialog.)
Cinema fonts (menu → Subtitles → Cinema font): system typefaces tied to real film subtitling/titling — Candara (laser-engraved Titra style), Century Gothic (geometric title-card look), Franklin Gothic Medium (classic Hollywood poster), Tahoma (digital cinema, Cinecav-style), Gill Sans MT (British prints). Your pick is remembered.
Position: in normal mode subtitles sit in the classic spot any player uses (bottom, using the bars if there are any). Content-anchoring only kicks in with cinema mode active:
Anchored to the real picture: turning on cinema mode measures the black
bars (even when they're baked into the file) and places subtitles 6%
above the bottom of the picture (close to theater standard) at a size
proportional to the picture — never inside the black bars. The margin is
MARGIN inside sub-style-35mm.lua, and t / T nudge the height live.
For 21:9 (or 4:3) films that leave black bars on a 16:9 screen: the fill is generated from the film itself (heavily reduced, blurred, and re-expanded), with the original overlaid untouched on top — zero quality loss.
- Ambilight — washed color reflections, like Philips TV tech.
- Blurred expansion — the film enlarged and blurred behind itself.
- Subtle cinema — a faint glow, barely visible, like YouTube's ambient mode.
Automatic baked-in bar detection: most 21:9 remuxes have the black bars recorded right into the video (16:9 container). GRAINLIGHT detects them automatically (~2 s after opening the film) and crops them, with two consequences:
- With a 35mm preset active and ambient off, grain/dust/vignette/cue marks act only on the real picture — the bars stay pure black (painted by the renderer, outside the shaders).
- With an ambient mode active, the fill takes over the bars and the effects cover the whole canvas (on purpose, so it reads as one image).
Detection needs to see picture: if a film opens on minutes of black, it may not crop yet — switch presets (key 1/2/3) during a lit scene to re-measure.
Requires a CPU copy of the video (hwdec=auto-copy-safe, enabled
automatically); on 4K this raises CPU usage somewhat. Parameters (blur,
saturation, fill brightness) live in
mpv\portable_config\scripts\ambient-modes.lua.
From the menu: Idioma / Language → Spanish or English. Saved to
mpv\portable_config\35mm-prefs.conf and remembered between sessions
(along with your chosen subtitle font).
Each preset is a file in mpv\portable_config\shaders\. At the top of each
block are #defines for the parameters (GRAIN, WEAVE, VIGNETTE,
DUST_PROB…). Edit, save, and press the preset's key again — it reloads
instantly, even mid-playback.
- Set Windows' (or the projector's) video output to 23 Hz / 24 Hz for
perfect cinema cadence;
video-sync=display-resamplehandles the rest. - Using an AV receiver and want bitstreaming (TrueHD/Atmos/DTS-HD)?
Uncomment the
audio-spdif=...line inmpv\portable_config\mpv.conf. - HDR material: presets are tuned for SDR; they still work on HDR but contrast/halation behave differently. On an SDR display, mpv tone-maps automatically and the presets look as designed.
GRAINLIGHT's own files (shaders, Lua scripts, configuration, launchers,
icon) are MIT licensed — see LICENSE.
mpv itself is not bundled in this repository. It's a third-party project under the GPL-2.0-or-later license; download it yourself following the instructions above. Its license is independent of this project's.