Skip to content
Added 13 Sept 2026
Back to library
dither-gradient
Dither Gradient
Filters & Blend Modes

Dither Gradient

Featured

A two-tone field resolved by an 8x8 Bayer matrix — the 1-bit look, with the dither grid pinned to layout pixels so it survives a retina screen.

Filters & Blend Modesditherbayerretro1-bitpixelshader
lines of CSS
24lines of CSS
dependencies
0dependencies
browser, for years
Everybrowser, for years
no motion at all
Noneno motion at all
Backdrop
Fragment shader, 3 files, no dependencies. The first one is this design. The other two are the runtime, shared by every shader effect in the catalog — copy them once and the next design you add is a single file. The HTML and CSS on this page are the preview surface and the gradient shown if WebGL is unavailable; they are not a substitute for these.
components/dither-gradient.tsx
'use client'

/**
 * Dither Gradient — a two-tone gradient, resolved by an 8×8 ordered matrix.
 *
 * A gradient is the one thing CSS does perfectly, so this is deliberately
 * the opposite of one: the field is quantised to two or three tones and the
 * in-between values are carried by a Bayer threshold pattern instead of by
 * colour. What you get is the 1-bit look — Playdate, old Mac, Obra Dinn —
 * which cannot be approximated by `background-image` at any size, because
 * the pattern has to be evaluated per pixel against a moving field.
 *
 * The dither grid is expressed against `u_resolution`, not `gl_FragCoord`.
 * Threshold patterns are usually written in device pixels, and on a 2x
 * screen that halves the apparent cell size — a dither that disappears on
 * the machines designers own is not a dither.
 */

import * as React from 'react'

import { ShaderSurface } from './shader-surface'
import type { GLProgram } from './shader-runtime'

export const DITHER_GRADIENT_PROGRAM: GLProgram = {
  id: 'dither-gradient',
  kind: 'webgl',
  speed: 1,
  light: { c0: '#334155', c1: '#0f172a', c2: '#64748b', bg: '#f1f5f9' },
  dark: { c0: '#a3e635', c1: '#ecfccb', c2: '#365314', bg: '#0a0f07' },
  fragment: `
vec4 render(vec2 uv) {
  // 140 dither cells across the short axis, whatever the device pixel
  // ratio is. Aspect-corrected so the cells stay square.
  vec2 cell = floor(uv * vec2(u_resolution.x / u_resolution.y, 1.0) * 140.0);

  vec2 p = aspect(uv);
  float t = u_time * 0.09;

  /*
   * The field being dithered: a vertical ramp with slow noise on top, so
   * the boundary between tones creeps rather than sitting still. The ramp
   * has to dominate — weighted evenly with the noise, as it was, the tone
   * boundaries wander far enough that the result reads as static rather
   * than as a dithered gradient.
   */
  float field = 0.95 * (1.0 - uv.y) + 0.38 * fbm(p * 1.5 + vec2(t, t * 0.6));

  float threshold = bayer8(cell);
  float lit = step(threshold, field);
  float hot = step(threshold + 0.34, field);

  vec3 col = mix(u_bg, u_c2, lit);
  col = mix(col, u_c0, hot);
  col = mix(col, u_c1, step(threshold + 0.62, field));

  return vec4(col, 1.0);
}
`,
}

export function DitherGradient({ className }: { className?: string }) {
  return <ShaderSurface program={DITHER_GRADIENT_PROGRAM} className={className} />
}

What's included

  • The markup and the stylesheet, in whichever framework you pick
  • No runtime dependencies

Works with

  • React
  • Vue
  • Svelte
  • Tailwind
  • styled-components
  • Plain CSS

npx hoverlab add dither-gradient

Or over MCP, from your editor's agent — no account needed.

License

Free to read, copy and install, for personal and non-commercial projects. Shipping it in client work or a paid product needs Pro ($79 once). The source lands in your repo and stops being ours — no attribution, nothing to upgrade.

Was this useful?

Motion safety

Not profiled. Canvas / WebGL effect: its deliverable is a shader, and the motion profile only reads CSS.

32 more effects in Filters & Blend Modes

All of them free to read, copy and install — no account, no locked tiles, no watermarked preview. The whole catalog is open, and so are the API and the CLI.

Browse Filters & Blend Modes

Shipping one commercially

Copying the code is free. Putting it in client work or a paid product is what Pro is for — the licence, not the access.

  • A commercial licence for everything in the catalog
  • Unlimited bundle exports, in Vue, Svelte and Tailwind
  • One payment — no subscription, nothing to renew
Pro — $79 once