Skip to content

Implement Open Graph image generation#22

Merged
br3ndonland merged 16 commits intomainfrom
codex/og
Apr 19, 2026
Merged

Implement Open Graph image generation#22
br3ndonland merged 16 commits intomainfrom
codex/og

Conversation

@br3ndonland
Copy link
Copy Markdown
Owner

@br3ndonland br3ndonland commented Apr 18, 2026

Description

The site previously reused one stale Open Graph asset for every page,
even when project and work entries already had page-specific hero images
in the content collection. It would be preferable to generate Open Graph
images for each page.

Open Graph images can be generated either statically at build time or
dynamically with Vercel
functions and the @vercel/og package. Static generation is the better
fit here because the repo is currently static Astro, has no Vercel
adapter, still builds for GitHub Pages, and does not need request-time
data. Dynamic Vercel generation would require @astrojs/vercel plus
server or hybrid output, add function/runtime constraints, and make the
feature Vercel-specific.

There are various pre-existing packages for Open Graph image generation
in Astro apps including satori-astro, satori-html, astro-og-canvas
and others, but they are all lacking in various ways. It was simplest to
implement a custom Astro integration from scratch.

Changes

This PR will add an Astro integration for build-time Open Graph images.
It will use the vercel/satori
package for platform-agnostic build-time image generation in a pipeline
(Satori-compatible HTML -> SVG -> sharp -> PNG) and will have modules
for the integration factory, HTML parser, image responses, and types.

