# 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