Skip to content

Redesign: share images and favicon - #37

Merged
meaningfool merged 2 commits into
redesignfrom
redesign-34-share-favicon
Nov 3, 2026
Merged

meaningfool merged 2 commits into
redesignfrom
redesign-34-share-favicon

Conversation

@meaningfool

@meaningfool meaningfool commented Nov 3, 2026 •

Copy link
Copy Markdown
Owner

Implements #34 (part of #35). The build draws the share images and the favicon from the designs in docs/redesign/paper/.

What changes

  • Share images, 1200×630 PNGs, made at build time.
    • Each article gets /articles/<slug>/share.png: "Article" on the tab, the title, then "Josselin Perrus" and " · min read" at the bottom.
    • Home and About share /share.png. It has the README's updated text: "Projects · Writing" on the tab and the home intro under the name. The bottom row reads "meaningfool.net" and "18 articles · 3 projects", counted at build time. Only articles are counted, not activity logs.
    • Activity logs have no image of their own, so they use /share.png.
    • These replace og-default.jpg in og:image, twitter:image and the article JSON-LD image. Pages now also send og:image:width/height (1200×630) and an alt text (og:image:alt, twitter:image:alt). public/og-default.jpg is removed.
  • Favicon, the paper tile, made at build time.
    • /favicon.svg is the 32px tile, with the glyphs as paths.
    • /favicon.ico holds the 16px and 32px tiles.
    • /apple-touch-icon.png is 180px.
    • A Favicons component links them from every page, including the 404 and /documents/. Astro's default logo (public/favicon.svg) is removed.
  • How they're drawn. src/lib/mono.ts reads the site's own DejaVu Sans Mono subset (src/fonts/dejavu-sans-mono.woff2, imported with ?inline) with fontkitten and turns the text into SVG paths. It lays text out the way the browser does: same character width plus letter-spacing, lines breaking at spaces and after hyphens, and CSS line-box baselines. src/lib/share-images.ts and src/lib/favicon.ts use the README's exact values, and sharp rasterises the result. Both packages were already installed through Astro and are now listed as direct dependencies, so bun.lock gains no new packages. Playwright isn't used.
  • Supporting code:
    • src/lib/share.ts: the text, paths and alt text of the images.
    • src/lib/reading-time.mjs: words at 235 a minute, rounded up. This gives the prototype's reading times for all 18 of its articles (any rate from 231 to 236 does).

Why the subset font, and not full TTFs

fontkitten reads WOFF2, so the committed 24 KB subset works as it is. That means no font download at build time, no new font files and no licence to add (the DejaVu licence is already in src/fonts/). The images also have exactly the letters the pages show. The subset covers Latin, punctuation, arrows and box drawing. Any other character (Greek, CJK, emoji) is drawn as the font's empty box, and the build prints a [mono] warning that names it. I checked this with a test title. No current title has such a character.

How close they are to the Paper exports (Menlo there, DejaVu Sans Mono here)

  • Article image (structured-extraction, the same title as the export): every row lands within 1px of the export.
    • Wordmark ink at y 74–109, tab 1003–1128 with its accent line at y 111–113, title lines at y 207/287/367 (export 208/288/368).
    • The 2px rule at y 518–519, the bottom text at y 549–571, and the right text ending at x 1125.
    • The line breaks are the same ("Time-" / "Sensitive Structured" / "Extraction").
    • 1.9% of pixels differ, almost all from glyph shapes: Menlo's hyphen is longer, its l and i have slabs, and its full stop is bigger.
  • Home and About image:
    • With the export's old text it matches the export row for row (name at y 228–294, intro at 339–366 and 381–408, the same as the export). 1.3% of pixels differ.
    • With the new intro, which wraps to 3 lines instead of 2, the middle block moves up 21px, as the design's "three rows spread from top to bottom" rule implies.
  • Favicon:
    • The "m" matches the 144px export to within half a pixel.
    • DejaVu Sans Mono's full stop is smaller than Menlo's: 252×305 units, against about 350×400. At 144px, the dot is 13×16px against the export's 18×21.
    • At 32px and 16px, the "m" is moved by under half a pixel so it starts on a pixel and stands on one. The full stop (a plain rectangle in this font) is fitted to whole pixels and kept at least 2px a side: 3×4px at 32px and 2×2px at 16px. Without that, at 16px it was a 1.5px smudge.

