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.
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.
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.
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.