# Architecture URL: /docs/architecture Explains how the architecture of Takumi is designed at a high level. ## Data Structure ### Format Takumi uses JSON format as its the most universal format that can be easily serialized and deserialized. ### 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 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 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 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 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 ### 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 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 This is relatively rare, but if you are using a Edge runtime or browser, you can use the [`@takumi-rs/wasm`](https://www.npmjs.com/package/@takumi-rs/wasm) package. 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). # Quick Start URL: /docs The fastest and simplest way to start using Takumi. Takumi is an **image rendering engine** written in Rust. The design is mainly inspired by [satori](https://github.com/vercel/satori), but with a focus on portability and performance (2-10x compared to next/og in [Image Bench](https://image-bench.kane.tw/)). You can try Takumi in [Playground](/playground) without any installation. If you are looking for Rust crate documentaiton, please visit [docs.rs](https://docs.rs/takumi). ## Installation The fastest/simplest way to use Takumi is with the `ImageResponse` API. It handles the internal state for font & image cache and it tries to be compatible with [Next.js ImageResponse API](https://nextjs.org/docs/app/api-reference/functions/image-response). npm pnpm yarn bun ```bash npm i @takumi-rs/image-response ``` ```bash pnpm add @takumi-rs/image-response ``` ```bash yarn add @takumi-rs/image-response ``` ```bash bun add @takumi-rs/image-response ``` ### Additional Bundler Setup Takumi offers two types of bindings for different environments. [`@takumi-rs/core`](https://www.npmjs.com/package/@takumi-rs/core) for Node.js and [`@takumi-rs/wasm`](https://www.npmjs.com/package/@takumi-rs/wasm) for WebAssembly. #### Node.js Runtime By default Next.js bundles the `@takumi-rs/core` package, which requires native Node.js `require` function to resolve the native binary. You need to opt-out from the bundling by setting the `serverExternalPackages` option. ```ts title="next.config.ts" export const config = { // [!code ++] serverExternalPackages: ["@takumi-rs/image-response"], }; ``` Opt-out from the bundling by setting the `ssr.external` and `optimizeDeps.exclude` options. ```ts title="vite.config.ts" export default defineConfig({ optimizeDeps: { // [!code ++] exclude: ["@takumi-rs/core"], }, ssr: { // [!code ++:2] external: ["@takumi-rs/core"], noExternal: ["@takumi-rs/image-response"], }, }); ``` If you still encounter issues after all, try opening issues on GitHub or try the WebAssembly version instead. First, install the `@takumi-rs/core` package where we grab the optional dependencies from. npm pnpm yarn bun ```bash npm i @takumi-rs/core ``` ```bash pnpm add @takumi-rs/core ``` ```bash yarn add @takumi-rs/core ``` ```bash bun add @takumi-rs/core ``` Then, configure Nitro to externalize the dependencies and include the optional dependencies in the trace. ```ts title="vite.config.ts" import { defineConfig } from "vite"; import takumiPackageJson from "@takumi-rs/core/package.json" with { type: "json", }; export default defineConfig({ nitro: { externals: { external: ["@takumi-rs/core"], // [!code ++] traceInclude: Object.keys(takumiPackageJson.optionalDependencies), // [!code ++] } }, optimizeDeps: { // [!code ++] exclude: ["@takumi-rs/core"], }, }); ``` ```toml title="netlify.toml" [build] command = "vite build" publish = "dist/client" [functions] // [!code ++] node_bundler = "esbuild" directory = "netlify/functions" // [!code ++] included_files = ["node_modules/@takumi-rs/core-linux-x64-gnu/**/*.*"] ``` If you are using package manager with virtual store such as `pnpm` or `yarn`, add the following to your `.npmrc` file and re-run `pnpm i` to allow hoisting of the native binary. ```text title=".npmrc" public-hoist-pattern[]=@takumi-rs/core-* ``` #### Edge Runtime / Browser Cloudflare Workers prohibited fetching WASM then initialize on the fly. You can import from `@takumi-rs/wasm/takumi_wasm_bg.wasm` and pass it to the `module` option. ```tsx twoslash /** @jsxImportSource react */ // ---cut-before--- import { ImageResponse } from "@takumi-rs/image-response/wasm"; import module from "@takumi-rs/wasm/takumi_wasm_bg.wasm"; // [!code ++] export default { fetch() { return new ImageResponse(
, { module, // [!code ++] // ... }); }, } ``` And make sure you have `wrangler.jsonc` / `wrangler.toml` setup to load assets. `compatibility_date` should be set to at least `2025-10-30`. ```jsonc title="wrangler.jsonc" { "$schema": "node_modules/wrangler/config-schema.json", "compatibility_date": "2025-10-30", // [!code ++] "rules": [ { "type": "Data", "globs": ["**/*.ttf", "**/*.woff2"], } ] } ``` Check the [example project](https://github.com/kane50613/takumi/tree/master/example/cloudflare-workers) with wrangler usage. Load the WASM file as an asset. ```tsx import { ImageResponse } from "@takumi-rs/image-response/wasm"; import module from "@takumi-rs/wasm/takumi_wasm_bg.wasm?url"; new ImageResponse(
, { module, }) ``` This works in both Node.js and Edge runtime. ```tsx twoslash /** @jsxImportSource react */ // ---cut-before--- import { ImageResponse } from "@takumi-rs/image-response/wasm"; import module from "@takumi-rs/wasm/next"; new ImageResponse(
, { module, }) ``` First, configure Webpack to recognize the WASM file as an asset. ```ts title="webpack.config.js" module.exports = { module: { rules: [ { test: /\.wasm$/, type: 'asset/resource', generator: { filename: 'wasm/[name].[hash][ext]' } } ] } }; ``` Then, in your code, import the WASM file and initialize the module: ```ts import { ImageResponse } from '@takumi-rs/image-response/wasm'; import wasmUrl from '@takumi-rs/wasm/takumi_wasm_bg.wasm'; new ImageResponse(
, { module: wasmUrl, }) ``` ## Usage Since `ImageResponse` extends standard [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) class, you can plug it into anywhere you want. It comes with pre-bundled full axis (which means 100-900 weights available) [Geist](https://vercel.com/font) and Geist Mono as default fonts. [Tailwind CSS](/docs/tailwind-css) is also supported out of the box. Next.js WebAssembly ```tsx twoslash /** @jsxImportSource react */ // ---cut-before--- import { ImageResponse, type ImageResponseOptions } from "@takumi-rs/image-response"; import { serve } from "bun"; serve({ fetch() { return new ImageResponse(, { width: 1200, height: 630, format: "webp", headers: { "Cache-Control": "public, max-age=3600", }, }); }, }); function Hello() { return (

