# Architecture URL: /docs/architecture Explains how the architecture of Takumi is designed at a high level. ## Data Structure [#data-structure] ### Format [#format] Takumi uses JSON format as its the most universal format that can be easily serialized and deserialized. ### Node [#node] HTML is complex, it defines [a lot of elements](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements) that are used to build the web. But since we are building static images, only three types of nodes are required: **an image, a text, or a container**. The details are described in the [Reference](/docs/reference#node-types) section. ### `fromJsx` helper [#fromjsx-helper] To bridge the gap between JSX and nodes, we provide a `fromJsx` helper function that helps mapping elements to nodes, and handle React specific features like Server Components and Fragments. The rules for this function are simple, you can just [look at the implementation](https://github.com/kane50613/takumi/blob/master/takumi-helpers/src/jsx/jsx.ts) to understand it. * React (Server) Components are resolved to their final values before processing. * `` and `` elements become an Image node with style applied. * All other React elements become a Container node with style and style presets applied. * Rest of the primitive types (string/number) are automatically converted to Text node. * `props.style` is passed on to the container node as is. ## Styling [#styling] Takumi uses [Taffy](https://github.com/DioxusLabs/taffy) to layout the positions, and [Parley](https://github.com/linebender/parley) to layout the text, so it mostly depends on the features that these two libraries support. ### CSS [#css] The syntax parser is inspired by [lightningcss](https://github.com/parcel-bundler/lightningcss), check [Reference](/docs/reference#style-properties) to get the full list of supported properties. ### Tailwind [#tailwind] Originally [`twrnc`](https://www.npmjs.com/package/twrnc) was used, but it was removed in favor of our own implementation. Arbitrary values would just be passed to the CSS parser mentioned above. ## Distribution [#distribution] ### As Rust Crate [#as-rust-crate] If you want to build a port of Takumi to your own language or just embed in Rust application, install `takumi` as a dependency. ```toml [dependencies] takumi = "*" # replace with the latest version ``` The documentation is available on [docs.rs](https://docs.rs/takumi/latest/takumi/). ### For Node.js Runtime [#for-nodejs-runtime] In order to utilize the power of multithreading and non-blocking, instead of building for wasm, we target [napi-rs](https://napi.rs/) to build the native binary for Node.js. The package is published as [`@takumi-rs/core`](https://www.npmjs.com/package/@takumi-rs/core) on npm. ### For Edge Runtime / Browser [#for-edge-runtime--browser] This is relatively rare, but if you are using a Edge runtime or browser, you can use the `@takumi-rs/wasm` entrypoint. And to keep the wasm file small, woff font loading is not supported and theres no bundled fonts (so font needs to be loaded to render text). # Introduction URL: /docs A Rust rendering engine that converts JSX, HTML, and node trees into images. No headless browser required. Takumi renders JSX, raw HTML, and structured node trees through a full CSS layout and compositing pipeline, then outputs PNG, JPEG, WebP, ICO, GIF, APNG, or raw video frames. This documentation covers the JavaScript bindings (`takumi-js`). For the low-level Rust API, see the [crate docs on docs.rs](https://docs.rs/takumi). ## How It Works [#how-it-works] Most image-generation solutions are either a headless Chromium instance eating 300 MB of RAM, or a minimal SVG-to-PNG renderer that falls apart the moment you need real CSS. Takumi is neither of those. It converts any template into a **node tree** with three node kinds: `container`, `image`, and `text`. That tree runs through: 1. **Layout** via [taffy](https://github.com/DioxusLabs/taffy): Flexbox, Grid, block, float, `calc()`, absolute positioning, z-index 2. **Text shaping** via [parley](https://github.com/linebender/parley) and [skrifa](https://github.com/googlefonts/fontations/tree/main/skrifa): WOFF/WOFF2 fonts, emoji, RTL, multi-span inline blocks 3. **Compositing**: stacking contexts, blend modes, filters, transforms, SVG via [resvg](https://github.com/linebender/resvg) 4. **Output**: PNG, JPEG, WebP, ICO for statics; GIF, APNG, WebP for animations; raw RGBA frames for video pipelines A **time axis** threads through the pipeline. Animations, GIFs, and video frames are not a separate API. They're the same renderer called at timestamp `t`. ## Features [#features] ### Advanced Layout [#advanced-layout] Full **Flexbox, CSS Grid, block, and float** layout engine via [taffy](https://github.com/DioxusLabs/taffy). Supports `calc()`, absolute positioning, z-index stacking, inline text spans, and nested inline blocks. ### Typography [#typography] Browser-grade text shaping and rendering via [parley](https://github.com/linebender/parley), with glyph loading from [skrifa](https://github.com/googlefonts/fontations/tree/main/skrifa). Native support for WOFF and WOFF2 fonts, emoji, RTL languages, and multi-span inline blocks. ### CSS & Tailwind [#css--tailwind] A full-featured stylesheet engine: complex selectors, CSS variables, shorthand properties, arbitrary values, `@keyframes`, linear/radial gradients, `box-shadow`, `filter`, `backdrop-filter`, `mix-blend-mode`, and `transform`. Tailwind v4 is supported out of the box. ### Animations [#animations] Parse CSS `@keyframes` and the `animation` shorthand property. Render frame-by-frame with support for percentage, `from`, and `to` offsets; `linear`, `ease`, `steps()`, and `cubic-bezier()` timing functions; fill modes, delays, and iteration counts. Built-in Tailwind presets like `spin`, `ping`, `pulse`, and `bounce` work automatically. ### SVG [#svg] Full SVG parsing and rasterization via [resvg](https://github.com/linebender/resvg). Use inline SVG or reference external files. ### Flexible Runtime [#flexible-runtime] Takumi runs everywhere without changing your code: | Target | Details | | :------------------------------- | :------------------------------------------------- | | **Node.js** | Native N-API binary with Rayon multithreading | | **Cloudflare Workers / Browser** | WebAssembly with SIMD optimization | | **Rust crate** | Embed `takumi` directly. Zero JS runtime required. | # Integration URL: /docs/integration Use Takumi with the framework you love! # Next.js URL: /docs/integration/nextjs Use Takumi to render your React components on the server. ### Install Takumi [#install-takumi] npm pnpm yarn bun ```bash npm i takumi-js ``` ```bash pnpm add takumi-js ``` ```bash yarn add takumi-js ``` ```bash bun add takumi-js ``` ### Mark Takumi core as a server external package [#mark-takumi-core-as-a-server-external-package] Add `@takumi-rs/core` to `serverExternalPackages` in your Next.js config. ```ts title="next.config.ts" import type { NextConfig } from "next"; const config: NextConfig = { serverExternalPackages: ["@takumi-rs/core"], // [!code ++] }; export default config; ``` ### Create an OG image component [#create-an-og-image-component] ```tsx title="app/og/OgImage.tsx" type OgImageProps = { title: string; description: string; }; export default function OgImage({ title, description }: OgImageProps) { return (

