@wrkspace/shell
theme

Dithering

the ordered bayer engine under every texture

shell paints its progress bars, spinners, skeletons, avatars and surfaces with an ordered dithering engine instead of css gradients. it is a small, framework-free set of functions that turn a continuous value into a pixel texture.

each pixel is compared to a threshold from a fixed matrix at its (x, y) position. a value above the threshold is on, below is off.

this produces a regular, repeatable texture with no per-pixel state, so it is cheap and deterministic. the bayer 4×4 matrix, below, is the coarsest option.

0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

two matrix sizes trade chunkiness for banding. bayer 4×4 shows the visible retro tile; bayer 8×8 is fine enough to read as smooth.

bayer 4x4 - coarse
bayer 8x8 - fine

the engine paints a single colour at varying alpha instead of different shades. an on-cell uses a higher alpha tier, an off-cell the same colour at a lower tier.

that keeps the texture readable on both light and dark themes without duplicating palettes.

drag the slider. the fill is a single accent colour, dithered by threshold.

60%

a tiny surface:

ditherLit(value, x, y, matrix?)ditherLevel(value, x, y, levels, matrix?)paintDitherBar(canvas, pct, cols, rows, fill, opts?)resolveColor(el, color?)

progress bars, spinners, skeletons, avatars, the logo, and dither surfaces all run through the same engine. browse the dither category to see them.

error diffusion (floyd-steinberg / atkinson) as an alternative to ordered bayer, for smooth classic-mac gradients with no repeating pattern.