Agent skill

Satori

by usenotra in usenotra/notra

Expert guidance for Satori, the library that converts JSX/HTML and CSS into SVG (the engine behind dynamic Open Graph images and social cards).

AGPL-3.0Auto-check passedMedia & Creative

Install Satori

skills CLI
$ npx skills add usenotra/notra --skill satori -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install usenotra/notra satori --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/usenotra/notra.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/satori .claude/skills/satori && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
satori
GitHub stars
256
Token cost
~3k tokens
SKILL.md length
1,411 words
Files
2 (incl. references)
Skills in repo
17
Repo updated
First seen
Licence
AGPL-3.0

At a glance

Expert guidance for Satori, the library that converts JSX/HTML and CSS into SVG (the engine behind dynamic Open Graph images and social cards).

  • Works in 6 steps: Did every multi-child container get… → Is the direction right? Remember the… → Did a shorthand value lose its unit?… → …
  • Debugging Satori markup e.g
  • SKILL.md covers Basic usage, Constraints, CSS support and HTML elements, plus 5 more sections
  • Reaches picsum.photos and cdnjs.cloudflare.com

What it does

Satori is an agent skill from usenotra/notra. Expert guidance for Satori, the library that converts JSX/HTML and CSS into SVG (the engine behind dynamic Open Graph images and social cards). Use whenever writing or debugging Satori markup e.g. authoring JSX for OG images, choosing CSS that Satori actually supports, fixing layout that renders wrong, embedding fonts, rendering emoji or images, or resolving Satori errors like "Expected length unit" or unsupported property issues. Reach for this any time someone renders HTML/CSS to SVG or PNG with Satori, even if…

Its SKILL.md is about 3k tokens, which your agent loads only when the skill is triggered. The skill folder holds 2 other files, including reference files (for example `references/css-support.md`).

It sits in Media & Creative, covering Social media graphics, React components and Embeddings. The repository describes itself as: Notra is a modern GEO tool that asks ChatGPT, Claude and Gemini the questions your buyers ask. See if you show up, who shows up instead and how to fix it. The licence is AGPL-3.0.

When your agent uses it

  • Debugging Satori markup e.g
  • Tasks that involve Social media graphics
  • Tasks that involve React components

Example prompts

  • “Expected length unit”
  • “/satori”

Requirements

  • Node.js

Workflow steps

6 steps, taken from the first numbered list in SKILL.md.

  1. Did every multi-child container get display: 'flex'? Missing display is the most common error and silent misalignment.
  2. Is the direction right? Remember the default is row. Vertical stacks need flexDirection: 'column'.
  3. Did a shorthand value lose its unit? Expected length unit means a padding/margin/border value needs px or %.
  4. Is the property actually supported? Check references/css-support.md. Unsupported properties are ignored or throw rather than approximated.
  5. Are you relying on z-index, calc, or currentColor off the color property? None of those work; reorder markup, precompute, or set explicit…
  6. Turn on debug: true to see bounding boxes and confirm the layout tree.

What it can do on your machine

Read from SKILL.md and the folder at commit 55d4d5d. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    No scripts in the folder and no shell commands in SKILL.md (its code samples are javascript).

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    Hosts in commands or code, which the agent is likely to contact:

    • picsum.photos
    • cdnjs.cloudflare.com
    • unpkg.com

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Satori loads about 3k tokens when it runs, and up to ~4.6k if it reads all its reference files. Until then it costs about 137 tokens; SKILL.md has 1,411 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~137
When it runs · the whole SKILL.md, loaded when a task matches
~3k
With references · SKILL.md plus every file in references/, read only if the agent opens them
~4.6k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from usenotra/notra at commit 55d4d5d, republished under its AGPL-3.0 licence (© usenotra). 1,411 words, ~2,974 tokens.