{title}

{description}

); } ``` ### Return an image in an App Router route handler [#return-an-image-in-an-app-router-route-handler] Create a route handler, render the component, and return an `ImageResponse`. ```tsx title="app/og/route.tsx" import { ImageResponse } from "takumi-js/response"; import OgImage from "./OgImage"; export function GET(request: Request) { const url = new URL(request.url); const title = url.searchParams.get("title") ?? "Takumi + Next.js"; const description = url.searchParams.get("description") ?? "Render OG images with React."; return new ImageResponse(, { width: 1200, height: 630, }); } ``` # Nuxt URL: /docs/integration/nuxt Use Takumi through Nuxt OG Image in Nuxt apps. If you're using Nuxt, the recommended integration is [Nuxt OG Image](https://nuxtseo.com/docs/og-image/getting-started/introduction). It already knows how to render Vue components as OG images, and its [Takumi renderer](https://nuxtseo.com/docs/og-image/renderers/takumi) is the easiest way to use Takumi in a Nuxt app. ### Install Nuxt OG Image and the Takumi binding [#install-nuxt-og-image-and-the-takumi-binding] Add the Nuxt module first, then install the Takumi package that matches your runtime. ```bash npx nuxt module add og-image ``` npm pnpm yarn bun ```bash npm install -D @takumi-rs/core ``` ```bash pnpm add -D @takumi-rs/core ``` ```bash yarn add --dev @takumi-rs/core ``` ```bash bun add --dev @takumi-rs/core ``` For edge runtimes such as Cloudflare Workers or Vercel Edge, install `@takumi-rs/wasm` instead of `@takumi-rs/core`. ### Set Takumi as the renderer [#set-takumi-as-the-renderer] Configure Nuxt OG Image to use Takumi by default. ```ts title="nuxt.config.ts" export default defineNuxtConfig({ ogImage: { defaults: { renderer: "takumi", }, }, }); ``` ### Create a `.takumi.vue` template [#create-a-takumivue-template] Nuxt OG Image detects the Takumi renderer from the `.takumi.vue` suffix. ```vue title="components/OgImage/BlogPost.takumi.vue" ``` ### Attach the template to a page [#attach-the-template-to-a-page] Use `defineOgImageComponent()` in the page that should emit the image. ```vue title="pages/blog/[slug].vue" ``` # SvelteKit URL: /docs/integration/sveltekit Use Takumi to render your Svelte components on the server. ### Install Takumi [#install-takumi] npm pnpm yarn bun ```bash npm i takumi-js ``` ```bash pnpm add takumi-js ``` ```bash yarn add takumi-js ``` ```bash bun add takumi-js ``` ### Make a Svelte component [#make-a-svelte-component] If you want to write component styles in the same file, you must set the `css` option to `injected` in the component options. ```svelte title="src/lib/components/OgImage.svelte"

