diff --git a/index.html b/index.html
index 79e14f4..7bb6b88 100644
--- a/index.html
+++ b/index.html
@@ -7,6 +7,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/package.json b/package.json
index c9a9816..c0f4c12 100644
--- a/package.json
+++ b/package.json
@@ -6,6 +6,7 @@
"scripts": {
"dev": "vite",
"generate-icons": "node scripts/generate-pwa-icons.mjs",
+ "generate-og-image": "bun run scripts/generate-og-image.mjs",
"build": "bun run generate-icons && tsc -b && vite build",
"lint": "oxlint",
"test": "vitest run",
diff --git a/public/og-image.png b/public/og-image.png
new file mode 100644
index 0000000..57d5794
Binary files /dev/null and b/public/og-image.png differ
diff --git a/scripts/generate-og-image.mjs b/scripts/generate-og-image.mjs
new file mode 100644
index 0000000..221c2fc
--- /dev/null
+++ b/scripts/generate-og-image.mjs
@@ -0,0 +1,34 @@
+import { readFileSync, writeFileSync } from 'node:fs'
+import { dirname, join } from 'node:path'
+import { fileURLToPath } from 'node:url'
+import sharp from 'sharp'
+
+const root = join(dirname(fileURLToPath(import.meta.url)), '..')
+const WIDTH = 1200
+const HEIGHT = 630
+
+const BACKGROUND = '#111111'
+const TITLE = '#fafafa'
+const TAGLINE = '#a3a3a3'
+const FONT = 'Helvetica, Arial, sans-serif'
+
+const logo = readFileSync(join(root, 'public/favicon.svg')).toString('base64')
+
+// Everything is centred on a single solid background
+const svg = `
+`
+
+const png = await sharp(Buffer.from(svg)).png().toBuffer()
+writeFileSync(join(root, 'public/og-image.png'), png)
+console.log(`Generated og-image.png (${WIDTH}x${HEIGHT})`)