ReviewOS

stacks/paweldregan

Dynamic per-page OG images: Swiss Alps background + per-page text overlay (server-rendered, ts-images)

#9
Open glennmichael123 opened this 8 days ago ·
8 days ago

Context

Right now every page that has OG meta would point at a single static /images/og.jpg. Per-page dynamic OG images (showing the page's title rendered over a brand background) get noticeably better click-through when shared, and they reinforce the brand because every link preview looks like paweldregan.com.

Spec

Background: scenic Swiss Alps mountain photograph, dimmed so foreground text reads cleanly (probably ~40-60% darkening overlay or a baked-in dim version of the source image).

Foreground:

  • Page title (from site.config.ts.pages[route].title) in the same Bebas Neue display face used on-site
  • Possibly a small kicker (e.g. "PAWEŁ DREGAN") + the page label
  • Brand wordmark in a corner

Output: 1200×630 PNG/JPEG per page, served from a stable URL (so crawlers can cache).

Implementation approach

Server-rendered, on-demand, using our own ts-images toolkit — not sharp.

  1. Check in a single high-quality Swiss Alps source image to public/images/og-bg.jpg (or wherever fits — see "asset" note below).
  2. Add a scripts/og.ts (or an API route) that, given a route + title + locale, composites:
    • dim background
    • text layer (rendered via ts-images / canvas-style API)
    • exports as 1200×630
  3. Two delivery models, pick whichever fits the deploy:
    • Static: pre-render at build time for each known route in site.config.ts.pages, write to public/og/<route>.jpg, point each page's og:image at it.
    • Dynamic: serve from /og?route=…&locale=… and have the OG meta point there. Cache aggressively (Cache-Control: public, max-age=…immutable).
    • Static is simpler and works without runtime cost. Dynamic lets new pages get OG images without a build step.
  4. Wire each page's og:image to the resolved URL (depends on the meta-tag-implementation issue landing).

Constraints

  • No sharp. Use ts-images and the ts-* codec libs.
  • Locale-aware. A page rendered in de or pl should get the title from the matching translation, so the OG image shows the right language.
  • Font choice matches site. Bebas Neue for the headline, Inter for any subhead.

Asset note

Need a high-quality Swiss Alps source image with the right composition (room for centered text, no busy mid-frame elements). If we don't already have one in the licensed asset set, source from Unsplash/Pexels (CC0) or commission. Do not reuse a generic stock photo we don't have rights to.

Verification

  • Render the OG image for /, /about, /races, /coaching in all 3 locales (12 total). Eyeball each — the title should be readable, the background should be evocative not distracting.
  • Paste a paweldregan.com URL into the Twitter Card validator — preview should show the dynamic image, not the static placeholder.
  • Devtools → Network: OG image requests should be cached on subsequent loads.

Depends on

  • The meta-tag pattern issue (this one wires OG images into the meta resolution that issue establishes).

Sign in to comment on this issue.