Dead simple dynamic image generation server for Bun using Satori + Sharp
rectram is a lightweight file-based image server framework that allows you to generate dynamic images (OG images, social cards, custom graphics) from JSX components using Satori and Sharp. Inspired by @vercel/og, it supports:
- File-based routing (
pages/.../page.tsx) - Dynamic props with
getProps - Satori-powered SVG generation
- Sharp-powered PNG rendering (fast af π₯)
- Full Bun-native support
- Dynamic Image Pages: Just create a
page.tsxunderpages/and it becomes a route. - Async Props: Fetch data or generate props dynamically with
getProps. - High Performance: Sharp handles PNG conversion fast, perfect for real-time OG image generation.
- Bun Native: No Node.js hacks needed β runs fully in Bun.
project/
ββ pages/
β ββ index/page.tsx # default route
ββ assets/
β ββ Inter-Regular.ttf
β ββ Inter-Italic.ttf
β ββ Inter-Bold.ttf
β ββ Inter-BoldItalic.ttf
ββ src/
β ββ index.ts # Bun server entrypoint
β ββ router.ts # file-based router
β ββ renderer.ts # Satori + Sharp helpers
β ββ types.ts # Type definitions
ββ bunfig.toml
ββ package.json / bun.lockb
- If you want your own version, use this repo as a template on GitHub:
- Go to the repo β Use this template β Create a new repo under your account.
git clone https://github.com/YOUR_USERNAME/YOUR_REPO.git
cd YOUR_REPO
bun install// pages/index/page.tsx
export const getProps = async ({ query }) => ({
title: query.get("title") ?? "Hello World",
subtitle: query.get("subtitle") ?? "Generated with rectram",
});
export default function Page({ title, subtitle }) {
return (
<div style={{
display: "flex",
width: "100%",
height: "100%",
alignItems: "center",
justifyContent: "center",
background: "#111827",
color: "white",
fontFamily: "Inter",
padding: 64
}}>
<div style={{ display: "flex", flexDirection: "column", gap: 16, maxWidth: 900 }}>
<div style={{ fontSize: 72, fontWeight: 700, lineHeight: 1.1 }}>{title}</div>
<div style={{ fontSize: 36, opacity: 0.9 }}>{subtitle}</div>
</div>
</div>
);
}bun devhttp://localhost:3000/?title=Hello&subtitle=rectram
- Add new routes by creating
page.tsxfiles underpages/. - Fetch dynamic data using
getProps. - Use plain inline styles for your components.
- Fonts must be placed under
assets/and imported inrenderer.ts.
- Returns PNG by default; SVG is optional via
contentType. - Fully typed with TypeScript.
- Made with love and ChatGPT π
Apache License 2.0 β do whatever the fuck you want w/ it.