From ea8f1ba1ace33597b4fc2400a8dca5bb277d6360 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 24 Aug 2026 15:51:42 +0000 Subject: [PATCH] The banners wear the logo's own mark, not an emoji MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Yesterday's hero put an emoji in a ring where each README's logo sits: 🧠 for the Brain, 📋 for the Mind. Beside the real logo — a circuit brain of traced lines and nodes; a profile head with a check inside it — the emoji read as a cartoon of the mark rather than the mark. `MARKS` now holds each organ's glyph as inline SVG line art traced off its `logo.png`: the ring (closed, or opened where the logo opens it), the glyph, and the small filled nodes the family draws with. Drawn rather than embedded, because these pages are single self-contained files read on phones over mobile data: a mark is ~1KB of path data that inherits the accent and stays sharp at any size, where the logo PNG is 80-150KB. Three details of the logos the hero was missing come with it: the wordmark's gradient (Brain runs blue → violet, Memory violet → purple; `glow2`, falling back to `glow` for the flat four), the hairline-and-dot rule between wordmark and tagline that every logo carries, and a hero glow that sits behind the glyph instead of pouring off the top edge — the logos are near-black with a breath of colour, so each lift drops about a third. The umbrella board still has no logo to sample; its helix is drawn in the same language so it sits in the family. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01FhsBsESQUAoJQ2fvLiDD5j --- board/_theme.py | 267 +++++++++++++++++++++++++++++++++----- tests/test_board_theme.py | 24 +++- 2 files changed, 257 insertions(+), 34 deletions(-) diff --git a/board/_theme.py b/board/_theme.py index 18ad7ed..364c51f 100644 --- a/board/_theme.py +++ b/board/_theme.py @@ -11,12 +11,18 @@ import it and ask for the stylesheet, the hero and the small components; they keep owning what goes in the rows. -The design in one line: *the page wears its organ's logo*. Each organ has an -accent taken from its logo's glyph colour, and every board opens with a dark -hero reproducing that logo's wordmark — white `PyAuto`, accent-coloured organ -name, letterspaced tagline underneath, inside the logo's ring. Below the hero -the page returns to a plain readable document, because these are lists people -scan on a phone before breakfast, not dashboards to admire. +The design in one line: *the page wears its organ's logo*. Every board opens +with a dark hero that redraws the logo it sits under: the organ's own mark in +line art, the wordmark (white `PyAuto`, the organ name in its accent), the +hairline-and-dot rule, and the letterspaced tagline. Below the hero the page +returns to a plain readable document, because these are lists people scan on +a phone before breakfast, not dashboards to admire. + +The mark is **drawn, not borrowed**. An emoji stood in for it at first, which +read as a cartoon beside the real logo — 🧠 is not the Brain's circuit brain. +`MARKS` holds each logo's glyph as inline SVG line art traced off the file: +it inherits the accent, stays sharp at any size, and costs ~1KB in the one +page that uses it, where the 80-150KB `logo.png` would be most of the page. Colour carries meaning, never decoration: @@ -30,8 +36,9 @@ `ORGANS` is the palette table, keyed by the same board names as `config/policy.yaml` `board: boards:` — that mapping is the declared config surface an adopting fork replaces, so no repo is named here. Five of the six -palettes are sampled from the actual logo files: the glyph colour and the -wordmark's own tagline, straight off `logo.png` in each organ's repo. The +palettes are sampled from the actual logo files: the mark, the glyph colour +and the wordmark's own tagline, straight off `logo.png` in each organ's repo. +The umbrella board has no logo, so its accent and tagline are designed to sit in the family instead. Every accent is checked for >= 4.5:1 contrast against its own background (light on `#fff`, dark on `#0d1117`). @@ -41,50 +48,215 @@ # ink_light / ink_dark: the accent as *text*, per colour scheme. # glow: the logo's own glyph colour — used only on the dark hero, where it # needs to sing rather than pass a contrast check against white. +# glow2: the far end of the wordmark's gradient, for the two logos that set +# their organ name in one (Brain runs blue → violet, Memory violet → +# purple). Omitted where the logo's wordmark is a flat colour. # hero: (lift, base) — the hero's radial gradient, echoing each logo's # vignette: a tinted lift behind the wordmark falling to near-black. ORGANS = { "mind": { "organ": "Mind", - "glyph": "\U0001f4cb", "tagline": "Intent. Priority. Flow.", + "tagline": "Intent. Priority. Flow.", "ink_light": "#0a7d72", "ink_dark": "#2ee6cf", "glow": "#00d1ba", - "hero": ("#0a3f39", "#000000"), + "hero": ("#07302b", "#000000"), }, "brain": { "organ": "Brain", - "glyph": "\U0001f9e0", "tagline": "Reason. Plan. Decide.", + "tagline": "Reason. Plan. Decide.", "ink_light": "#2159c9", "ink_dark": "#6f9dff", "glow": "#4d8bff", - "hero": ("#1b2a6b", "#000312"), + "glow2": "#a855f7", + "hero": ("#16234f", "#000312"), }, "heart": { "organ": "Heart", - "glyph": "❤️", "tagline": "Check. Validate. Protect.", + "tagline": "Check. Validate. Protect.", "ink_light": "#b50f1a", "ink_dark": "#ff6b73", "glow": "#ff1c28", - "hero": ("#4a0a10", "#000000"), + "hero": ("#37080d", "#000000"), }, "hands": { "organ": "Hands", - "glyph": "\U0001f6e0️", "tagline": "Build. Execute. Deliver.", + "tagline": "Build. Execute. Deliver.", "ink_light": "#9a5400", "ink_dark": "#ffa733", "glow": "#ff9201", - "hero": ("#4a2c00", "#000000"), + "hero": ("#372100", "#000000"), }, "memory": { "organ": "Memory", - "glyph": "\U0001f4da", "tagline": "Remember. Learn. Evolve.", + "tagline": "Remember. Learn. Evolve.", "ink_light": "#6b34d6", "ink_dark": "#b37eff", "glow": "#b37eff", - "hero": ("#2e1a5c", "#000000"), + "glow2": "#8b5cf6", + "hero": ("#221345", "#000000"), }, # The umbrella is the one board with no logo to sample: the accent and # the tagline are designed to sit in the family rather than read off a # file. Replace both from the logo if that repo ever grows one. "organism": { "organ": "Scientist", - "glyph": "\U0001f9ec", "tagline": "Describe. Build. Release.", + "tagline": "Describe. Build. Release.", "ink_light": "#0b6fa4", "ink_dark": "#5ec7f5", "glow": "#38bdf8", - "hero": ("#0c3f5c", "#00070d"), + "hero": ("#092e43", "#00070d"), }, } + +# ----------------------------------------------------------------- marks --- +# Each organ's logo glyph, traced off `logo.png` as line art on a 48x48 grid: +# a ring (closed, or left open where the logo opens it), the glyph inside it, +# and the small filled nodes the family's drawing style uses. Stroke colour +# is inherited, so one mark serves the hero, light mode and dark mode alike. +# +# Why drawn rather than embedded: the boards are self-contained single files +# read on phones over mobile data. The logos are 80-150KB of PNG each; these +# are ~1KB of path data, stay sharp on any screen, and take the accent. +# Keep them that way — a mark is a logo's glyph in line art, not a rendering. +MARKS = { + # Mind — a left-facing head profile, a check inside the skull, three + # node-tipped signal lines leaving the back of the head, inside a ring. + "mind": ( + '' + '' + '' + '' + '' + '' + '' + '' + '' + ), + # Brain — a circuit brain: two lobed hemispheres either side of a spine, + # each branching into elbowed, node-tipped traces, inside a ring. + "brain": ( + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + ), + # Heart — a heart outline crossed by an ECG trace, with the check badge + # sitting in the ring's lower-right gap. + "heart": ( + '' + '' + '' + '' + '' + ), + # Hands — an open palm offering a gear, speed lines behind the cuff, + # inside a ring left open at the lower-left where the lines enter. + "hands": ( + '' + '' + '' + '' + '' + '' + '' + ), + # Memory — an open book with a node-tree growing out of its spine and a + # scatter of stars, under an arc open at the bottom. + "memory": ( + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + ), + # Umbrella — no logo to sample, so the family language (ring, line-art, + # node dots) applied to the double helix the board already carried. + "organism": ( + '' + '' + '' + '' + '' + '' + '' + '' + ), +} + import html as _html WORD = "PyAuto" # the half of every wordmark that stays white @@ -100,6 +272,18 @@ def organ(key): return ORGANS.get(key, ORGANS["organism"]) +def mark(key): + """The organ's logo glyph as an inline SVG, drawn in the current colour. + + Unknown keys fall back with `organ()`, so an adopting fork's board wears + the umbrella's mark rather than rendering an empty ring. + """ + art = MARKS.get(key) or MARKS["organism"] + return ('') + + # -------------------------------------------------------------------- css --- # One stylesheet, two colour schemes, one substituted accent. Kept in the # same dense hand-wrapped style as the renderers that inline it: this ships @@ -108,7 +292,8 @@ def organ(key): :root{color-scheme:light dark;--bg:#fff;--fg:#1f2328;--muted:#59636e; --line:#d8dee4;--btn:#f6f8fa;--ok:#1a7f37;--warn:#9a6700;--bad:#d1242f; --accent:%(ink_light)s;--tint:%(ink_light)s14;--edge:%(ink_light)s3d; - --hero-lift:%(hero_lift)s;--hero-base:%(hero_base)s;--glow:%(glow)s} + --hero-lift:%(hero_lift)s;--hero-base:%(hero_base)s;--glow:%(glow)s; + --glow2:%(glow2)s} @media(prefers-color-scheme:dark){:root{--bg:#0d1117;--fg:#f0f6fc; --muted:#9198a1;--line:#2c333c;--btn:#151b23;--ok:#3fb950;--warn:#d29922; --bad:#f85149;--accent:%(ink_dark)s;--tint:%(ink_dark)s1f; @@ -127,23 +312,37 @@ def organ(key): /* --- hero: the logo, rendered as type ---------------------------------- */ .hero{margin:0 -1rem 1.4rem;padding:2.1rem 1.4rem 1.7rem;position:relative; overflow:hidden;text-align:center;color:#fff;background:var(--hero-base); - background-image:radial-gradient(105%% 130%% at 50%% -25%%, - var(--hero-lift) 0%%,var(--hero-base) 68%%)} + background-image:radial-gradient(78%% 104%% at 50%% 14%%, + var(--hero-lift) 0%%,var(--hero-base) 72%%)} @media(min-width:46rem){.hero{margin:1rem 0 1.6rem;border-radius:16px}} .hero::after{content:"";position:absolute;left:12%%;right:12%%;bottom:0; height:2px;background:linear-gradient(90deg,transparent,var(--glow), transparent);opacity:.75} -.orb{display:inline-flex;align-items:center;justify-content:center; - width:3.1rem;height:3.1rem;margin-bottom:.85rem;border-radius:50%%; - font-size:1.45rem;line-height:1;border:1.5px solid var(--glow); - background:radial-gradient(circle,#ffffff14 0%%,transparent 70%%); - box-shadow:0 0 22px -4px var(--glow)} +/* The mark carries its own ring, so the frame is light and glow only — + the logos set their glyph on black with a halo, not in a chip. */ +.orb{display:block;width:5.6rem;height:5.6rem;margin:0 auto .75rem; + color:var(--glow);filter:drop-shadow(0 0 9px %(glow)s7a)} +.orb svg{display:block;width:100%%;height:100%%} .hero h1{margin:0;font-size:1.85rem;line-height:1.1;font-weight:700; letter-spacing:-.022em;color:#fff} -.hero h1 b{color:var(--glow);font-weight:700} +/* Two wordmarks run their organ name as a gradient; for the rest --glow2 + repeats --glow, so the same rule paints a flat colour. */ +.hero h1 b{font-weight:700;color:var(--glow); + background:linear-gradient(96deg,var(--glow),var(--glow2)); + -webkit-background-clip:text;background-clip:text} +@supports(-webkit-background-clip:text){ + .hero h1 b{-webkit-text-fill-color:transparent}} .hero .kind{display:block;margin-top:.5rem;font-size:.66rem;font-weight:600; letter-spacing:.26em;text-transform:uppercase;color:#ffffffa6} -.hero .tag{margin:.85rem 0 0;font-size:.63rem;font-weight:600; +/* The hairline with a lit dot at its centre: every logo separates wordmark + from tagline with one, and it is the detail that reads as "same mark". */ +.hero .rule{position:relative;width:11.5rem;height:1px;margin:1rem auto .75rem; + background:linear-gradient(90deg,transparent,var(--glow),transparent); + opacity:.7} +.hero .rule::after{content:"";position:absolute;left:50%%;top:50%%; + width:.4rem;height:.4rem;margin:-.2rem 0 0 -.2rem;border-radius:50%%; + background:var(--glow);box-shadow:0 0 7px 1px var(--glow)} +.hero .tag{margin:0;font-size:.63rem;font-weight:600; letter-spacing:.3em;text-transform:uppercase;color:var(--glow);opacity:.9} .lede{margin:0 0 .9rem} /* --- sections ---------------------------------------------------------- */ @@ -231,7 +430,8 @@ def css(key): o = organ(key) lift, base = o["hero"] sheet = _CSS % {"ink_light": o["ink_light"], "ink_dark": o["ink_dark"], - "glow": o["glow"], "hero_lift": lift, "hero_base": base} + "glow": o["glow"], "glow2": o.get("glow2", o["glow"]), + "hero_lift": lift, "hero_base": base} chips = "".join(_CHIP % {"sel": f'.boards a[data-organ="{k}"]', "light": v["ink_light"], "dark": v["ink_dark"]} for k, v in ORGANS.items()) @@ -240,16 +440,17 @@ def css(key): # ------------------------------------------------------------- components --- def hero(key, kind, lede_html=""): - """The masthead: the organ's logo re-drawn as type. + """The masthead: the organ's logo re-drawn — mark, wordmark, rule, tagline. `kind` is what this page *is* under the wordmark ("Dashboard", "Board"), so the mark stays the organ's and the page keeps its own name. """ o = organ(key) lede = f'

