feat(landing-page): refresh brand mark and publish a real favicon.ico (#2561)

Replaces the four icon assets in `apps/landing-page/public/` with
renders of the new brand mark — black-fill speech bubble + white
pointer arrow — and adds a real multi-resolution `favicon.ico` at
the path SEO crawlers actually probe.

Why
- The brand mark was refreshed on 2026-05-21 (canonical source:
  black 2988×2988 PNG of the speech-bubble + pointer logo). The
  marketing site needed the matching favicon, apple-touch-icon, and
  header brand mark refreshed in lockstep so the browser tab, iOS
  home-screen tile, and the in-page nav glyph all line up with the
  new identity.
- `/favicon.ico` did not exist on the published site. The Astro head
  declares `<link rel="icon" href="/favicon.png">`, which modern
  browsers honor, but a long tail of SEO crawlers, link-preview
  services (Slack, Discord, third-party SEO tools), and older
  clients hard-probe `/favicon.ico` regardless of the link tag. Hits
  to that URL were falling through to the SPA fallback HTML
  (200 with `content-type: text/html`), so those clients rendered
  an empty/broken favicon. Several SEO surfaces showed an empty
  black circle instead of the brand mark.
- Adding a real `favicon.ico` plus an explicit
  `<link rel="icon" type="image/x-icon" href="/favicon.ico">` is
  the smallest defensive fix that covers both well-behaved and
  hard-probing clients.

What
- Regenerated icon assets from the new logo source:
  - `favicon.ico` — multi-resolution ICO with 16/32/48/64 PNG-encoded
    entries. The 16/32 entries are what browser tabs, bookmarks, and
    most crawlers sample; 48/64 cover high-DPI tabs and Windows
    pinned-tile sampling.
  - `favicon.png` — 32×32 PNG (existing slot).
  - `apple-touch-icon.png` — 180×180 PNG (existing slot, iOS
    home-screen).
  - `logo.webp` — 144×144 WebP, 4× the 36px logical size used by
    the header brand mark for crisp retina rendering.
- Added `<link rel="icon" type="image/x-icon" href="/favicon.ico" sizes="any">`
  to both `app/pages/index.astro` and the shared `sub-page-layout`
  so every route under `open-design.ai` advertises the ICO. Existing
  PNG and apple-touch links are preserved — modern browsers will
  still pick the PNG, the ICO catches the hard-probing tail.

Surface area
- Marketing site only. No `apps/web`, `apps/daemon`, contracts, or
  CLI surfaces touched.
- No new dependencies; assets generated locally from the canonical
  source via `magick` + `cwebp` and committed as static files.

Validation
- `pnpm --filter @open-design/landing-page typecheck` — 0 errors.
- File integrity:
  - `favicon.ico` — `MS Windows icon resource - 4 icons,
    16x16, 32x32, 48x48, 64x64`
  - `logo.webp` — `RIFF Web/P image, VP8 encoding, 144x144`
- Manual: `/favicon.ico` will return `image/x-icon` once deployed,
  not the SPA fallback HTML it returns today.

Followup
- Once Cloudflare's edge cache rolls (or is purged), third-party
  favicon caches (Google SERP, Slack link-preview) take days-to-weeks
  to refresh on their own; that lag is expected and not a deploy
  problem.

Co-authored-by: Joey-nexu <joeylee12629@gmail.com>
This commit is contained in:
Jane 2026-05-21 17:39:43 +08:00 committed by GitHub
parent 10192dcc52
commit af63af3951
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 12 additions and 0 deletions

View file

@ -80,6 +80,10 @@ const ldArray = jsonLd ? (Array.isArray(jsonLd) ? jsonLd : [jsonLd]) : [];
<link rel="alternate" hreflang={item.hreflang} href={new URL(item.href, Astro.site).toString()} />
))}
{/* See `index.astro` for why we publish + link `/favicon.ico` in
* addition to the PNG: SEO crawlers and link-preview services
* hard-probe that exact path. */}
<link rel="icon" type="image/x-icon" href="/favicon.ico" sizes="any" />
<link rel="icon" type="image/png" sizes="32x32" href="/favicon.png" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />

View file

@ -35,6 +35,14 @@ const pageHtml = renderToStaticMarkup(
<link rel="alternate" hreflang={item.hreflang} href={new URL(item.href, Astro.site).toString()} />
))}
{/*
* Favicon links. Modern browsers prefer the explicit PNG. We also
* publish `/favicon.ico` and link it because many SEO crawlers,
* link-preview services, and older clients hard-probe that exact
* path — without a real ICO at that URL they get the SPA fallback
* HTML and render an empty/broken icon in third-party UIs.
*/}
<link rel="icon" type="image/x-icon" href="/favicon.ico" sizes="any" />
<link rel="icon" type="image/png" sizes="32x32" href="/favicon.png" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB