Introduction
Generate Open Graph images, social cards, SVG, and animations from JSX, HTML, and CSS with Takumi.
Takumi generates Open Graph (OG) images, social cards, and banners from JSX, HTML, or node trees. Style them with CSS or Tailwind, then render PNG, JPEG, WebP, SVG, or animations without a headless browser.
Use takumi-js for image output. For invoices, reports, and other documents, start with PDF generation.
Install
npm i takumi-jstakumi-js bundles both bindings: the native renderer (@takumi-rs/core) and the WebAssembly one (@takumi-rs/wasm). It picks the right one at runtime: native on Node.js, WebAssembly on Cloudflare Workers, Vercel Edge, Deno, and the browser. No extra install.
Render an image
render takes JSX and returns image bytes. The built-in font covers the Latin text in this example. Save it as image.tsx and run bun image.tsx, or compile the JSX before running it in Node.js.
import { } from "takumi-js";
import { } from "node:fs/promises";
const = await (
<
={{
: 72,
: "linear-gradient(to bottom right, #fff7ed, #fecaca)",
}}
="w-full h-full flex items-center justify-center"
>
Hello Takumi
</>,
{ : 1200, : 630 },
);
await ("hello.png", );widthandheightset the canvas.tw="w-full h-full"makes the root fill that canvas.
Serve it over HTTP
ImageResponse extends the web Response, so any runtime with Request and Response can return it. The API matches next/og.
import { } from "takumi-js/response";
export function () {
return new (< ="w-full h-full grid place-items-center">Hello Takumi</>, {
: 1200,
: 630,
});
}Takumi never reads system fonts. One last-resort font ships built in (Geist, Latin only, weights
300 to 800). Load fonts for other scripts through fonts to avoid missing glyphs. See
Fonts.
Load a font
googleFonts fetches families in one request and returns fonts entries. A weight range or an axes entry loads the variable font, so font-weight and font-variation-settings drive its axes per element.
import { } from "takumi-js";
import { } from "takumi-js/helpers";
const = await (
<
={{
: 72,
: "Fraunces",
: "'opsz' 72, 'wght' 700",
}}
="w-full h-full flex items-center justify-center"
>
Hello Takumi
</>,
{
: 1200,
: 630,
: ([
{
: "Fraunces",
: "100..900",
: { : "9..144" },
},
]),
},
);fontsalso takes raw bytes, a descriptor, or a bare URL string.- Rendering many images? Register the fonts once on a
Rendererand reuse it.
Coming from satori
Takumi defaults a bare <div> to block layout. Keep explicit Flexbox styles when migrating a Satori template, and compare the rendered output. renderSvg() returns SVG, while render() returns encoded image bytes. See the Satori comparison and migration guide.
Next steps
Last updated on