diff --git a/docs/assets/build-card.cjs b/docs/assets/build-card.cjs
new file mode 100644
index 00000000..a7990480
--- /dev/null
+++ b/docs/assets/build-card.cjs
@@ -0,0 +1,59 @@
+// Generates the FastroAI cross-sell card as transparent light/dark PNGs.
+// Used in the FastAPI-boilerplate docs to promote FastroAI.
+// Run: NODE_PATH= node docs/assets/build-card.cjs
+const path = require('path');
+const sharp = require('sharp');
+
+const OUT = __dirname;
+
+// Wordmark tracking. Negative = tighter. The previous card jammed the letters
+// together; this opens them up to match the FastroAI docs cover.
+const WORDMARK_TRACKING = -0.5;
+
+const MODES = {
+ light: { primary: '#111827', body: '#4b5563', muted: '#6b7280', termBorder: '#1f2937' },
+ dark: { primary: '#f9fafb', body: '#d1d5db', muted: '#9ca3af', termBorder: '#30363d' },
+};
+
+const card = ({ primary, body, muted, termBorder }) => ``;
+
+(async () => {
+ for (const [mode, vars] of Object.entries(MODES)) {
+ const out = path.join(OUT, `fastroai-card-${mode}.png`);
+ const info = await sharp(Buffer.from(card(vars)), { density: 240 }).resize(2400).png({ compressionLevel: 9 }).toFile(out);
+ console.log('ok', path.basename(out), `${info.width}x${info.height}`);
+ }
+})();
diff --git a/docs/assets/build-cover.cjs b/docs/assets/build-cover.cjs
new file mode 100644
index 00000000..9781d520
--- /dev/null
+++ b/docs/assets/build-cover.cjs
@@ -0,0 +1,59 @@
+// Generates the Fastro (open-source FastAPI boilerplate) cover as transparent
+// light/dark PNGs, used at the top of the docs.
+// Run: NODE_PATH= node docs/assets/build-cover.cjs
+const path = require('path');
+const sharp = require('sharp');
+
+const OUT = __dirname;
+
+// Wordmark tracking. Negative = tighter. The previous cover jammed the letters
+// together; this opens them up to match the rest of the brand covers.
+const WORDMARK_TRACKING = -0.5;
+
+const MODES = {
+ light: { primary: '#111827', body: '#4b5563', muted: '#6b7280', termBorder: '#1f2937' },
+ dark: { primary: '#f9fafb', body: '#d1d5db', muted: '#9ca3af', termBorder: '#30363d' },
+};
+
+const cover = ({ primary, body, muted, termBorder }) => ``;
+
+(async () => {
+ for (const [mode, vars] of Object.entries(MODES)) {
+ const out = path.join(OUT, `fastro-cover-${mode}.png`);
+ const info = await sharp(Buffer.from(cover(vars)), { density: 240 }).resize(2400).png({ compressionLevel: 9 }).toFile(out);
+ console.log('ok', path.basename(out), `${info.width}x${info.height}`);
+ }
+})();
diff --git a/docs/assets/fastro-cover-dark.png b/docs/assets/fastro-cover-dark.png
index 84a17d73..46072eb3 100644
Binary files a/docs/assets/fastro-cover-dark.png and b/docs/assets/fastro-cover-dark.png differ
diff --git a/docs/assets/fastro-cover-light.png b/docs/assets/fastro-cover-light.png
index d0f63393..0365f4a1 100644
Binary files a/docs/assets/fastro-cover-light.png and b/docs/assets/fastro-cover-light.png differ
diff --git a/docs/assets/fastroai-card-dark.png b/docs/assets/fastroai-card-dark.png
index 884448e8..53881b57 100644
Binary files a/docs/assets/fastroai-card-dark.png and b/docs/assets/fastroai-card-dark.png differ
diff --git a/docs/assets/fastroai-card-light.png b/docs/assets/fastroai-card-light.png
index 67e1a94e..182f6001 100644
Binary files a/docs/assets/fastroai-card-light.png and b/docs/assets/fastroai-card-light.png differ