You're reading the v2 prerelease docs. For the stable release, switch to v1 →
TakumiTakumi

Images & emoji

Load and cache images, and render emoji.

External Images

Takumi fetches external images in src attributes and CSS background-image / mask-image.

To reuse fetched bytes across renders, pass a fetchCache — a Map<string, Promise<ArrayBuffer>>, or anything with Map-like get/set/delete. It stores the in-flight promise, so concurrent renders needing the same URL share one fetch:

import {  } from "takumi-js";

const  = < ="https://example.com/image.png" />;

const  = new <string, <ArrayBuffer>>();

const  = await (, {
  : {
    ,
  },
});

A plain Map never evicts. If your URLs are high-cardinality (a different image per render), pass a bounded cache such as an LRU, or omit fetchCache.

Pre-fetched Images

Provide images by key so the renderer doesn't have to fetch them itself. Each key can be used in any src field or in the background-image / mask-image CSS properties.

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

export function () {
  return new (< />, {
    : [
      {
        : "my-logo",
        : () => ("/logo.png").(() => .()),
      },
      {
        : "background",
        : () => ("/background.png").(() => .()),
      },
    ],
  });
}

function () {
  return (
    <
      ={{
        : "url(background)",
      }}
    >
      < ="my-logo" />
    </>
  );
}

Decode caching

Takumi caches each decoded image so repeated content is decoded once. Two independent layers exist:

LayerStoresKeyed bySet with
Byte cacheFetched bytesURLimages.fetchCache
Decode cacheDecoded pixelsHash of image bytesper-image cache / images.cache

The decode cache lives in the renderer and is bounded: entries weigh in at their decoded size against a 64 MiB budget, and once it fills the cache evicts the least recently used. A high-cardinality workload (a different image every render) won't grow memory; it misses the cache and decodes each time. SVGs skip the cache and re-parse per render.

The per-image cache mode takes two values:

  • auto (default): cache the decoded image within the byte budget.
  • none: read the cache but never populate it. Use it for a one-off image you won't render again, so it can't displace images worth keeping.
import {  } from "takumi-js/response";

export function () {
  return new (< />, {
    : [
      {
        : "banner",
        : () => ("/banner.png").(() => .()),
        : "none", 
      },
    ],
  });
}

To set the mode for every image in a render, including ones Takumi fetches itself, pass images as a group instead of an array. A per-source cache still wins. For a route where each request renders a different image, cache: "none" keeps one-off decodes out of the cache:

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

export function () {
  return new (< />, {
    : {
      : "none", 
      : [{ : "logo", : () => ("/logo.png").(() => .()) }],
    },
  });
}

function () {
  return < ="logo" />;
}

Emoji

Dynamic fetching

ImageResponse accepts a satori-compatible emoji option. The providers are twemoji, blobmoji, noto, openmoji, fluent, and fluentFlat.

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

export function () {
  return new (< ="flex justify-center items-center text-3xl">Hello 👋😁</>, {
    : "twemoji", 
  });
}

Manual extraction

ImageResponse calls the extractEmojis helper for you. The helper splits emoji from text into image nodes pointing at a CDN. Run the steps yourself to fetch emoji bytes alongside other images.

import {  } from "takumi-js/helpers/emoji";
import {  } from "takumi-js/helpers/jsx";
import {  } from "takumi-js";
import {  } from "takumi-js/node";

let {  } = await (< ="flex justify-center items-center text-3xl">Hello 👋😁</>);
 = (, "twemoji");

const  = await ({  });

const  = new ();

const  = await .(, {
  ,
});

prepareImages walks the node tree for remote <img>, backgroundImage, and maskImage URLs, fetches the ones missing from sources, and returns images entries. Pass a fetchCache (a Map<string, Promise<ArrayBuffer>>, or anything with Map-like get/set/delete) to deduplicate concurrent fetches and reuse bytes across renders.

COLR / bitmap fonts

Takumi renders COLR (Color Layer) fonts, the format behind packs like Twemoji-COLR. A COLR file is much smaller than a bitmap emoji font like Noto Color Emoji. The renderer draws emoji from the loaded glyphs, with no network request.

Two steps:

  • Register the font through fonts.
  • Set emoji: "from-font".
Edit on GitHub

Last updated on

On this page