From a title and a brand kit to a cached PNG \u2014 in four stages.
No canvas editor sits between your agent and the output. Every request runs the same deterministic pipeline: resolve, render, convert, cache.
Agent sends structured fields
A title, a theme, a size, and a brandKitId — nothing else to decide. No prompt to iterate on.
- Validated against the template's typed schema
- Missing fields fall back to brand-kit defaults, never a blank
{"template": "blog-gradient-v1","title": "How the algorithm ranks posts","size": "1200x630","brandKitId": "brand_9f2c"}
Props merge with the brand kit
Logo, colors, and font resolve from the brand kit — fetched once at save time, never re-fetched per request.
- Logo/font fetches are cached and SSRF-guarded
- Font buffers pre-loaded per workspace, not per call
{"accent": "#2F5BFF","font": "Sora-Bold","logo": "cache://brand_9f2c/logo"}// resolved from brand_9f2c, not the request
Satori renders JSX → SVG
Each template is a typed JSX component. Satori lays it out and produces SVG — no headless browser, no Chromium process to keep warm.
- resvg converts SVG → PNG/WebP
- Line balancing and font scaling run automatically on overflow
export default function Template(props) {return (<div style={{ background: props.accent }}><h1>{props.title}</h1></div>);}
Cached, CDN’d, returned
The render is keyed by a hash of the fully-resolved input — same title, template, and brand kit hits cache instantly, even across different agents.
- <300ms on a cache hit, globally distributed
- Response includes ready-to-embed alt text
{"url": "cdn.imageclaw.dev/9f2c/a83e.png","width": 1200, "height": 630,"cached": true, "ms": 214}
Why it's fast \u2014 and self-hostable.
No headless browser
Templates render to SVG via layout, not a Chromium instance — dramatically lighter to run and package than Puppeteer-based renderers.
Fast raster conversion
SVG → PNG/WebP via native Rust bindings, benchmarked against sharp and librsvg for your template complexity.
Hash of resolved input
Template + resolved props + font version — so identical requests from different agents share a cache entry.
Run the whole pipeline yourself.
Render engine, template registry, and CLI are AGPL-licensed. Clone it, point it at your own CDN.