Introduction
Takumi lays out JSX, HTML, and CSS with one engine and turns the result into images, PDFs, or paint trees, without a browser.
Takumi is one layout engine, with text and inline layout ported from Chromium. It turns JSX, HTML, and CSS into images, PDFs, and other outputs without a headless browser.
Pick a package
Each package runs the same layout engine. Pick the one that produces your output.
Images and animations
takumi-js renders PNG, JPEG, WebP, SVG, and animated WebP, APNG, or GIF. Open Graph images are one use.
PDF documents
takumi-pdf writes paged documents such as invoices, reports, and tickets.
Paint
takumi-paint returns every box, text run, and image with its position. Draw them with Canvas, slides, or a native API, or read the layout.
Command line
The takumi CLI renders an HTML file to an image or a PDF from a terminal or a script, without writing code.
The rest of this page uses takumi-js.
For how a render goes from input to output, and where it differs from a browser, see How Takumi works.
Install
npm i takumi-jstakumi-js ships two backends and picks one at runtime. You install nothing else.
| Runtime | Backend |
|---|---|
| Node.js, Bun | native (@takumi-rs/core) |
| Cloudflare Workers, edge runtimes, Deno, browsers | WebAssembly (@takumi-rs/wasm) |
Render an image
render takes JSX and returns encoded image bytes. Save this as image.tsx and run bun image.tsx. In Node.js, compile the JSX first.
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 image size. Leave one out to size that side to the content.tw="w-full h-full"makes the root fill the image.
Serve it over HTTP
ImageResponse extends the web Response. Return it from any route handler that uses Request and Response. Its 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. The only built-in font is Geist, which covers Latin at weights
300 to 800. Load fonts for other scripts through fonts, or their glyphs go missing. See
Fonts.
Load a font
googleFonts loads Google Fonts families in one request. A weight range or an axes entry loads the variable font. Then font-weight and font-variation-settings set 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" },
},
]),
},
);fonts also takes a font URL, raw bytes, or a descriptor. To load fonts before the first request, register them on a Renderer.
Coming from satori
A bare <div> lays out as a block, as in a browser. Keep explicit Flexbox styles when you move a Satori template, and compare the output. renderSvg() returns SVG like satori() does. render() returns encoded image bytes. See the Satori comparison and migration guide.
Coding agents
Takumi ships skills that teach coding agents its API and rules, and how to migrate from satori or a headless browser. Install them into your project:
npx skills add kane50613/takumiThe docs are also indexed for agents at /llms.txt, and each page is available as Markdown by adding .md to its URL.
Next steps
Last updated on