From dc914cebd04dbbafb3f61184f6ad84b17b59ef2f Mon Sep 17 00:00:00 2001 From: John Niche Date: Wed, 8 Apr 2026 00:19:03 -0300 Subject: [PATCH] fix(landing): ship favicon + icons to prod, fix X share preview MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Deploy workflow now copies landing/favicon.svg, favicon.ico, apple-touch-icon.png, and landing/assets/* into the built site, resolving 404s on production GitHub Pages that were breaking the browser tab favicon and the X/Twitter share card. - Add apple-touch-icon.png (180x180) and favicon.ico (16/32/48) generated by a new scripts/build_favicons.py that redraws the [ • ] mark from primitives (no font or SVG-renderer dependency). - Add og:image:secure_url meta tag for older Slack/LinkedIn unfurlers. - Collapse 3 wordmark variants to just variant 3 (terminal banner art), removing the ?logo= URL param, localStorage state, and ~85 lines of variant-switching CSS + markup. - Add .playwright-mcp/ to .gitignore (tool artifact). --- .github/workflows/docs.yml | 14 ++++ .gitignore | 2 + landing/apple-touch-icon.png | Bin 0 -> 4808 bytes landing/favicon.ico | Bin 0 -> 2999 bytes landing/index.html | 90 +++---------------------- scripts/build_favicons.py | 127 +++++++++++++++++++++++++++++++++++ 6 files changed, 152 insertions(+), 81 deletions(-) create mode 100644 landing/apple-touch-icon.png create mode 100644 landing/favicon.ico create mode 100644 scripts/build_favicons.py diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 928fda0..0e7aac1 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -44,6 +44,20 @@ jobs: mkdir -p site/simulations cp landing/simulations/index.html site/simulations/index.html 2>/dev/null || true + - name: Copy landing favicon and assets + # Landing index.html references /favicon.svg, /favicon.ico, + # /apple-touch-icon.png, and /assets/og-image.png. Without these + # the X/Twitter share preview 404s and the browser tab falls back + # to the MkDocs Material favicon. Merge into the existing + # site/assets dir rather than replacing it (Material ships its + # own assets there). + run: | + cp landing/favicon.svg site/favicon.svg + cp landing/favicon.ico site/favicon.ico + cp landing/apple-touch-icon.png site/apple-touch-icon.png + mkdir -p site/assets + cp -R landing/assets/. site/assets/ + - name: Install selectools (for builder assembly) run: pip install -e . diff --git a/.gitignore b/.gitignore index 764a777..55a48e9 100644 --- a/.gitignore +++ b/.gitignore @@ -54,3 +54,5 @@ mypy_output.txt # Hypothesis test artifacts .hypothesis/ + +.playwright-mcp/ diff --git a/landing/apple-touch-icon.png b/landing/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..495dcbd5c7d604cab68c1de670a1e1cfcff59ec4 GIT binary patch literal 4808 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 V-Sy822X@4r(G*OO^?%>s{{UVfiB - + + @@ -33,6 +19,7 @@ + @@ -3907,61 +3894,12 @@ } /* ════════════════════════════════════════════════════════════════ - OVERDRIVE FUSED — wordmarks (3 switchable variants) - The body carries data-logo="1|2|3" set on load by reading the - ?logo= URL param (default "1"). Each variant renders inside the - nav-logo slot; only the active one is displayed. + OVERDRIVE FUSED — wordmark (terminal banner art) + Single variant: 3-row box-drawing wordmark in the nav-logo slot. ════════════════════════════════════════════════════════════════ */ - .wm { display: none; align-items: center; } - [data-logo="1"] .wm--1, - [data-logo="2"] .wm--2, - [data-logo="3"] .wm--3 { display: inline-flex; } - - /* Variant 1 — [•] selectools */ - .wm--1 { - gap: 8px; - font-family: var(--font-ui); - font-weight: 800; - font-size: 17px; - color: #fff; - letter-spacing: -0.03em; - } - .wm--1__brackets { - font-family: var(--font-mono); - font-weight: 600; - color: var(--exec-color); - font-size: 16px; - display: inline-flex; - align-items: center; - gap: 3px; - } - .wm--1__brackets::before { content: "["; } - .wm--1__brackets::after { content: "]"; } - .wm--1__brackets .exec-dot { width: 6px; height: 6px; } - - /* Variant 2 — s▌electools (cursor inside the word) */ - .wm--2 { - font-family: var(--font-ui); - font-weight: 800; - font-size: 17px; - color: #fff; - letter-spacing: -0.03em; - gap: 0; - } - .wm--2__pre, - .wm--2__post { display: inline-block; } - .wm--2__caret { - display: inline-block; - width: 0.18em; - height: 0.95em; - background: var(--exec-color); - box-shadow: 0 0 6px var(--exec-glow); - vertical-align: text-bottom; - animation: exec-blink 1.05s steps(2, jump-none) infinite; - margin: 0 1px; - } + .wm { display: inline-flex; align-items: center; } - /* Variant 3 — terminal banner art (3-row box-drawing) */ + /* Terminal banner art (3-row box-drawing) */ .wm--3 { font-family: var(--font-mono); color: var(--exec-color); @@ -4351,8 +4289,7 @@ .exec-caret { animation: none; opacity: 1; } .exec-scan.in-view::after { animation: none; display: none; } - /* OVERDRIVE FUSED — wordmarks: kill blink + scan animations */ - .wm--2__caret { animation: none !important; opacity: 1; } + /* OVERDRIVE FUSED — wordmark: kill scan animation */ .wm--3__banner.is-typing { mask-image: none !important; -webkit-mask-image: none !important; } /* OVERDRIVE FUSED — #faq: kill answer fade-in */ @@ -4417,16 +4354,7 @@