In‑browser playground for designing and rendering Open Graph style images using Takumi (WASM). Type JSX on the left, see a PNG/WEBP preview on the right, inspect logs, and download the result — all client‑side.
https://github.com/takumi-rs (packages used: @takumi-rs/wasm, @takumi-rs/helpers)
- Live editor: Monaco‑powered JSX editor with auto/ manual render and adjustable debounce
- PNG/WEBP output: Render via
@takumi-rs/wasmand download as a data URL - Tailwind‑like styling: Use
tw-to-css(twj()) to turn utility strings into inline styles - Image inlining: External
<img src>URLs are fetched and embedded as Data URIs (CORS‑friendly) - Debug panel: View transformed code, final JSX, image inlining stats, and errors
- Themes: Light/Dark UI toggle
- 100% client‑side: No server; everything runs in your browser
- Bun (recommended) or Node.js 20+
- Modern browser with WebAssembly enabled
bun install
bun run devVite will print a local URL to open in your browser.
Scripts in package.json use Bun. If you prefer Node, run Vite directly:
npm install # or pnpm/yarn
npx vite # dev
npx vite build
npx vite preview- Edit the JSX in the left panel. The default snippet shows Tailwind‑like styles via
twj()and an external image. - Toggle Auto/Manual render and tweak the debounce delay as needed.
- Switch output format between PNG/WEBP.
- Download the rendered image.
- Use the Debug Logs panel to inspect parsing/transform errors, inlined image counts, and final JSX.
Example snippet (same as the default):
<div style={twj("h-full w-full flex items-start justify-start bg-white")}>
<div style={twj("flex items-start justify-start h-full w-full relative")}>
<img
style={{ ...twj("absolute inset-0 w-full h-full"), ...{ objectFit: "cover" } }}
src="https://picsum.photos/seed/picsum/1200/630"
/>
<div
style={{ ...twj("absolute inset-0 w-full h-full"), ...{ backgroundColor: "rgba(0,0,0,0.6)" } }}
></div>
<div style={twj("flex items-center justify-center w-full h-full absolute inset-0")}>
<div style={twj("text-[80px] text-white font-black text-center mx-20")}>
Takumi Playground
</div>
</div>
</div>
{/* tip: PNG and WEBP are supported */}
</div>The core flow lives in src/components/Playground.tsx:
- Transform:
sucrasecompiles the editor’s JSX/TS to JS. Parse errors are surfaced with line/column info. - Evaluate: The compiled expression is evaluated into a React element with
Reactandtwjin scope. - Inline images:
inlineImageSources()fetches external<img src>and replaces them with Data URIs to avoid cross‑origin issues. - Convert:
fromJsxfrom@takumi-rs/helpers/jsxturns the React element tree into a Takumi node. - Render:
@takumi-rs/wasmrenders to PNG/WEBP.useTakumi()initializes the renderer and providesrenderAsDataUrl().
Fonts: On first run the hook fetches Inter Variable from jsDelivr for better text rendering. Rendering still works without it, but text may differ.
src/
components/Playground.tsx # Main UI and render pipeline
components/playground/* # Header, editor, preview, logs
hooks/useTakumi.ts # WASM init, fonts, render helpers
utils/ # Image inlining, JSX debug, blob utils
index.css, playground.css # Styles
vite.config.ts # Vite + React
bun run dev: Start Vite dev serverbun run build: Build todist/bun run preview: Preview the production buildbun run lint: ESLint (eslint.config.js)
Node users can replace these with npx vite, npx vite build, etc.
- Security: The editor evaluates code client‑side. Do not paste untrusted code. This tool is for local development and experimentation.
- CORS & images: External images must be publicly fetchable; failures are logged and the renderer continues.
- Fonts: Inter loads from a CDN; offline first runs may render with fallback fonts.
- Browser support: Requires a modern browser with WebAssembly.
- Takumi WASM renderer:
@takumi-rs/wasm - Helpers and JSX conversion:
@takumi-rs/helpers - Editor:
@monaco-editor/react - Styling utilities:
tw-to-css