27

I wanted my pixel games to look like they're running on an old arcade monitor, not a crisp modern LCD. Most AI attempts gave me faint horizontal lines and called it a CRT, which fools nobody.

Asking for "scanlines" got me a 10% opacity line pattern and nothing else. A real CRT look needs scanlines PLUS barrel distortion, phosphor bloom, chromatic aberration at the edges, a subtle vignette, and a bit of flicker. I wrote the prompt to enumerate all of those as a WebGL post-process pass with intensities I could dial back.

Two answers below, both improved it. Curious how far people push the aberration before it's too much.

THE PROMPT
Write a reusable CRT post-processing effect for a 2D canvas game, implemented as a WebGL fragment shader that samples the game's rendered frame as a texture (single HTML file, vanilla JS, render the game to an offscreen canvas, then draw it through the shader to the visible canvas at 60fps).

The shader must combine ALL of these, each with a uniform so intensity is tunable 0..1:
1. Barrel/pincushion distortion (screen curvature) that bends the edges outward slightly.
2. Scanlines: darkened horizontal bands scaled to the output resolution, with a slow vertical roll option.
3. Aperture-grille / RGB subpixel mask that tints columns r/g/b faintly.
4. Chromatic aberration that increases toward the screen edges (sample r/g/b at slightly offset UVs).
5. Bloom/phosphor glow on bright pixels (cheap 1-pass blur of the bright areas, added back).
6. Vignette darkening the corners, plus a very subtle brightness flicker (sine + a little noise).

Constraints: keep it a single extra draw pass (budget under 1ms on a mid laptop); expose a `crtStrength` master uniform that scales everything so I can dial it 0 (off) to 1 (heavy). Default to a tasteful ~0.5. Respect prefers-reduced-motion by disabling the roll and flicker. Comment each effect block. Do NOT fake it with a CSS overlay; it must be a real shader sampling the frame texture.
1the 'do NOT fake it with a CSS overlay' line is exactly the constraint i was missing. models default to the lazy overlay every time.vibecoder 2 months ago
add a comment

2 Answers

19

Nice, this is the right set of ingredients. Two shader nits: apply the barrel distortion FIRST and, when the distorted UV lands outside [0,1], render black, otherwise you get smeared edge texels that look wrong. And do the scanline mask in linear space, not on the gamma-encoded color, or bright areas bloom too aggressively. For the bloom pass, a separable 5-tap Gaussian at half resolution is plenty and keeps you under budget.

THE PROMPT
In the shader: 1) compute curved UV from barrel distortion, 2) if any component of curvedUV is outside [0,1], output vec4(0,0,0,1), 3) convert sampled color to linear, apply scanline/mask/bloom in linear, then encode back to sRGB at the end.
18

If you're going for the full arcade illusion, pair this with a faint 15kHz-ish flyback whine and a power-on 'thunk' when the game boots. Sounds silly but the CRT hum is half of why the visuals feel real. I gate the whine at very low volume and let players mute it. Multi-sensory nostalgia hits way harder than the shader alone.

Your Answer