{lede_html}

' if lede_html else "" - return (f'
{o["glyph"]}' + return (f'
{mark(key)}' f'

{WORD}{o["organ"]}' f'{kind}

' + f'
' f'

{o["tagline"]}

{lede}') diff --git a/tests/test_board_theme.py b/tests/test_board_theme.py index 760b250..d4b4b94 100644 --- a/tests/test_board_theme.py +++ b/tests/test_board_theme.py @@ -30,10 +30,13 @@ def test_every_declared_board_has_a_complete_palette_entry(): for key in POLICY_BOARDS: assert key in _theme.ORGANS, key o = _theme.ORGANS[key] - for field in ("organ", "glyph", "tagline", + for field in ("organ", "tagline", "ink_light", "ink_dark", "glow", "hero"): assert o.get(field), f"{key}.{field}" assert len(o["hero"]) == 2 + # The mark is the logo's own glyph; a board without one would render + # an empty ring where its logo should be. + assert key in _theme.MARKS, key def _luminance(hex_colour): @@ -71,11 +74,30 @@ def test_each_board_wears_its_own_accent(): assert _theme.ORGANS["mind"]["glow"] not in brain +def test_every_mark_is_line_art_that_takes_the_accent(): + # The marks replaced emoji precisely so they inherit the organ colour and + # stay sharp; a hard-coded fill or a stray emoji would undo both. + for key, art in _theme.MARKS.items(): + assert "currentColor" in art or "