socle

stand-variety: every pedestal is its own drawing

commit fd556e017253d30d61df7bbe7278a19c521c8aad · parent 6b3477bda1 · browse this tree
Ximianth, 2026-10-30 14:53:07 UTC

Each entrance stand's pedestal is generated fresh, seeded by its repo name:
same silhouette, same family, a different hand's wobble -- a sketchbook,
not a rubber stamp.  Drawn inline with currentColor strokes, so one drawing
follows the ink through both color schemes (the per-scheme asset pair that
CSS backgrounds force is not needed here), and the index needs no extra
fetches.  The name now sits on the cap (the tune-name-on-cap item):
baseline on the cap's top edge, descenders kissing the stroke.

On its own branch for separate judgment: if nine different wobbles read as
noise rather than a hand, this dies here.
diff --git a/chrome.go b/chrome.go
index 6c97770..586ed8b 100644
--- a/chrome.go
+++ b/chrome.go
@@ -242,15 +242,14 @@ article ul.entrance {
 	gap: 2.8rem 1.5rem;
 }
 .stand { text-align: center; min-width: 0; }
-.stand .name { font-size: 1.35rem; margin: 0; }
+/* The name sits on the cap (negative margin; the svg below is its seat). */
+.stand .name { font-size: 1.35rem; margin: 0 0 -7px; position: relative; }
 .stand .name a { text-decoration: none; }
 .stand .name a:hover { text-decoration: underline; }
