It’s time to present my work. It’s been in development for quite some time, and this is the first release of my main work. In fact, there are at least two works I’ve done in recent years. I decided to publish them because I undoubtedly need the community to evaluate my work and share impressions and reviews. Over time, I’ve seen, tested, and evaluated the most popular presets in the scene, and I thought I could give my opinion. These shaders have been taken and extensively modified, almost completely, with the help of AI. The scanline generator, like perhaps others, were even created from scratch and with the help of generic, free AI. The goal was to create an extremely lightweight shader capable of running on any machine. My reference hardware, an AmLogic S905x3, runs this shader without any problems, and with plenty of GPU headroom. At the same time, I wanted to recreate a truly unique feel combined with complete customization. The result I achieved was based on the perception of the final result, and not on rigorous mathematical calculations. I present my Universal Shader here, along with an explanation of the individual parameters for ease of use. I also attach an explanation of how the whole thing works. As mentioned before, the shader is in glslp format, and I tested it on my reference hardware, an AmLogic S905x3. It obviously works great on PC too. I use a 1080p monitor without HDR or anything special; a perfectly normal monitor. Therefore, I recommend a 1080p resolution, simply because I’ve never tried it at other resolutions. To give you an idea, the GPU on my reference hardware is about 10 times less powerful than the old Intel HD4600 integrated graphics from almost twenty years ago, and as mentioned previously, I still have some headroom on the GPU in my S905x3. My second project, which I’ll probably post in another thread, aims for even better rendering, but with a fraction of the resources of the Universal Shader.
Thanks to my research into how CRTs work, the Universal Shader passes the three most demanding tests of modern shaders with flying colors.
Sonic Falls The Earthworm Jim screenshot The Vectorman intro
In addition to obviously delivering sharp rendering with very few parameter changes. I tried shaders for dithering, but while they worked well on the pattern, most reduced overall detail; this was too great a compromise, as in some cases the loss of detail was significant. The Universal Shader can blend the pattern of the three aforementioned games without blurring the image too much. You’ll notice that while it provides a convincing transparency effect on certain Mega Drive games, the image isn’t blurred too much.
To adjust the “blending” of the dithering pattern, or even more simply if we just want a less precise look, we need to adjust the X-axis values for each RGB color channel of the noise filter. The Y-axis values can remain very low, around 0.02. Why only on the X-axis? The CRT cannon sweeps from left to right across the screen, moving down one line of resolution each time. While the transition between the lines (Y-axis) is quite sharp and defined by the game’s vertical resolution (value 0.02), for horizontal movement (X-axis), the pixel’s dwell time depends heavily on the video signal, which could mix the values as the brush sweeps along the X-axis. Remember that the brush always moves horizontally! For this reason, the shader value along the X-axis of the three primary colors is a fundamental parameter for determining the sharpness or blending of the pattern’s colors. By increasing the values for the X-axis of the noise shader, we increase the blending and merging of adjacent pixels along the axis.
Universal Shader Preset – CRT Emotion, Reimagined
After months of experimentation and fine-tuning, I’ve created a RetroArch shader preset that captures the warm, organic, and imperfect feel of old CRT televisions — while adding a modern touch and full customization.
This is not just a filter: it’s a creative tool for anyone who wants full control over the look of their retro games.
Preset Overview
This preset is made of 5 chained shaders , executed in sequence:
- Image Adjustment – global gamma, brightness, contrast, and saturation.
- Candy Bloom – soft glow effect, similar to a luminous halo.
- Film Noise – cinematic grain and subtle chromatic aberration.
- Frame Overlay – curved bezel with rounded corners and fade-to-black edges.
- Dynamic Dotmask – advanced CRT phosphor emulation with per-channel dynamic expansion .
The result is an image that looks like it’s being played on an old cathode ray tube, but with the quality and depth only a modern shader can provide.
Lightweight & Fast – Even on an S905X3
Despite its complexity, this shader preset is extremely lightweight .
No heavy post-processing
No expensive multiple passes
No high-resolution framebuffers
All effects are applied in a single pass per shader , with simple arithmetic operations. It runs smoothly even on low-power devices like the Amlogic S905X3 (used in many TV boxes and handhelds like the Super Console X, X96 Air, etc.).
You can expect full speed even on demanding emulators (PS1, N64, Dreamcast) on S905X3-based devices.
What Makes This Preset Unique?
Dynamic Per-Channel Phosphor Expansion
Unlike classic CRT masks (Lottes, aperture grille, etc.), here each phosphor (R, G, B) expands independently based on the original color intensity. A bright red pixel will only expand the red phosphor, and so on.
Additionally, vertical expansion can be centered (simulating a cathode ray expanding from the center of the screen) or traditional (bottom-up).
Smooth Fade-to-Black Frame
The frame isn’t just a black border. It fades smoothly toward the image with a customizable fade curve (from linear to high-power curves). This creates a very cinematic “fade to black” effect.
Adjustable Chromatic Aberration
Red, green, and blue channels can be independently shifted horizontally and vertically, creating the typical misalignment of old tubes or film stock.
Technical Breakdown of Each Shader
image-adjustment.glsl – Base Correction
| Parameter | Effect |
|---|---|
Gamma Correction |
Expands or compresses mid-tones. <1 darkens mid-tones, >1 lightens them. |
Brightness |
Shifts the whole image toward white (>0) or black (<0). |
Contrast |
Increases or decreases the difference between light and dark areas. |
Saturation |
Controls color intensity. 0 = grayscale, >1 = saturated colors. |
Candy-Bloom.glsl – Glow Effect
| Parameter | Effect |
|---|---|
Glow Level |
Overall glow intensity. |
Glow Tightness |
How tightly the glow follows bright areas. Low = diffused glow, high = concentrated glow. |
film_noise.glsl – Grain & Chromatic Aberration
| Parameter | Effect |
|---|---|
X/Y Offset Red/Green/Blue |
Independent shift of the three color channels (chromatic aberration). |
Grain Strength |
Intensity of the cinematic grain. Higher = dirtier look. |
overlay.glsl – Curved & Faded Frame
| Parameter | Effect |
|---|---|
Enable Frame |
Enables/disables the frame overlay. |
Frame Size % |
Thickness of the frame relative to the screen’s smallest dimension. |
Curve Amount |
How much the sides curve inward. |
Corner Radius % |
Roundness of the corners. |
Fade Width % |
Width of the transition zone between image and black frame. |
Fade Curve |
Shape of the transition. 1 = linear, >1 = steeper curve toward the image. |
dotmask.glsl – The Heart of the CRT Effect (
Emphasis)
This is the most important shader in the chain. It simulates the actual phosphor grid of a CRT.
| Parameter | Effect |
|---|---|
Phosphor Intensity |
How much the CRT mask affects the final image. |
Black between Phosphors |
Amount of black space between phosphors (simulates the dark grille). |
Mask Light / Dark |
Maximum and minimum brightness of lit/unlit phosphors. |
Grid Columns / Rows |
Number of columns and rows in the phosphor grid. |
Vertical Stagger |
Row shifting effect (typical of shadow mask CRTs). |
Horizontal Expansion |
How much color intensity widens the phosphor horizontally. |
Min / Max Width |
Minimum and maximum phosphor width (as a fraction of the cell). |
Vertical Expansion |
How much color intensity widens the phosphor vertically. |
Min / Max Height |
Minimum and maximum phosphor height. |
Vertical Center Expansion |
Key parameter : 0 = expansion from the bottom, 1 = symmetrical expansion from the center (simulates a beam originating from the center of the screen). |
Why is this unique? Most CRT shaders use a static mask . Here, the mask is dynamic and per-channel . A bright red pixel will literally “grow” only the red phosphor. This creates a much more organic, responsive CRT feel.
Visual Example (imaginary)
“With this preset, 8/16-bit games feel alive. The reds in Super Mario World’s title pulse, the blues in Sonic shine without washing out, and the grain adds a cinematic depth that no clean filter can match.”
Universal Shader Preset – CRT Emotion, Reimagined
Preset Overview
Lightweight & Fast – Even on an S905X3
You can expect full speed even on demanding emulators (PS1, N64, Dreamcast) on S905X3-based devices.
What Makes This Preset Unique?
Dynamic Per-Channel Phosphor Expansion
Smooth Fade-to-Black Frame
Adjustable Chromatic Aberration
Technical Breakdown of Each Shader
Emphasis)
Visual Example (imaginary)