Hello

); } ```
```tsx twoslash /** @jsxImportSource react */ // ---cut-before--- import { ImageResponse } from "@takumi-rs/image-response/wasm"; import { serve } from "bun"; // Check the additional bundler setup section for more details. import module from "@takumi-rs/wasm/next"; export default { fetch() { return new ImageResponse(, { width: 1200, height: 630, format: "webp", module, headers: { "Cache-Control": "public, max-age=3600", }, }); }, } function Hello() { return (

Hello

); } ```
### Templates If you don't have any idea about where to start, or just want quick and easy way to get started, you can use our built-in [Templates](/docs/templates). They are available via our [Shadcn-compatible Registry](/templates/registry.json) and can be added to your project with a single command: npm pnpm yarn bun ```bash npx shadcn@latest add https://takumi.kane.tw/templates/registry/docs-template.json ``` ```bash pnpm dlx shadcn@latest add https://takumi.kane.tw/templates/registry/docs-template.json ``` ```bash yarn dlx shadcn@latest add https://takumi.kane.tw/templates/registry/docs-template.json ``` ```bash bun x shadcn@latest add https://takumi.kane.tw/templates/registry/docs-template.json ``` We need your help to improve and create more templates! Please feel free to submit PRs to add more templates to the [`takumi-template` folder](https://github.com/kane50613/takumi/tree/master/takumi-template/src/templates). ## Examples Check out the [`example` folder](https://github.com/kane50613/takumi/tree/master/example) for different framework usages. ## Learn More ### Why build a satori alternative? Takumi's focus is on how to rasterize images fast, while satori outputs SVG. More discussion can be found in [this X thread by @shuding\_](https://x.com/shuding_/status/1958853749004542445). * All in one. No need to output SVG then have [resvg-js](https://github.com/thx/resvg-js) rendering it again to output PNG. * Inline layout support (display `block` or `inline`). * Tailwind CSS support out of the box. * RTL support. * Variable fonts support. * COLR font support (e.g. twemoji-colr). * WOFF2 font format support. * PNG, JPEG, WebP output support. * WebP, APNG animation rendering support. # Layout Engine URL: /docs/layout-engine How Takumi implements layout. Takumi uses [Taffy](https://github.com/DioxusLabs/taffy), a Rust implementation of the CSS Flexbox and CSS Grid specifications. ## Box Model Every node in Takumi follows the standard CSS box model. The total size of an element is calculated based on its content, padding, border, and margin. ## Auto Sizing The `width` and `height` parameters are optional, which means Takumi can calculate the size based on the content. ```tsx twoslash /** @jsxImportSource react */ // ---cut-before--- import { ImageResponse } from "@takumi-rs/image-response"; export function GET() { return new ImageResponse(, { width: 1200 }); } function List() { const items = Array.from({ length: Math.floor(Math.random() * 10) + 1 }, (_, i) => i); return (
{items.map((item) => (
Item {item}.
))}
); } ``` ## Intrinsic Size for Images By default, the image would be measured based on its intrinsic size, you can override it by setting `width` and `height` properties. ```tsx twoslash /** @jsxImportSource react */ // ---cut-before--- import { ImageResponse } from "@takumi-rs/image-response"; export function GET() { return new ImageResponse( ); } ``` ## # Load Images URL: /docs/load-images Choose the right way to load images. ## External Images In order to make loading more flexible, we do not handle any fetching for you. Instead, exposes the fetched resources via `fetchedResources` option. If you are using `@takumi-rs/image-response`, it will handle fetching for you, or you can override the default fetching behavior by passing your own `fetchResources` option. @takumi-rs/core @takumi-rs/wasm ```tsx twoslash /** @jsxImportSource react */ // ---cut-before--- import { fromJsx } from "@takumi-rs/helpers/jsx"; import { Renderer, extractResourceUrls } from "@takumi-rs/core"; import { fetchResources } from "@takumi-rs/helpers"; const renderer = new Renderer(); const node = await fromJsx(); // [!code ++:2] const urls = extractResourceUrls(node); const fetchedResources = await fetchResources(urls); const image = await renderer.render(node, { // [!code ++] fetchedResources, }); ``` ```tsx twoslash /** @jsxImportSource react */ // ---cut-before--- import { fromJsx } from "@takumi-rs/helpers/jsx"; import { Renderer, extractResourceUrls } from "@takumi-rs/wasm"; import { fetchResources } from "@takumi-rs/helpers"; const renderer = new Renderer(); const node = await fromJsx(); // [!code ++:2] const urls = extractResourceUrls(node); const fetchedResources = await fetchResources(urls); const image = await renderer.render(node, { // [!code ++] fetchedResources, }); ``` ## Persistent Images Preload frequently used images like logo, background, etc. to avoid redundant image decoding and improve performance. It's recommended to declare images in global scope so Takumi can identify and cache them with [`WeakSet`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakSet) reference to the image object. The image key can be used in any `src` field or `background-image`, `mask-image` CSS property. ```tsx twoslash /** @jsxImportSource react */ // ---cut-before--- import { ImageResponse } from "@takumi-rs/image-response"; import type { PersistentImage } from "@takumi-rs/core"; const [logo, background] = await Promise.all([ fetch("/logo.png").then((res) => res.arrayBuffer()), fetch("/background.png").then((res) => res.arrayBuffer()), ]); const persistentImages: PersistentImage[] = [ { src: "my-logo", data: logo, }, { src: "background", data: background, }, ]; export function GET() { return new ImageResponse(, { // [!code ++] persistentImages, }); } function OgImage() { return (
); } ``` # The measure() API URL: /docs/measure-api Measure the node layout without rendering it. This functionality is useful if you want to get the node layout for further calculations. @takumi-rs/core @takumi-rs/wasm ```tsx twoslash /** @jsxImportSource react */ // ---cut-before--- import { Renderer } from "@takumi-rs/core"; import { fromJsx } from "@takumi-rs/helpers/jsx"; const renderer = new Renderer(); const node = await fromJsx( I'm a text node ); // [!code ++] const { width, height } = await renderer.measure(node); ``` ```tsx twoslash /** @jsxImportSource react */ // ---cut-before--- import { Renderer } from "@takumi-rs/wasm"; import { fromJsx } from "@takumi-rs/helpers/jsx"; const renderer = new Renderer(); const node = await fromJsx( I'm a text node ); // [!code ++] const { width, height } = renderer.measure(node); ``` # From Next.js ImageResponse URL: /docs/migration/image-response Migrate from Next.js ImageResponse to Takumi with your existing components. Takumi aims to create a universal image generation library that can be used in any environment and not just limited to JavaScript runtime. It delivers up to 10x performance improvement compared to next/og shown in the [Image Bench](https://image-bench.kane.tw/). ## Installation npm pnpm yarn bun ```bash npm i @takumi-rs/image-response ``` ```bash pnpm add @takumi-rs/image-response ``` ```bash yarn add @takumi-rs/image-response ``` ```bash bun add @takumi-rs/image-response ``` ### Mark as external By default Next.js bundles the `@takumi-rs/core` package, which requires native Node.js `require` function to resolve the native binary. You need to opt-out from the bundling by setting the `serverExternalPackages` option. ```ts title="next.config.ts" export const config = { serverExternalPackages: ["@takumi-rs/image-response"], }; ``` ## Code changes ```tsx twoslash /** @jsxImportSource react */ // ---cut-before--- // @noErrors import { ImageResponse } from "next/og"; // [!code --] import { ImageResponse } from "@takumi-rs/image-response"; // [!code ++] // Takumi comes with full axis Geist and Geist Mono by default, // if this is what you want, you can just remove fonts array. const fonts = [ { name: "Inter", data: await fetch("/fonts/Inter-Regular.ttf").then((res) => res.arrayBuffer()), style: "normal", weight: 400 } ]; function OgImage({ title }: { title: string }) { return (

