Takumi

Generate Open Graph images for your documentation pages.

Installation

This plugin is included in fumapress and enabled by default through the recommended preset. Add it yourself to configure it:

press.config.tsx
import { defineConfig } from "fumapress";
import { takumiPlugin } from "fumapress/plugins/takumi";

export default defineConfig({
  // ...
})
  .plugins(takumiPlugin());

The plugin creates a .webp Open Graph image for every content page with Takumi, and adds the matching metadata:

<meta property="og:image" content="/docs/page.webp" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="twitter:card" content="summary_large_image" />

The default image shows the page title, description, and site name.

Set site.baseUrl in your config to make og:image resolve to an absolute URL.

press.config.tsx
import { defineConfig } from "fumapress";

export default defineConfig({
  site: {
    baseUrl: "https://press.fumadocs.dev",
  },
});

Options

generate

Customize the image of a page, this is the app context:

press.config.tsx
import { defineConfig } from "fumapress";
import { takumiPlugin } from "fumapress/plugins/takumi";

export default defineConfig({
  // ...
}).plugins(
  takumiPlugin({
    generate(page) {
      return {
        node: (
          <div
            style={{
              width: "100%",
              height: "100%",
              display: "flex",
              flexDirection: "column",
              justifyContent: "center",
              padding: 80,
              background: "#111",
              color: "white",
            }}
          >
            <p>{this.siteConfig.name}</p>
            <h1>{page.data.title}</h1>
          </div>
        ),
        // image response options of this page
        options: {
          quality: 80,
        },
      };
    },
  }),
);

options

Image response options shared by every image, the ones returned from generate() override them per page.

Anything resolved once belongs here. googleFonts() downloads the font files on every call, so create the promise at module scope instead of inside generate():

press.config.tsx
import { defineConfig } from "fumapress";
import { googleFonts, takumiPlugin } from "fumapress/plugins/takumi";

const fonts = googleFonts([{ name: "Geist", weight: [500, 800] }]);

export default defineConfig({
  // ...
}).plugins(
  takumiPlugin({
    options: { fonts },
  }),
);

fontFromUrl() does the same for a self-hosted font file. Both come from takumi-js through fumapress/plugins/takumi, don't install takumi-js yourself: a second copy renders with mismatched versions.

width / height

The image dimensions, defaulting to 1200x630. They are applied to the rendered image and the og:image meta tags, the response format is always webp.

press.config.tsx
takumiPlugin({ width: 1600, height: 840 });

Route Images

Pages outside your content, like the ones in src/pages, get an image from their route config:

src/pages/about.tsx
import type { RouteConfig } from "fumapress";

export function getConfig() {
  return {
    takumiOptions: { title: "About", description: "Who we are" },
  } satisfies RouteConfig;
}

The image is prerendered as /about.webp with the default template, and the page receives the same og:image meta tags as a content page. Pass node to draw it yourself, and options for the image response options of this route.

For routes with slugs, a function receives the route params, lang included with i18n, and this is the app context:

src/pages/tags/[tag].tsx
import type { RouteConfig } from "fumapress";

export function getConfig() {
  return {
    staticPaths: ["react", "vue"],
    takumiOptions: ({ tag }) => ({ node: <TagImage tag={tag} /> }),
  } satisfies RouteConfig;
}

A static page gets a prerendered .webp file next to it, one per entry of staticPaths. A dynamic page renders its image on request from an image route under /_takumi.

WebAssembly

Takumi renders with its native Rust addon on Node.js and Bun, and with WebAssembly on other runtimes. When the machine building your site can't load the native addon, like Cloudflare Workers Builds, pass the WebAssembly build instead:

press.config.tsx
import { takumiPlugin } from "fumapress/plugins/takumi";
import wasm from "fumapress/plugins/takumi.wasm";

takumiPlugin({
  options: {
    module: wasm,
  },
});

It is the takumi-js of fumapress again, and the binary is only bundled when you import it.

Last updated on

On this page