clone

an offline sliding-block puzzle game in gleam and lustre, with an endless ladder of puzzles ranked by search

Goal mark becomes an inlay; toolbar icons get their boxes

Dami committed 56a7690
The 2x2's identifying mark was a struck ring in bare paper, which fought
every screen it was drawn over -- a hard outline across a Ben-Day field or
a hatch reads as damage. It is now a tone: a disc laid down before the
threshold and put through the same screen in the same ink, so what shows
is a change in the density of the dots already there.

Denser rather than thinner. Thinning it vanished, because at a coarse
ruling the disc is barely wider than one cell of the screen and there is no
room in it for a density change to show; going the other way needs none.
It still fades at the coarsest rulings and is absent under SOLID, which
discards tone by definition.

RECORD and SETTINGS become a bar chart and a pair of sliders in hard-ruled
squares -- inline SVG on integer coordinates in currentColor, so they
invert with the box when pressed.
commit
56a7690cd4471d62b9658cc13687127694ac89bd
parent
846d74086e74399ff970a2254a72e71cc0d27200
author
Dami <dami.etoile@gmail.com>
4 files changed, +105 -20
MREADME.md25++++++++++++++
Mmockup/index.html25+++++++++++++-
Mmockup/src/render.js55++++++++++++++++++++----------
Mmockup/styles.css20+++++++++++
M README.md +25 -0
@@ -100,6 +100,31 @@ was originally built for.
100100 Nothing small is ever set on the desktop pattern — including the title screen, which is a single101101 centred window holding the title, the specimen board and the prompt. An About box, essentially.102102 103+**The goal block's mark is made of the shading, not stamped on it.** It used to be a struck ring104+in bare paper, and a struck ring is an opinion about colour: stamping paper through the middle of a105+shaded block fought whatever screen the rung drew, and a hard outline across a Ben-Day field or a106+hatch reads as damage rather than as a mark. Under almost every screen, it did.107+108+So it is a *tone* instead — a disc laid down before the threshold and put through the same screen109+in the same ink, so what shows is a change in the density of the dots already there. An inlay110+rather than an inscription, and it cannot clash with a pattern it is made of. Under a line screen111+it appears as the rules themselves bulging; under diffusion, as a solid roundel in a dotted field.112+113+Denser rather than thinner, which took a look to settle: thinning it was the first instinct and it114+vanished, because at a coarse ruling the disc is barely wider than one cell of the screen and there115+is no room inside it for a change in density to show. Going the other way needs no room — the disc116+simply runs out of paper before the field around it does. It still fades at the coarsest rulings,117+which is what a coarse screen does to any fine detail, and is a far better failure than fighting118+the pattern. Under SOLID it is absent, honestly: that screen discards tone by definition, so a mark119+made of tone has nothing to be made of.120+121+**Toolbar icons carry their boxes.** RECORD and SETTINGS are a bar chart and a pair of sliders in122+hard-ruled squares rather than words — the way a system of this vintage drew a toolbar, and the123+reason it drew the rectangle every time: an unboxed glyph on a menu bar reads as a picture of124+something rather than as a thing to press. They are inline SVG on integer coordinates with125+`crispEdges`, in `currentColor` so they invert with the box when pressed. The canvas still has no126+SVG anywhere and should not; this is DOM chrome, which is where a vector glyph belongs.127+103128 **The dev-logo** sits at the far left of the menu bar on the puzzle list, which is where a104129 Macintosh put the Apple and the reason that position reads as a signature rather than as an icon105130 someone left lying there. It is constant in shape and position; the one thing that varies is which
M mockup/index.html +23 -2
M mockup/src/render.js +37 -18
@@ -462,28 +462,47 @@ function drawBlock(c, x, y, w, h, cls, opt = {}) {
462462 c.fillRect(bx + 1, by + 1, bw - 2, 1); c.fillRect(bx + 1, by + bh - 2, bw - 2, 1);463463 c.fillRect(bx + 1, by + 1, 1, bh - 2); c.fillRect(bx + bw - 2, by + 1, 1, bh - 2);464464 }465- // A struck ring on the goal block: the one piece whose identity matters.465+ // The mark on the goal block: the one piece whose identity matters.466466 //467- // Plotted a pixel at a time rather than stroked. A stroked arc is468- // anti-aliased, and a half-covered pixel comes out somewhere in the middle of469- // the range -- which error diffusion carries happily and an ordered screen470- // does not: under a flat threshold every partial pixel fell on the ink side471- // and the ring dropped to four stray dashes. A plotted circle is either on or472- // off, so it survives whichever style the rung drew.467+ // It used to be a struck ring in bare paper, and a struck ring is an opinion468+ // about colour. Stamping paper through the middle of a shaded block fights469+ // whatever screen the rung drew -- a hard outline across a Ben-Day field or a470+ // hatch reads as damage rather than as a mark, and it did so under almost471+ // every one of them.472+ //473+ // So it is not drawn on top of the shading at all. It is a *tone*: a disc474+ // laid down before the threshold and put through the same screen, in the same475+ // ink, so what shows is a change in the density of the dots already there.476+ // An inlay rather than an inscription, and it cannot clash with a pattern it477+ // is made of.478+ //479+ // Denser rather than thinner, which took a look to settle. Thinning it was480+ // the first instinct and it disappeared: at a coarse ruling the disc is481+ // barely wider than one cell of the screen, so there is no room inside it for482+ // a change in density to show. Going the other way needs no room at all --483+ // the disc simply runs out of paper before the field around it does, and a484+ // solid roundel inside a dotted one reads at every ruling because it is not485+ // competing with the screen, it is the absence of it.486+ //487+ // Plotted span by span rather than filled as an arc: a filled path is488+ // anti-aliased, and every half-covered pixel would land on some in-between489+ // tone and become its own group in the area pass.490+ //491+ // Under SOLID it does not appear, and that is the honest outcome rather than492+ // a gap: that screen discards tone by definition, so a mark made of tone has493+ // nothing to be made of. The block is still the only 2x2 and the only red.473494 if (opt.device) {474495 const cx = Math.round(bx + bw / 2), cy = Math.round(by + bh / 2);475- let px = Math.max(3, Math.round(bw * 0.19)), py = 0, err = 1 - px;476- c.fillStyle = grey(255);477- while (px >= py) {478- for (const [ox, oy] of [[px, py], [py, px], [-py, px], [-px, py],479- [-px, -py], [-py, -px], [py, -px], [px, -py]]) {480- c.fillRect(cx + ox, cy + oy, 1, 1);481- }482- py++;483- if (err < 0) err += 2 * py + 1;484- else { px--; err += 2 * (py - px) + 1; }496+ // Generous, because the disc has to be wider than the screen's own period497+ // before it can read as a shape at all. It still fades away at the coarsest498+ // rulings, which is what a coarse screen does to any fine detail and is a499+ // far better failure than fighting the pattern.500+ const r = Math.max(3, Math.round(Math.min(bw, bh) * 0.26));501+ c.fillStyle = grey(Math.round(tone * 0.3));502+ for (let dy = -r; dy <= r; dy++) {503+ const half = Math.floor(Math.sqrt(r * r - dy * dy));504+ c.fillRect(cx - half, cy + dy, half * 2 + 1, 1);485505 }486- c.fillRect(cx - 1, cy - 1, 2, 2);487506 }488507 if (cls && PIECE32[cls]) {489508 const p = PATTERNS[opt.shading];
M mockup/styles.css +20 -0