Render JSX to images.
Skip the browser.

Headless Chromium needs ~300 MB and a cold start for one OG card. Takumi needs a function call.

Takumi OG image rendered by TakumiX post image rendered by TakumiPrisma-style OG image rendered by Takumi

The code is the design file.

Drop-in for next/og. The card is this source file, rendered.

export default function DemoCard() {
  return (
    <div tw="flex h-full w-full flex-col justify-between bg-[#16130f] p-14 text-white">
      <div tw="flex items-center justify-between">
        <span tw="text-2xl text-[#a8a29a]">takumi.kane.tw</span>
        <span tw="h-10 w-10 bg-[#ff4d4d]" />
      </div>
      <h1
        tw="text-7xl font-bold leading-tight"
        style={{
          backgroundClip: "text",
          backgroundImage: "linear-gradient(110deg, #fff 60%, #ff4d4d)",
          color: "transparent",
        }}
      >
        This card is the code beside it.
      </h1>
      <div tw="flex items-center justify-between text-2xl text-[#a8a29a]">
        <span>Rendered without a browser</span>
        <span>1200 × 630</span>
      </div>
    </div>
  );
}
The card rendered from the source on the left

home-demo-card@2x.webp · 52 KB · rendered by bun example/twitter-images

One tree, sampled across time.

Pass a timestamp. PNG is t = 0. Animated WebP is the same tree over t.

@keyframes morph {
  from { border-radius: 12%; transform: rotate(0deg) scale(1); }
  50%  { border-radius: 50%; transform: rotate(90deg) scale(0.72); }
  to   { border-radius: 12%; transform: rotate(180deg) scale(1); }
}
Frame sampled at t=0ms
t=0
Frame sampled at t=125ms
t=125
Frame sampled at t=250ms
t=250
Frame sampled at t=375ms
t=375
Frame sampled at t=500ms
t=500
Frame sampled at t=625ms
t=625
Frame sampled at t=750ms
t=750
Frame sampled at t=875ms
t=875

The CSS you write.

Not a tiny OG subset. Put the property back.

Layout

  • display: grid
  • float
  • position: absolute
  • calc()
  • z-index

Selectors

  • :is()
  • :where()
  • ::before
  • ::after

Paint

  • backdrop-filter
  • mix-blend-mode
  • conic-gradient()
  • clip-path
  • mask
  • background-clip: text

Text

  • WOFF2 fonts
  • emoji
  • RTL scripts
  • multi-span inline

Motion

  • @keyframes
  • animation
  • Tailwind animate-*

Native on Node. WASM on Workers and browsers. Crate for Rust.

macOS · Linux · Windows · x64 · ARM64

In production.

Dcard share cards. Fumadocs OG images. Built into Nuxt OG Image.

OG image from dcard.twOG image from tanstack.comOG image from fumadocs.devOG image from wotaku.wikiOG image from stepperize.comOG image from swetrix.comOG image from github.comOG image from bookhive.buzz

View all projects →

Render your first image.

bun i takumi-js

Layout by taffy · text by parley & skrifa · SVG by resvg

MIT / Apache-2.0