Friday, 16 October 2026

diarioempresas

IBEX 3519.342,40▲ +0,86%EuroStoxx 506209,35▲ +0,67%S&P 5007744,06▲ +0,33%€/$1,1246▲ +0,22%Brent105,98▲ +0,06%Bitcoin72.890▼ -0,49%
Breaking

Dithering in WebGL Revives 90s Aesthetics in Websites and Apps

Dithering, a 90s technique, returns as an aesthetic resource in websites using WebGL. Bayer matrix and limited palettes achieve a recognizable retro finish.

Marta Uriarte Elizondo
Marta Uriarte Elizondo
· 4 min read

The graphics technique from the 90s returns as an aesthetic resource to differentiate 3D scenes on websites. Using a 4x4 Bayer matrix and an 8-colour palette achieves a recognizable finish.

The dithering, a technique used by 90s consoles to simulate colours that their hardware could not display, has become an aesthetic choice for websites seeking a unique finish. This is noted by ecosistemastartup.com, which analyses how this technique is applied in React Three Fiber and Three.js projects.

The key lies in post-processing: instead of modifying the geometry or materials, a shader is applied over the already rendered scene, like an image filter over a photo. In React Three Fiber, this is done by declaring a class that extends Effect, defining the fragment shader, the necessary uniforms, and wrapping everything with wrapEffect from @react-three/postprocessing to use it as a JSX component within EffectComposer.

The first experiment is white noise dithering: the luminance of each pixel is taken, compared with a random number, and a decision is made whether the result is white or black. It works, but the result is chaotic. The solution is ordered dithering, which replaces random noise with a threshold map defined by a Bayer matrix. Instead of comparing against a random value, each pixel is compared against the corresponding value in the matrix. The resulting pattern is regular and more visually pleasing.

The article shows an implementation with a 4x4 Bayer matrix: the luminance of the pixel is obtained, its position within the matrix is calculated, and compared. If the difference is positive, the pixel is white; if not, black. The size of the matrix and the shades of grey in the scene determine the final pattern.

There is a third approach, blue noise dithering, which uses a noise texture instead of a matrix. The result is a middle ground: less repetitive than ordered and less chaotic than white noise. The author had previously used it in volumetric raymarching scenes to eliminate banding or layering effects.

So far, all examples convert the scene to black and white. This is luminance-based dithering, compressing the palette to 2 bits: each pixel is either white or black, and intermediate shades appear through the dithering pattern. To recover colour, colour quantization is used, with a formula that seeks the nearest neighbouring colour based on how many colours are desired in the output. With a palette of two values per channel, 2^3 = 8 colours are obtained; with four values per channel, 4^3 = 64 colours. This range allows for an approximation of the aesthetics of old consoles and computers.

The article also includes a variant by Alex Charlton in his text “Dithering on the GPU”: instead of using the formula, he converts each pixel to HSL, finds its two nearest neighbours in hue within an arbitrary palette, and uses the distance between them to decide which to apply. It is a more artistic process, designed for hand-curated palettes.

The next leap is pixelation: remapping UV coordinates and adjusting them to a grid so that the scene appears to have lower resolution. The larger the pixel size, the more pixelated the image; but if exaggerated, the dithering pattern disappears because there are no longer enough pixels to form it. The balance between both is what makes the effect work.

The most recognisable part is the emulation of the CRT monitor. These monitors had three electron guns—one for each colour channel—that excited phosphors on the screen, with a shadow mask preventing the beams from hitting the wrong phosphor. The article reproduces the Schiltzmaske, an aperture grid where each column is offset by half a cell, generating red, green, and blue subcells. Added to this are details that make a difference: the curvature of the screen (CRTs were not flat), chromatic aberration due to beam misalignment, some bloom, horizontal scanlines, and a slight flicker.

The author of the analysis, Maxime Heckel, applies it to React Three Fiber and Three.js projects with a clear goal: to ensure that a 3D scene does not look like a generic render, but has its own style. For developers wishing to implement it, the complete code and technical explanations are available in the original article.

Marta Uriarte Elizondo

Written by

Marta Uriarte Elizondo

Redactora

Graduada en ADE por la Autónoma y emprendedora frustrada (dos veces). Coleccionista de pitch decks, cafetera y optimista pese a las estadísticas; en Diario Empresas firma las pymes y las startups.