1/// The ground: what is behind everything, when nothing is in front of it.2///3/// There used to be exactly one of these — a 4px lattice of ink dots on bare4/// paper — and it had to be drawn *into* the greyscale scene before the5/// threshold. That put a hard constraint on it: both its values had to sit at6/// the extremes, because error diffusion has no error to spread at 0 and 2557/// and so passes such a pattern through untouched. Anything with a midtone in8/// it, or in any colour other than ink and paper, was simply not available.9///10/// The ground is the *absence* of scene instead. The scene is cleared to11/// transparent, the screens paint their opaque windows onto it, and every pixel12/// still transparent when the frame is thresholded is ground. That is13/// pixel-exact occlusion for the cost of one alpha test, and it moves the14/// ground to after the threshold, where it is free to be any two colours.15///16/// So a pattern here is not a tone. It is a stencil: one bit per pixel saying17/// dot or field. Every tile is 8x8 because the period is 8 — slides are18/// quantised to it so a pattern never lands out of phase, and a tile with any19/// other period would beat against that.20///21/// They are deliberately sparse. A background is not a picture; the densest22/// here is one pixel in eight, and the lattice that shipped first is one in23/// sixteen. A ground that competes with the board is a ground that has to be24/// looked past.25import gleam/list26import gleam/result2728pub type Backdrop {29 Lattice30 Sparse31 Twill32 Rule33 Graph34 Benday35 Plain36}3738pub fn all() -> List(Backdrop) {39 [Lattice, Sparse, Twill, Rule, Graph, Benday, Plain]40}4142pub fn id(backdrop: Backdrop) -> String {43 case backdrop {44 Lattice -> "lattice"45 Sparse -> "sparse"46 Twill -> "twill"47 Rule -> "rule"48 Graph -> "graph"49 Benday -> "benday"50 Plain -> "plain"51 }52}5354pub fn from_id(value: String) -> Backdrop {55 all()56 |> list.find(fn(backdrop) { id(backdrop) == value })57 |> result.unwrap(Lattice)58}5960/// The stencil, row-major, 64 entries of 0 or 1.61pub fn tile(backdrop: Backdrop) -> List(Int) {62 case backdrop {63 // The original, preserved exactly: rows every 4px, alternate rows offset64 // by 2. One pixel in sixteen.65 Lattice -> [66 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,67 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,68 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,69 ]7071 // Two dots in sixty-four. Almost nothing — which is the point on a dark72 // theme, where the ground reads as a field of stars rather than a texture.73 Sparse -> [74 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,75 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,76 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,77 ]7879 // A single diagonal thread. The only pattern with a direction in it, which80 // is exactly why there is one and not two: crossing it with its mirror81 // doubles the density and reads as a mesh rather than a weave.82 Twill -> [83 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0,84 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,85 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,86 ]8788 // Dotted rules every 4px. A solid scanline was tried and it stripes the89 // screen; broken in half it reads as ruled paper.90 Rule -> [91 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,92 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,93 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,94 ]9596 // Graph paper: one dotted rule each way per tile.97 Graph -> [98 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,99 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,100 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,101 ]102103 // Clustered dots — the newsprint ground, and the backdrop that belongs104 // with the Ben-Day block screen. Clustered rather than dispersed is the105 // whole difference between a halftone and a dither.106 Benday -> [107 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0,108 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0,109 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,110 ]111112 // No pattern at all. Not an omission — a flat ground is a real member of113 // the family, and it is the only one that lets a pure-black theme actually114 // reach pure black across the whole screen.115 Plain -> [116 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,117 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,118 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,119 ]120 }121}