From 65f9e43559bee95fb0e17a8a0c7426672680913d Mon Sep 17 00:00:00 2001 From: Nathan Zylbersztejn Date: Tue, 2 Jun 2026 12:46:48 +0200 Subject: [PATCH 1/3] fix(site): render the feature illustration on story detail views PRArticle (side panel + full PR page) and the commit detail page showed the headline, standfirst, and body but never rendered story.imageUrl, so images appeared only in the feed. Add the 3:2 illustration after the standfirst on both, matching PRFeedItem's Image usage. Co-Authored-By: Claude Opus 4.8 (1M context) --- site/src/app/commit/[sha]/[slug]/page.tsx | 17 +++++++++++++++++ site/src/components/PRArticle.tsx | 16 ++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/site/src/app/commit/[sha]/[slug]/page.tsx b/site/src/app/commit/[sha]/[slug]/page.tsx index b1d3a5f..6f97e56 100644 --- a/site/src/app/commit/[sha]/[slug]/page.tsx +++ b/site/src/app/commit/[sha]/[slug]/page.tsx @@ -1,6 +1,7 @@ import type { Metadata } from 'next'; import { notFound } from 'next/navigation'; import Link from 'next/link'; +import Image from 'next/image'; import { primaryCategory, categoryDisplayName } from '@/lib/stories'; import { loadStories, loadStoryBySha } from '@/lib/stories-loader'; import { buildStoryMetadata, canonicalUrl } from '@/lib/seo'; @@ -89,6 +90,22 @@ export default async function CommitStoryPage({

{story.standfirst}

+ {story.imageUrl && ( +
+ {story.headline} +
+ )} +
{story.story}
diff --git a/site/src/components/PRArticle.tsx b/site/src/components/PRArticle.tsx index 6cbd475..47df64c 100644 --- a/site/src/components/PRArticle.tsx +++ b/site/src/components/PRArticle.tsx @@ -1,3 +1,4 @@ +import Image from 'next/image'; import type { Story } from '@/lib/stories'; import { PRMetaRow } from './PRMetaRow'; import { PRSubtitle, PRMobileReference } from './PRSubtitle'; @@ -42,6 +43,21 @@ export function PRArticle({ commitUrl={story.kind === 'direct-push' ? story.commitUrl : undefined} />

{story.standfirst}

+ {story.imageUrl && ( +
+ {story.headline} +
+ )} Date: Tue, 2 Jun 2026 13:57:49 +0200 Subject: [PATCH 2/3] perf(cli): generate 1K story images instead of 2K 2K (~2048px) exceeds our largest render (feed hero 720px CSS / ~1440px retina; side panel ~480px), costing ~50% more per image ($0.101 vs $0.067) and producing heavier Blob uploads for resolution we never show. 1K covers all display sizes. Per the Gemini docs, gemini-3.1-flash-image may already cap the preview model at 1K regardless, so this also aligns intent with actual output. Co-Authored-By: Claude Opus 4.8 (1M context) --- cli/src/image/generator.test.ts | 2 +- cli/src/image/generator.ts | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/cli/src/image/generator.test.ts b/cli/src/image/generator.test.ts index 6981fe6..b008b36 100644 --- a/cli/src/image/generator.test.ts +++ b/cli/src/image/generator.test.ts @@ -59,7 +59,7 @@ describe('generateImage (gemini)', () => { contents: 'the prompt', config: { responseModalities: ['TEXT', 'IMAGE'], - imageConfig: { aspectRatio: '3:2', imageSize: '2K' }, + imageConfig: { aspectRatio: '3:2', imageSize: '1K' }, }, }); }); diff --git a/cli/src/image/generator.ts b/cli/src/image/generator.ts index 4a64b53..28389db 100644 --- a/cli/src/image/generator.ts +++ b/cli/src/image/generator.ts @@ -33,7 +33,11 @@ export async function generateImage( contents: prompt, config: { responseModalities: ['TEXT', 'IMAGE'], - imageConfig: { aspectRatio: '3:2', imageSize: '2K' }, + // 1K (~1024px) covers our largest render — the feed hero at 720px CSS + // (~1440px on a 2x display) and the ~480px side panel. 2K (~2048px) is + // bigger than anything we show and costs ~50% more per image + // ($0.101 vs $0.067), so it's wasted resolution + heavier Blob uploads. + imageConfig: { aspectRatio: '3:2', imageSize: '1K' }, }, }), GEMINI_TIMEOUT_MS, From 972ba34a7f2add7049cccb0df8ed1c33f3084ef1 Mon Sep 17 00:00:00 2001 From: Nathan Zylbersztejn Date: Tue, 2 Jun 2026 14:18:57 +0200 Subject: [PATCH 3/3] perf(site): eager-load the above-the-fold detail illustration (LCP) The full-page/commit detail illustration sits above the fold and is a likely LCP element; without priority Next.js lazy-loads it, delaying the largest paint. Set priority on the page variant and commit detail image (adds a preload hint); the side panel stays lazy since it can open below the fold. Co-Authored-By: Claude Opus 4.8 (1M context) --- site/src/app/commit/[sha]/[slug]/page.tsx | 1 + site/src/components/PRArticle.tsx | 3 +++ 2 files changed, 4 insertions(+) diff --git a/site/src/app/commit/[sha]/[slug]/page.tsx b/site/src/app/commit/[sha]/[slug]/page.tsx index 6f97e56..f572aaf 100644 --- a/site/src/app/commit/[sha]/[slug]/page.tsx +++ b/site/src/app/commit/[sha]/[slug]/page.tsx @@ -101,6 +101,7 @@ export default async function CommitStoryPage({ fill className="object-cover" sizes="(max-width: 768px) 100vw, 672px" + priority unoptimized /> diff --git a/site/src/components/PRArticle.tsx b/site/src/components/PRArticle.tsx index 47df64c..b27bcf4 100644 --- a/site/src/components/PRArticle.tsx +++ b/site/src/components/PRArticle.tsx @@ -54,6 +54,9 @@ export function PRArticle({ fill className="object-cover" sizes={variant === 'panel' ? '(max-width: 768px) 100vw, 480px' : '(max-width: 768px) 100vw, 720px'} + // The full-page illustration is above the fold (likely LCP) — eager-load + // + preload it. The panel can open below the fold, so leave it lazy. + priority={variant === 'page'} unoptimized />