snatching amp's walkthrough for my own purposes mwhahaha
traverse.dunkirk.sh/diagram/6121f05c-a5ef-4ecf-8ffc-02534c5e767c
1import satori from "satori";
2import { initWasm, Resvg } from "@resvg/resvg-wasm";
3import { join } from "path";
4
5// Load Inter font files (woff, not woff2 — satori doesn't support woff2)
6const fontsDir = join(import.meta.dir, "../fonts");
7const [interRegular, interBold] = await Promise.all([
8 Bun.file(join(fontsDir, "inter-latin-400-normal.woff")).arrayBuffer(),
9 Bun.file(join(fontsDir, "inter-latin-700-normal.woff")).arrayBuffer(),
10]);
11
12// Initialize resvg-wasm
13// Try bundled WASM first, then fall back to node_modules
14const possiblePaths = [
15 // Bundled WASM file (most reliable)
16 join(import.meta.dir, "../vendor/index_bg.wasm"),
17 // Development: node_modules is a sibling of src
18 join(import.meta.dir, "../node_modules/@resvg/resvg-wasm/index_bg.wasm"),
19 // Installed: in parent node_modules
20 join(import.meta.dir, "../../@resvg/resvg-wasm/index_bg.wasm"),
21 join(import.meta.dir, "../../../@resvg/resvg-wasm/index_bg.wasm"),
22];
23
24let wasmPath: string | undefined;
25for (const path of possiblePaths) {
26 if (await Bun.file(path).exists()) {
27 wasmPath = path;
28 break;
29 }
30}
31
32if (!wasmPath) {
33 console.error("Failed to find @resvg/resvg-wasm WASM file. Tried:");
34 for (const path of possiblePaths) {
35 console.error(` - ${path}`);
36 }
37 console.error(`\nCurrent directory: ${import.meta.dir}`);
38 throw new Error("Could not find @resvg/resvg-wasm WASM file");
39}
40
41await initWasm(Bun.file(wasmPath).arrayBuffer());
42
43// Cache generated images by diagram ID
44const cache = new Map<string, Buffer>();
45
46export async function generateIndexOgImage(
47 mode: "local" | "server",
48 diagramCount: number,
49): Promise<Buffer> {
50 const cacheKey = `__index_${mode}_${diagramCount}`;
51 const cached = cache.get(cacheKey);
52 if (cached) return cached;
53
54 const subtitle = mode === "server"
55 ? `${diagramCount} diagram${diagramCount !== 1 ? "s" : ""} shared`
56 : `${diagramCount} diagram${diagramCount !== 1 ? "s" : ""}`;
57
58 const tagline = mode === "server"
59 ? "Interactive code walkthrough diagrams, shareable with anyone."
60 : "Interactive code walkthrough diagrams";
61
62 const svg = await satori(
63 {
64 type: "div",
65 props: {
66 style: {
67 width: "100%",
68 height: "100%",
69 display: "flex",
70 flexDirection: "column",
71 justifyContent: "center",
72 alignItems: "center",
73 padding: "60px",
74 backgroundColor: "#0a0a0a",
75 color: "#e5e5e5",
76 fontFamily: "Inter",
77 },
78 children: [
79 {
80 type: "div",
81 props: {
82 style: {
83 display: "flex",
84 flexDirection: "column",
85 alignItems: "center",
86 gap: "20px",
87 },
88 children: [
89 {
90 type: "div",
91 props: {
92 style: {
93 fontSize: "80px",
94 fontWeight: 700,
95 color: "#e5e5e5",
96 },
97 children: "Traverse",
98 },
99 },
100 {
101 type: "div",
102 props: {
103 style: {
104 fontSize: "32px",
105 color: "#a3a3a3",
106 textAlign: "center",
107 },
108 children: tagline,
109 },
110 },
111 {
112 type: "div",
113 props: {
114 style: {
115 display: "flex",
116 alignItems: "center",
117 gap: "8px",
118 marginTop: "16px",
119 fontSize: "24px",
120 color: "#a3a3a3",
121 backgroundColor: "#1c1c1e",
122 padding: "10px 24px",
123 borderRadius: "8px",
124 border: "1px solid #262626",
125 },
126 children: subtitle,
127 },
128 },
129 ],
130 },
131 },
132 ],
133 },
134 },
135 {
136 width: 1200,
137 height: 630,
138 fonts: [
139 { name: "Inter", data: interRegular, weight: 400, style: "normal" as const },
140 { name: "Inter", data: interBold, weight: 700, style: "normal" as const },
141 ],
142 },
143 );
144
145 const resvg = new Resvg(svg, {
146 fitTo: { mode: "width", value: 1200 },
147 });
148 const png = Buffer.from(resvg.render().asPng());
149
150 cache.set(cacheKey, png);
151 return png;
152}
153
154export async function generateOgImage(
155 id: string,
156 summary: string,
157 nodeNames: string[],
158): Promise<Buffer> {
159 const cached = cache.get(id);
160 if (cached) return cached;
161
162 const nodeCount = nodeNames.length;
163 const displayNodes = nodeNames.slice(0, 8);
164 const extra = nodeCount > 8 ? nodeCount - 8 : 0;
165
166 const svg = await satori(
167 {
168 type: "div",
169 props: {
170 style: {
171 width: "100%",
172 height: "100%",
173 display: "flex",
174 flexDirection: "column",
175 justifyContent: "space-between",
176 padding: "60px",
177 backgroundColor: "#0a0a0a",
178 color: "#e5e5e5",
179 fontFamily: "Inter",
180 },
181 children: [
182 // Top: Traverse label + node count
183 {
184 type: "div",
185 props: {
186 style: {
187 display: "flex",
188 alignItems: "center",
189 justifyContent: "space-between",
190 },
191 children: [
192 {
193 type: "div",
194 props: {
195 style: {
196 fontSize: "20px",
197 fontWeight: 700,
198 color: "#a3a3a3",
199 letterSpacing: "0.05em",
200 textTransform: "uppercase" as const,
201 },
202 children: "Traverse",
203 },
204 },
205 {
206 type: "div",
207 props: {
208 style: {
209 fontSize: "16px",
210 color: "#666",
211 },
212 children: `${nodeCount} node${nodeCount !== 1 ? "s" : ""}`,
213 },
214 },
215 ],
216 },
217 },
218 // Middle: Summary headline
219 {
220 type: "div",
221 props: {
222 style: {
223 display: "flex",
224 flexDirection: "column",
225 gap: "24px",
226 flex: 1,
227 justifyContent: "center",
228 },
229 children: [
230 {
231 type: "div",
232 props: {
233 style: {
234 fontSize: summary.length > 60 ? "36px" : "44px",
235 fontWeight: 700,
236 lineHeight: 1.2,
237 color: "#e5e5e5",
238 overflow: "hidden",
239 textOverflow: "ellipsis",
240 },
241 children: summary,
242 },
243 },
244 ],
245 },
246 },
247 // Bottom: Node pills
248 {
249 type: "div",
250 props: {
251 style: {
252 display: "flex",
253 flexWrap: "wrap",
254 gap: "8px",
255 },
256 children: [
257 ...displayNodes.map((name) => ({
258 type: "div",
259 props: {
260 style: {
261 fontSize: "14px",
262 color: "#a3a3a3",
263 backgroundColor: "#1c1c1e",
264 padding: "4px 12px",
265 borderRadius: "6px",
266 border: "1px solid #262626",
267 },
268 children: name,
269 },
270 })),
271 ...(extra > 0
272 ? [
273 {
274 type: "div",
275 props: {
276 style: {
277 fontSize: "14px",
278 color: "#666",
279 padding: "4px 8px",
280 },
281 children: `+${extra} more`,
282 },
283 },
284 ]
285 : []),
286 ],
287 },
288 },
289 ],
290 },
291 },
292 {
293 width: 1200,
294 height: 630,
295 fonts: [
296 { name: "Inter", data: interRegular, weight: 400, style: "normal" as const },
297 { name: "Inter", data: interBold, weight: 700, style: "normal" as const },
298 ],
299 },
300 );
301
302 const resvg = new Resvg(svg, {
303 fitTo: { mode: "width", value: 1200 },
304 });
305 const png = Buffer.from(resvg.render().asPng());
306
307 cache.set(id, png);
308 return png;
309}