favicon: the pedestal glyph, in the theme hue
commit f748a0a9425d99f8e8afd0aa827aa651249128b3 · parent 9d1cce7ca2
· browse this tree
Ximianth, 2026-10-30 14:36:27 UTC
One asset, not per-scheme: a favicon renders on tab chrome whose color socle cannot know, so it wears the theme hue at a middle lightness that stays visible on both light and dark tab bars, with proportionally bold strokes (checked by eye at 16/32/64px against mock tabs in both chromes). Known limit: Safari ignores SVG favicons and keeps 404ing on /favicon.ico.
diff --git a/chrome.go b/chrome.go index b009eeb..0f0e5d5 100644 --- a/chrome.go +++ b/chrome.go @@ -75,6 +75,7 @@ var soclePageTmpl = template.Must(template.New("socle").Parse(`<!doctype html> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>{{.Title}}</title> <link rel="stylesheet" href="/-/style.css"> +<link rel="icon" type="image/svg+xml" href="/-/sketch/favicon.svg"> </head> <body> <div class="flank left"></div><div class="flank right"></div> diff --git a/sketch.go b/sketch.go index c4cf578..adf619e 100644 --- a/sketch.go +++ b/sketch.go @@ -5,6 +5,8 @@ import ( "hash/fnv" "math" "strings" + + "vitrine/display" ) // This file generates the sketch assets: small SVGs of hand-wobbled strokes, boxes, @@ -146,6 +148,7 @@ func sketchAssets(seed string) map[string][]byte { m["circle-"+v+"-"+p.scheme+".svg"] = circleSVG(seed+"/"+v, p) } } + m["favicon.svg"] = faviconSVG(seed) return m } @@ -345,6 +348,30 @@ func plinthSVG(seed string, p sketchPalette) []byte { return []byte(sb.String()) } +// faviconSVG is the tab's identity mark: the pedestal glyph in the theme hue. +// One asset, not per-scheme: a favicon renders on tab chrome whose color socle +// cannot know, so instead of the accent's paper-tuned per-scheme lightnesses it +// wears the same hue at a middle lightness that stays visible on both. +// Strokes are proportionally bold: at tab size the usual hairlines would vanish. +func faviconSVG(seed string) []byte { + ink := fmt.Sprintf("hsl(%d 70%% 50%%)", display.ThemeHue(seed)) + rng := newSketchRand(seed + "/favicon") + var sb strings.Builder + svgOpen(&sb, 64, 64) + boxes := func(d *strings.Builder, amp, over float64) { + roughBox(d, rng, 12, 8, 40, 9, amp, over) + roughBox(d, rng, 20, 17, 24, 29, amp, over) + roughBox(d, rng, 6, 46, 52, 10, amp, over) + } + var d1, d2 strings.Builder + boxes(&d1, 1.0, 2.0) + boxes(&d2, 1.5, 2.5) + svgPath(&sb, d1.String(), ink, 5.0, 0.92) + svgPath(&sb, d2.String(), ink, 3.0, 0.4) + sb.WriteString("</svg>\n") + return []byte(sb.String()) +} + // chipSVG is the frame's small sibling: a border-image tile for inline chips // (the ledger's sha buttons). A 48x48 tile sliced at 8 with lines at inset 4, // so a border a hair under the slice renders the stroke near 1:1; displacement diff --git a/testdata/pages.md b/testdata/pages.md index cfd6cd5..f4fe89d 100644 --- a/testdata/pages.md +++ b/testdata/pages.md @@ -30,6 +30,7 @@ Content-Type: text/html; charset=utf-8 <meta name="viewport" content="width=device-width, initial-scale=1"> <title>test</title> <link rel="stylesheet" href="/-/style.css"> +<link rel="icon" type="image/svg+xml" href="/-/sketch/favicon.svg"> </head> <body> <div class="flank left"></div><div class="flank right"></div> @@ -79,6 +80,7 @@ Content-Type: text/html; charset=utf-8 <meta name="viewport" content="width=device-width, initial-scale=1"> <title>fixturama</title> <link rel="stylesheet" href="/-/style.css"> +<link rel="icon" type="image/svg+xml" href="/-/sketch/favicon.svg"> </head> <body> <div class="flank left"></div><div class="flank right"></div> @@ -137,6 +139,7 @@ Content-Type: text/html; charset=utf-8 <meta name="viewport" content="width=device-width, initial-scale=1"> <title>fixturama @ main</title> <link rel="stylesheet" href="/-/style.css"> +<link rel="icon" type="image/svg+xml" href="/-/sketch/favicon.svg"> </head> <body> <div class="flank left"></div><div class="flank right"></div> @@ -185,6 +188,7 @@ Content-Type: text/html; charset=utf-8 <meta name="viewport" content="width=device-width, initial-scale=1"> <title>fixturama/docs @ main</title> <link rel="stylesheet" href="/-/style.css"> +<link rel="icon" type="image/svg+xml" href="/-/sketch/favicon.svg"> </head> <body> <div class="flank left"></div><div class="flank right"></div> @@ -239,6 +243,7 @@ Content-Type: text/html; charset=utf-8 <meta name="viewport" content="width=device-width, initial-scale=1"> <title>fixturama/README.md @ main</title> <link rel="stylesheet" href="/-/style.css"> +<link rel="icon" type="image/svg+xml" href="/-/sketch/favicon.svg"> </head> <body> <div class="flank left"></div><div class="flank right"></div> @@ -284,6 +289,7 @@ Content-Type: text/html; charset=utf-8 <meta name="viewport" content="width=device-width, initial-scale=1"> <title>fixturama/docs/with space.txt @ main</title> <link rel="stylesheet" href="/-/style.css"> +<link rel="icon" type="image/svg+xml" href="/-/sketch/favicon.svg"> </head> <body> <div class="flank left"></div><div class="flank right"></div> @@ -329,6 +335,7 @@ Content-Type: text/html; charset=utf-8 <meta name="viewport" content="width=device-width, initial-scale=1"> <title>fixturama/README.md @ ced91a8519</title> <link rel="stylesheet" href="/-/style.css"> +<link rel="icon" type="image/svg+xml" href="/-/sketch/favicon.svg"> </head> <body> <div class="flank left"></div><div class="flank right"></div> @@ -378,6 +385,7 @@ Content-Type: text/html; charset=utf-8 <meta name="viewport" content="width=device-width, initial-scale=1"> <title>fixturama log @ main</title> <link rel="stylesheet" href="/-/style.css"> +<link rel="icon" type="image/svg+xml" href="/-/sketch/favicon.svg"> </head> <body> <div class="flank left"></div><div class="flank right"></div> @@ -435,6 +443,7 @@ Content-Type: text/html; charset=utf-8 <meta name="viewport" content="width=device-width, initial-scale=1"> <title>fixturama commit ced91a8519</title> <link rel="stylesheet" href="/-/style.css"> +<link rel="icon" type="image/svg+xml" href="/-/sketch/favicon.svg"> </head> <body> <div class="flank left"></div><div class="flank right"></div> @@ -547,6 +556,7 @@ Content-Type: text/html; charset=utf-8 <meta name="viewport" content="width=device-width, initial-scale=1"> <title>fixturama commit 64ac67a35d</title> <link rel="stylesheet" href="/-/style.css"> +<link rel="icon" type="image/svg+xml" href="/-/sketch/favicon.svg"> </head> <body> <div class="flank left"></div><div class="flank right"></div> diff --git a/testdata/sketch.md b/testdata/sketch.md index 826c9b7..129b07b 100644 --- a/testdata/sketch.md +++ b/testdata/sketch.md @@ -227,3 +227,13 @@ Regenerate with `go test -run TestSketchSnapshots -testmark.regen` and review th </svg> ``` +### favicon.svg + +[testmark]:# (favicon.svg) +```svg +<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64"> +<path d="M10.9 7.7C24.9 8.1 38.8 8.6 52.8 8.1M52.2 6.5C51.9 10.8 51.3 15.1 51.5 19.4M52.2 17.4C38.4 18.0 24.5 16.9 10.7 16.8M12.4 16.6C11.6 13.4 12.1 10.1 11.7 6.9M20.2 16.6C28.6 17.0 37.1 16.2 45.5 16.6M44.1 16.3C43.3 26.7 44.7 37.2 43.8 47.6M44.5 46.2C35.9 45.7 27.2 46.0 18.6 46.1M19.7 47.0C19.0 37.1 20.1 27.2 19.8 17.3M5.7 46.0C23.3 46.4 40.9 45.2 58.5 45.5M58.2 46.0C58.8 49.9 58.2 53.9 58.2 57.8M59.7 56.4C41.8 55.7 23.9 56.0 6.0 55.7M6.1 56.4C6.6 52.6 5.9 48.9 6.2 45.1" fill="none" stroke="hsl(125 70% 50%)" stroke-width="5.0" stroke-opacity="0.92" stroke-linecap="round"/> +<path d="M10.0 8.5C24.7 7.6 39.4 9.4 54.1 7.6M51.8 6.3C53.2 10.7 53.1 15.1 52.0 19.5M51.7 16.7C38.4 18.4 25.1 16.8 11.9 17.5M11.3 19.6C12.2 15.2 11.4 10.8 11.8 6.4M17.1 17.6C26.1 18.7 35.0 16.3 44.0 17.4M43.5 16.9C42.3 27.2 45.0 37.3 44.0 47.6M43.3 46.3C35.1 45.2 26.9 46.6 18.8 46.2M20.2 47.3C20.5 36.3 20.8 25.4 19.3 14.6M5.6 46.4C23.1 46.4 40.7 45.2 58.2 46.4M57.7 44.0C59.1 48.7 57.4 53.5 57.7 58.3M59.4 55.5C41.0 55.3 22.6 56.3 4.3 56.0M6.7 56.2C7.4 52.7 5.5 49.5 5.4 46.1" fill="none" stroke="hsl(125 70% 50%)" stroke-width="3.0" stroke-opacity="0.40" stroke-linecap="round"/> +</svg> +``` +