Grace Kim Howard

A CRT Shader in WebGL

I.

I have a lot of love for the medium of print. Print can be blurry, it can have imperfections, but this quality is what gives it warmth and charm.

I think a similar sentiment is what underlies the digicam revival of recent years, despite the fact that high resolution cameras are ubiquitous in modern smartphones, or what drives retro game enthusiasts to seek out CRT monitors over modern displays.

Something that people often talk about is how jarring it is to play older games on newer screens — high resolution LCD or OLED monitors produce graphics that are too sharp, too blocky, too pixel perfect. This underscores the core argument put forth by retro game enthusiasts: that CRTs are uniquely suited to represent the art as it was intended, for the simple reason that CRTs were the target medium for games of this era. Console emulators such as libretro even provide shaders that replicate the visual effects of CRT screens, allowing players to experience retro games in a way that is more true to original form or, to take it further, preserving artistic intent and integrity.

While I'm not necessarily a retro game enthusiast, CRT monitors have a lot of history in the realm of new media art. They're also a lot of fun to work with. So as an exercise in nostalgia, and to pay homage to this epoch-defining technology, I decided to try piecing together my own CRT shader.

II.

During the process of iteration, I used a side-by-side view of various stills from older games until it started to look "correct" (this is kind of how it goes with GPU programming).

This screenshot of a character from Streets of Rage 2, first released for the Sega Genesis, is commonly used to showcase the difference in how pixel art is rendered on a CRT monitor.

One thing that is immediately apparent is the anti-aliasing effect, which blends together the blocky pixels and makes for a result that is much more dimensional. This distinct look and feel is the result of several technical features and properties working together in tandem, including, but not limited to:

  • Either an aperture grille or shadow mask type screen
  • Scan lines
  • Analog signal distortion (i.e., noise)
  • Light bleeding
  • Chromatic aberration
  • The curvature of the glass screen
  • Vignetting (I skipped this out of personal preference)

III.

Ultimately, I chose to soften the intensity of certain characteristics to create a visual result that aligned with my own preferences. Popular shaders used in real-time console emulation are much more faithful in their reproductions of CRT technology. While that wasn't my goal for this first attempt, I'll leave it as something to be explored in future iterations, along with a potential port to WebGPU/WGSL.