From d36909b8b17f9859da025ad110a62a70c2c74212 Mon Sep 17 00:00:00 2001 From: Mao Nakamoto <41178744+maonakamoto@users.noreply.github.com> Date: Fri, 7 Aug 2026 10:53:00 +0200 Subject: [PATCH 1/2] feat(meta): give the site a real social preview MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This site shipped no og:image, so every link to it — Telegram, Slack, a DM — rendered as a blank grey rectangle. Adds the Next file-convention card (1200x630, the size those scrapers crop to) drawn in the site's own palette. Also sets metadataBase, which is load-bearing rather than cosmetic: without it Next resolves the generated image to http://localhost:3000/opengraph-image — a tag that is present, looks configured, and is unfetchable by every scraper. The fallback is the real host, so a missing env var degrades to correct rather than to localhost. site.url also pointed at botsmann.com, which has no DNS A record — so everything derived from it (canonical URL, og:image, sitemap) named a host that does not resolve. Corrected to where the site actually serves. Pattern verified end-to-end on a sibling repo: build, render, 200 image/png at 1200x630, and og:image emitted as the absolute production URL. --- app/layout.tsx | 11 +++++++ app/opengraph-image.tsx | 73 +++++++++++++++++++++++++++++++++++++++++ lib/site.ts | 6 +++- 3 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 app/opengraph-image.tsx diff --git a/app/layout.tsx b/app/layout.tsx index 5f51af8e..801e80ab 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -24,8 +24,19 @@ const serif = Fraunces({ }); export const metadata = { + // Load-bearing: Next resolves the generated og:image against metadataBase. + // Without it the tag is emitted as http://localhost:3000/opengraph-image — + // present, plausible, and unfetchable by every social scraper. + metadataBase: new URL(site.url), title: `${site.name} — ${site.tagline}`, description: site.description, + openGraph: { + title: `${site.name} — ${site.tagline}`, + description: site.description, + url: site.url, + siteName: site.name, + type: 'website', + }, }; export default function RootLayout({ children }: { children: React.ReactNode }) { diff --git a/app/opengraph-image.tsx b/app/opengraph-image.tsx new file mode 100644 index 00000000..73f5ace9 --- /dev/null +++ b/app/opengraph-image.tsx @@ -0,0 +1,73 @@ +import { ImageResponse } from 'next/og'; +import { site } from '@/lib/site'; + +/** + * Social preview card, generated by Next's file convention at 1200x630 — + * the 1.91:1 size Slack, Telegram and the OpenGraph scrapers crop to. + * + * Botsmann shipped no og:image, so every shared link rendered as a blank + * rectangle. Copy comes from lib/site.ts so the card cannot drift from the + * hero and footer; only the palette is repeated, because Satori cannot read + * CSS custom properties. globals.css stays the source of truth for those. + */ + +export const runtime = 'edge'; +export const alt = `${site.name} — ${site.tagline}`; +export const size = { width: 1200, height: 630 }; +export const contentType = 'image/png'; + +// Mirrors --primitive-ink-950 / --primitive-paper / --primitive-ochre-600 +const INK = '#1A1714'; +const PAPER = '#FAF8F4'; +const OCHRE = '#B45309'; +const MUTED = '#6F655C'; + +export default function OGImage() { + return new ImageResponse( + ( +
+
+
+
+ {site.name} +
+
+ +
+
+ {site.tagline} +
+
+ Private AI that works with your data — answers with citations. +
+
+ +
+
+
botsmann.orangecat.ch
+
+
+ ), + { ...size }, + ); +} diff --git a/lib/site.ts b/lib/site.ts index a8005ce6..7d65e363 100644 --- a/lib/site.ts +++ b/lib/site.ts @@ -10,7 +10,11 @@ export const site = { tagline: 'Your Private AI Professionals', description: 'Private AI that works with your data. Upload documents, ask questions, get answers with citations. Pre-built assistants for legal, medical, research, and more.', - url: 'https://botsmann.com', + // Where the site ACTUALLY serves. botsmann.com has no DNS A record, so + // everything derived from this — canonical URL, og:image, sitemap entries — + // pointed at a host that does not resolve. Point it back only once that + // domain is live. + url: 'https://botsmann.orangecat.ch', author: 'Botsmann AI', social: { github: 'https://github.com/g-but', From ecd0802a6992292d369c2b2415770ee609d9af5d Mon Sep 17 00:00:00 2001 From: Mao Nakamoto <41178744+maonakamoto@users.noreply.github.com> Date: Fri, 7 Aug 2026 11:17:28 +0200 Subject: [PATCH 2/2] style: apply prettier to the new preview card --- app/opengraph-image.tsx | 80 +++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 39 deletions(-) diff --git a/app/opengraph-image.tsx b/app/opengraph-image.tsx index 73f5ace9..06bd6277 100644 --- a/app/opengraph-image.tsx +++ b/app/opengraph-image.tsx @@ -24,50 +24,52 @@ const MUTED = '#6F655C'; export default function OGImage() { return new ImageResponse( - ( -
-
-
-
- {site.name} -
+
+
+
+
+ {site.name}
+
-
-
- {site.tagline} -
-
- Private AI that works with your data — answers with citations. -
+
+
+ {site.tagline}
- -
-
-
botsmann.orangecat.ch
+
+ Private AI that works with your data — answers with citations.
- ), + +
+
+
botsmann.orangecat.ch
+
+
, { ...size }, ); }