Hello from {title}!

); } export function GET(request: Request) { return new ImageResponse(, { width: 1200, height: 630, fonts, }); } ``` ### For WASM environment If you are using in Edge runtime or a browser environment like Cloudflare Workers, you can import from the `@takumi-rs/image-response/wasm` package. ```tsx twoslash /** @jsxImportSource react */ // ---cut-before--- // @noErrors import { ImageResponse } from "@takumi-rs/image-response"; // [!code --] import { ImageResponse } from "@takumi-rs/image-response/wasm"; // [!code ++] import module from "@takumi-rs/wasm/next"; // [!code ++] new ImageResponse(, { module, // [!code ++] width: 1200, height: 630, // @noErrors fonts, }); ``` Now you have an `GET` handler with Takumi setup! If theres any issues or unexpected behavior, please open an issue on [our GitHub repository](https://github.com/kane50613/takumi/issues). # Migration URL: /docs/migration Learn how to migrate from other image generation libraries to Takumi. # From Satori URL: /docs/migration/satori Migrate from Satori to Takumi with your existing components. Takumi aims to create a universal image generation library that can be used in any environment and not just limited to JavaScript runtime. If you are migrating from `next/og`, check out the [From Next.js ImageResponse](/docs/migration/image-response) guide instead. Takumi renders your nodes/components to rasterized images directly, we don't support rendering to SVG at this moment. ## Installation npm pnpm yarn bun ```bash npm i @takumi-rs/core @takumi-rs/helpers ``` ```bash pnpm add @takumi-rs/core @takumi-rs/helpers ``` ```bash yarn add @takumi-rs/core @takumi-rs/helpers ``` ```bash bun add @takumi-rs/core @takumi-rs/helpers ``` Make sure to mark `@takumi-rs/core` as `external` if you are using a bundler like Vite or Webpack ## Code changes ```tsx twoslash /** @jsxImportSource react */ // ---cut-before--- // @noErrors import satori from "satori"; // [!code --] import { Resvg } from "@resvg/resvg-js"; // [!code --] import { fromJsx } from "@takumi-rs/helpers/jsx"; // [!code ++] import { Renderer } from "@takumi-rs/core"; // [!code ++] // You can use variable fonts with Takumi! // Takumi comes with full axis Geist and Geist Mono by default, // if this is what you want, you can just remove fonts array. const fonts = [ { name: "Inter", data: await fetch("/fonts/Inter-Regular.ttf").then((res) => res.arrayBuffer()), style: "normal" as const, weight: 400 } ]; const svg = await satori(, { // [!code --] fonts, // [!code --] }); // [!code --] const buffer = new Resvg(svg).render().asPng(); // [!code --] const renderer = new Renderer({ // [!code ++] fonts, // [!code ++] }); // [!code ++] const node = await fromJsx(); // [!code ++] const png = await renderer.render(node, { // [!code ++] width: 1200, // [!code ++] height: 630, // [!code ++] format: "png", // "webp" is recommended as well. // [!code ++] }); // [!code ++] function OgImage({ title }: { title: string }) { return (

Hello from {title}!

); } ``` Now you have Takumi setup! If theres any issues or unexpected behavior, please open an issue on [our GitHub repository](https://github.com/kane50613/takumi/issues). # Performance & Optimization URL: /docs/performance-and-optimization Best practices for building high-performance rendering pipelines with Takumi. Takumi is designed from the ground up for speed. However, as your node trees grow in complexity, following these best practices will ensure you get the most out of the engine. ## The Renderer ### Reuse the Renderer Instance For both `@takumi-rs/core` and `@takumi-rs/wasm`, the `Renderer` is the heart of Takumi's resource management. Try to reuse the renderer instance across multiple renderings. #### For ImageResponse An internal renderer instance is managed automatically, or you can pass your own renderer instance via `renderer` option. It's recommended to reuse the `font` and `persistentImage` object for internal [`WeakSet`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakSet) to identify the same font and image and avoid re-decoding. Refer to both [Typography & Fonts](/docs/typography-and-fonts) and [Persistent Images](/docs/persistent-images) for more details. ### Preload Frequently Used Images Loading images from URLs or bytes during the rendering pass can be a bottleneck. Register [Persistent Images](/docs/persistent-images) to avoid re-decoding. ### Parallel Rendering Always prefer `@takumi-rs/core` over `@takumi-rs/wasm` for utilizing multiple threads. ## Component Design ### Stack Filters in a Single Node A composition layer with the same size as viewport has to be created in order to apply filters and blurs, which incurs additional memory usage. # Reference URL: /docs/reference List of everything in Takumi. ## Node Types ### Container A container node is used to group other nodes and arrange them in a layout. ### Text A text node displays text. ### Image An image node displays rasterized or svg images. ## Style Properties
Property Property Expanded Supported Values
`display` `flex` , `grid` , `block` , `inline`
`position` `relative` , `absolute`
`width` Supported
`height` Supported
`maxWidth` Supported
`maxHeight` Supported
`minWidth` Supported
`minHeight` Supported
`aspectRatio` Supported
`padding` `paddingTop` , `paddingRight` , `paddingBottom` , `paddingLeft` Supported
`margin` `marginTop` , `marginRight` , `marginBottom` , `marginLeft` Supported
`inset` `top` , `right` , `bottom` , `left` Supported
`border` `borderWidth` ( `borderTopWidth` , `borderRightWidth` , `borderBottomWidth` , `borderLeftWidth` ), `borderColor` Only `solid` style is supported
`borderRadius` `borderTopLeftRadius` , `borderTopRightRadius` , `borderBottomRightRadius` , `borderBottomLeftRadius` Supported
`flex` `flexBasis` Supported
`flexGrow` Supported
`flexShrink` Supported
Flexbox `flexDirection` Supported
`justifyContent` Supported
`justifySelf` Supported
`alignContent` Supported
`justifyItems` Supported
`alignItems` Supported
`alignSelf` Supported
`justifySelf` Supported
`flexWrap` `nowrap` , `wrap` , `wrap-reverse`
`gap` Supported
`objectFit` Supported
`objectPosition` Supported
`overflow` `overflowX` , `overflowY` `visible` , `hidden`
`background` `backgroundImage` `linear-gradient()` , `radial-gradient()` , `noise-v1()` , `url()`
`backgroundPosition` Supported
`backgroundSize` Supported
`backgroundRepeat` Supported
`backgroundColor` Supported
`backgroundClip` Supported
`boxShadow` Supported
Clip `clipPath` `inset()` , `circle()` , `ellipse()` , `polygon()` , `path()`
`clipRule` Supported
`mask` `maskImage` Supported
`maskSize` Supported
`maskPosition` Supported
`maskRepeat` Supported
`transform` `translate` Only 2D is supported
`rotate`
`scale`
`transformOrigin` Supported
Grid `gridAutoColumns` Supported
`gridAutoRows` Supported
`gridAutoFlow` Supported
`gridColumn` Supported
`gridRow` Supported
`gridTemplateColumns` Supported
`gridTemplateRows` Supported
`gridTemplateAreas` Supported
Typography `textOverflow` `ellipsis` , `clip` , custom character
`textTransform` `none` , `uppercase` , `lowercase` , `capitalize`
`fontStyle` Supported
`color` Supported
`textShadow` Supported
`fontSize` Supported
`fontFamily` Font fallback supported
`lineHeight` Supported
`fontWeight` Supported
`fontVariationSettings` Supported
`fontFeatureSettings` Supported
`lineClamp` number, `1 "ellipsis character"`
`textAlign` Supported
`letterSpacing` Supported
`wordSpacing` Supported
`overflowWrap` Supported
`wordBreak` `normal` , `break-all` , `keep-all` , `break-word`
`whiteSpace` `normal` , `pre` , `pre-wrap` , `pre-line` , ` `
`whiteSpaceCollapse` `preserve` , `collapse` , `preserve-spaces` , `preserve-breaks`
`textWrap` `textWrapMode` `wrap` , `nowrap`
`textWrapStyle` `auto` , `balance` , `pretty`
`boxSizing` Supported
`opacity` Supported
`imageRendering` `auto` , `smooth` , `pixelated`
`filter` `blur()` , `brightness()` , `contrast()` , `drop-shadow()` , `grayscale()` , `hue-rotate()` , `invert()` , `opacity()` , `saturate()` , `sepia()`
`backdropFilter` `blur()` , `brightness()` , `contrast()` , `grayscale()` , `hue-rotate()` , `invert()` , `opacity()` , `saturate()` , `sepia()`
`WebkitTextStroke` `WebkitTextStrokeWidth` , `WebkitTextStrokeColor` Supported
`textDecoration` `textDecorationLine` `underline` , `line-through` , `overline`
`textDecorationColor` Supported
# Tailwind CSS URL: /docs/tailwind-css Use Tailwind CSS classes to style your Takumi components. Takumi includes a built-in Tailwind CSS parser that allows you to style your components using familiar utility classes. This provides a productive developer experience similar to modern web development. ## Usage You can use the `tw` prop on any element (`div`, `span`, `img`, etc.) in your JSX. ```tsx

