Typography & 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 Geist and Geist Mono are embedded by default.
For @takumi-rs/wasm, a single variable Latin font, Manrope, is embedded by default.
If you need a monospace family in WASM, provide your own font.
Adding fonts
Pass the fonts a render needs through the fonts option. Each entry is raw bytes or a { name, data, weight, style } descriptor, and data may be a loader that returns the bytes. The renderer registers and deduplicates them, so a reused renderer pays the decode cost once.
import { } from "takumi-js/response";
export function () {
return new (< />, {
: [
{
: "Inter",
: () => ("/path-to-inter.woff2").(() => .()),
},
],
});
}The same fonts option works on render, renderAnimation, and encodeFrames.
Preloading with registerFont
registerFont is the escape hatch for preloading: register a font on a renderer up front, outside the request path, then reuse that renderer. It accepts the same entry shape as fonts and resolves to the families it produced.
const renderer = new Renderer();
await renderer.registerFont({ name: "Inter", data: inter });
return new ImageResponse(<OgImage />, { renderer });Font fallback chain
fontFamilies is the ordered list of families tried in turn when a glyph is missing. It defaults to the families you passed, in order, so the chain follows the order you listed your fonts. Set it to pin which family wins and what backs it up.
const image = await renderer.render(node, {
fontFamilies: ["Inter", "Noto Sans JP"],
});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" <weight>.
<div
style={{
fontFamily: "Manrope",
fontVariationSettings: "'wght' 700, 'wdth' 150",
fontFeatureSettings: "ss01",
}}
>
Variable Font Text
</div>Render Emojis
Dynamic fetching
If you are using ImageResponse API, theres a satori compatible emoji option.
import { } from "takumi-js/response";
export function () {
return new (< ="flex justify-center items-center text-3xl">Hello 👋😁</>, {
: "twemoji",
});
}Under the hood it calls extractEmojis helper function, which separates the emoji segments from the text and modifies the text node.
import { } from "takumi-js/helpers/emoji";
import { } from "takumi-js/helpers/jsx";
import { , } from "takumi-js/helpers";
import { } from "takumi-js/node";
let { } = await (< ="flex justify-center items-center text-3xl">Hello 👋😁</>);
= (, "twemoji");
const = ();
const = await ();
const = new ();
const = await .(, {
,
});COLR/Bitmap Font File
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.
<div
style={{
textOverflow: "ellipsis",
lineClamp: 3,
}}
>
Super Long Text
</div>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).
Wrapping
Takumi supports both balance and pretty text wrapping. The algorithm is modified from satori's implementation.
<div style={{ textWrap: "balance" }}>Super Long Text</div>Last updated on