Skip to content

Halftone Depth Field

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

Probrutalisteditorialminimal
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
√coverage · srgb decoded

Props

14
45
0.06
210
Decode gamma
Map by area
No runtime dependencies
"use client";

import { useEffect, useRef } from "react";

/**
 * A halftone screen that reacts to the pointer.
 *
 * Two pieces of colour science decide whether the tonal ramp looks even or
 * looks like a bad photocopy, and both are one line each:
 *
 *  · the eye integrates the AREA of a dot, not its radius, so radius has to go
 *    as the square root of the intended coverage;
 *  · coverage is a LINEAR-LIGHT quantity while the tone you are aiming at is
 *    sRGB-encoded, so it must be decoded before the square root is taken.
 */

/** sRGB transfer function, inverse. A 50% sRGB grey is ~21% linear light. */
function srgbToLinear(c: number): number {

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

About this background

A halftone is a tonal ramp made of dots, and two pieces of colour science decide whether that ramp reads as even or as a bad photocopy. The first is that the eye integrates the AREA a dot covers, not its radius — and area goes as radius squared, so a dot sized in direct proportion to the tone you want delivers that tone squared, and every midtone collapses toward the dark end. The correction is a square root. The second is that coverage is a linear-light quantity while the tone being aimed at is sRGB-encoded, and a 50% sRGB grey is only about 21% of the light; without running the target through the inverse transfer function first, the midtones come out far too bright. Both are exposed as switches here, because the failure modes are much easier to believe when you can toggle them. Two details come straight from print. Full coverage needs a radius of pitch over root two rather than half the pitch — at exactly half, neighbouring circles only touch and leave about a fifth of the area as diamond-shaped gaps, so the darkest tone never goes solid. And the screen is rotated, because an axis-aligned dot grid bands hard against any horizontal or vertical edge in the content and moirés against the pixel grid itself; the lattice is generated rotated rather than the canvas being rotated, so the dots stay circular and culling stays trivial.

Curator’s note

Switch off 'map by area' and watch every midtone collapse. It is a square root, and it is the whole difference.

Related

Pairs well with

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

Featured
NewPro

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

canvasditherprint
Pro

A grid of dots that pulses outward in concentric ripples, drawn on canvas.

dotsmatrixcanvas
Featured
NewPro

Two photographs interleaved in hard-edged strips that wipe between each other as the pointer crosses the plate.

imagemaskprint