diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 06d75a2..ba657d3 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -31,10 +31,21 @@ jobs: # commit the push carried at once. That SHA is all zeros on a # branch's first push and may be gone after a force push, so it # is only used when the clone actually has it. + # + # The base is fetched at full depth, not --depth=1. A shallow + # fetch writes .git/shallow and grafts the branch one commit + # deep, and because the base shares its history with this one + # that truncates the whole clone: git log -- then reports + # the graft point rather than the commit that last touched the + # file, which is what the sitemap-dates check reads. It failed + # on every page at once the first time a pull request ran after + # that check was added, naming today's date for files nobody had + # touched. fetch-depth: 0 above already pays for the history, so + # there is nothing to save here. run: | BASE="" if [ -n "${{ github.base_ref }}" ]; then - git fetch --no-tags --depth=1 origin "${{ github.base_ref }}" + git fetch --no-tags origin "${{ github.base_ref }}" BASE="origin/${{ github.base_ref }}" elif git cat-file -e "${{ github.event.before }}^{commit}" 2>/dev/null; then BASE="${{ github.event.before }}" diff --git a/index.html b/index.html index f5c1001..e4987b9 100644 --- a/index.html +++ b/index.html @@ -193,7 +193,7 @@ files (not the vendored third-party ones, which are pinned and don't change). Bump it whenever style.css or generator.js changes, or a returning visitor's cached copy silently goes stale. --> - + + it moves, a still is the default, and the flash warning here + should not be the first line a new visitor reads. + + The warning is a sentence in the description rather than a + paragraph of its own: the section was four lines tall before + a single control, and a notice that takes that much room gets + read past as chrome. -->

Animation

-

Plays on the canvas as soon as you pick one.

-

Motion flashes the whole canvas. Skip it if flashing affects you.

+

Plays as soon as you pick one. Skip it if flashing affects you.

+ Opens at thirteen and a half, well up from the three it + used to and the two the example clips in examples/ were + rendered at. A background is looked past rather than at, + and at three seconds a whole turn of the field goes by + inside a glance, which reads as something demanding + attention rather than something behind the work. Slow + enough and the canvas is never seen to move, only to have + moved. The ladder is eight steps to a doubling, so step 46 + is 13454ms, which the panel rounds to 13.5s. + + This is long enough to matter to a GIF. One pass is 168 + frames at the 80ms the preview draws at, and the byte + budget below affords 69 on the default canvas, so an + export is slow motion at about 5fps. That reads fine at + this cycle length and is what GIF_FRAME_BUDGET's comment + anticipates; it is not a sign the budget is wrong. --> +
- + either. Stepped is the difference between them. + + Opens at four, not the two it used to. Two seconds is + about as long as it takes to notice what a composition is + doing, so rerolling on it means never seeing one settle; + four gives each one a beat to be looked at before the next + replaces it. Step 32 is exactly 4000ms. --> +

Saved states

@@ -892,7 +912,7 @@

Export & share

It stops at three. Five and eight were here, and under Motion they are what took an export to 1.9GB of retained - frames on the Web preset: the budget now trims that, but + frames at 1080p: the budget now trims that, but what it trims is the frames within each pass, so both settings bought more passes by making every one of them too coarse to read as motion. They cost nothing with @@ -2056,7 +2076,7 @@

Flield: seamless animated b // frame is width x height x 4 bytes and an export retains all of // them at once, before the encoder has allocated anything of its // own. Measured on the default 1200x630 canvas that is 2.9MB a - // frame, so the 240 above is 700MB; on the Web preset's 1920x1080 + // frame, so the 240 above is 700MB; on a hand-typed 1920x1080 // it is 7.9MB a frame and 1.9GB, which is past what a phone's tab // survives and enough to hang a desktop one. Canvas size is a free // text field, so there is no size this can assume. Whichever of the @@ -2386,9 +2406,15 @@

Flield: seamless animated b render(); } - // Web and Tablet are real, recognizable resolutions (1080p; iPad - // portrait) that also happen to divide evenly by most of the block - // size range. Mobile's old 375x812 (iPhone X) was both a narrower, + // Web is the 1200x630 the document already opens at, so the chip is + // lit on arrival rather than offering a size nothing starts on. It + // is a wide canvas to work from, not a screen to fill: the + // width field is free text, so anyone wanting 1080p or wider types + // it, and nobody wanting a card-sized background has to shrink one. + // Tablet is a real, recognizable resolution (iPad portrait). Both + // divide evenly by most of the block size range. + // + // Mobile's old 375x812 (iPhone X) was both a narrower, // dated reference and the one preset that couldn't tile evenly at // any block size: 375 is odd, so no even block size divides it, and // 812 only shares factors with a handful of block sizes (2, 4, 7, @@ -2405,7 +2431,7 @@

Flield: seamless animated b // so Tile forces it off. 512 is a nice round, highly divisible size // for a texture swatch, not a specific device or screen to match. const DIMENSION_PRESETS = { - web: { width: 1920, height: 1080 }, + web: { width: 1200, height: 630 }, tablet: { width: 768, height: 1024 }, mobile: { width: 400, height: 800 }, tile: { width: 512, height: 512, shapeMask: "none", symmetry: "quad" }, @@ -2440,7 +2466,7 @@

Flield: seamless animated b // Lights a preset chip while the current values still match it, // derived from state rather than from the click: Web is lit however - // the size came to be 1920x1080, Tile only while the size is square + // the size came to be 1200x630, Tile only while the size is square // with no mask and both layers on 4-way mirror, and a palette chip // only while all six of its ranges still hold. Nudge anything and // the chip goes quiet on its own. diff --git a/style.css b/style.css index 124a8c9..96d149c 100644 --- a/style.css +++ b/style.css @@ -2065,37 +2065,6 @@ button.secondary:hover:not(:disabled) { margin-bottom: var(--space-2); } -/* Two descriptions are one block, not two. */ -.field .hint + .hint { - margin-top: calc(var(--space-1) - var(--space-2)); -} - -/* One hint carries a health warning rather than an explanation. It reads - in the same colour as the description above it, because a notice that - shouts gets taken for chrome and read past. A hanging marker carries - the difference instead, the way a footnote does. */ -.hint-warn { - padding-left: 13px; - text-indent: -13px; -} - -/* An asterisk is drawn small and parked up near the ascender, so at the - text's own size it reads as a footnote mark rather than as part of the - line. 1.54em makes its ink exactly the x-height of the 12px text, and - the negative vertical-align drops it from its own baseline onto the - text's, so it fills the same band the lowercase letters do. The zero - line-height keeps the bigger glyph from opening the line box up. - 5px plus the glyph's advance is the 13px the hang is indented by, so - a second line starts under the first word rather than under the mark. */ -.hint-warn::before { - content: "*"; - font-size: 1.54em; - line-height: 0; - vertical-align: -0.356em; - padding-right: 5px; - color: var(--text); -} - /* Not in the strip above the bar on a phone: that row exists to put one control within reach of the artwork, and a paragraph in it costs a line of the picture for something already read in the sheet. */