-.stand .pedestal {
-	height: 84px;
-	background-position: top center;
-	background-size: 140px 84px;
-	background-repeat: no-repeat;
-}
+/* Each stand's pedestal is its own inline drawing (seeded by the repo name;
+   see standSVG): currentColor strokes follow the ink through both schemes. */
+.stand .pedestal { height: 84px; color: var(--ink); }
+.stand .pedestal svg { display: block; margin: 0 auto; }
 .stand .placard {
 	font-size: .8rem;
 	letter-spacing: .12em;
@@ -494,7 +493,7 @@ func sketchCSS(scheme string) string {
 	return fmt.Sprintf(`
 .flank { background-image: %s; }
 footer.ground .floor { background-image: %s; }
-.stand .pedestal, .emptyroom .pedestal { background-image: %s; }
+.emptyroom .pedestal { background-image: %s; }
 .marquee .pedestal { background-image: %s; }
 /* Hand-ruled lines replace solid borders on the nav and headings. */
 nav.crumbs, article h1, article h2 {
diff --git a/pages.go b/pages.go
index edf48c0..2179ccd 100644
--- a/pages.go
+++ b/pages.go
@@ -100,7 +100,7 @@ var indexTmpl = template.Must(template.New("index").Parse(`<header class="marque
 <ul class="entrance">
 {{range .Rows}}<li class="stand">
 <p class="name"><a href="/{{.Name}}/">{{.Name}}</a></p>
-<div class="pedestal"></div>
+<div class="pedestal">{{.Pedestal}}</div>
 {{if or .Description .LangColor}}<p class="placard">{{if .LangColor}}<span class="swatch" style="background:{{.LangColor}}" title="{{.Lang}}"></span>{{end}}{{.Description}}</p>
 {{end}}{{if .Head}}<p class="showing" title="latest commit on {{.Branch}}">{{.Head}}</p>
 {{end}}</li>
@@ -109,6 +109,7 @@ var indexTmpl = template.Must(template.New("index").Parse(`<header class="marque
 
 type indexRow struct {
 	Name        string
+	Pedestal    template.HTML // this repo's own pedestal drawing; see standSVG
 	Description string
 	Branch      string // the default branch the caption was read from
 	Head        string // subject of the newest commit on the default branch; empty if none
@@ -120,7 +121,7 @@ func (s *server) serveIndex(w http.ResponseWriter, r *http.Request, snap *snapsh
 	var rows []indexRow
 	for _, name := range sortedNames(snap.repos) {
 		rp := snap.repos[name]
-		row := indexRow{Name: name, Description: rp.description, Branch: rp.defaultBranch()}
+		row := indexRow{Name: name, Pedestal: template.HTML(standSVG(name)), Description: rp.description, Branch: rp.defaultBranch()}
 		// Enrichment is best-effort, matching the caption's existing stance:
 		// the entrance still stands when one repo cannot answer.
 		if cs, err := rp.commits(row.Branch, 1); err == nil && len(cs) > 0 {
diff --git a/sketch.go b/sketch.go
index 7d1582a..0c422b1 100644
--- a/sketch.go
+++ b/sketch.go
@@ -373,6 +373,29 @@ func faviconSVG(seed string) []byte {
 	return []byte(sb.String())
 }
 
+// standSVG is one entrance pedestal, drawn fresh for one repo: the plinth family's
+// geometry, seeded by the repo's name, so no two stands in the gallery are the same
+// drawing.  Emitted inline in the page (not served as an asset) with currentColor
+// strokes, so one drawing follows the page's ink through both color schemes --
+// which is also why this one, unlike its asset siblings, needs no per-scheme pair.
+func standSVG(name string) []byte {
+	rng := newSketchRand("stand/" + name)
+	var sb strings.Builder
+	svgOpen(&sb, 140, 84)
+	boxes := func(d *strings.Builder, amp, over float64) {
+		roughBox(d, rng, 20, 10, 100, 14, amp, over)
+		roughBox(d, rng, 34, 24, 72, 40, amp, over)
+		roughBox(d, rng, 10, 64, 120, 16, amp, over)
+	}
+	var d1, d2 strings.Builder
+	boxes(&d1, 1.0, 2.5)
+	boxes(&d2, 1.5, 3.0)
+	svgPath(&sb, d1.String(), "currentColor", 1.6, 0.75)
+	svgPath(&sb, d2.String(), "currentColor", 1.2, 0.28)
+	sb.WriteString("</svg>\n")
+	return []byte(sb.String())
+}
+
 // plinthGrandSVG is the marquee's pedestal: the same cap/die/plinth family at the
 // entrance-masthead size, drawn natively rather than scaled so the stroke weight
 // stays in step with its siblings.  The site's own name stands on this one.
diff --git a/testdata/pages.md b/testdata/pages.md
index c523dc4..b0f2f97 100644
--- a/testdata/pages.md
+++ b/testdata/pages.md
@@ -51,7 +51,11 @@ test
 <ul class="entrance">
 <li class="stand">
 <p class="name"><a href="/fixturama/">fixturama</a></p>
-<div class="pedestal"></div>
+<div class="pedestal"><svg xmlns="http://www.w3.org/2000/svg" width="140" height="84" viewBox="0 0 140 84">
+<path d="M19.1 10.1C53.2 10.5 87.3 10.1 121.4 10.1M119.8 8.9C120.6 14.3 119.4 19.7 119.6 25.2M120.2 23.6C86.3 23.6 52.4 23.9 18.4 23.8M19.7 24.7C20.1 19.1 20.0 13.5 19.8 8.0M32.8 24.5C57.5 23.9 82.3 23.8 107.0 24.4M106.1 23.3C106.9 37.6 106.6 51.8 106.1 66.1M106.1 64.4C81.5 64.5 57.0 64.2 32.4 64.4M34.2 64.6C35.1 50.6 33.6 36.6 34.1 22.6M9.6 64.4C50.4 64.5 91.2 63.4 132.0 63.7M130.3 63.9C129.7 69.7 130.8 75.5 130.2 81.3M130.8 79.6C90.3 79.6 49.8 79.9 9.3 79.5M9.6 80.0C9.1 74.3 10.7 68.7 10.2 62.9" fill="none" stroke="currentColor" stroke-width="1.6" stroke-opacity="0.75" stroke-linecap="round"/>
+<path d="M17.8 10.5C52.4 9.7 87.0 9.0 121.6 10.3M120.5 9.4C119.6 15.0 121.6 20.6 120.2 26.2M121.4 23.8C86.8 24.4 52.1 22.7 17.5 23.7M20.0 24.9C20.1 19.2 19.2 13.5 20.3 7.9M31.3 23.4C56.9 22.4 82.4 23.1 108.0 24.3M105.9 22.0C106.3 36.0 106.1 50.1 105.8 64.1M108.2 63.9C82.7 63.3 57.2 64.7 31.7 64.6M34.5 64.7C35.2 50.6 33.7 36.5 34.6 22.3M9.0 64.1C50.2 63.6 91.4 64.8 132.6 63.9M130.1 61.9C129.7 68.9 128.7 76.0 130.0 83.0M129.9 80.6C89.2 80.6 48.5 81.2 7.8 79.4M10.6 80.9C10.0 74.4 9.1 67.8 9.5 61.2" fill="none" stroke="currentColor" stroke-width="1.2" stroke-opacity="0.28" stroke-linecap="round"/>
+</svg>
+</div>
 <p class="placard"><span class="swatch" style="background:#00ADD8" title="Go"></span>the fixture</p>
 <p class="showing" title="latest commit on main">add docs and src</p>
 </li>