feat(brand): use the supplied logo artwork instead of a reconstruction #90

Merged
tudor merged 2 commits from feat/brand-logo-artwork into main 2026-08-08 21:41:47 +00:00
Owner

Replaces my SVG approximation of the mark with the supplied artwork.

The reconstruction was wrong, and not subtly: the real mark is a teardrop pin with a white window and a path flowing out of its base, carrying three leaves. I had drawn a circle with a separate tail.

The supplied sheet has a genuinely transparent background, so both colourways are extracted rather than traced:

file colourway
public/brand/mark.png teal pin, white window and path, green leaves
public/brand/mark-on-dark.png white pin, counter knocked through to the ground

Why two colourways and not one

I rendered the teal artwork against every ground the site actually uses before deciding. It holds up on Warm White, white cards, Sand and both dark-theme grounds — but on the teal footer band it disappears, leaving only a floating white window with no silhouette.

So the header serves the teal artwork and swaps to the on-dark artwork for dark-theme viewers through a <picture> source — no JavaScript, no client boundary. The footer forces variant="onDark", because its band is teal in both themes.

Everything downstream derives from those two files

  • app/icon.png — favicon, replacing icon.svg
  • app/apple-icon.png — touch icon, replacing the generated apple-icon.tsx
  • public/icon-192.png, icon-512.png, icon-maskable-512.png
  • the share card, which reads public/brand/mark.png off disk so it can never drift from the header

The logo sizing CSS keyed off a square box in both the header and the footer, which would have squashed a 153:189 artwork. Height now drives and width follows.

Two judgement calls

The wordmark stays live text in Manrope. The sheet's wordmark is a raster with visible edge fringing; the written style guide specifies Manrope; and live text stays selectable, scales cleanly and recolours with the theme. Easy to switch to the image if you'd rather.

Known limitation — the 512px PWA icon is slightly soft. The largest instance anywhere on the sheet is 153×189. That is ample for the header at 38px, the favicon and the share card, but a 512px icon needs upscaling. A vector (SVG/AI/EPS) dropped into public/brand fixes it and is a single swap, because every consumer goes through components/Logo.tsx or that folder.

Verification

tsc clean, 159/159 unit tests, production build green, /icon.png and /apple-icon.png emit as static routes. The header (both themes), the footer, the share card and all five icons were rendered from the compiled output and inspected.

🤖 Generated with Claude Code

Replaces my SVG approximation of the mark with the supplied artwork. The reconstruction was wrong, and not subtly: the real mark is a **teardrop pin with a white window and a path flowing out of its base**, carrying three leaves. I had drawn a circle with a separate tail. The supplied sheet has a genuinely transparent background, so both colourways are *extracted* rather than traced: | file | colourway | |---|---| | `public/brand/mark.png` | teal pin, white window and path, green leaves | | `public/brand/mark-on-dark.png` | white pin, counter knocked through to the ground | ## Why two colourways and not one I rendered the teal artwork against every ground the site actually uses before deciding. It holds up on Warm White, white cards, Sand and **both** dark-theme grounds — but on the teal footer band it disappears, leaving only a floating white window with no silhouette. So the header serves the teal artwork and swaps to the on-dark artwork for dark-theme viewers through a `<picture>` source — no JavaScript, no client boundary. The footer forces `variant="onDark"`, because its band is teal in *both* themes. ## Everything downstream derives from those two files - `app/icon.png` — favicon, replacing `icon.svg` - `app/apple-icon.png` — touch icon, replacing the generated `apple-icon.tsx` - `public/icon-192.png`, `icon-512.png`, `icon-maskable-512.png` - the share card, which reads `public/brand/mark.png` off disk so it can never drift from the header The logo sizing CSS keyed off a **square** box in both the header and the footer, which would have squashed a 153:189 artwork. Height now drives and width follows. ## Two judgement calls **The wordmark stays live text in Manrope.** The sheet's wordmark is a raster with visible edge fringing; the written style guide specifies Manrope; and live text stays selectable, scales cleanly and recolours with the theme. Easy to switch to the image if you'd rather. **Known limitation — the 512px PWA icon is slightly soft.** The largest instance anywhere on the sheet is 153×189. That is ample for the header at 38px, the favicon and the share card, but a 512px icon needs upscaling. A vector (SVG/AI/EPS) dropped into `public/brand` fixes it and is a single swap, because every consumer goes through `components/Logo.tsx` or that folder. ## Verification `tsc` clean, 159/159 unit tests, production build green, `/icon.png` and `/apple-icon.png` emit as static routes. The header (both themes), the footer, the share card and all five icons were rendered from the compiled output and inspected. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
tudor added 1 commit 2026-08-08 21:23:58 +00:00
feat(brand): use the supplied logo artwork instead of a reconstruction
PR Checks / Frontend Typecheck + Tests (pull_request) Successful in 1m6s
PR Checks / Backend Smoke (pull_request) Successful in 7s
PR Checks / Build Backend (no push) (pull_request) Successful in 12s
PR Checks / Build Frontend (no push) (pull_request) Successful in 49s
PR Checks / Build Pipeline (no push) (pull_request) Successful in 10s
PR Checks / AI Code Review (Claude) (pull_request) Successful in 2m7s
b11ee3c8de
The mark shipped so far was my SVG approximation, and it was wrong: the real
mark is a teardrop pin with a white window and a path flowing out of its base,
carrying three leaves — not a circle with a separate tail.

Both colourways are extracted from the supplied sheet, which has a genuinely
transparent background, so these are the artwork rather than a trace:

  public/brand/mark.png          teal pin, white window and path, green leaves
  public/brand/mark-on-dark.png  white pin with the counter knocked through