Choices to check

  • The orange dot is DejaVu's full stop, the same as in the site's wordmark, so it is smaller than in the Menlo export (see above).
  • The SVG favicon uses the 32px tile's values, the size browsers mostly draw it at (16 CSS px on 2× screens).
  • The apple-touch-icon is the 144px tile scaled by 1.25 (135px glyphs, 17.5px under them) and keeps the 1px border. iOS rounds the corners, so the border fades out there. It can be dropped if that looks off.
  • Dates use the site's long month ("September 26, 2025 · 2 min read"), in UTC so the day never shifts with the build machine's time zone.
  • Activity logs use the Home and About image.
  • Alt text and image size meta are new (og:image:width/height/alt, twitter:image:alt).

Works in parallel with #32

  • src/data/projects.ts wasn't on redesign yet, so this adds a minimal one: export const projects = [...], with slug and name for Voice Todos, Agent SDKs for the Rest of Us and Data Lineage. The count comes from projects.length. Redesign: article page #32's version will replace this file on merge.
  • Redesign: article page #32 shows the reading time on the article page. src/lib/reading-time.mjs (readingMinutes(article.body)) is here so both show the same number.
  • My only change to src/pages/articles/[slug].astro is passing share={postShare(article)} to Layout and using its path in the JSON-LD image. The meta description is untouched.
  • The home intro is HOME_INTRO in src/lib/share.ts, which Redesign: home page #31 can import.

Validation

Head commit 6250a4e5848fbbbb330724ce58c584344d5a3082, on base 4cf01a49dae20915b1a6939ac7a2d7e53c890a62. Node 24.22.1, Bun 1.4.4, content submodule at bf783ba (git submodule update --init --remote; the submodule pointer is not changed).

