Skip to content

Repository files navigation

Colophon logo  @kensio/colophon

npm version CI Coverage Node TypeScript License

Generate social meta images (Open Graph and share-card images) for the posts of a static website, driven by each post's frontmatter.

https://colophonjs.dev/

You describe an image in frontmatter with a title, a subtitle, a version and a template name, and Colophon renders branded PNGs at the sizes you need. The name comes from the printer's colophon, the emblem a publisher stamps on a finished work.

  • Frontmatter-driven. Props are read from a post rather than fixed by a schema.
  • Templates. A small registry of layouts, picked per post from frontmatter.
  • Syntax-highlighted code images. The code template renders a snippet from frontmatter with real VS Code theme colours.
  • Configurable branding. Colours, gradient, fonts, footer and badge come from config, not from any one site's stylesheet.
  • Themes. Eight named looks, or your own colours with a mesh, a dot grid or ruled lines over them.
  • Multiple sizes from one input. A 1:1 square and a 1.91:1 landscape by default, or whatever set you configure.
  • Manifest and meta tags. A JSON record of what was generated, and the Open Graph and Twitter tags that go with it.
  • Small, reusable API. A render core with no filesystem concerns, plus an optional content walker and CLI.

Install

pnpm add @kensio/colophon

@resvg/resvg-js rasterises the SVG to PNG, and shiki provides the grammars and themes for the code template. No headless browser is involved. Outfit and JetBrains Mono ship with the package and are used by default, so a build renders the same image everywhere without configuring anything; point fonts at your own files to use those instead.

Quick start

Add image props to a post's frontmatter:

---
title: My post
meta_img_props:
  template: banner
  title: "@kensio/colophon"
  subtitle: Generate social meta images from frontmatter
  version: 1.2.0
---

Create a config module, or omit it to use the neutral defaults:

// colophon.config.ts
import { defineConfig } from "@kensio/colophon";

export default defineConfig({
  colors: { brand: "#2563eb", brandDark: "#1e3a8a", brandWarm: "#f59e0b" },
  footer: "example.com",
  badge: { text: "npm" },
});

colophon init writes that file for you, guessing where your content lives.

Run it over a content tree:

colophon content --config colophon.config.ts

For every file that declares meta_img_props, Colophon writes one PNG per output size next to it, named <slug>-<size>.png, so post/index.md produces post/post-og.png and post/post-square.png. Set format to webp, jpeg or avif for a quarter of the bytes.

While tuning a template, colophon preview <file> renders one post and opens it, --watch rebuilds on every change, and --dry-run reports what would change without writing anything.

There is also a programmatic API. renderMetaImages takes props and config and returns rendered bytes, and generate ties walking, rendering and writing together.

Documentation

Full documentation is in docs/.

Sample output

These are generated by scripts/gen-samples.ts from the sample list in test/samples.ts. Run pnpm samples to regenerate them after changing a template, then commit the updated PNGs so this gallery stays in sync.

banner template, square
banner · 1200×1200 · gradient, badge, version, subtitle, footer
card template, square
card · 1200×1200 · centred title and subtitle
banner template, landscape
banner · 1200×630 · the same input at Open Graph size
card template, solid background
card · 1200×630 · solid background, title only
code template, square
code · 1200×1200 · bash, github-dark
code template, landscape
code · 1200×630 · TypeScript, night-owl
article template, landscape
article · 1200×630 · tags, headline, byline and avatar
terminal template, landscape
terminal · 1200×630 · a command and its output
quote template, square
quote · 1200×1200 · pull quote with attribution
release template, square
release · 1200×1200 · version and headline changes
stat template, square
stat · 1200×1200 · one figure and a caption
event template, square
event · 1200×1200 · date, title and location
photo template, landscape
photo · 1200×630 · the post's own photograph, scrimmed
wordmark template, landscape
wordmark · 1200×630 · logo, name and tagline
docs template, landscape
docs · 1200×630 · breadcrumb, title and summary
thumbnail template, 16:9
thumbnail · 1280×720 · title grown to fill the frame, texture scaled up
cover template, 3:1
cover · 3:1 · profile header, kept clear of X's avatar corner
cover template, 16:9
cover · 16:9 · same layout in YouTube's centred safe area

Themes

One line of config each: theme: "midnight". See Themes and background treatments for what a theme sets and how to override part of one.

midnight theme
midnight
aurora theme
aurora
ember theme
ember
forest theme
forest
bloom theme
bloom
slate theme
slate
paper theme
paper
sandstone theme
sandstone

Development

Script What it does
pnpm build Compile to dist/.
pnpm test, pnpm test:coverage Run Vitest.
pnpm lint Oxlint, ESLint and oxfmt check, run together.
pnpm fmt Auto-fix.
pnpm samples Regenerate the sample images into docs/samples/.
pnpm baselines Re-record the visual regression baselines in test/baselines/.
pnpm fta FTA scores, failing on any file 50 or above.
pnpm check Format, FTA, typecheck, build and test with coverage. Run before committing.

Visual regression

Templates are pictures, so pnpm test renders every sample and compares it against a committed baseline in test/baselines/. A change to a template shows up as a failure naming how far the image moved, and writes what it rendered to test/.visual/ so you can open the two side by side. CI uploads the same images as an artifact when the check fails.

When the change was the point, run pnpm baselines and commit the new PNGs with it. The diff is then the before and after, which is the review the check exists to make possible.

The baselines are rendered with font files rather than whatever the machine has installed, and at a fraction of the width they are laid out at, which keeps them reproducible anywhere and small enough to live in the repository. The gallery above is rendered separately, as a project would render it.

License

Apache-2.0

About

Generate social meta images for posts from frontmatter

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Contributors

Languages