agentleFS
karerokarero/croftweaver/skills/og-images/SKILL.md

og-images

Skill9 starsChanged 30 days agoMITView on GitHub

Generate branded per-page Open Graph (social share) cards for a website: a 1200×630 JPEG ≤300 KB for every page, rendered by a committed Python+Pillow script and wired so each page sets its own `image=` (with a default fallback) and the test suite proves the card exists at the right size. Use when building or auditing a site's share previews — "OG image", "og:image", "social share image", "share card", "WhatsApp/Slack/LinkedIn preview", "Twitter card image", "the picture when I share the link", "per-page OG images", "generate share images". For general marketing image creation/optimization use the `image` skill; this one is specifically the build-time, tested, per-page card generator for the suite's Astro starter.

  • Installs packages

5 other projects use a version of this.

Adopted by

Most recently taken up by

The file

We split this skill into the rules it gives an agent

2 rules. 0 are common, 0 are distinctive, and 2 are very specific to this project.

  • 0

    Common

    Most of the 4 edited versions we read keep these.

  • 0

    Distinctive

    This author's own choices. Worth a look.

  • 2

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    When a URL is shared (WhatsApp, Slack, iMessage, X, LinkedIn, Discord), the og:image is the preview.

    line 19
  2. Very specific:

    If you hit one: shorten the text to a near-synonym, or insert a plain space at a natural compound boundary (Suchmaschinen Optimierung) — …

    line 83

“Common” is measured: kept by at least 6 in 10 of the 4 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

OG images — per-page share cards

When a URL is shared (WhatsApp, Slack, iMessage, X, LinkedIn, Discord), the og:image is the preview. Get it wrong and the link shares with no picture or a badly cropped one — a silent conversion leak. This skill makes every page render a consistent, on-brand 1200×630 JPEG ≤300 KB, generated by a committed script and enforced by the test gate.

The three hard rules (messengers enforce them)

  1. 1200×630, exactly (1.91:1). Square images get cropped on X/Teams; off-ratio ones letterbox. The starter's Base.astro already emits og:image:width/height = 1200×630.
  2. ≤300 KB. WhatsApp silently drops previews heavier than ~300 KB — the link then shares with no image at all. Encode JPEG and compress to fit.
  3. Extension matches the bytes. A PNG renamed .jpg trips strict scrapers. Use JPEG for photographic cards, PNG only for flat logo/gradient cards that still come ≤300 KB.

How it's wired in the Astro starter

  • scripts/generate_og_cards.py — the generator. Renders one card per page you list, plus a default.jpg. Run it with npm run og. Idempotent; commit the output.
  • src/layouts/Base.astro — image prop defaults to /images/og/default.jpg. A page gets its own card by passing image="/images/og/<slug>.jpg"; a page with no image= falls back to the default — which only exempt utility pages should do (the test below enforces it). og:image + twitter:image are derived from that one prop.
  • tests/seo.spec.ts — for every page, reads the referenced card off disk and asserts it exists in public/, is ≤300 KB, a real JPEG/PNG, and exactly 1200×630. It also enforces that every page has its own card (not the generic default) and that no two pages share one — except an OWN_CARD_EXEMPT allowlist (home + utility pages, default ['/', '/privacy']). Opt-out: as you add content pages, leave them OUT of the allowlist and the guard flags any that forgot a card. A missing/oversized/shared card fails the build — OG cards can't silently rot, and a new page can't silently ship on the generic default.

The starter ships a generated public/images/og/default.jpg so the suite is green from commit 1; you replace it with your brand by editing the script and re-running npm run og.

Setup for a site (two edits, one command)

  1. Fill the BRAND block in scripts/generate_og_cards.py — BRAND_NAME, SITE_URL_LABEL, the background/accent/text colours (copy the hexes from src/styles/global.css / BRAND.md), and optionally point LOGO at a transparent raster PNG for a faint emblem watermark (SVG won't load — Pillow needs raster). The card is a dark share card by design: light text on a deep background reads well in every chat app regardless of whether the site theme is light or dark.
  2. List per-page cards in the PAGES block — one (slug, title, [subtitle, …]) per content page. Then set image="/images/og/<slug>.jpg" on that page's <Base>. Only exempt utility pages (home, privacy, …) may fall back to default.jpg; every other content page must be listed here and wired to its own card, or seo.spec.ts fails it.
  3. Run npm run og, then npm test. Commit the generated JPEGs.

npm run og -- --check exits non-zero if any card exceeds 300 KB — wire it into CI or the pre-push hook if you want generation (not just validation) gated.

Long or unbreakable words (German compounds)

fit_title() shrinks the font until every wrapped line actually fits the card's text area, not just until the line count looks right. Three overflow cases fail the run loudly (OG card OVERFLOW: ...) instead of drawing past the edge, all unconditional (not gated behind --check, which only guards file size):

  • a single unbroken word wider than the text area at the smallest size (52pt) — long German compounds (Suchmaschinenoptimierung, Datenschutz-Grundverordnung) are the classic trigger;
  • a title still needing more than 3 lines at 52pt (it would collide with the subtitles/footer);
  • a subtitle wider than the text area (subtitles render at a fixed 30pt).

If you hit one: shorten the text to a near-synonym, or insert a plain space at a natural compound boundary (Suchmaschinen Optimierung) — the generator deliberately does not hyphenate compounds automatically.

Prerequisite

Pillow, a local authoring dependency only (not shipped to the site or its runtime):

pip3 install Pillow

On Windows, run authoring/build inside WSL2 — the suite's recommended Windows environment (SETUP.md), where python3 and the bash helpers all work. Running natively is fine too: py -m pip install Pillow, and npm run og already falls back python3 → py -3 → python.

Going further — photo-driven cards

The generator deliberately ships the text-card core (emblem + wordmark + accent bar + title + subtitles + footer URL) because it works for any site with zero per-page art. When a content type has a natural image — a speaker headshot, a product shot, an author avatar — extend build_page() to read that image from frontmatter and composite a circular portrait

  • glow beside the text: iterate a content collection (src/content/<type>/*.md), render one portrait card per entry alongside the static-page cards, and keep the same encode-under-300 KB step. The template ships the text-card core; the portrait variant is a small, additive change.

Don't

  • Don't hand-export cards in Figma/Canva per page. They drift and balloon past 300 KB. The script is the single source of truth; re-running it is free.
  • Don't ship a square logo as og:image. It crops badly. Always 1200×630.
  • Don't point og:image at a remote/CDN URL the repo can't verify. Keep cards on-site in public/ so seo.spec.ts can prove they exist and fit.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.