Download SKILL.mdSave it as .claude/skills/satori/SKILL.md (or your agent's skills folder). This skill also uses 1 other file; get the full folder from GitHub.
name
satori
description
Expert guidance for Satori, the library that converts JSX/HTML and CSS into SVG (the engine behind dynamic Open Graph images and social cards). Use whenever writing or debugging Satori markup e.g. authoring JSX for OG images, choosing CSS that Satori actually supports, fixing layout that renders wrong, embedding fonts, rendering emoji or images, or resolving Satori errors like "Expected length unit" or unsupported property issues. Reach for this any time someone renders HTML/CSS to SVG or PNG with Satori, even if they do not name it.

Satori

Satori converts JSX-like HTML and CSS into SVG. It runs its own Flexbox layout engine (the same Yoga engine React Native uses) and handles font shaping and typography, then emits an SVG string that closely matches what a browser would render. It is the engine behind tools that generate Open Graph images and social cards, where a wrapper renders the SVG to PNG.

Treat yourself as an expert in Satori. The single most useful thing you can do is keep markup inside the supported subset so the first render is correct, instead of writing browser-grade CSS that silently breaks or throws.

Basic usage

jsx
import satori from 'satori'

const svg = await satori(
  <div style={{ color: 'black', display: 'flex' }}>hello, world</div>,
  {
    width: 600,
    height: 400,
    fonts: [
      { name: 'Roboto', data: robotoArrayBuffer, weight: 400, style: 'normal' },
    ],
  },
)

satori(...) returns an SVG string. width and height set the canvas. At least one font is required whenever any text is rendered (see Fonts).

Constraints

These behaviors most often produce wrong output or runtime errors. Account for them before writing markup.

  • Every element that contains more than one child must declare display: 'flex' (or display: 'none'). Satori is Flexbox only. A div with multiple children and no explicit display will throw. Default to putting display: 'flex' on every container. Single text children are tolerated, but being explicit is safest.
  • Default flexDirection is row, not column. This is the opposite of how people mentally stack divs. Set flexDirection: 'column' whenever you want vertical stacking.
  • Padding and margin shorthand need explicit units on every value. padding: '0 36' throws Expected length unit. Write padding: '0px 36px', and '0px 36px 36px 36px' for the four value form. A single bare number like padding: 36 is fine, because Satori treats a lone number as px.
  • Use flex layout for everything, including overlap. For overlapping or precisely placed elements, use position: 'absolute' with top/left/right/bottom on a position: 'relative' parent.
  • Never put HTML entity references in text. Satori does not decode them, so publish&#8209;ready renders the literal characters &#8209; on the image instead of a non-breaking hyphen. This applies to numeric (&#8209;, &#160;) and named (&nbsp;, &amp;, &mdash;) entities alike. Write the actual Unicode character directly in the string instead — publish‑ready (or the literal glyph publish‑ready) for a non-breaking hyphen,   for a non-breaking space, & for an ampersand, — for an em dash.

CSS support

Satori implements a subset of CSS. Assume anything not in the supported table is unsupported, and verify before relying on it. For the complete matrix with allowed values and defaults, read references/css-support.md.

Supported
CategoryProperties
Layoutdisplay (flex, contents, none), position (relative, static, absolute), top/right/bottom/left, width/height, min/max width/height, overflow (visible, hidden)
FlexflexDirection, flexWrap, flexGrow, flexShrink, flexBasis, alignItems, alignContent, alignSelf, justifyContent, gap
Boxmargin, padding, border (width, solid/dashed style, color, shorthand), borderRadius, boxSizing, boxShadow, opacity
Color and backgroundcolor, backgroundColor (single value), backgroundImage (linear-gradient, repeating-linear-gradient, radial-gradient, repeating-radial-gradient, url), backgroundPosition, backgroundSize (cover, contain, auto, two-value), backgroundClip (border-box, text), backgroundRepeat
TextfontFamily, fontSize, fontWeight, fontStyle, textAlign, textTransform, textOverflow (clip, ellipsis), textDecoration, textShadow, lineHeight, letterSpacing, whiteSpace, wordBreak, textWrap (wrap, balance), textIndent, tabSize, lineClamp
Transform and effectstransform (translate, rotate, scale, skew), transformOrigin, filter, clipPath, mask (maskImage, maskPosition, maskSize, maskRepeat), objectFit, objectPosition, WebkitTextStroke
Variables--name declarations and var(--name, fallback) usage, including inheritance and nesting
Unsupported
Property or featureNotes and workaround
z-indexNo stacking contexts. Elements paint in document order, so later siblings render on top. Reorder markup to control layering.
calc()Precompute values in JavaScript before they reach the style object.
currentColor outside colorResolves only for the color property. Set explicit values for borders, backgrounds, and fills.
3D transformsNot supported. Use 2D translate, rotate, scale, and skew only.
min-content, max-content, fit-contentNot supported for min/max width and height.
flexBasis: autoNot supported. Use an explicit basis or rely on width/height.
Interactive or resource elementsNo <input>, <style>, <script>, or <link>. Only static, visible elements render.
<img> alt, SVG <title>Render as visible text on the image. Omit alt; strip <title> from inline SVG (see Images and Inline SVG).
WOFF2 fontsConvert to TTF, OTF, or WOFF (see Fonts).
AVIF / WebP imagesConvert to PNG or JPEG (see Images).
Kerning, ligatures, OpenType featuresAdvanced typography is not supported.
RTL languagesNot supported.

HTML elements

Satori supports only static, visible elements. Interactive or resource-loading elements are out: no <input>, no <style>, no <script>, no <link>. The output is not guaranteed to match a browser pixel for pixel, because Satori runs its own SVG 1.1 based layout engine. Stick to <div>, <span>, <img>, <svg>, and text.

Inline SVG

Inline <svg> works and is the reliable way to place vector logos and icons. Keep the markup well formed: include a viewBox, and use explicit width/height. Grouping (<g transform=...>), fill-rule, and paths without fills render correctly.

Strip any <title> element from the SVG markup before passing it in. Satori treats it as text content, so the title can leak into the render as visible words drawn on the image. Logos pulled from icon libraries often ship with one, so check and remove it.

Show full SKILL.md (603 more words)Show less
Images

Use <img> and set width and height explicitly so layout is stable:

jsx
<img src="https://picsum.photos/200/300" width={200} height={300} />

With backgroundImage: url(...), the image stretches to fit the element unless you set backgroundSize. When the SVG will be rasterized to PNG afterward, prefer a base64 data URI (or a Buffer/ArrayBuffer) as src so Satori does not perform extra network I/O.

Only PNG, JPEG, and GIF decode reliably. AVIF and WebP do not work and silently fail to render. Convert them to PNG or JPEG before passing them in (for example with sharp), and remember that a modern URL ending in .jpg may still serve WebP via content negotiation, so convert the bytes rather than trusting the extension.

Do not put an alt attribute on <img>. Satori treats it as text content, so the value can leak into the render as visible words drawn on the canvas. Leave it off; the output is a static image and gains nothing from it.

Fonts

Any rendered text requires at least one font. Satori accepts TTF, OTF, and WOFF. WOFF2 is not supported. Pass font data as ArrayBuffer (web) or Buffer (Node.js):

jsx
await satori(<div style={{ fontFamily: 'Inter', display: 'flex' }}>Hello</div>, {
  width: 600,
  height: 400,
  fonts: [
    { name: 'Inter', data: inter, weight: 400, style: 'normal' },
    { name: 'Inter', data: interBold, weight: 700, style: 'normal' },
  ],
})

Pass multiple fonts and reference any of them via fontFamily. Define fonts once and reuse the object across renders for better performance rather than rebuilding it per call.

Advanced typography (kerning, ligatures, other OpenType features) is not supported, and RTL languages are not supported.

Emoji

Text glyphs render from the provided fonts; emoji do not come for free. Map specific graphemes to image sources with graphemeImages, where each image is sized to the current font size as a square:

jsx
await satori(<div style={{ display: 'flex' }}>Ship it 🚀</div>, {
  ...,
  graphemeImages: { '🚀': 'https://cdnjs.cloudflare.com/.../1f680.svg' },
})
Locales

The same characters can render differently per locale. Set lang on an element to force a locale, for example <div lang="ja-JP">骨</div>.

Dynamically loading fonts and emoji

When a text segment needs a font or emoji image that was not provided up front, Satori calls loadAdditionalAsset(code, segment). code is the detected language code, or 'emoji', or 'unknown'. Return a data URI for emoji, or font data for text:

jsx
loadAdditionalAsset: async (code, segment) => {
  if (code === 'emoji') return `data:image/svg+xml;base64,...`
  return loadFontFromSystem(code)
}

Output and rendering options

  • embedFont (default true): text is emitted as <path> with the glyph outlines inlined, so downstream tools need no font files. Set embedFont: false to emit <text> instead (smaller output, but the renderer must have the font).
  • pointScaleFactor: passed through to Yoga to control how layout values round to the pixel grid; raise it for crisper output on high-DPI targets.
  • debug: true: draws bounding boxes, which is the fastest way to see why layout is off.

Runtime support

Satori runs in the browser, Node.js (>= 16), and Web Workers. It bundles its WASM (Yoga) dependency as base64 and loads it at runtime. In environments that forbid dynamic WASM loading, use the standalone build and initialize Yoga yourself:

jsx
import satori, { init } from 'satori/standalone'

const res = await fetch('https://unpkg.com/satori/yoga.wasm')
await init(await res.arrayBuffer())
const svg = await satori(...)

Debugging workflow

When output looks wrong, work through these in order, since they cover the overwhelming majority of cases:

  1. Did every multi-child container get display: 'flex'? Missing display is the most common error and silent misalignment.
  2. Is the direction right? Remember the default is row. Vertical stacks need flexDirection: 'column'.
  3. Did a shorthand value lose its unit? Expected length unit means a padding/margin/border value needs px or %.
  4. Is the property actually supported? Check references/css-support.md. Unsupported properties are ignored or throw rather than approximated.
  5. Are you relying on z-index, calc, or currentColor off the color property? None of those work; reorder markup, precompute, or set explicit values.
  6. Turn on debug: true to see bounding boxes and confirm the layout tree.

Reference files

  • references/css-support.md — the complete supported-CSS matrix with allowed values and defaults, plus the global limitation notes. Read it whenever you are unsure if a property or value is supported.

© usenotra, AGPL-3.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 1 other file (references) in .agents/skills/satori of usenotra/notra.

  • SKILL.md
  • references/css-support.md

Open the folder on GitHubat commit 55d4d5d

Compare with similar skills

Satori next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Satori compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Satori this skillusenotra/notra256—~3kAutomated safety check: PassAGPL-3.0
Slabstencil-hq/slab112—~3.1kAutomated safety check: PassMIT
Brand and Design Toolkitnextlevelbuilder/ui-ux-pro-max-skill134k1 repos~3.5kAutomated safety check: PassMIT
AI SDKvercel-labs/ai-facts16820 repos~1.2kAutomated safety check: PassNone
After Effectsaedev-tools/adobe-agent-skills1081 repos~5.2kAutomated safety check: PassApache-2.0
Text to PNG Card Casterlijigang/ljg-skills7.5k—~1.9kAutomated safety check: PassMIT

Similar skills

  • Slab

    stencil-hq/slab

    Writing, editing, and rendering Slab documents (.slab) — the declarative design language for app screens, posters, terminal UIs, and interactive components.

    112 GitHub stars~3.1k tokensUpdated 1 mo ago
    Frontend & DesignAuto-check passed
  • Brand and Design Toolkit

    nextlevelbuilder/ui-ux-pro-max-skill

    Bundles design tasks behind one skill: brand identity, tokens, UI styling, logos, corporate identity mockups, slides, banners, icons and social images.

    134k GitHub starsUsed in 1 repo~3.5k tokens
    Media & CreativeAuto-check passed
  • AI SDK

    vercel-labs/ai-facts

    Official

    Answer questions about the AI SDK and help build AI-powered features.

    168 GitHub starsUsed in 20 repos~1.2k tokens
    AI & LLM EngineeringAuto-check passed
  • After Effects

    aedev-tools/adobe-agent-skills

    Automate Adobe After Effects via ExtendScript. An agent skill from aedev-tools/adobe-agent-skills.

    108 GitHub starsUsed in 1 repo~5.2k tokens
    Media & CreativeAuto-check passed
  • Text to PNG Card Caster

    lijigang/ljg-skills

    Turns text, URLs or local files into tall PNG cards through HTML typography, with four modes: long reading card, full-text layout, comic and whiteboard.

    7.5k GitHub stars~1.9k tokensUpdated yesterday
    Media & CreativeAuto-check passed
  • Typography Cover Designer

    sugarforever/01coder-agent-skills

    Designs typography-driven video covers and thumbnails in HTML/CSS and screenshots them with Chrome DevTools at 16:9, 16:10, 9:16 and 3:4.

    137 GitHub stars~3.3k tokensUpdated 3 mo ago
    Media & CreativeAuto-check passed

More from usenotra/notra

All 17 skills in this repo
  • Ponytail Help

    usenotra/notra

    Quick-reference card for all ponytail modes, skills, and commands.

    256 GitHub starsUsed in 3 repos~697 tokens
    Auto-check passed
  • Neon Postgres

    usenotra/notra

    Guides and best practices for working with Lakebase Postgres, the database behind Neon.

    256 GitHub stars~4.1k tokensUpdated today
    Auto-check: notes
  • Workos Widgets

    usenotra/notra

    A skill your agent uses when the user is implementing, embedding, or debugging a WorkOS Widget — specifically the User Management, User Profile, Admin Portal SSO Connection, or Admin Portal Domain…

    256 GitHub stars~2k tokensUpdated today
    Auto-check passed
  • Autumn Catalog

    usenotra/notra

    Modeling a user's pricing into an Autumn catalog — deciding the structure (plans, variants, add-ons, licenses, credit systems, pooled balances) before writing config, then filling in the numbers.

    256 GitHub stars~6.1k tokensUpdated today
    Auto-check passed
  • Code Organization

    usenotra/notra

    Repo file-organization convention for TypeScript projects. An agent skill from usenotra/notra.

    256 GitHub stars~893 tokensUpdated today
    Auto-check passed
  • Effect

    usenotra/notra

    Opinionated guide for building production TypeScript applications with Effect v4.

    256 GitHub starsUsed in 1 repo~1.8k tokens
    Auto-check passed

Questions about Satori

What does Satori do?

Expert guidance for Satori, the library that converts JSX/HTML and CSS into SVG (the engine behind dynamic Open Graph images and social cards). Satori is an agent skill from usenotra/notra. Expert guidance for Satori, the library that converts JSX/HTML and CSS into SVG (the engine behind dynamic Open Graph images and social cards).

When should I use Satori?

Satori fits situations like: debugging Satori markup e.g; tasks that involve Social media graphics; tasks that involve React components.

How do I install Satori in Claude Code?

Run `npx skills add usenotra/notra --skill satori -a claude-code`. Or copy the skill folder (.agents/skills/satori in usenotra/notra) into .claude/skills/satori in your project. Claude Code loads it when a task matches its description.

How do I install Satori in Codex?

Run `npx skills add usenotra/notra --skill satori -a codex`. Or copy the skill folder (.agents/skills/satori in usenotra/notra) into .agents/skills/satori in your project. Codex loads it when a task matches its description.

Can I use Satori in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add usenotra/notra --skill satori -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/satori, .gemini/skills/satori, .github/skills/satori and .opencode/skills/satori in your project.

What does Satori need to run?

SKILL.md names no scripts, command-line tools or credentials: Satori is instructions for the agent only. Our summary lists: Node.js.

Does Satori access the network?

SKILL.md names 3 domains. In commands or code: picsum.photos, cdnjs.cloudflare.com and unpkg.com; the agent is likely to contact these when it follows the instructions. This is read from the text; nothing was executed.

Is Satori safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Satori use?

Satori is published under the AGPL-3.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Satori use?

About 3k tokens (SKILL.md is roughly 12k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 1.6k tokens, read only when the agent opens those files.

What are the alternatives to Satori?

Skills that share tags, products or a category with Satori: Slab (stencil-hq/slab, 112 stars), Brand and Design Toolkit (nextlevelbuilder/ui-ux-pro-max-skill, 134k stars), AI SDK (vercel-labs/ai-facts, 168 stars) and After Effects (aedev-tools/adobe-agent-skills, 108 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Satori?

usenotra (a GitHub organization) maintains it in usenotra/notra, which has 256 GitHub stars. The repository holds 17 skills in this directory. The repository was last updated on October 9, 2026.

Source: usenotra/notra on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.