# Building Layouts URL: /docs/deep-dives/building-layout Learn how to construct and style nodes to create complex layouts. Nodes are the foundation of building layouts with Takumi. The `@takumi-rs/helpers` package provides convenient functions for constructing and styling different types of nodes: containers, text, and images. ## Prerequisites Make sure you have installed the `@takumi-rs/helpers` package: ```bash npm install @takumi-rs/helpers ``` ## Constructing Nodes ### Container Nodes A container node is used to group other nodes and arrange them in a layout. Use the `container` function: ```typescript import { container } from "@takumi-rs/helpers"; const root = container({ // extra styling goes here children: [ // child nodes go here ], }); ``` ### Text Nodes A text node displays text. Use the `text` function: ```typescript import { text } from '@takumi-rs/helpers'; const helloText = text('Hello, Takumi!', { // extra styling goes here }); ``` ### Image Nodes An image node displays an image from a URL or local path. Use the `image` function: ```typescript import { image, percentage } from '@takumi-rs/helpers'; const logo = image({ src: '/logo.png', width: 64, height: 64, style: { borderRadius: percentage(50), // extra styling goes here }, }); ``` ## Styling Nodes You can pass a style object as the second argument to `text` and `image`, or as properties to `container`. Style properties are inspired by CSS, but use camelCase or snake\_case. ### Example: Styling a Container ```typescript import { container } from "@takumi-rs/helpers"; const root = container({ style: { width: 400, height: 200, backgroundColor: 0xf0f0f0, padding: 16, alignItems: "center", justifyContent: "center", }, children: [ text("Hello, Takumi!"), ], }); ``` ### Example: Styling Text ```typescript import { text } from "@takumi-rs/helpers"; const heading = text("Hello, Takumi!", { fontSize: 32, color: 0x333333, fontWeight: 700, textAlign: "center", }); ``` ## Using Helper Functions The helpers package provides functions for common value types: * `percentage(50)` — 50% of parent * `rem(2)` — x2 root font size * `rgb(255, 0, 0)` — Red * `rgba(0, 0, 0, 0.5)` — Semi-transparent black ```typescript import { container, text, percentage, rem, rgba } from "@takumi-rs/helpers"; const layout = container({ style: { width: percentage(100), height: rem(10), backgroundColor: rgba(0, 128, 255, 0.1), }, children: [ text("50% width, 10rem height", { color: 0x222222 }) ], }); ``` # The fromJsx function URL: /docs/deep-dives/from-jsx-helper Turn React JSX components into Takumi nodes without the need to rewrite the entire component. This function lowers the barrier for people coming from a similar project like [vercel/satori](https://github.com/vercel/satori) to adopt Takumi. ## Quick Example ```tsx import { fromJsx } from "@takumi-rs/helpers/jsx"; function SayHello({ name }: { name: string }) { return (
Hello, {name}!
); } // await is required to handle async components const node = await fromJsx(); // You can then pass the node as a "root node" to render function ``` ## How components are processed 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. 1. React (Server) Components are resolved to their final values before processing. 2. `` and `` elements become an Image node with style applied. 3. All other React elements become a Container node with style and [style presets](#styling-presets-for-common-elements) applied. 4. Rest of the primitive types (string/number) are automatically converted to Text node. `props.style` is passed on to the container node as is. ## CSS Styling ### Styling Presets for Common Elements Browsers like Chromium have [default stylesheets used to render HTML](https://chromium.googlesource.com/chromium/blink/+/master/Source/core/css/html.css). In order to maintain consistency across web and Takumi rendered images, we take reference from [vercel/satori Pre-defined styles for elements](https://github.com/vercel/satori/blob/main/src/handler/presets.ts) and then made [our own maintained presets](https://github.com/kane50613/takumi/blob/master/takumi-helpers/src/jsx/style-presets.ts). ### Style Parsing Compatibility Takumi aims to support a wide range of CSS properties, but some advanced features may not be fully supported yet. So you should always test your styles to ensure they render as expected. Checkout [Stylesheets](/docs/deep-dives/stylesheets) for more details. # Deep Dives URL: /docs/deep-dives Explore advanced topics and techniques for using Takumi. # Load Image URL: /docs/deep-dives/rendering-extenral-image How to load and render images in Takumi Before reading this guide, make sure you know how to construct and style image nodes. See [Building Layouts](/docs/how-to/building-layouts) for more details. ## Persistent Storage Takumi provides a persistent storage in every renderer instance. It allows you to load images from files or URLs and cache them for later use. The storage is basically a key-value store, so you can name your keys with any identifier you like. This is particularly useful for frequently used images, as it avoids the overhead of fetching them repeatedly. ## Image Source Compatibility The `src` property of an image node can accept a URL, file path, or a data URI. However, support for these sources varies depending on the Takumi package you are using. This is primarily to minimize binary size for embedded Takumi versions, as certain features are disabled by default. The table below outlines the compatibility for each package: | Type / Package | URL (Remote) | Persistent Storage | Data URI (Base64 Encoded) | | :---------------- | :-------------------------------------------------- | :----------------- | :------------------------ | | `@takumi-rs/core` | ❌ (Requires manual fetching, then pass as Data URI) | ✅ | ✅ | | `@takumi-rs/wasm` | ❌ (Requires manual fetching, then pass as Data URI) | ✅ | ✅ | | `takumi-server` | ✅ (Handles fetching internally) | ✅ | ✅ | # Rendering Text URL: /docs/deep-dives/rendering-text How to load fonts and render styled text in Takumi Before reading this guide, make sure you know how to construct and style text nodes. See [Building Layouts](/docs/how-to/building-layouts) for more details. To render styled text in your Takumi layouts, you must load fonts explicitly before rendering. ## Loading Fonts Takumi requires you to explicitly load fonts before rendering text. This ensures your text appears as expected. ```javascript // Load a font from your assets const fontResponse = await fetch('/fonts/NotoSans-Regular.ttf'); const fontData = new Uint8Array(await fontResponse.arrayBuffer()); renderer.loadFont(fontData); // Load multiple fonts const fontUrls = [ '/fonts/NotoSans-Regular.ttf', '/fonts/NotoSans-Bold.ttf', '/fonts/NotoColorEmoji.ttf' ]; for (const url of fontUrls) { const response = await fetch(url); const data = new Uint8Array(await response.arrayBuffer()); renderer.loadFont(data); } ``` > **Note:** The font loader expects a `Uint8Array` of font data. The format is auto-detected, but you can provide a format hint if needed. ## Example: Centered Bold Text ```typescript import { container, text } from '@takumi-rs/helpers'; const layout = container({ width: 400, height: 200, alignItems: 'center', justifyContent: 'center', children: [ text('Centered Bold', { fontSize: 32, color: 0x333333, fontFamily: 'NotoSans', fontWeight: 'bold', textAlign: 'center', }), ], }); ``` # Stylesheets URL: /docs/deep-dives/stylesheets Takumi aims to support a wide range of CSS properties, read this to understand how to use them. ## How is it implemented? Takumi uses [Taffy](https://github.com/DioxusLabs/taffy) to layout the positions, and [cosmic\_text](https://github.com/pop-os/cosmic-text) to render the text, so it mostly depends on the features that these two libraries support. But for box shadow and linear gradient, Takumi has its own implementation. ## CSS Properties We support CSS values parsing or structured values parsing. You can check the [`Style` interface in `takumi-helpers`](https://github.com/kane50613/takumi/blob/master/takumi-helpers/src/bindings/Style.ts) or [`Style` struct](https://docs.rs/takumi/latest/takumi/style/properties/struct.Style.html) to see how structured values are parsed. ## Compatibility Matrix
Property Property Expanded Supported Values Inherited
`display` Supported No
`position` Supported No
`width` Supported No
`height` Supported No
`maxWidth` Supported No
`maxHeight` Supported No
`minWidth` Supported No
`minHeight` Supported No
`aspectRatio` Supported No
`padding` `paddingTop`, `paddingRight`, `paddingBottom`, `paddingLeft` Supported No
`margin` `marginTop`, `marginRight`, `marginBottom`, `marginLeft` Supported No
`inset` `top`, `right`, `bottom`, `left` Supported No
`borderWidth` `borderWidthTop`, `borderWidthRight`, `borderWidthBottom`, `borderWidthLeft` Supported No
`flexDirection` Supported No
`justifyContent` Supported No
`alignContent` Supported No
`justifyItems` Supported No
`alignItems` Supported No
`alignSelf` Supported No
`flexWrap` Supported No
`flexBasis` Supported No
`flexGrow` Supported No
`flexShrink` Supported No
`gap` Supported No
`objectFit` Supported No
`backgroundImage` Supported No
`backgroundColor` Supported No
`boxShadow` Supported No
`gridAutoColumns` Supported No
`gridAutoRows` Supported No
`gridAutoFlow` Supported No
`gridColumn` Supported No
`gridRow` Supported No
`gridTemplateColumns` Supported No
`gridTemplateRows` Supported No
`gridTemplateAreas` Supported No
`borderRadius` `borderRadiusTop`, `borderRadiusRight`, `borderRadiusBottom`, `borderRadiusLeft` Supported Yes
`boxSizing` Supported Yes
`textOverflow` Supported Yes
`textTransform` Supported Yes
`textStyle` Supported Yes
`borderColor` Supported Yes
`color` Supported Yes
`fontSize` Supported Yes
`fontFamily` Supported Yes
`lineHeight` Supported Yes
`fontWeight` Supported Yes
`lineClamp` Supported Yes
`textAlign` Supported Yes
`letterSpacing` Supported Yes
`imageRendering` Supported Yes
# Host Takumi Somewhere Else URL: /docs/getting-started/external-hosted-server Learn how to host Takumi on an external server and call from your application. # Getting Started URL: /docs/getting-started Learn how to use Takumi for image generation in various environments. # Use Takumi in Node.js or Bun URL: /docs/getting-started/nodejs Integrate Takumi with Node.js or Bun for server-side image generation. Takumi provides [N-API bindings](https://napi.rs/) for Node.js and Bun, leveraging Node.js's libuv thread pool for multi-threaded image generation. Checkout [the Next.js example](https://github.com/kane50613/takumi/blob/master/example/nextjs) for a full-functioning example of using Takumi in a Node.js environment. ## Installation ```bash npm i @takumi-rs/core @takumi-rs/helpers ``` ## Usage First, initialize a Renderer instance to render images. ```ts import { Renderer } from "@takumi-rs/core"; export const renderer = new Renderer({ fonts: [/* Add your font buffers */], persistentImages: [/* Add your persistent images */] }); ``` Create a function to construct layout. you can take existing React component with [`fromJsx` function](/docs/deep-dives/from-jsx-helper). ```ts import { container, text } from "@takumi-rs/helpers"; function createOpenGraphImage(name: string) { return container({ width: 1200, height: 630, backgroundColor: 0x000000, children: [ text(`Hello, ${name}!`, { fontSize: 48, color: 0xffffff, x: 100, y: 100, }), ], }); } ``` Finally, render the layout to an image buffer. ```ts import type { OutputFormat } from "@takumi-rs/core"; const imageBuffer = await renderer.renderAsync(createOpenGraphImage("John Doe"), { width: 1200, height: 630, format: "WebP" as OutputFormat.WebP, // when `isolatedModules` is enabled, you need to use the enum value directly }); ``` ## Deep dive Into Advanced Usages If you are interested in more advanced usages of Takumi, consider take a look at [Deep Dives](/docs/deep-dives) section. # Use Takumi in Browser (WASM) URL: /docs/getting-started/wasm-web Integrate Takumi with WebAssembly (WASM) for client-side image generation. Web worker integration is under development. Contributions welcome! For server-side rendering, consider using the [Node.js/Bun Integration](/docs/getting-started/nodejs) for improved performance and compatibility. Takumi provides WebAssembly (WASM) bindings for browser compatibility, allowing client-side image generation. The WASM binary is downloaded client-side. ```bash npm install @takumi-rs/wasm @takumi-rs/helpers ``` ## Load the WASM Module Since WASM files are binary, they need to be loaded and initialized properly. The Takumi WASM package provides an `init` function that takes the URL of the WASM binary. Different bundlers and frameworks have different ways to handle WASM files. Below are examples for popular setups. ### Vite Setup ```javascript import init, { Renderer } from "@takumi-rs/wasm"; import wasmUrl from "@takumi-rs/wasm/takumi_wasm_bg.wasm?url"; await init(wasmUrl); const renderer = new Renderer(); ``` ### Webpack Setup To use Takumi WASM with Webpack, you need to configure Webpack to handle `.wasm` files as assets. Add the following to your `webpack.config.js`: ```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: ```js import init, { Renderer } from '@takumi-rs/wasm'; import wasmUrl from '@takumi-rs/wasm/takumi_wasm_bg.wasm'; await init(wasmUrl); const renderer = new Renderer(); ``` ### Next.js Setup Next.js (with Webpack 5+) also supports importing WASM as assets. You can use the [same Webpack rule as above](#webpack) by customizing your `next.config.js`: ```js // next.config.js module.exports = { webpack(config) { config.module.rules.push({ test: /\.wasm$/, type: 'asset/resource', generator: { filename: 'static/wasm/[name].[hash][ext]' } }); return config; }, }; ``` Then, import and initialize the WASM module in your component or page: ```js import init, { Renderer } from '@takumi-rs/wasm'; import wasmUrl from '@takumi-rs/wasm/takumi_wasm_bg.wasm'; useEffect(() => { (async () => { await init(wasmUrl); const renderer = new Renderer(); // ... your code ... })(); }, []); ``` ### Cloudflare Workers Setup This is setup using [worker-sdk](https://github.com/cloudflare/workers-sdk) template, checkout working [cloudflare-workers example](https://github.com/kane50613/takumi/blob/master/example/cloudflare-workers/src/index.ts) here. Add this rule to `wrangler.jsonc` to allow importing of font files, do the same thing with images if needed. ```json { "rules": [ { "type": "Data", "globs": ["**/*.ttf", "**/*.woff", "**/*.woff2"], "fallthrough": true } ] } ``` Use `initSync` function to setup initialized WebAssembly module. ```ts import module from "@takumi-rs/wasm/takumi_wasm_bg.wasm"; import { initSync, Renderer } from "@takumi-rs/wasm"; initSync({ module }); const renderer = new Renderer(); ``` ### No Bundler Setup For direct browser usage without a bundler, download files locally or use a CDN like unpkg. ## Usage ```javascript import { container, text, percentage } from "https://unpkg.com/@takumi-rs/helpers"; import init, { Renderer } from "https://unpkg.com/@takumi-rs/wasm"; await init("http://unpkg.com/@takumi-rs/wasm/takumi_wasm_bg.wasm"); const renderer = new Renderer(); ``` First, initialize a Renderer instance to render images. ```ts import init, { Renderer } from "@takumi-rs/wasm"; import wasmUrl from "@takumi-rs/wasm/takumi_wasm_bg.wasm?url"; await init(wasmUrl); const renderer = new Renderer(); // load fonts using renderer.loadFont() // load images using renderer.putPersistentImage() ``` Create a function to construct layout. you can take existing React component with [`fromJsx` function](/docs/deep-dives/from-jsx-helper). ```ts import { container, text } from "@takumi-rs/helpers"; function createOpenGraphImage(name: string) { return container({ width: 1200, height: 630, backgroundColor: 0x000000, children: [ text(`Hello, ${name}!`, { fontSize: 48, color: 0xffffff, x: 100, y: 100, }), ], }); } ``` Finally, render the layout to an image buffer. ```ts import type { ImageOutputFormat } from "@takumi-rs/wasm"; const imageBuffer = await renderer.render( // root node createOpenGraphImage("John Doe"), // width 1200, // height 630, // format "WebP" as ImageOutputFormat.WebP, // when `isolatedModules` is enabled, you need to use the enum value directly ); // Data URL rendering is also supported through renderer.renderAsDataUrl() ``` ## Deep dive Into Advanced Usages If you are interested in more advanced usages of Takumi, consider take a look at [Deep Dives](/docs/deep-dives) section. # Overview URL: /docs An overview of the Takumi image generation library. Welcome to the documentation for Takumi! Takumi is a library for generating images from code using a CSS Flexbox-like layout engine. It allows you to create complex images with the same flexbox principles you're familiar with from web development. At its core, Takumi works by constructing a tree of nodes, similar to the HTML DOM. You then style them with properties like in CSS, and then render the entire tree into a final image. *Takumi (匠) means "artisan" or "craftsman" in Japanese - reflecting the precision and artistry required to craft beautiful images through code.* ## Start Here Looking to dive in quickly? Check out the [Getting Started](/docs/getting-started) guides to begin learning how to use Takumi