sky: stale comments, the grain file in the handler test, old weights kept (review)
Claude Fable 5.1 (both branches mergeable): comments still described five files and the intermediate state; the handler test gains grain.svg; the haze/clouds weights stay in sky.css for pages cached from when they were linked; the grain's brightness claim is stated exactly. Dark grain compared by eye with the approved sky: comparable, so no extra gain.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
5 files changed,
+22
−15
sky/generate.go+8 −7sky/placeholder.go+2 −1sky/sky.css+4 −0sky/sky.go+6 −6sky/sky_test.go+2 −1
CI passed — run details
CI log
=== modcache === all modules verified === vet === CGO_ENABLED=0 go vet ./... === fmt === === build === CGO_ENABLED=0 go build -buildvcs=false ./... === go-test === CGO_ENABLED=0 go test -count=1 ./... ok amadan.net/oficina/estilo.git/base 0.005s ok amadan.net/oficina/estilo.git/brand 0.004s ok amadan.net/oficina/estilo.git/busy 0.005s ok amadan.net/oficina/estilo.git/callui 0.005s ok amadan.net/oficina/estilo.git/chrome 0.162s ? amadan.net/oficina/estilo.git/cmd/oficina-notices [no test files] ok amadan.net/oficina/estilo.git/credits 0.006s ok amadan.net/oficina/estilo.git/credits/catalog 0.005s ok amadan.net/oficina/estilo.git/homeconnect 0.005s ok amadan.net/oficina/estilo.git/internal/lint 0.004s ? amadan.net/oficina/estilo.git/internal/tokencheck [no test files] ok amadan.net/oficina/estilo.git/menu 0.008s ok amadan.net/oficina/estilo.git/savestatus 0.075s ok amadan.net/oficina/estilo.git/sky 0.019s ok amadan.net/oficina/estilo.git/theme 0.005s
diff --git a/sky/generate.go b/sky/generate.go| index 43697ec..98935fe 100644 |
| --- a/sky/generate.go |
| +++ b/sky/generate.go |
| @@ -165,9 +165,10 @@ func Clouds(id string, t Tone) string { |
| // grainOnly is the clouds' grain as a texture of its own: faint white |
| // specks where the noise is above its middle and faint black ones where it |
| // is below, kept only where the clouds are (their alpha). Drawn with |
| -// ordinary blending, so it averages to no change in brightness over any |
| -// backdrop — an overlay blend would show its grey wherever the sky beneath |
| -// is thin, and lift the whole dark sky. grainAmp is each speck's most. |
| +// ordinary blending, so it barely moves the average brightness (a fraction |
| +// of a level; the dark specks show more on a light sky, the light ones on |
| +// a dark one) — an overlay blend showed its grey wherever the sky beneath |
| +// was thin, and lifted the whole dark sky. grainAmp is each speck's most. |
| const grainAmp = 0.34 |
| var grainOnly = fmt.Sprintf(`<filter id="n" filterUnits="userSpaceOnUse" x="0" y="0" width="1600" height="640">`+ |
| @@ -180,10 +181,10 @@ var grainOnly = fmt.Sprintf(`<filter id="n" filterUnits="userSpaceOnUse" x="0" y |
| `<feComposite in="specks" in2="SourceGraphic" operator="in"/></filter>`, |
| 2*grainAmp, -grainAmp, -2*grainAmp, grainAmp) |
| -// Grain is the clouds' texture as a layer of its own. The clouds layer |
| -// now sits over the placeholder at a quarter of its weight, which took its |
| -// grain down with it (impeccable's detector, and a zoomed look, 2026-09-29); |
| -// on its own layer the grain keeps the strength Paul chose. One file for |
| +// Grain is the clouds' texture as a layer of its own. When the placeholder |
| +// took over the sky's colour, the clouds layer that carried the grain went |
| +// faint and then unlinked (impeccable's detector, and a zoomed look, |
| +// 2026-09-29); on its own layer the grain keeps the strength Paul chose. One file for |
| // both schemes: it is the clouds' shape, not their colour. |
| func Grain(id string) string { |
| var b strings.Builder |
diff --git a/sky/placeholder.go b/sky/placeholder.go| index 5df0a36..b442c94 100644 |
| --- a/sky/placeholder.go |
| +++ b/sky/placeholder.go |
| @@ -15,7 +15,8 @@ import ( |
| // frame so the page never shows a blank where the sky will be. It plays |
| // blurhash's part without the script blurhash needs to decode: a tiny |
| // PNG, inline as a data: URI, that the browser's upscaling smooths into |
| -// the same soft nebula the SVG layers draw a moment later. |
| +// the soft nebula the haze and clouds SVGs draw — and it is now the sky's |
| +// colour on its own, with only the grain and filaments over it. |
| // |
| // It is computed, not rendered: each blob is a blurred ellipse, which is |
| // close to a Gaussian, so a pixel is the blobs' Gaussians composited in |
diff --git a/sky/sky.css b/sky/sky.css| index 0a0304d..50067a9 100644 |
| --- a/sky/sky.css |
| +++ b/sky/sky.css |
| @@ -49,6 +49,10 @@ |
| [estilo-sky] img { object-fit: cover; } |
| [estilo-sky-layer="placeholder"] { filter: blur(24px); } |
| [estilo-sky-layer="grain"] { --estilo-sky-k: 1; } |
| +/* The weights haze and clouds had when they were linked, kept for a page |
| + cached from then that still names them. */ |
| +[estilo-sky-layer="haze"] { --estilo-sky-k: 0.175; } |
| +[estilo-sky-layer="clouds"] { --estilo-sky-k: 0.25; } |
| [estilo-sky-layer="filaments"] { --estilo-sky-k: 1.3; } |
| /* One placeholder per scheme; show the one that matches. An explicit |
diff --git a/sky/sky.go b/sky/sky.go| index 74787af..b3c2f70 100644 |
| --- a/sky/sky.go |
| +++ b/sky/sky.go |
| @@ -9,9 +9,9 @@ |
| // (placeholder.go), 50x20 pixels inline, so it is there in the first frame; |
| // the grain and filaments are two static SVGs served by Handler. Handler |
| // still serves the haze and clouds SVGs too, for pages cached before they |
| -// stopped being linked. Light and dark each get their own haze and clouds; |
| -// sky.css shows the pair matching the page's scheme, drifts them slowly, |
| -// and holds them still for anyone who asks their system for less motion. |
| +// stopped being linked. Light and dark each get their own placeholder; |
| +// sky.css shows the one matching the page's scheme, drifts the sky slowly, |
| +// and holds it still for anyone who asks their system for less motion. |
| // No script. |
| package sky |
| @@ -38,7 +38,7 @@ func Templates() embed.FS { return templateFS } |
| // Prefix is the URL path Handler serves under. The version is the |
| // generator's: a change to what a given ID draws is a new version, so |
| // the year-long cache below never serves a stale sky. TestSkyGoldens holds |
| -// one sky's five files still; when it fails, the drawing changed — bump |
| +// one sky's six files still; when it fails, the drawing changed — bump |
| // the version here, then update the goldens. |
| const Prefix = "/static/estilo/sky/v1/" |
| @@ -48,7 +48,7 @@ const SuiteSeed = "oficina" |
| // Layer is one image of a sky. |
| type Layer struct { |
| - Name string // placeholder, haze, clouds or filaments |
| + Name string // placeholder, grain or filaments (haze and clouds are served, no longer linked) |
| Tone string // light, dark, or "" for both |
| Src string // a URL under Prefix; empty for the placeholder |
| // Inline is the placeholder's data: URI, typed so html/template |
| @@ -75,7 +75,7 @@ func For(seed string) View { |
| var idShape = regexp.MustCompile(`^[0-9a-f]{16}$`) |
| // draw returns the SVG for one layer file of sky id, or "" when the name |
| -// is not one of the five. |
| +// is not one of the six. |
| func draw(id, file string) string { |
| switch file { |
| case "haze-light.svg": |
diff --git a/sky/sky_test.go b/sky/sky_test.go| index cb676d7..e5cecef 100644 |
| --- a/sky/sky_test.go |
| +++ b/sky/sky_test.go |
| @@ -74,12 +74,13 @@ func TestIDIsClosedAndOpaque(t *testing.T) { |
| } |
| } |
| -func TestHandlerServesOnlyTheFiveLayers(t *testing.T) { |
| +func TestHandlerServesOnlyTheSixLayers(t *testing.T) { |
| h := Handler() |
| id := ID("acme") |
| for path, want := range map[string]int{ |
| Prefix + id + "/clouds-dark.svg": 200, |
| Prefix + id + "/filaments.svg": 200, |
| + Prefix + id + "/grain.svg": 200, |
| Prefix + id + "/clouds.svg": 404, |
| Prefix + id + "/haze-light.svg/x": 404, |
| Prefix + "ACME0000000000000/haze-light.svg": 404, |