tinyrelayfile
tinyrelay/internal/seedmark/seedmark.go/

internal/seedmark/seedmark.go raw
1// Package seedmark renders version 1 of the Seedmark avatar design without
2// JavaScript. It follows the upstream generator at c808a94; fixtures pin its
3// visual output. Avatars are decorative and are not identity verification.
4package seedmark
5
6import (
7 "strconv"
8 "strings"
9 "unicode/utf16"
10)
11
12const Version = 1
13
14var families = [...]string{"masks", "creatures", "botanical", "orbital", "landscapes", "glyphs", "woven", "machines"}
15
16var palettes = [...][4]string{
17 {"#142d36", "#f5dfad", "#ed7351", "#65c4ae"},
18 {"#24223c", "#f7dfbf", "#a89cfc", "#f7788b"},
19 {"#163b32", "#f4eacb", "#b4cf66", "#f69c64"},
20 {"#3a2330", "#ffe5b9", "#ef7689", "#8dceba"},
21 {"#1d304c", "#e8eff0", "#f4b855", "#72b9d0"},
22 {"#422d26", "#f8e8c8", "#e8a04d", "#72afa0"},
23 {"#283526", "#f4edcf", "#d3c65e", "#ed8863"},
24 {"#292745", "#efe8f5", "#d89ada", "#8fcabc"},
25 {"#18343c", "#f8e4d0", "#f88c66", "#a7cee0"},
26 {"#393127", "#f4ebd8", "#adb77a", "#da8c6f"},
27 {"#2c2440", "#fbe8c2", "#f2b54f", "#b2a1e2"},
28 {"#1b3537", "#e9f0d7", "#79c7b8", "#e5a4aa"},
29}
30
31type recipe struct {
32 Family string
33 Palette [4]string
34 Layout struct{ Variant, Flip, Tilt int }
35 Silhouette struct{ Variant, Width, Height int }
36 Features struct{ Variant, Count, Accent int }
37 Texture struct{ Variant, Marks int }
38}
39
40type rng struct{ a, b, c, d uint32 }
41
42func newRNG(seed, namespace string) *rng {
43 var framed strings.Builder
44 for _, part := range []string{"seedmark", "1", seed, namespace} {
45 framed.WriteString(strconv.Itoa(len(utf16.Encode([]rune(part)))))
46 framed.WriteByte(':')
47 framed.WriteString(part)
48 }
49 a, b, c, d := uint32(1779033703), uint32(3144134277), uint32(1013904242), uint32(2773480762)
50 for _, unit := range utf16.Encode([]rune(framed.String())) {
51 k := uint32(unit)
52 a = b ^ (a^k)*597399067
53 b = c ^ (b^k)*2869860233
54 c = d ^ (c^k)*951274213
55 d = a ^ (d^k)*2716044179
56 }
57 a = (c ^ (a >> 18)) * 597399067
58 b = (d ^ (b >> 22)) * 2869860233
59 c = (a ^ (c >> 17)) * 951274213
60 d = (b ^ (d >> 19)) * 2716044179
61 return &rng{a ^ b ^ c ^ d, b ^ a, c ^ a, d ^ a}
62}
63
64func (r *rng) integer(minimum, maximum int) int {
65 t := r.a + r.b + r.d
66 r.d++
67 r.a = r.b ^ (r.b >> 9)
68 r.b = r.c + (r.c << 3)
69 r.c = ((r.c << 21) | (r.c >> 11)) + t
70 return minimum + int(float64(t)/4294967296*float64(maximum-minimum+1))
71}
72
73func recipeFor(seed string) recipe {
74 var r recipe
75 r.Family = families[newRNG(seed, "family").integer(0, len(families)-1)]
76 r.Palette = palettes[newRNG(seed, "palette").integer(0, len(palettes)-1)]
77 layout, silhouette := newRNG(seed, "layout"), newRNG(seed, "silhouette")
78 features, texture := newRNG(seed, "features"), newRNG(seed, "texture")
79 r.Layout.Variant, r.Layout.Flip = layout.integer(0, 3), layout.integer(0, 1)
80 r.Layout.Tilt = [...]int{-12, 0, 12}[layout.integer(0, 2)]
81 r.Silhouette.Variant = silhouette.integer(0, 3)
82 r.Silhouette.Width, r.Silhouette.Height = silhouette.integer(26, 38), silhouette.integer(28, 42)
83 r.Features.Variant, r.Features.Count = features.integer(0, 3), features.integer(2, 5)
84 r.Features.Accent = features.integer(0, 1)
85 r.Texture.Variant, r.Texture.Marks = texture.integer(0, 2), texture.integer(2, 4)
86 return r
87}
88
89// Avatar returns a standalone 64-pixel SVG for the full seed. The version 1
90// geometry remains fixed; CSS may resize the SVG without changing its design.
91func Avatar(seed string) string {
92 r := recipeFor(seed)
93 render := map[string]func(recipe) string{"masks": masks, "creatures": creatures, "botanical": botanical, "orbital": orbital, "landscapes": landscapes, "glyphs": glyphs, "woven": woven, "machines": machines}
94 texture := ""
95 for i := 0; i < r.Texture.Marks; i++ {
96 x := float64(8 + i*6)
97 if r.Texture.Variant == 1 {
98 texture += circle(x, 6, 1.5, r.Palette[3])
99 } else if r.Texture.Variant == 2 {
100 texture += rect(x-1, 5, 3, 3, 0, r.Palette[2])
101 }
102 }
103 flip := "1"
104 if r.Layout.Flip != 0 {
105 flip = "-1"
106 }
107 transform := "translate(32 32) rotate(" + strconv.Itoa(r.Layout.Tilt) + ") scale(" + flip + " 1) translate(-32 -32)"
108 return `<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64"><rect width="64" height="64" fill="` + r.Palette[0] + `"/>` + texture + group(render[r.Family](r), transform) + `</svg>`
109}

About

ownerc01503e8035f
visibilitypublic
headd730679639bf

Maintainers

  • c01503e8035f owner
  • ba1b5beed5b5 agent hermes

Clone

  • https://012.run/npub1cq2s86qrtadf36eqq3epm38wmhdynrrcwxf84eldk3f94dkv7ttsrulrz5/tinyrelay.git

Refs