Dithering
the ordered bayer engine under every texture
shell paints its progress bars, spinners, 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.
a mini-lab for paintDitherCell. tweak density, matrix, off tier, floor, opacity and colour - every cell uses the same params.
while ordered bayer dithering uses fixed threshold matrices, error diffusion calculates quantization error per cell and distributes it to forward neighbors.
floyd-steinberg conserves 100% of error across 4 neighbors for smooth, fine-grained photographic stippling. atkinson (bill atkinson, classic mac 1984) diffuses 75% of error across 6 neighbors and absorbs 25%, keeping clean punchy highlights and shadows without worms.
classic mac and hypercard style 1-bit pixel reveals. instead of fading alpha, transitions dissolve, wipe, or open shutters using dithered threshold geometry.
play the animation or scrub progress manually to inspect the frame-by-frame pixel pattern.
a tiny surface:
ditherLit(value, x, y, matrix?)ditherLevel(value, x, y, levels, matrix?)ditherDiffusion(cols, rows, density, opts?)ditherTransitionMask(cols, rows, progress, type?, opts?)paintDitherGradient(canvas, cols, rows, from, to?, opts?)paintDitherTransition(canvas, progress, type, fill, opts?)paintDitherBar(canvas, pct, cols, rows, fill, opts?)resolveColor(el, color?)progress bars, spinners, avatars, the logo, and dither surfaces all run through the same engine. browse the dither category to see them.