Artifact 438f8cad889d5e69d7fce22b2d3330f5fa9df21b24712d3564028ae06aced98b:
- File
internal/idn/idn.go
— part of check-in
[0ba22dea9e]
at
2026-08-23 22:31:40
on branch trunk
— markdown: mentions carry the identity mark, quotes are visible
An @mention now renders the same glyph as the person's byline, through the resolver seam so markup still knows nothing about accounts. The identicon moved to internal/idn — web and api each hashed the name separately and agreed by luck. Blockquotes had no rule at all. (user: dmestas, size: 2471) [annotate] [blame] [check-ins using]
// Package idn is quarry's identity mark: one hue and one small grid per // person, derived from the name alone. // // It lives on its own because THREE packages need the same answer and a // person must look the same in all of them. web draws the mark beside a // byline, api hands it to the markup resolver so an @mention carries it, // and both hash the name to the same hue. When userHue was written twice — // once in web, once in api — nothing checked that the two agreed; they did, // by luck, and a one-character edit in either would have given the same // person two colours on the same page. package idn import ( "fmt" "hash/fnv" "strings" "sync" ) // Hue is the person's colour, 0-359. One hue per person keeps the mark // recognisable at a glance: the colour IS the identity as much as the // pattern is. func Hue(name string) int { h := fnv.New64a() h.Write([]byte(name)) return int(h.Sum64() % 360) } var memo sync.Map // name -> string // Mark is the person's identicon as an inline SVG: a 5x3 half-grid // mirrored into a 5x5 face, in two lightness steps of their hue, on a wash // of the same hue. // // Memoised because a busy page draws the same handful of people dozens of // times, and the answer never changes. func Mark(name string) string { if v, ok := memo.Load(name); ok { return v.(string) } h := fnv.New64a() h.Write([]byte(name)) v := h.Sum64() hue := v % 360 cells := v >> 9 // 15 bits: which of the 5x3 half-grid cells are on shades := v >> 24 // 15 more: which on-cells take the deeper shade if cells&0x7FFF == 0 { cells = 0x1084 // a degenerate hash still gets a face: centre column } var b strings.Builder fmt.Fprintf(&b, `<svg class="idn" viewBox="-0.6 -0.6 6.2 6.2" aria-hidden="true">`) fmt.Fprintf(&b, `<rect x="-0.6" y="-0.6" width="6.2" height="6.2" rx="1" fill="hsl(%d, 45%%, 50%%)" fill-opacity="0.14"/>`, hue) deep := fmt.Sprintf("hsl(%d, 62%%, 40%%)", hue) lit := fmt.Sprintf("hsl(%d, 60%%, 56%%)", hue) cell := func(x, y int, fill string) { fmt.Fprintf(&b, `<rect x="%d" y="%d" width="1" height="1" rx="0.22" fill="%s"/>`, x, y, fill) } for row := 0; row < 5; row++ { for col := 0; col < 3; col++ { i := uint(row*3 + col) if cells>>i&1 == 1 { fill := lit if shades>>i&1 == 1 { fill = deep } cell(col, row, fill) if col < 2 { cell(4-col, row, fill) } } } } b.WriteString(`</svg>`) out := b.String() memo.Store(name, out) return out }