Takumi

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.

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-js

takumi-js ships two backends and picks one at runtime. You install nothing else.

RuntimeBackend
Node.js, Bunnative (@takumi-rs/core)
Cloudflare Workers, edge runtimes, Deno, browsersWebAssembly (@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.

image.tsx
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", );
  • width and height set 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.

app/og/route.tsx
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.

Load a variable font
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/takumi

The 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