Two colourways are needed, not one. Rendered against every real ground, the
teal pin holds up on Warm White, white cards, Sand and both dark-theme grounds
— but it vanishes on the teal footer band, where only the white window
survives. The header therefore serves the teal artwork and swaps to the
on-dark artwork for dark-theme viewers through a <picture> source, needing no
JavaScript; the footer forces on-dark, because its band is teal in both
themes.

Everything downstream now derives from those two files: the favicon
(app/icon.png, replacing icon.svg), the touch icon (app/apple-icon.png,
replacing the generated apple-icon.tsx), the three PWA rasters, and the share
card, which reads public/brand/mark.png off disk so it can never drift from
the header. The logo sizing CSS keyed off a square box, which would have
squashed a 153:189 artwork — height now drives and width follows.

The wordmark stays live text in Manrope. The sheet's wordmark is a raster with
visible edge fringing, and the written style guide specifies Manrope; live
text also stays selectable, scales cleanly and recolours with the theme.

KNOWN LIMITATION: the largest instance on the sheet is 153×189. That is ample
for the header at 38px, the favicon and the share card, but short of the 512px
PWA icon, which is upscaled and slightly soft. A vector would fix it and is a
single swap — every consumer goes through components/Logo.tsx or public/brand.

Verified: tsc clean, 159/159 tests, build green, /icon.png and /apple-icon.png
emit as static routes, and the header, footer, share card and all five icons
were rendered and inspected in both themes.

🤖 AI Code Review (Claude Code)

This PR replaces the site's programmatically-generated SVG logo/favicon/OG-image system with supplied raster brand artwork (mark.png / mark-on-dark.png), updating the favicon, apple-touch-icon, manifest, header, and footer to use the new PNGs. The change is otherwise clean and well-reasoned (CSP/cache headers and Next.js icon conventions updated consistently), with one real but cosmetic aspect-ratio bug.

🟡 Minor

  • nextjs-app/components/Logo.tsx: LogoMark computes width from a single hardcoded ASPECT (153/189, derived from mark.png) for both colourways, but mark-on-dark.png's actual intrinsic ratio is 98x112 (~0.875), not ~0.810. Since both call sites (Footer's onDark variant, and Navigation's auto variant for OS dark-mode viewers) rely on CSS width:auto/height:100%, the mismatched width/height attributes will cause the on-dark mark to render stretched or shift on load.
## 🤖 AI Code Review (Claude Code) This PR replaces the site's programmatically-generated SVG logo/favicon/OG-image system with supplied raster brand artwork (mark.png / mark-on-dark.png), updating the favicon, apple-touch-icon, manifest, header, and footer to use the new PNGs. The change is otherwise clean and well-reasoned (CSP/cache headers and Next.js icon conventions updated consistently), with one real but cosmetic aspect-ratio bug. ### 🟡 Minor - **nextjs-app/components/Logo.tsx**: LogoMark computes width from a single hardcoded ASPECT (153/189, derived from mark.png) for both colourways, but mark-on-dark.png's actual intrinsic ratio is 98x112 (~0.875), not ~0.810. Since both call sites (Footer's onDark variant, and Navigation's auto variant for OS dark-mode viewers) rely on CSS width:auto/height:100%, the mismatched width/height attributes will cause the on-dark mark to render stretched or shift on load.
tudor added 1 commit 2026-08-08 21:39:38 +00:00
fix(brand): give both logo colourways one canvas so the aspect hint is right
PR Checks / Frontend Typecheck + Tests (pull_request) Successful in 1m3s
PR Checks / Backend Smoke (pull_request) Successful in 7s
PR Checks / Build Backend (no push) (pull_request) Successful in 10s
PR Checks / Build Frontend (no push) (pull_request) Successful in 50s
PR Checks / Build Pipeline (no push) (pull_request) Successful in 10s
PR Checks / AI Code Review (Claude) (pull_request) Successful in 9s
9ee4d45a94
LogoMark derived width from a single hardcoded 153/189, taken from mark.png,
while mark-on-dark.png was 98×112. Both call sites size the mark with
height:100%/width:auto, so the rendered size came out right in the end — but
the width/height attributes are the pre-load aspect hint, so the on-dark
artwork reserved the wrong box and reflowed on load. Any future call site
without that CSS would have rendered it stretched outright.

Per-variant attributes would not have fixed it. variant="auto" is a single
<img> whose srcset swaps the file underneath it, so one set of attributes has
to serve both colourways; the only correct fix is for the two files to share
a ratio.

They also had different artwork ratios (0.810 against 0.833) and different
padding, which the review did not reach: the logo changed size slightly
whenever the OS theme flipped. Both are now written onto one 176×208 canvas
with the artwork at the same height, centred, so they are drop-in swappable.

Measured on the built output, header mark, before → after:
  light   attr 31×38, rendered 30.75×38   →   attr 32×38, rendered 32.15×38
  dark    attr 31×38, rendered 33.25×38   →   attr 32×38, rendered 32.15×38
A 2.25px reflow and a cross-theme size jump both become 0.15px of rounding.

The share card reads the same file and had its own hardcoded 45×56, which the
re-crop would have stretched; it is now 47×56, with a comment tying it to the
canvas. The comment on ASPECT records that re-cropping either file means
re-normalising both.

Verified: tsc clean, 159/159 tests, build green, and both files report
naturalWidth 176 × naturalHeight 208 in the browser.
tudor merged commit 6b117dd26c into main 2026-08-08 21:41:47 +00:00
Sign in to join this conversation.
No Reviewers
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: tudor/school_compare#90