To use the Astro integration, this PR will update the Astro site to:

  • Delete the stale public/images/og.jpg.
  • Add TTF equivalents of existing fonts (Satori does not support WOFF2).
  • Add an @integrations/* path alias for source imports, while keeping
    astro.config.ts on a relative import because the config loader does
    not resolve that alias during startup.
  • Add Astro endpoints to src/pages/og/ that serve 1200 x 630 PNG
    routes under /og/.... Content pages will use entry.data.image. A
    fallback image will use a generated default based on the homepage.
  • Support Open Graph image generation for Vercel preview deployments by
    reading the Vercel system environment variables VERCEL_ENV and
    VERCEL_URL while keeping the configured Astro.site for production.
  • Use descriptions from content collections when possible. A fallback
    description will be used when descriptions are not provided.
  • Match the site's background color, fonts, header text and logo.
  • Use the site's accent color in a full-height stripe on the left.
  • Resize Open Graph thumbnail artwork with contain so hero images and
    logos fit inside the right side image area instead of being cropped.
  • Update MainHead.astro to get the appropriate OG image for each page.
Validation
pnpm install --frozen-lockfile
env VERCEL_ENV=preview VERCEL_URL=bws-preview-test.vercel.app pnpm run build
pnpm run check
pnpm run build
pnpm run test
preview build: generated og:image and twitter:image on bws-preview-test.vercel.app
pnpm run check: 0 errors, 0 warnings, 1 existing hint
pnpm run build: completed successfully and generated /og/*.png routes
pnpm run test: 2 test files passed, 12 tests passed

Related

MainHead previously pointed every page at /images/og.jpg, so the
site shared one stale Open Graph image even when a content page had a
hero image available.

This commit will add a static Astro endpoint that generates 1200 by
630 PNG cards at build time with Satori and sharp, using Recursive TTF
fonts and content collection hero images where available. It will
default non-content pages to the current portrait image, update Open
Graph and Twitter image metadata to generated /og routes, and remove
the outdated public/images/og.jpg asset.

- https://docs.astro.build/en/guides/endpoints/
- https://vercel.com/docs/og-image-generation
- https://vercel.com/docs/og-image-generation/og-image-api
- https://github.com/florian-lefebvre/satori-astro/tree/main/packages/satori-astro
The OG endpoint previously depended on satori-astro and satori-html
for a small response wrapper and HTML-to-Satori conversion. Those
dependencies made the feature rely on package code that can be kept
locally for this static build workflow.

This commit will add a local AstroOpenGraph integration and helper
module that converts the controlled OG template markup into a Satori
element tree, renders through satori and sharp, and returns PNG
responses with cache headers. It will register and re-export the
integration from astro.config.ts, switch the OG endpoint to the local
helper, remove satori-astro and satori-html, and add unit coverage for
HTML parsing and PNG response generation.

- https://github.com/florian-lefebvre/satori-astro/tree/main/packages/satori-astro
- https://github.com/natemoo-re/satori-html/tree/main/packages/satori-html
Comment thread src/lib/astro-open-graph.ts Fixed
The local OG HTML helper previously decoded named entities through a
sequence of replacements. CodeQL reports that pattern as a double
unescaping risk because an input like < can be reduced again in
the same decoder.

This commit will decode supported entities in a single regex pass so
derived entity text is not decoded a second time. It will add a unit
test that verifies < remains < after one pass.

- #22
The local OG integration previously lived in src/lib beside site-level
helpers. That made reusable integration code look like ordinary
application utility code, while moving it to packages/ would imply a
workspace package this repo does not currently have.

This commit will move the integration into
src/integrations/astro-open-graph with separate modules for the
integration factory, HTML parser, image response helper, and public
types. It will move site-specific OG route helpers to src/open-graph.ts,
add an @integrations path alias for source imports, and keep astro.config.ts
on a relative import because config loading does not resolve that alias.

- https://github.com/withastro/starlight
- https://github.com/florian-lefebvre/astro-integration-template/tree/main/templates/github
Open Graph image metadata currently resolves relative image paths against Astro.url. Because Astro.url is derived from the production site config during static builds, preview deployments advertise image URLs on www.bws.bio before those generated images exist in production.

This commit will resolve Open Graph and Twitter image URLs against Vercel's deployment URL when building preview deployments, while keeping canonical page URLs on the production site. It will add unit coverage for route normalization, production fallbacks, and preview deployment image URLs.

- https://vercel.com/docs/deployments/og-preview

- https://vercel.com/docs/environment-variables/system-environment-variables
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 19, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
bws Ready Ready Preview Apr 19, 2026 4:13am

The generated Open Graph cards now resolve correctly on Vercel preview deployments, but the visual template still used a light card style and cropped page hero images into a square. Content page titles in the generated cards also repeated the site and section labels instead of focusing on the entry title.

This commit will resize source artwork with contain instead of cover, render project and work cards with entry titles only, add the italic Recursive Mono brand row with the terminal mark, and move the card colors toward the site's dark mode palette.

- #22
The generated Open Graph card template now uses a darker card layout with contained artwork, but the title is still too prominent and the right image area has an extra framed panel. Project pages also still use a generic summary in the card artwork even though project frontmatter already provides descriptions.

This commit will reduce generated card title sizes, flatten the card background so the artwork sits on the same surface, restore the purple accent as a full-height straight stripe, and use project content collection descriptions in generated project cards.

- https://vercel.com/docs/deployments/og-preview
The generated project Open Graph cards now use content collection descriptions, but the project route itself still advertises generic summary text in page metadata. Open Graph inspectors can therefore show different descriptions between the generated card and the metadata table.

This commit will point project page descriptions at entry.data.description so regular meta, og:description, and generated project card copy share the content collection source.

- https://vercel.com/docs/deployments/og-preview
@br3ndonland br3ndonland changed the title Generate static OG images Implement Open Graph image generation Apr 19, 2026
Note that the `astro.config.ts` does not use an `@integrations/*` alias
for source imports. This is because the config loader does not resolve
aliases during startup.
This reverts commit a3d91f3.

Actually it is needed in `src/pages/og/[...route].ts`.
@br3ndonland br3ndonland marked this pull request as ready for review April 19, 2026 04:27
@br3ndonland br3ndonland merged commit a6f2550 into main Apr 19, 2026
6 checks passed
@br3ndonland br3ndonland deleted the codex/og branch April 19, 2026 04:36
br3ndonland added a commit that referenced this pull request Apr 19, 2026
This commit will update the Open Graph image generation Astro endpoints
introduced in #22 and a6f2550 by increasing the font sizes of the header
text and footer URL, and by adjusting the length cutoff for shrinking
the description text to 256 characters, which is just within the amount
of space available to the Open Graph image description at font size 32.
br3ndonland added a commit to br3ndonland/dotfiles that referenced this pull request Apr 19, 2026
This commit will refine the wording in the guidance on PRs provided in
`.codex/AGENTS.md`. In PR br3ndonland/br3ndonland.github.io#22, Codex
misinterpreted some of the instructions, such as adding info on code
changes to the description section and including numerous sentences all
beginning with "This PR will" in the changes section that would have
been better suited to unordered lists.
br3ndonland added a commit that referenced this pull request Apr 19, 2026
This commit will refine the wording in the guidance on PRs provided in
`.codex/AGENTS.md`. In PR #22, Codex
misinterpreted some of the instructions, such as adding info on code
changes to the description section and including numerous sentences all
beginning with "This PR will" in the changes section that would have
been better suited to unordered lists.
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