{title}

{description}

```
### Render the component on a server route [#render-the-component-on-a-server-route] Import the component and CSS file if Tailwind is used. Then, use `render` from `svelte/server` to render the component to HTML. Finally, return an `ImageResponse`. ```ts title="src/routes/og-image/+server.ts" import { render } from "svelte/server"; import style from "../app.css?inline"; import ImageResponse from "takumi-js/response"; import OgImage from "$lib/components/OgImage.svelte"; import type { RequestEvent } from "./$types"; export async function GET({ url }: RequestEvent) { const { body, head } = await render(OgImage, { props: { title: url.searchParams.get("title"), description: url.searchParams.get("description"), }, }); return new ImageResponse(`${head}${body}`, { width: 1200, height: 630, stylesheets: [style], fonts: [ { name: "Geist", data: () => fetch("https://takumi.kane.tw/fonts/Geist.woff2").then((res) => res.arrayBuffer()), }, ], }); } ```
# TanStack Start URL: /docs/integration/tanstack-start Use Takumi to render your React components on the server. ### Install Takumi [#install-takumi] npm pnpm yarn bun ```bash npm i takumi-js ``` ```bash pnpm add takumi-js ``` ```bash yarn add takumi-js ``` ```bash bun add takumi-js ``` ### Create a server file route [#create-a-server-file-route] TanStack Start lets you define HTTP handlers on a file route with `server.handlers`. ```tsx title="src/routes/og-image.tsx" import { createFileRoute } from "@tanstack/react-router"; import ImageResponse from "takumi-js/response"; export const Route = createFileRoute("/og-image")({ server: { handlers: { GET({ request }) { const url = new URL(request.url); const title = url.searchParams.get("title") ?? "Takumi + TanStack Start"; const description = url.searchParams.get("description") ?? "Render OG images from a route handler."; return new ImageResponse(

{title}

{description}

, { width: 1200, height: 630, }, ); }, }, }, }); ```
### Request the endpoint [#request-the-endpoint] Visit `/og-image?title=Hello&description=From%20TanStack%20Start` to generate an image.
# Keyframe Animation URL: /docs/keyframe-animation Animate scenes with CSS keyframes and render them as GIFs, WebP, APNG, or video frames. Takumi supports two animation workflows: * Use `renderAnimation()` when you want a simple animated `webp`, `apng`, or `gif`. * Use `render()` with `timeMs` when you want full control over frame rendering, structured `keyframes`, or external encoding tools like ffmpeg. This is an example of a keyframe animation rendered with ffmpeg + shiki for syntax highlighting: