# Comparison to satori (/docs/comparison-to-satori) [satori](https://github.com/vercel/satori) pioneered OG images without a headless browser and powers `next/og`. It turns JSX into an SVG string, so a bitmap takes a pipeline: yoga computes layout in WebAssembly, satori emits SVG, and `resvg` or `sharp` rasterizes it. Takumi is one Rust engine that does the whole job: JSX in, encoded image out. Migration is mostly an import swap: `ImageResponse` matches the `next/og` API, and templates written for satori declare `display: flex` explicitly, so they render unchanged. Compare rendered output across providers at [image-bench.kane.tw](https://image-bench.kane.tw). ## Features [#features] ### Templates and styling [#templates-and-styling] | Feature | satori / `next/og` | Takumi | | :---------------------------------- | :----------------------- | :---------------------------- | | Template input | JSX | JSX, HTML strings, node trees | | Styling | Inline styles, `tw` prop | + ` ``` ### Render the component on a server route [#render-the-component-on-a-server-route] * Import the component, and `app.css` if you use Tailwind. * Render to HTML with `render` from `svelte/server`. * Return an `ImageResponse`. ```ts title="src/routes/+server.ts" import { render } from "svelte/server"; import style from "../app.css?inline"; import ImageResponse from "takumi-js/response"; import OgImage from "$lib/components/OgImage.svelte"; import type { RequestEvent } from "./$types"; export async function GET({ url }: RequestEvent) { const { body, head } = await render(OgImage, { props: { name: url.searchParams.get("name") ?? "Goo goo gaga", }, }); return new ImageResponse(`${head}${body}`, { width: 1200, height: 630, stylesheets: [style], fonts: ["https://takumi.kane.tw/fonts/Geist.woff2"], }); } ``` # TanStack Start (/docs/integration/tanstack-start) ### Install Takumi [#install-takumi] npm pnpm yarn bun ```bash npm i takumi-js ``` ```bash pnpm add takumi-js ``` ```bash yarn add takumi-js ``` ```bash bun add takumi-js ``` ### Create a server file route [#create-a-server-file-route] TanStack Start lets you define HTTP handlers on a file route with `server.handlers`. ```tsx title="src/routes/og-image.tsx" import { createFileRoute } from "@tanstack/react-router"; import ImageResponse from "takumi-js/response"; export const Route = createFileRoute("/og-image")({ server: { handlers: { GET({ request }) { const url = new URL(request.url); const title = url.searchParams.get("title") ?? "Takumi + TanStack Start"; const description = url.searchParams.get("description") ?? "Render OG images from a route handler."; return new ImageResponse(

{title}

{description}

, { width: 1200, height: 630, }, ); }, }, }, }); ```
### Request the endpoint [#request-the-endpoint] Visit `/og-image?title=Hello&description=From%20TanStack%20Start`.
# Keyframe Animation (/docs/keyframe-animation) Takumi animates scenes two ways: * `renderAnimation()` produces an animated `webp`, `apng`, or `gif` directly. * `render()` with `timeMs` renders one frame at a time, for structured `keyframes` or external encoders like ffmpeg. Below is a keyframe animation rendered with ffmpeg + shiki for syntax highlighting: