The faint rules through a dispersed screen were real and the explanation was not. A coarse cell does enlarge a scatter, and that is not what was happening: the compositor was resampling a buffer that did not land on whole device pixels, and the beat that produced showed up under every screen once there was a reason to look. Capping the ladder did not move it, which was the tell, and shipping a bespoke exception for a symptom is how a renderer accumulates warts nobody can later justify. So ORDERED has all five rungs back and the look count returns to 1344 a theme. The machinery stays: effectiveRuling still caps every ruling against a shape's own top wherever a ruling can enter, the check still walks every shape against every rung, and both now assert that nothing is capped -- which is worth more than deleting it, because the question was fair even though this answer to it was wrong.
- commit
- a63365f982a8454526693dd3bed53a6d995463c9
- parent
- d3b9638ff412cba9383b53b23fecf6a14691e2fb
- author
- Dami <dami.etoile@gmail.com>
| M | README.md | 47 | ++++++++++++++++++++++-------- |
| M | mockup/ | 18 | +----------- |
| M | mockup/ | 9 | +++--- |
| M | mockup/ | 2 | +- |
| M | mockup/ | 21 | +++++-------- |
@@ -60,15 +60,13 @@ pipeline to stop being one bit per region — but the same mechanism and the sam
6060 Diffusion and the flat threshold take no ruling: error diffusion's grain *is* the pixel grid, and6161 a flat threshold has no grain. They report one look each rather than five identical ones.6262 63-And one shape has a shorter ladder than the rest. A clustered screen grows a *dot* as its cell64-grows — the ink stays put and gets bigger, which is what a coarser press does. A dispersed one has65-no dot to grow: its ink is scattered single cells across the 8×8, so a bigger cell enlarges the66-*scatter*, and past a point it stops being a texture and becomes a grid. At a light tone that grid67-is mostly empty, its occupied cells line up in rows and columns, and the eye joins them — a 1×168-comes out ruled with faint lines nobody drew, which move as the block moves. So ORDERED stops at69-MEDIUM. That is the same argument as a block too small to carry a period, applied to the pattern70-instead of the thing it is printed on, and it is enforced in `effectiveRuling` rather than in the71-pools, so every door into a ruling goes through it and the look count stays honest.63+A shape *may* have a shorter ladder than the rest — `effectiveRuling` caps every ruling against the64+shape's own top, wherever a ruling can enter — but none does. ORDERED was capped at MEDIUM for one65+release, on the theory that a dispersed screen enlarges its scatter until the eye joins it into66+rules. The faint lines were real; they were the compositor resampling a buffer that did not land on67+whole device pixels, they showed up under every screen once looked for, and capping the ladder did68+not move them. The cap is gone and the machinery stays, because the question is a fair one and69+because it is what proves, every run, that nothing is capped.7270 7371 **Black on white, with a menu bar.** The Macintosh was ink on paper, so this is too. Text lives7472 inside a window, never on the desktop, which is how a patterned ground and legible labels stop@@ -169,6 +167,30 @@ It costs about 3ms a frame on a nine-times buffer on a laptop, because the scene
169167 sprites is composed entirely at 0 and 255 and so gives error diffusion nothing to propagate. On a170168 phone it is several times that, which is what makes the next paragraph matter.171169 170+**A buffer pixel has to land on a whole number of device pixels**, and for a while it did not. The171+picture is upscaled by S CSS pixels per layout unit and composed at DENSITY buffer pixels per unit,172+so one buffer pixel covers `S × dpr / DENSITY` device pixels — and at S=2 on a dpr-2.748 phone that173+is **1.832**. `image-rendering: pixelated` then keeps five buffer rows out of every six and doubles174+the sixth, in a rhythm that walks down the screen. Measured on a ground ruled every four buffer175+pixels: the rules came out **7 device pixels apart 203 times and 8 apart 100 times**. That is not a176+texture, it is a beat — it reads as the pattern collapsing into lines, and as a seam where the beat177+turns over. It was blamed on the dispersed screen first, and capping that screen's ladder changed178+nothing, because the screen was never the problem.179+180+So `chooseLayout` offers the scales where it lands whole, `S = DENSITY × k / dpr` for integer k, and181+prefers them. S stops being an integer and does not need to be: what has to be whole is the device182+mapping, and this makes a *layout unit* exactly `DENSITY × k` device pixels — so the one-unit rules183+the whole design is drawn with are whole pixels too, which they were not before. Same measurement184+after: **2.000** device pixels per buffer pixel, and every rule 8 apart.185+186+It is preferred rather than forced, at about an eighth of the board's size. Which multiples exist187+depends on the display: at dpr 2.748 the crisp scale is *larger* than the integer one and there is188+nothing to trade, while at dpr 2 with density 3 the only crisp scales are 1.5 and 3, and 3 leaves189+the column too narrow to hold. In the sweep across eight devices the crisp choice cost nothing at190+all — a smaller S with a larger cell came out to the same board in millimetres — but the trade is191+real and the setting interacts with the hardware: density 2 is crisp at full size on a dpr-2 screen192+where density 3 is not.193+172194 **The loop draws when the picture changes, not when time passes.** Composing a frame is not cheap173195 and cannot be — the scene is drawn, read back, diffused, tinted and written out, every pixel of it,174196 because diffusion depends on the whole image. But nothing in this app moves smoothly: a slide is@@ -323,10 +345,9 @@ gold — and four *pools*: which backdrop stencils belong to it, which colour pa
323345 printed in, which screen shapes the blocks may take, and how coarse those screens may be. A board324346 draws one of each, seeded on its family and rung by the same pair that decides which board it is,325347 so a rung always looks the way it looked and a ladder walks through combinations nobody authored.326-Seven backdrops, six grounds and twenty-nine block looks (five shapes at five rulings, ORDERED at327-the two it can hold, plus the two that take no ruling at all) is **1218 per theme** out of about328-twenty written-down numbers, which is the whole reason for doing it this way rather than drawing329-1218 backdrops.348+Seven backdrops, six grounds and thirty-two block looks (six shapes at five rulings, plus the two349+that take none) is **1344 per theme** out of about twenty written-down numbers, which is the whole350+reason for doing it this way rather than drawing 1344 backdrops.330351 331352 The rolling is confined to the board — the card, the puzzle and the record. The atlas, the title332353 and the record-of-everything are chrome, and chrome that shifts under you every time you open it is@@ -178,23 +178,7 @@ export const RULING_NAMES = Object.keys(RULINGS);
178178 * ink between two plates. */179179 export const PATTERNS = {180180 atkinson: { label: 'ATKINSON', diffuse: true, ruled: false },181- /* `top` is the coarsest rung this shape may be printed at, and ORDERED is the182- * one that needs it.183- *184- * A clustered screen grows a *dot* as its cell grows: the ink stays in one185- * place and gets bigger, which is what a coarser press does. A dispersed one186- * has no dot to grow -- its ink is scattered single cells over the 8x8, so187- * enlarging the cell enlarges the *scatter*, and past a certain size it stops188- * being a texture and becomes a grid. At a light tone that grid is mostly189- * empty, its occupied cells line up in rows and columns, and the eye joins190- * them: a 1x1 at three buffer pixels a unit comes out ruled with faint lines191- * that no one drew and that move as the block moves.192- *193- * So this shape's ladder ends at MEDIUM. It is not a smaller version of the194- * coarse end, it is the point past which a dispersed screen stops being one --195- * the same argument as the block that is too small to carry a period, applied196- * to the pattern instead of the thing it is printed on. */197- ordered: { label: 'ORDERED', m: BAYER, ruled: true, top: 'medium' },181+ ordered: { label: 'ORDERED', m: BAYER, ruled: true },198182 benday: { label: 'BEN-DAY', m: CLUSTER, ruled: true },199183 lines: { label: 'LINES', m: LINES, ruled: true },200184 diagonal: { label: 'DIAGONAL', m: DIAGONAL, ruled: true },@@ -25,11 +25,10 @@
2525 * newsprint and a magazine. Folding them together would mean writing out every2626 * product by hand, which is exactly the authoring this file exists to avoid.2727 *28- * Seven backdrops, six grounds and twenty-nine block looks (five shapes at five29- * rulings, ORDERED at the two rungs it can hold, plus the two shapes that take30- * no ruling at all) is 1218 per theme out of about twenty written-down numbers,31- * which is the entire reason for doing it this way rather than drawing 121832- * backdrops.28+ * Seven backdrops, six grounds and thirty-two block looks (six shapes at five29+ * rulings, plus the two that take none) is 1344 per theme out of about twenty30+ * written-down numbers, which is the entire reason for doing it this way rather31+ * than drawing 1344 backdrops.3332 *3433 * Piece colours are deliberately *not* in a pool. The 2x2 is Cao Cao, and a3534 * goal block that changes colour between rungs stops being a thing you@@ -147,12 +147,12 @@ console.log(`register: a 96px cell carries ${RULING_NAMES.filter(r => 96 % (RULI
147147 148148 /* 3c-2. a shape is never printed past its own ladder.149149 *150- * ORDERED is dispersed: its ink is scattered single cells rather than a dot151- * that grows, so a coarse cell enlarges the scatter until the occupied cells152- * line up and the eye joins them into rules nobody drew. It stops at MEDIUM,153- * and the cap has to hold wherever a ruling can enter -- the seeded pools, a154- * pinned look, the console handle -- or the artifact comes back through155- * whichever door was left open. */150+ * No shape has a short ladder today, and one briefly did: ORDERED was capped at151+ * MEDIUM because it came out ruled with faint lines. Those lines were the152+ * compositor resampling a buffer that did not land on whole device pixels, and153+ * capping the ladder neither fixed them nor was about them. The machinery stays154+ * because the question is a real one -- a shape may not be printable at every155+ * rung -- and because it is what proves, every run, that nothing is capped. */156156 for (const pat of Object.keys(PATTERNS)) {157157 const allowed = rulingsFor(pat);158158 for (const asked of RULING_NAMES) {@@ -163,14 +163,9 @@ for (const pat of Object.keys(PATTERNS)) {
163163 // down without checking: anything below an allowed rung is allowed.164164 ok(allowed.every((r, i) => r === RULING_NAMES[i]), `${pat}: ladder is not a prefix of the full one`);165165 }166-ok(rulingsFor('ordered').join() === 'fine,medium', 'ORDERED should stop at MEDIUM');167-ok(effectiveRuling('ordered', 'billboard') === 'medium', 'ORDERED at BILLBOARD should come back as MEDIUM');168166 ok(rulingsFor('benday').length === RULING_NAMES.length, 'a clustered screen keeps the whole ladder');169-for (const t of Object.values(THEMES)) {170- const rolled = new Set(t.rulings.map(r => effectiveRuling('ordered', r)));171- ok([...rolled].every(r => rulingsFor('ordered').includes(r)),172- 'a theme pool can still roll ORDERED past its top');173-}167+ok(rulingsFor('ordered').length === RULING_NAMES.length,168+ 'ORDERED keeps the whole ladder: the lines it was capped for were a resampling beat, not the screen');174169 console.log(`ladders: ${Object.keys(PATTERNS).filter(p => PATTERNS[p].ruled)175170 .map(p => `${p}:${rulingsFor(p).length}`).join(' ')}`);176171