Skip to content

feat: add Takumi renderer support#414

Merged
harlan-zw merged 14 commits into
mainfrom
feat/takumi
Jan 11, 2026
Merged

feat: add Takumi renderer support#414
harlan-zw merged 14 commits into
mainfrom
feat/takumi

Conversation

@harlan-zw

@harlan-zw harlan-zw commented Jan 11, 2026

Copy link
Copy Markdown
Collaborator

Summary

#411

Adds Takumi as an alternative rendering engine for OG images. Takumi is a Rust-based renderer that directly rasterizes to PNG/JPEG/WebP without SVG intermediates.

  • 2-10x faster than Satori+Resvg pipeline
  • Native Tailwind CSS support via tw prop
  • Direct raster output (no SVG intermediate)
  • Variable font and COLR emoji support
  • RTL text support

Changes

New files:

  • bindings/takumi/node.ts - Node.js binding
  • bindings/takumi/wasm.ts - WASM binding for edge runtimes
  • takumi/instances.ts - Lazy-loaded renderer instance
  • takumi/nodes.ts - HTML to Takumi node converter
  • takumi/renderer.ts - Main renderer implementation
  • test/unit/takumiNodes.test.ts - Unit tests for node conversion

Modified files:

  • types.ts - Added takumi renderer type and options
  • instances.ts - Added useTakumiRenderer()
  • context.ts - Added takumi case to renderer switch
  • compatibility.ts - Added takumi to all runtime configs

Usage

// Per-page
defineOgImage({
  renderer: 'takumi',
  component: 'MyOgImage',
})

// Module defaults
export default defineNuxtConfig({
  ogImage: {
    defaults: {
      renderer: 'takumi'
    }
  }
})

Test plan

  • Unit tests for style parsing pass
  • Manual testing with actual @takumi-rs/core package once installed
  • E2E tests with fixture app using takumi renderer

🤖 Generated with Claude Code

Adds Takumi as an alternative rendering engine for OG images. Takumi is a Rust-based
renderer that directly rasterizes to PNG/JPEG/WebP without SVG intermediates,
offering 2-10x faster rendering compared to Satori+Resvg.

New files:
- bindings/takumi/node.ts - Node.js binding
- bindings/takumi/wasm.ts - WASM binding for edge runtimes
- takumi/instances.ts - Lazy-loaded renderer instance
- takumi/nodes.ts - HTML to Takumi node converter
- takumi/renderer.ts - Main renderer implementation

Features:
- Native Tailwind CSS support via `tw` prop
- Direct PNG/JPEG/WebP output (no SVG intermediate)
- Variable font support
- COLR emoji support
- RTL text support

Configuration:
- Set renderer: 'takumi' in defineOgImage() or module defaults
- Supports node and wasm bindings based on runtime environment

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@harlan-zw

Copy link
Copy Markdown
Collaborator Author

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

harlan-zw and others added 13 commits January 11, 2026 13:35
- Add @ts-expect-error for optional dependencies (@takumi-rs/core, @takumi-rs/wasm, linkedom)
- Use `any` types for external Renderer class to avoid missing type declarations
- Add @ts-expect-error for virtual module imports (#og-image/bindings/takumi, #og-image/renderers/takumi)
- Add @ts-expect-error for runtime hook (nuxt-og-image:takumi:nodes)
- Fix potential undefined access in nodes.ts with optional chaining
- Remove webp from supportedFormats (not in extension types)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add takumi page fixture with basic example
- Add e2e test that conditionally runs when @takumi-rs/core is available
- Test skips gracefully when takumi packages not installed

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix linkedom HTML parsing by using document.documentElement instead of body.firstElementChild
- Add TakumiTest component for e2e testing
- Add image snapshot test for takumi renderer
- Add @takumi-rs/core and @takumi-rs/wasm to catalog
- Update trust policy exclusions for pnpm

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add comparison pages using same TakumiTest component
- Generate snapshots for both renderers
- Results show near-identical output for simple Tailwind components

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Rename to comparison-simple-satori/takumi for clarity
- Skip NuxtSeo template test (uses hash-based URLs, prerender only)
- Both renderers produce identical output for simple Tailwind components

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Shows compatibility differences:
- Satori: gradient backgrounds, opacity colors, full flexbox
- Takumi: limited - no gradients, opacity issues, flexbox gaps

Useful for documenting current Takumi limitations vs Satori.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Documents:
- Installation requirements
- Pros/cons vs Satori
- Supported/unsupported CSS features
- Example template
- Runtime compatibility table

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove console.log in skipped test
- Lowercase test title for 'nuxtseo template'
- Remove unused props variable in Vue components
- Fix yaml key ordering in pnpm-workspace.yaml

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@harlan-zw harlan-zw merged commit 7a34746 into main Jan 11, 2026
4 checks passed
@harlan-zw harlan-zw mentioned this pull request Jan 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant