Commit Graph
3 Commits
Author SHA1 Message Date
bvandeusenandClaude Opus 5 b06a1adfe8 feat(brand): draw a reduced mark so the favicon reads at 16px
The full hat does not resolve below ~32px, which the header worked around
by sizing up. A browser tab cannot: it renders the favicon at 16px and
does not ask. There the mark was a blob.

Deriving a small form from the traced art does not work, and this is the
non-obvious part. Hole-filling, morphological smoothing and dropping
components were all tried; every one of them preserves the overall
silhouette, and the overall silhouette — dominated by a long diagonal
plume — is precisely what fails. The result each time was a diagonal
smear that reads as no object at all.

So the reduced form is drawn rather than derived: a strong horizontal
brim under a crown that peaks left of centre, a band slit so the two do
not fuse, and a short pointed plume. Same lean and proportions as the
full mark, detail removed instead of minified.

favicon.svg and favicon.png now use it; apple-touch, icon-512 and the
Android launcher icons keep the full art, being large enough for it. The
plume carries the accent, which measures 3.04:1 on obsidian and 5.43:1 on
the light ground — both clear of the 3:1 graphics floor.

Also corrects the accent-on-iron figure in the generator's comment from
2.80:1 to 2.70:1. The real --fs-iron is #1E2228; 2.80 came from measuring
against a value I had guessed rather than read.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SQ31KQpYbStyK5y58UmPLH
2026-09-09 13:49:31 -04:00
bvandeusenandClaude Opus 5 5593f7ce17 feat(brand): replace the M mark with the traced bard-hat logo
test-web / test (push) Successful in 44s
android / Build + lint + test (push) Successful in 5m9s
The mark is now a feathered hat with an arc of eighth notes, traced from
the operator's reference artwork at 99.74% IoU. The hat takes the text
colour and the note arc holds the accent — the same construction the M
used, and for the same reason: parchment on a light surface is invisible,
so the silhouette has to flip with its background while the accent stays
constant.

This reverses the subject-neutrality argument recorded in Minstrel's
design system, which held that depicting a bard would tell a new user the
app is for renaissance-faire music and had twice rejected a hat. The
operator commissioned this artwork and chose it with that objection on the
table; the record is updated rather than silently contradicted.

Both accent-filled alternatives were measured and rejected: #4A6B5C is
3.04:1 on obsidian and 2.80:1 on the raised iron, so an accent hat drops
under the 3:1 graphics floor as soon as it sits on a card.

tools/gen-brand-assets.py is the single source for the four copies, which
cannot share a file because each needs a different colour mechanism —
currentColor inlined, a prefers-color-scheme swap in the favicon, literal
fills in mark.svg, flat pixels in the rasters. Hand-copying 20KB of path
data four ways is how a silhouette change lands in three of them.

Two notes on the trace, both non-obvious: it runs on the original
antialiased greyscale rather than a binary mask, because tracing a
supersampled mask scores ~100% IoU by reproducing the pixel staircase
exactly — a perfect number for jagged art at 120KB of path, versus 99.74%
at 20KB. And potrace reads PBM where bit 1 is black, so the ink mask is
inverted going in; backwards, it traces the background and still emits a
plausible-looking SVG.

The header lockup moves 20px → 28px: the hat carries far more detail than
the M and does not resolve below ~32px. The 16px browser-tab favicon is
still a blob at that size and is not addressed here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SQ31KQpYbStyK5y58UmPLH
2026-09-09 12:52:57 -04:00
bvandeusenandClaude Opus 5 e1e591b520 feat(brand): Minstrel mark — favicon, header lockup, Android adaptive icon
test-web / test (push) Successful in 45s
android / Build + lint + test (push) Successful in 4m14s
A Didone M whose right leg is an eighth note: stem, flag and notehead in the
accent, the letter in parchment. Traced from the operator's reference at
99.74% IoU (potrace, 26 + 22 segments), so the geometry is theirs, not an
approximation of it.

Subject-neutral on purpose. "Minstrel" pulls toward a lute or a bard, which
would tell a new user this is a renaissance-faire player rather than one for
all music. A geometric letter plus universal notation says "music" without
saying which music. The family look arrives through palette and drawing
style instead of through the subject — see the design-system discussion.

Starting state: web/static/favicon.png was a 1x1 PIXEL placeholder, so there
was effectively no favicon at all; Android had legacy bitmaps only, so modern
launchers letterboxed the square instead of masking it.

## The colour problem, and why each surface differs

Parchment on white is invisible — the operator caught this. The M therefore
has to flip with its background, while the accent note holds in both:

  - mark.svg / MinstrelMark.svelte use currentColor, so the letter takes the
    surrounding text colour and one asset covers both palettes.
  - favicon.svg bakes colours with a prefers-color-scheme swap, because a
    favicon sits on browser chrome and has no cascade to inherit from.
  - PNG fallback, apple-touch-icon and Android are PLATED. A PNG can't
    respond to scheme and iOS composites onto white regardless.

MinstrelMark is inlined rather than <img src>, because an <img> cannot
inherit currentColor and inheriting it is the entire point.

## Plate colour chosen by measurement

Obsidian (#14171A), not the raised-surface iron. The accent note only clears
the 3:1 non-text contrast threshold against the darker value: 3.04:1 vs iron's
2.70:1. My own earlier suggestion — lighten the plate — is WRONG and the
numbers say so: slate scores 2.21:1, worse, because the note is a dark colour
and lifting the plate closes the gap. Recorded in colors.xml so the reasoning
sits with the value.

## Construction

Traced as a full ink silhouette with the note painted OVER it, rather than as
two separate shapes. Separate shapes needed either a 2px seam where letter and
note touch, or an anti-aliasing fringe (2,430 misclassified pixels) around the
note. Painting over avoids both and yields a monochrome version for free — the
base layer alone is the whole mark in one colour, which is what
mipmap-anydpi-v26's <monochrome> uses for themed icons.

Android foreground sits at 61% of the 108dp canvas so it stays inside the
66dp safe zone and no launcher mask can clip it.

Paths are duplicated between the component and the two static SVGs, since one
needs currentColor and the others need literals. A comment in each names the
others.

Verified by render at 16/20/32/64/180 on obsidian, white, parchment and
plated; one optical size holds across the whole range.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-03 16:37:25 -04:00