Skip to content

Commit 9eea3d4

Browse files
committed
fix(brand): the tab was showing a different mark from every page
Measured, not eyeballed. logo.png — what the site header, the footer, the deck, the one-pager and the social card all draw — is 44.8% violet #6E54FF and 42.6% amber #FEAD44. The icons were 85% violet background and 10.9% white mark, with no amber at all. So the browser tab showed a one-colour silhouette while every surface underneath it showed a two-colour one, and the split is the idea: two parties on two sides of one debt. It was also failing at the size that matters. White on violet has so little edge left after downscaling that at 16px it collapsed into a violet blob. docs/build-icons.py now derives all three from the one mark, on the site's own --color-surface. Checked against a light and a dark tab bar at 32/24/16px: the square is load-bearing, because on transparent the violet half disappears into dark browser chrome while the amber survives — which would have traded one inconsistency for a worse one. apple-icon is deliberately full-bleed, since iOS applies its own mask and rounding it here leaves white notches in the corners. Everything else was already consistent: header, footer and pitch nav on all three routes, both deck footers (the accent slide's white mono mark is the intended inversion), the one-pager and the OpenGraph card.
1 parent f07ef94 commit 9eea3d4

4 files changed

Lines changed: 69 additions & 0 deletions

File tree

dashboard/src/app/apple-icon.png

1.1 KB
Loading

dashboard/src/app/favicon.ico

-1.89 KB
Binary file not shown.

dashboard/src/app/icon.png

8.43 KB
Loading

docs/build-icons.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#!/usr/bin/env python3
2+
"""Regenerate the browser and app icons from the one brand mark.
3+
4+
The site, the deck, the one-pager and the social card all draw the same file:
5+
dashboard/public/logo.png — a violet half and an amber half, roughly 45/43 of the
6+
mark's pixels. The split is the idea: two parties, two sides of one debt.
7+
8+
The icons did not. They were a white silhouette on a solid violet square, so the tab
9+
showed a one-colour mark while every page showed a two-colour one, and the amber was
10+
absent entirely. Worse at 16px: white-on-violet has so little edge left after
11+
downscaling that it collapses into a violet blob.
12+
13+
So the icons are derived from the same mark, on the site's own surface colour. Checked
14+
against both a light and a dark tab bar at 16px: the square is load-bearing, because a
15+
transparent background loses the violet half against dark chrome.
16+
17+
python3 docs/build-icons.py
18+
"""
19+
20+
import pathlib
21+
from PIL import Image, ImageDraw
22+
23+
ROOT = pathlib.Path(__file__).resolve().parent.parent
24+
LOGO = ROOT / "dashboard" / "public" / "logo.png"
25+
APP = ROOT / "dashboard" / "src" / "app"
26+
27+
# --color-surface from globals.css: the same near-white the mark sits on everywhere else.
28+
SURFACE = (247, 248, 252, 255)
29+
PAD = 0.13 # breathing room so the mark does not touch the corner radius
30+
RADIUS = 0.22
31+
32+
33+
def render(size: int, rounded: bool = True, pad: float = PAD) -> Image.Image:
34+
logo = Image.open(LOGO).convert("RGBA")
35+
canvas = Image.new("RGBA", (size, size), (0, 0, 0, 0))
36+
37+
square = Image.new("RGBA", (size, size), SURFACE)
38+
if rounded:
39+
mask = Image.new("L", (size, size), 0)
40+
ImageDraw.Draw(mask).rounded_rectangle(
41+
[0, 0, size - 1, size - 1], radius=int(size * RADIUS), fill=255
42+
)
43+
canvas.paste(square, (0, 0), mask)
44+
else:
45+
canvas.paste(square, (0, 0))
46+
47+
inner = int(size * (1 - 2 * pad))
48+
mark = logo.resize((inner, inner), Image.LANCZOS)
49+
offset = (size - inner) // 2
50+
canvas.paste(mark, (offset, offset), mark)
51+
return canvas
52+
53+
54+
def main() -> None:
55+
render(512).save(APP / "icon.png")
56+
print(f" icon.png 512x512 rounded")
57+
58+
# Full-bleed: iOS applies its own mask, and rounding it here would leave the
59+
# corners transparent inside Apple's rounding — a white notch on every home screen.
60+
render(180, rounded=False, pad=0.16).save(APP / "apple-icon.png")
61+
print(f" apple-icon.png 180x180 full-bleed for iOS masking")
62+
63+
sizes = [(16, 16), (32, 32), (48, 48)]
64+
render(256).save(APP / "favicon.ico", sizes=sizes)
65+
print(f" favicon.ico {', '.join(f'{w}x{h}' for w, h in sizes)}")
66+
67+
68+
if __name__ == "__main__":
69+
main()

0 commit comments

Comments
 (0)