Share cards
A share card is the image social sites show for a link (og:image). In taragen
it's an ordinary output whose content type is image/png: the template returns
SVG, and taragen rasterizes it into a PNG using the site's own fonts. No
headless browser or external tool is involved.
A card template
Name the template _outputs/<name>.png.jsx and return an <svg> with numeric width and height:
// _outputs/card.png.jsx
const W = 1200, H = 630, title = { family: "Recursive", size: 72, weight: 800 };
const lines = wrap(page.title ?? siteTitle, title, W - 160).slice(0, 4);
<svg width={W} height={H} viewBox={`0 0 ${W} ${H}`}>
<rect width={W} height={H} fill="#fff" />
<text x="80" y="104" font-family="Silkscreen" font-size="32">EXAMPLE.COM</text>
<text font-family="Recursive" font-size={title.size} font-weight={title.weight}>
{lines.map((line, i) => <tspan x="80" y={232 + i * 84}>{line}</tspan>)}
</text>
<rect x="80" y="520" width="1040" height="4" fill="#000" />
<text x="80" y="574" font-family="Recursive" font-size="28">{page.date ?? ""}</text>
</svg>
(wrap is the helper shown in
Defaults and globals
.)
Point your layout at it. og:image needs an absolute URL, so use siteURL:
// in _layout.jsx
{page.outputs?.card && <>
<meta property="og:image" content={`${page.siteURL}${page.outputs.card}`} />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
</>}
build writes /articles/2021/ngrok.card.png for every HTML page, and serve renders each card when it's requested, so you can open a card URL in the browser
while designing it.
Rules for card SVG
- Return a root
<svg>element, or a string of SVG markup. Thexmlnsattribute is added if it's missing. -
The root needs numeric
widthandheightin pixels, each at most 4096. These set the image size. -
data({ scale: 2 })renders at 2× (any whole number from 1 to 4) without changing your coordinates, for sharper cards on dense screens. -
Supported: shapes, paths, gradients, patterns, clipping, masks, filters,
<text>,<tspan>, and<image>. Scripts, animation, and<foreignObject>are ignored. SVG has no text wrapping; measure and break lines yourself (below). - Any output can be made a PNG output with
data({ contentType: "image/png" }), whatever its suffix.
The same SVG and fonts always produce byte-identical PNGs.
Fonts
Cards can use only fonts that are in your site. Every .ttf, .otf, .ttc, .woff, and .woff2 file anywhere in the site folder (except _public/ and
dot-prefixed paths) is available, so a card can use the same font files your
CSS serves, such as _assets/fonts/Recursive.woff2. System fonts are never
used, so cards look the same on every machine.
Text picks a face by font-family, font-weight, and font-style, as in CSS.
If two files provide the same family, weight, and style, the one whose path sorts
first wins.
Every font-family must name at least one font your site has. Generic names
like sans-serif don't count unless you have a font with that name. An unknown
family fails the card with an error that lists the families taragen found, so a
typo shows up immediately instead of silently falling back.
Variable fonts work. font-weight sets the wght axis (up to 900; for heavier
weights use font-variation-settings="'wght' 1000"), and font-variation-settings sets any other axis, such as Recursive's CASL and MONO. A font with a slnt axis but no ital axis, like Recursive, ignores font-style="italic"; use font-style="oblique" or 'slnt' -15 instead.
Pixel fonts stay crisp at sizes on their pixel grid with whole-pixel x and y. Silkscreen, for example, is 8 pixels per em, so use 16, 24, 32, and so on. text-rendering="optimizeSpeed" turns antialiasing off at any size.
Measuring text with measureText()
measureText(text, font) returns the width of a string in pixels, using the
same fonts and shaping as the rasterizer:
measureText("Building your own Ngrok", { family: "Recursive", size: 72, weight: 700 })
| Option | Default |
|---|---|
family |
required |
size |
16 (pixels) |
weight |
400 |
style |
"normal" |
letterSpacing |
0 (pixels, added between letters, not after the last) |
An unknown family throws. measureText works in any JSX file, not just card
templates. Line breaking is up to you; the wrap helper above is a simple word
wrapper you can extend with ellipses or line limits.
Images in cards
<image href="..."> can use a root-relative path to a file in your site
(/_assets/avatar.png) or a data: URI. PNG, JPEG, GIF, WebP, and SVG are
supported. Remote URLs, file: URLs, relative paths, and paths that lead
outside the site folder are errors.
Card errors
A card fails the build (or returns a 500 in serve) when the template doesn't
return SVG, width or height is missing or over 4096, a font family is
unknown, or an image reference isn't allowed.