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 sameBebas Neuedisplay 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.
- Check in a single high-quality Swiss Alps source image to
public/images/og-bg.jpg(or wherever fits — see "asset" note below). - Add a
scripts/og.ts(or an API route) that, given aroute+title+locale, composites:- dim background
- text layer (rendered via ts-images / canvas-style API)
- exports as 1200×630
- Two delivery models, pick whichever fits the deploy:
- Static: pre-render at build time for each known route in
site.config.ts.pages, write topublic/og/<route>.jpg, point each page'sog:imageat 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.
- Static: pre-render at build time for each known route in
- Wire each page's
og:imageto the resolved URL (depends on the meta-tag-implementation issue landing).
Constraints
- No
sharp. Usets-imagesand thets-*codec libs. - Locale-aware. A page rendered in
deorplshould get the title from the matching translation, so the OG image shows the right language. - Font choice matches site.
Bebas Neuefor the headline,Interfor 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,/coachingin 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).