Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

g1t.sh
50 linesCodeBlameRaw

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

The sidebar asks billing whether it is on, not for the account, so no page waits on the card processor1/**
2 * Turns a card into a PNG: satori lays it out as SVG, with the text as
3 * outlines, and resvg rasterises that. Both run as WebAssembly, which the
4 * caller hands in: as modules in the Worker, as bytes in Node.
5 */
6import { Resvg, initWasm } from "@resvg/resvg-wasm";
7import satori, { init as initYoga, type Font } from "satori/standalone";
8
9import { HEIGHT, WIDTH, cardTree } from "./card.ts";
10import type { Card } from "./resolve.ts";
11
12export type Assets = {
13 yoga: WebAssembly.Module | ArrayBuffer | Uint8Array;
14 resvg: WebAssembly.Module | ArrayBuffer | Uint8Array;
15 fonts: Font[];
16};
17
18let ready: Promise<void> | null = null;
19
20function start(assets: Assets): Promise<void> {
21 ready ??= Promise.all([initYoga(assets.yoga), initWasm(assets.resvg)]).then(
22 () => undefined,
23 (error) => {
24 ready = null;
25 throw error;
26 },
27 );
28 return ready;
29}
30
31/** The card as SVG, for tests and for looking at without rasterising. */
32export async function cardSvg(card: Card, assets: Assets): Promise<string> {
33 await start(assets);
34 // Satori takes React elements; the tree is the same shape without React.
35 return satori(cardTree(card) as unknown as Parameters<typeof satori>[0], {
36 width: WIDTH,
37 height: HEIGHT,
38 fonts: assets.fonts,
39 });
40}
41
42export async function cardPng(card: Card, assets: Assets): Promise<Uint8Array> {
43 const svg = await cardSvg(card, assets);
44 const resvg = new Resvg(svg, { fitTo: { mode: "width", value: WIDTH }, font: { loadSystemFonts: false } });
45 try {
46 return resvg.render().asPng();
47 } finally {
48 resvg.free();
49 }
50}

This file's history is long; its oldest lines are credited to the oldest commit read.