The review then moved the reading rate from 230 to 235 words a minute (9fab9bf). That changes only the share image and alt text of "Agent Frameworks for the Rest of Us", now 39 minutes as in the prototype; its checkpoint comment lists what was checked on that commit.

  • bun install, then bun run build: passes, 62 pages, plus 19 share images, favicon.svg, favicon.ico and apple-touch-icon.png. No [mono] warnings. The share images are 23–43 KB each and the icons under 2 KB.
  • bun run test:documents: 10 tests, 10 passed. tsc --noEmit (strict, the repo's tsconfig): no errors.
  • bun dev serves all the new files. /articles/<daily-log>/share.png returns 404, as it should.
  • Pages outside the issue. I diffed the build of the base commit against this one, both with the same content.
    • Files removed: og-default.jpg only.
    • Files added: the 19 share.png files, favicon.ico and apple-touch-icon.png.
    • In every page's <head>, only the favicon links and the og:image/twitter:image tags change.
    • In <body>, the only change is the JSON-LD image URL on the 58 article and log pages.
    • rss.xml, the sitemap, _redirects and _headers are unchanged, and llms*.txt differ only in their build timestamp.
  • Headless Chromium (Playwright), at 1440px and 375px:
    • Screenshots of /, /about/, an article, an activity log, an unknown URL (the 404) and /documents/ are pixel-identical before and after. This issue changes nothing on the pages themselves.
    • The prototype (docs/redesign/prototype/index.html) has no favicon or share image, so the reference for this unit is the Paper exports above.
    • Chromium decodes favicon.svg, favicon.ico (16 and 32) and apple-touch-icon.png.
    • Every page links all three icons, and each og:image URL resolves to a 1200×630 PNG.

🤖 Generated with Claude Code

https://claude.ai/code/session_013MdjUerTCBDeF5DG9puDd2

Each article gets its own 1200x630 share image (its title, date and
reading time) at /articles/<slug>/share.png, and Home and About share
/share.png, with the label "Projects · Writing", the home intro and
the article and project counts. Activity logs use the site's image.
They replace og-default.jpg as og:image and twitter:image, now with
their size and alt text.

The favicon is the paper tile: favicon.svg (the 32px tile), a
favicon.ico at 16px and 32px and a 180px apple-touch-icon. They
replace Astro's default logo on every page, the 404 and /documents/
included.

Everything is drawn from the site's DejaVu Sans Mono subset, read with
fontkitten and turned into SVG paths laid out as the browser lays out
text, then rasterised with sharp. The values are those of
docs/redesign/paper/README.md. src/data/projects.ts is a minimal
project list for the count, until #32's replaces it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013MdjUerTCBDeF5DG9puDd2
@github-actions

github-actions Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

Preview: https://pr-37-meaningfool.josselin-perrus.workers.dev

Built from 9fab9bf with the latest content. The link stays the same and shows the latest push. Search engines are asked not to index it.

At 230 words a minute, "Agent Frameworks for the Rest of Us" came out at
40 minutes, where the approved prototype shows 39. Any rate from 231 to
236 gives the prototype's reading time for all 18 articles; only that
article's share image and alt text change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013MdjUerTCBDeF5DG9puDd2

Copy link
Copy Markdown
Owner Author

Review checkpoint: accepted at 9fab9bf24290f8f7bad03466a24884764accf7d2, on base 4cf01a4 (redesign). This is an independent review of #34. Setup: Node 24.22.1, Bun 1.4.4, content at bf783ba (git submodule update --init --remote), bun install --frozen-lockfile with no lockfile changes. The Deploy build check passed on this commit.

Fix pushed (1 commit, 9fab9bf). Reading time is now 235 words a minute instead of 230. At 230, "Agent Frameworks for the Rest of Us" came out at 40 minutes, where the approved prototype (maps.js) shows 39. Any rate from 231 to 236 gives the prototype's minutes for all 18 articles, and #31 and #32 will show this same number. Only that article's share image and alt text change. I also updated the PR description to match.

What I checked

  • Issue requirements.
    • Each of the 18 articles has a 1200×630 share image with its title, date and reading time. Activity logs have none.
    • Home and About share /share.png, with "Projects · Writing", the home intro (word for word as in the prototype's template.html) and "18 articles · 3 projects".
    • og-default.jpg is gone. og:image, twitter:image and the JSON-LD image point to the new images.
    • The favicon is the paper tile, shipped as an SVG with paths (no <text>), a favicon.ico holding 16px and 32px PNGs, and a 180px apple-touch-icon. Astro's default logo is removed.
  • Against the Paper exports. I measured the ink bands row by row.
    • Article image: within 1px of share-article.png in every row (title lines 207/287/367 against 208/288/368), with the same line breaks.
    • Home image, drawn with the export's old text: identical rows to share-home-about.png (228–294, 339–366, 381–408). With the new 3-line intro, the middle block is centred between the top and bottom rows.
    • Favicon at 144px: the "m" is within 0.5px of favicon-paper-tile@4x.png. The orange dot is DejaVu's full stop, smaller than Menlo's. That is already listed under "Choices to check".
    • I looked at all 18 article images. They all wrap well, and no glyphs are missing: every title character is in the subset.
  • Outside the scope. I built origin/redesign and this branch with the same content and compared every file.
    • All 62 pages have an identical <body>, except the JSON-LD image URL.
    • In <head>, only the icon links and the og:/twitter: image tags change.
    • rss.xml, the sitemaps, _redirects, _headers and _astro/ are unchanged, and llms*.txt differ only in their timestamp.
    • Files removed: og-default.jpg. Files added: 19 share.png, favicon.ico and apple-touch-icon.png.
  • Merged pages, at 1440px and 375px (headless Chromium, full page): /, /about/, two articles, an activity log, the 404 and /documents/ are pixel-identical to redesign.
  • Head of every page. All 62 pages link the three icons. Each og:image resolves and decodes as a 1200×630 PNG, and the size and alt meta are present. Chromium decodes all three icons.
  • Build and tests. bun run build passes with no [mono] warnings. bun run test:documents passes 10 of 10, and tsc --noEmit reports no errors. bun dev serves every new file, and a daily log's share.png returns 404.
  • Rules.
    • Icon and image URLs are files with no trailing slash, and the pages' internal links are unchanged.
    • No secrets or personal data. All files are under 45 KB.
    • sharp and fontkitten were already in bun.lock through Astro, and Playwright isn't used.

Not blocking (P3): a title that ends in "?" gives a ?. in the alt text, as in "How long for that change?. Josselin Perrus, …".


Generated by Claude Code

@meaningfool
meaningfool marked this pull request as ready for review November 3, 2026 18:52
@meaningfool
meaningfool merged commit 3df7e38 into redesign Nov 3, 2026
1 check passed
meaningfool pushed a commit that referenced this pull request Nov 3, 2026
Brings in the share images and favicon (#37). Layout keeps their share prop
and adds textColumn and noindex next to it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013MdjUerTCBDeF5DG9puDd2
@meaningfool
meaningfool deleted the redesign-34-share-favicon branch November 5, 2026 10:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants