TakumiTakumi

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.

Font

import {  } from "takumi-js/response";
import type {  } from "takumi-js";

export function () {
  return new (< />, {
    : [
      {
        : "Inter",
        : () => ("/path-to-inter.woff2").(() => .()),
      },
    ],
  });
}

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, there's 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>

Variable fonts

A single variable font file replaces a whole family. Drive its axes through font-variation-settings; the renderer passes them straight to the shaper.

import {  } from "takumi-js/response";

export function () {
  return new (
    <
      ={{
        : "Manrope",
        : "'wght' 700, 'wdth' 110, 'opsz' 48",
        : 64,
      }}
    >
      Variable font axes
    </>,
    { : 800, : 200 },
  );
}

font-weight: 700 is shorthand for font-variation-settings: 'wght' 700. Use the longhand when you need to set axes other than weight (width, optical size, slant, italic, or any custom axis the font ships).

Fallback chain

Takumi resolves glyphs in load order. Every font you pass to the renderer becomes a fallback candidate for every Unicode script; when the primary family is missing a glyph, the shaper walks the registered fonts until one supplies it.

Practical consequence: load your text font first, then a color emoji font, then a CJK font, then any script-specific fallback. The first font that owns the glyph wins.

const renderer = new Renderer({
  fonts: [
    interRegular, // primary Latin
    notoColorEmoji, // emoji fallback
    notoSansJP, // CJK fallback
    notoSansArabic, // Arabic fallback
  ],
});

A character with no provider anywhere in the chain renders as .notdef (the font's "tofu" box). If you see those, you're missing a font for that script.

COLR vs bitmap glyphs

Color emoji ship in two main formats:

FormatStorageFile sizeBest for
COLR (v0 / v1)Vector layers~1 MBDefault. Scales cleanly.
CBDT / sbixRaster bitmap5-20 MBPixel-accurate match to a target.

Reach for COLR unless you need byte-identical output with a specific platform (Apple's sbix Apple Color Emoji, for example). Twemoji-COLR is COLR; Google's Noto Color Emoji ships primarily as CBDT/CBLC bitmaps, with separate COLR/COLRv1 builds derived from the same artwork. If you want a per-glyph image instead of a font, see Emoji.

Edit on GitHub

Last updated on

On this page