og-image: optimized Open Graph image
Goal: produce the PNG asset of a share image (1200×630), through the
project's pipeline (Satori -> resvg), aligned with the guidelines. BrandArtisan
generates the image only; the og:/twitter: tags live on the site that
hosts it.
This is a specialization of new-template with the OG constraints hard-coded.
Same conventions: the Template contract (from brand-artisan), assets through
brand(), fonts discovered in fonts/, export default ... satisfies Template.
0. Prerequisites (blocking)
The chain project -> template folder -> guidelines must exist before you
start. Do not begin until it does:
- Resolve
<project> (from the arguments, otherwise ask).
- Check
templates/<project>/ and brands/<project>/brand.md.
- If the guidelines or the project are missing -> STOP: ask the user to run
/new-project <project> first. No visual without guidelines (CLAUDE.md rule).
1. Frame it
<name> is a kebab-case slug, default og (or og-<page> if there are
several previews). Check that templates/<project>/<name>.tsx does not exist.
- Read
brands/<project>/brand.md: palette (hex), type, which logo variant to
use depending on the background, and the don'ts.
- Read
brands/<project>/project.md if it exists: set the tone and the
claims (don't invent figures or promises). If absent -> ask for the tone
and the message rather than guessing.
- Ask for the message: short headline + tagline (1 sentence). No paragraph.
2. OG constraints (to respect in the template)
- Exact size 1200×630 (1.91:1 ratio). The standard recognized by Facebook,
LinkedIn, Slack, Discord and X. Do not deviate; absolute minimum 600×315.
- Opaque background, never transparency: the platforms compose the image over
varied backgrounds.
- Safe area of roughly 80 px of margin: keep the logo and the text towards
the center. The corners can be cropped or rounded (Discord, X), so nothing
important goes in them.
- Legible when small: the preview often displays about 400 px wide on mobile.
Large headline (~60–90 px), short tagline, strong contrast. Mental test: still
legible once shrunk to 400 px wide.
- Light weight: aim for < 300 KB. Beyond that, some consumers (WhatsApp
in particular) do not generate the preview. The engine's flat rendering is
naturally light: favor the mark as an SVG data-URI (as
og.tsx does),
avoid embedding large raster PNGs, and don't inflate with scale: leaving
scale out (= 1) is enough at 1200×630 for OG.
- PNG: that is the engine's output, ideal for crisp text.
3. Write the template
templates/<project>/<name>.tsx, with colors as constants taken from the
guidelines (invent nothing). Skeleton:
import type { ReactNode } from "react";
import { brand, type Template } from "brand-artisan";
// import { readFile } from "node:fs/promises"; // if you load the mark (SVG/PNG)
const SIZE = { width: 1200, height: 630 }; // OG standard, no scale
// <Project> guideline palette (from brands/<project>/brand.md).
const INK = "#......";
// const markSvg = await readFile(brand("<project>/favicon/icon.svg"));
function render(): ReactNode {
return (
<div
style={{
width: "100%",
height: "100%",
display: "flex",
flexDirection: "column",
justifyContent: "center",
padding: 80, // safe area
backgroundColor: INK, // opaque background
}}
>
{/* logo + large headline + short tagline, strong contrast */}
</div>
);
}
export default { size: SIZE, title: "<Human title>", render } satisfies Template;
Keep the code minimal (principle #2): factor out a background effect locally
only if it repeats.
4. Verify
npm run typecheck -> green.
npm run build -> writes out/<project>/<slug>.png.
- Check the PNG: dimensions 1200×630, opaque background, weight < 300 KB
(beyond that, warn and lighten: drop a heavy raster, lower a
scale).
- Preview:
npm run dev then /<project>/<name>; check legibility by mentally
shrinking to about 400 px.
Success criterion: a 1200×630 PNG, opaque, under 300 KB, legible when small,
and using only the colors and type from brand.md except where the user says
otherwise.
1---2name: og-image3description: Creates an Open Graph image (social share preview) optimized for BrandArtisan. Use when the user wants an "og image", a "share image", or an "Open Graph / Twitter / LinkedIn / Discord" preview for a project. Produces a 1200x630 .tsx template aligned with the brand guidelines, rendered as a light PNG through the project's Satori engine. Requires a project with its brand.md in place.4---56# og-image: optimized Open Graph image78Goal: produce the **PNG asset** of a share image (1200×630), through the9project's pipeline (Satori -> resvg), aligned with the guidelines. BrandArtisan10generates **the image only**; the `og:`/`twitter:` tags live on the site that11hosts it.1213This is a specialization of `new-template` with the OG constraints hard-coded.14Same conventions: the `Template` contract (from `brand-artisan`), assets through15`brand()`, fonts discovered in `fonts/`, `export default ... satisfies Template`.1617## 0. Prerequisites (blocking)1819The chain **project -> template folder -> guidelines** must exist before you20start. Do not begin until it does:2122- Resolve `<project>` (from the arguments, otherwise ask).23- Check `templates/<project>/` **and** `brands/<project>/brand.md`.24- If the guidelines or the project are missing -> **STOP**: ask the user to run25 `/new-project <project>` first. No visual without guidelines (CLAUDE.md rule).2627## 1. Frame it2829- `<name>` is a kebab-case slug, default `og` (or `og-<page>` if there are30 several previews). Check that `templates/<project>/<name>.tsx` does not exist.31- Read `brands/<project>/brand.md`: palette (hex), type, which logo variant to32 use depending on the background, and the **don'ts**.33- Read `brands/<project>/project.md` if it exists: set the **tone** and the34 **claims** (don't invent figures or promises). If absent -> ask for the tone35 and the message rather than guessing.36- Ask for the **message**: short headline + tagline (1 sentence). No paragraph.3738## 2. OG constraints (to respect in the template)3940- **Exact size 1200×630** (1.91:1 ratio). The standard recognized by Facebook,41 LinkedIn, Slack, Discord and X. Do not deviate; absolute minimum 600×315.42- **Opaque background**, never transparency: the platforms compose the image over43 varied backgrounds.44- **Safe area** of roughly 80 px of margin: keep the logo and the text towards45 the center. The corners can be cropped or rounded (Discord, X), so nothing46 important goes in them.47- **Legible when small**: the preview often displays about 400 px wide on mobile.48 Large headline (~60–90 px), short tagline, strong contrast. Mental test: still49 legible once shrunk to 400 px wide.50- **Light weight**: aim for **< 300 KB**. Beyond that, some consumers (WhatsApp51 in particular) do not generate the preview. The engine's flat rendering is52 naturally light: favor the mark as an **SVG data-URI** (as `og.tsx` does),53 avoid embedding large raster PNGs, and **don't inflate with `scale`**: leaving54 `scale` out (= 1) is enough at 1200×630 for OG.55- **PNG**: that is the engine's output, ideal for crisp text.5657## 3. Write the template5859`templates/<project>/<name>.tsx`, with colors as constants taken from the60guidelines (invent nothing). Skeleton:6162```tsx63import type { ReactNode } from "react";64import { brand, type Template } from "brand-artisan";65// import { readFile } from "node:fs/promises"; // if you load the mark (SVG/PNG)6667const SIZE = { width: 1200, height: 630 }; // OG standard, no scale6869// <Project> guideline palette (from brands/<project>/brand.md).70const INK = "#......";7172// const markSvg = await readFile(brand("<project>/favicon/icon.svg"));7374function render(): ReactNode {75 return (76 <div77 style={{78 width: "100%",79 height: "100%",80 display: "flex",81 flexDirection: "column",82 justifyContent: "center",83 padding: 80, // safe area84 backgroundColor: INK, // opaque background85 }}86 >87 {/* logo + large headline + short tagline, strong contrast */}88 </div>89 );90}9192export default { size: SIZE, title: "<Human title>", render } satisfies Template;93```9495Keep the code minimal (principle #2): factor out a background effect locally96only if it repeats.9798## 4. Verify99100- `npm run typecheck` -> green.101- `npm run build` -> writes `out/<project>/<slug>.png`.102- Check the PNG: **dimensions 1200×630**, opaque background, **weight < 300 KB**103 (beyond that, warn and lighten: drop a heavy raster, lower a `scale`).104- Preview: `npm run dev` then `/<project>/<name>`; check legibility by mentally105 shrinking to about 400 px.106107**Success criterion**: a 1200×630 PNG, opaque, under 300 KB, legible when small,108and using only the colors and type from `brand.md` except where the user says109otherwise.