Skip to content

Ordered Dither Plate

A gradient quantised to a few tones by an 8x8 Bayer matrix — offset then quantised, dithered in linear light, one cell per device pixel.

Proeditorialminimalbrutalist
Category
Backgrounds
Added
2026-09-21
Deps
none
Updated
2026-09-21

This is a viberdy Pro component

The live preview, the props panel and the write-up are open to everyone. The full source, the AI prompt and CLI install are part of Pro.

Preview
bayer 8×8 · linear light
3 tones · 2px cell

Props

3
2
0.22
No runtime dependencies
"use client";

import { useEffect, useRef } from "react";

// RECURSIVE BAYER CONSTRUCTION. M(2n) = [[4M, 4M+2], [4M+3, 4M+1]], which is
// the only ordering that spreads consecutive thresholds as far apart as
// possible. A hand-typed 8x8 table is where the typos live.
function bayer(order: number): number[][] {
  let m = [[0, 2], [3, 1]];
  for (let s = 2; s < order; s *= 2) {
    const n = m.length;
    const out: number[][] = [];
    for (let y = 0; y < n * 2; y++) out.push(new Array(n * 2).fill(0));
    for (let y = 0; y < n; y++) {
      for (let x = 0; x < n; x++) {
        const v = m[y][x] * 4;
        out[y][x] = v;
        out[y][x + n] = v + 2;

  // ---------------------------------------------------------------
  // Full source available with a viberdy Pro subscription.
  // https://viberdy.dev/pricing
  // ---------------------------------------------------------------
}
Notes

About this background

Ordered dithering is the newspaper-plate look, and it is routinely confused with halftoning. A halftone varies dot area on a screen rotated to an angle; ordered dithering keeps a fixed grid and varies which cells cross the threshold, with no dot and no screen angle — which is exactly why it reads as a printed plate rather than a photograph of one. Three details separate a working implementation from the usual broken one. The Bayer matrix is a signed OFFSET rather than a threshold: normalise it into minus a half to plus a half, add it to the tone, then quantise. Compare the tone against the matrix instead, as most attempts do, and every pixel resolves to the darkest or lightest level, so the whole midtone range collapses into a hard cut and the gradient disappears. The quantisation has to happen in linear light, because a gradient as authored is sRGB-encoded — a display curve, not a measure of light — and quantising it directly gives the shadows too many steps and the midtones too few, leaving a visible band across the middle. And the canvas backing store has to match device pixels, since the matrix is defined on a pixel grid: size it to CSS pixels and let the browser scale it and the cell structure resamples into grey mush with moire crawling through it. The matrix itself is built recursively rather than typed out, because one wrong entry in a hand-written table shows up forever as a speck.

Curator’s note

Compare the tone against the Bayer value and you get a hard cut; add the value as a signed offset and you get a gradient. Same table, opposite result.

Related

Pairs well with

Matched on shared tags and category — the entries most likely to be used alongside this one.

Featured
NewPro

A rotated print screen that swells into a pool of light under the pointer, with the gamma actually done right.

canvashalftoneprint
Featured
NewPro

A live Gray-Scott solver as a background plate — coral, mitosis and maze are the same two equations at different feed and kill rates.

canvasgenerativesimulation
Featured
New

A canvas dot grid that bulges and brightens away from the cursor.

backgroundcanvascursor