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:
| Layer | Stores | Keyed by | Set with |
|---|---|---|---|
| Byte cache | Fetched bytes | URL | images.fetchCache |
| Decode cache | Decoded pixels | Hash of image bytes | per-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".
Last updated on