Hello Tailwind!

``` ### Dynamic Classes Since `tw` is just a prop, you can use template literals or conditional logic to apply classes dynamically. ```tsx import clsx from "clsx"; const isError = true;
{isError ? "Something went wrong" : "Success!"}
``` ## Limitations * No custom theme config, but arbitrary values are supported. * Read the [parser mapping](https://github.com/kane50613/takumi/blob/master/takumi/src/layout/style/tw/map.rs) for all supported classes. # Templates URL: /docs/templates A collection of ready-to-use templates for Takumi. Takumi comes with several pre-designed templates to help you get started quickly. You can use these templates as a starting point for your own designs or use them as-is. Templates can be installed using shadcn CLI or [download from latest commit](https://github.com/kane50613/takumi/tree/master/takumi-template/src/templates). ## Blog Post Template A sleek and modern template for blog posts, featuring a large title and a descriptive subtitle. Blog Post Template npm pnpm yarn bun ```bash npx shadcn@latest add https://takumi.kane.tw/templates/registry/blog-post-template.json ``` ```bash pnpm dlx shadcn@latest add https://takumi.kane.tw/templates/registry/blog-post-template.json ``` ```bash yarn dlx shadcn@latest add https://takumi.kane.tw/templates/registry/blog-post-template.json ``` ```bash bun x shadcn@latest add https://takumi.kane.tw/templates/registry/blog-post-template.json ``` ## Docs Template A professional documentation template designed for clarity and ease of reading. Docs Template npm pnpm yarn bun ```bash npx shadcn@latest add https://takumi.kane.tw/templates/registry/docs-template.json ``` ```bash pnpm dlx shadcn@latest add https://takumi.kane.tw/templates/registry/docs-template.json ``` ```bash yarn dlx shadcn@latest add https://takumi.kane.tw/templates/registry/docs-template.json ``` ```bash bun x shadcn@latest add https://takumi.kane.tw/templates/registry/docs-template.json ``` ## Product Card Template A vibrant and eye-catching product card template, perfect for showcasing your latest offerings. Product Card Template npm pnpm yarn bun ```bash npx shadcn@latest add https://takumi.kane.tw/templates/registry/product-card-template.json ``` ```bash pnpm dlx shadcn@latest add https://takumi.kane.tw/templates/registry/product-card-template.json ``` ```bash yarn dlx shadcn@latest add https://takumi.kane.tw/templates/registry/product-card-template.json ``` ```bash bun x shadcn@latest add https://takumi.kane.tw/templates/registry/product-card-template.json ``` # Troubleshooting URL: /docs/troubleshooting Common issues and solutions when using Takumi. ## General Issues You can try to use the `drawDebugBorder` option to draw a border around the nodes. ```tsx import { ImageResponse } from "@takumi-rs/image-response"; export function GET() { return new ImageResponse(<>, { width: 100, height: 100, drawDebugBorder: true, // ... }); } ``` If the issue still exists, please file an issue on [our GitHub repository](https://github.com/kane50613/takumi/issues). ## Node.js Related issues This happens when `@takumi-rs/core` package failed to find the native binding. Make sure you have finished the [Additional Bundler Setup](/docs/index#additional-bundler-setup) step. If you are using package manager with virtual store such as `pnpm` or `yarn`, add the following to your `.npmrc` file and re-run `pnpm i` to allow hoisting of the native binary. ```text title=".npmrc" public-hoist-pattern[]=@takumi-rs/core-* ``` Node.js fetch implementation with [undici](https://github.com/nodejs/undici) is not really stable in my experience and [#349](https://github.com/kane50613/takumi/issues/349). Try using [bun](https://bun.sh) runtime instead. # Typography & Fonts URL: /docs/typography-and-fonts font management and advanced text rendering. Takumi does not use system fonts. All fonts must be explicitly loaded to be available for rendering. For `@takumi-rs/core` (napi-rs version), full axis (which means 100-900 weights available) [Geist](https://vercel.com/font) and Geist Mono are embedded by default. ## Font It's recommended to declare fonts in global scope so Takumi can identify and cache them with [`WeakSet`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakSet) reference to the font object. ```tsx twoslash /** @jsxImportSource react */ // ---cut-before--- import { ImageResponse } from "@takumi-rs/image-response"; import type { Font } from "@takumi-rs/core"; const interBuffer = await fetch("/path-to-inter.woff2").then((res) => res.arrayBuffer()); const fonts: Font[] = [ { name: "Inter", data: interBuffer } ]; export function GET() { return new ImageResponse(
, { fonts, }); } ``` ### Variations & Features Thanks to underlying engine support, you can control font axes using the `font-variation-settings` CSS property, or `font-feature-settings` for OpenType features. For variable fonts, `font-weight` has the same effect as `font-variation-settings: "wght" `. ```tsx
Variable Font Text
``` ### Emoji Support (COLR) Takumi supports the COLR font format, which is commonly used for emojis like `Twemoji-COLR`. The file size is much smaller than rasterized emoji fonts like `Noto Color Emoji`. ## Typography ### Overflow Ellipsis When `text-overflow` is set to `ellipsis`, Takumi tries to match the expected `line-clamp` constraint or maximum container height. Setting `white-space: nowrap` is not required, which enables multiline ellipsis handling. ```tsx
Super Long Text
``` ### RTL & Bidirectional Text Support for Right-to-Left (RTL) languages like Arabic or Hebrew is handled automatically by the underlying Parley engine. But currently there's no manual control over the direction of the text (see [issue #330](https://github.com/kane50613/takumi/issues/330)). ### Wrapping Takumi supports both `balance` and `pretty` text wrapping. The algorithm is modified from [satori's implementation](https://github.com/vercel/satori/blob/2a0878a7f329bdba3a17ad68f71186a47add0dde/src/text/index.ts#L365). ```tsx
Super Long Text
```