Skip to content

Conversation

@ibetitsmike
Copy link
Contributor

@ibetitsmike ibetitsmike commented Jan 29, 2026

Summary

Replace manually-captured README screenshots with a deterministic, reproducible pipeline using Storybook stories + Playwright + Sharp. All 7 documentation screenshots are now generated at 3800px (1900 CSS × DPR 2) from isolated mock states, ensuring visual consistency across regenerations.

Background

  • README screenshots were previously captured manually and varied in resolution (1600px), aspect ratio, and data density
  • Keeping screenshots up-to-date with UI changes was manual and error-prone
  • Legacy images were low-resolution compared to the retina displays most users view them on (~3694px reference assets)

Implementation

Stories (App.readmeScreenshots.stories.tsx)

  • 8 stories under Docs/README Screenshots (7 captured + ProductHero for regression only)
  • Full desktop chrome simulation: macOS traffic lights, 36px titlebar, 80px left inset
  • Deterministic mock data via mockFactory.ts with stable timestamps, ANSI terminal output, multi-model token costs, git divergence states, and project secrets

Capture Pipeline (scripts/capture-readme-screenshots.ts)

  • Playwright headless browser with DPR 2 at 1900×1188 viewport
  • Per-story playInteraction for Radix popovers/tooltips/modals (hover, click, tab switch)
  • Per-story postProcess for custom Sharp pipelines (sidebar crop+upscale, focused region extraction)
  • Retry logic (3 attempts) for flaky interactive stories under sequential load
  • WebP output at quality 90 with lanczos3 resampling

Agent Skill (.mux/skills/generate-readme-screenshots/)

  • Documents the full pipeline: prerequisites, step-by-step procedure, troubleshooting
  • Instructs agents to fail loudly if dependencies (playwright, sharp) are missing
  • Intended trigger: Chromatic visual diffs in readme stories, story data changes, or explicit request

Screenshot Mapping

Story Output Notes
CodeReview code-review.webp 7-turn conversation with typecheck, web search, bug fix
AgentStatusSidebar agent-status.webp Sidebar crop + upscale to full width
GitStatusPopover git-status.webp Hover tooltip with Commits tab, ↑3/↓2 divergence
PlanMermaidWithCosts plan-mermaid.webp Mermaid diagram + Costs tab
ProjectSecretsModal project-secrets.webp Manage Secrets modal with 4 keys
CostsTabRich costs-tab.webp Multi-model breakdown with cached tokens
OpportunisticCompactionTooltip opportunistic-compaction.webp "Replace all chat history" tooltip

Validation

  • All 7 screenshots generated at 3800px width and committed
  • Capture script runs end-to-end with retry logic for flaky interactive stories
  • Storybook builds cleanly (make storybook-build)

Generated with mux • Model: anthropic:claude-opus-4-6 • Thinking: xhigh • Cost: $153.96

Expand MessageWithImages into a 4-message bug-report arc with screenshots,
add MultipleImageFormats story with 3 distinct placeholder image types
(screenshot, diagram, photo), and add SingleLargeImage for non-gallery
layout testing.
…tories

- Enrich WithTitles: 8 workspaces across 3 projects (my-app, backend-api,
  docs-site) with mixed titles/no-titles and varied age timestamps
- Add FuzzySearch: same rich set with 'refac' typed into palette input to
  demonstrate fuzzy filtering behavior
- Add ManyWorkspaces: 14 workspaces across 5 projects (adds infra-tools,
  design-system) to stress-test palette scrolling and grouping
- Extract shared helpers (createRichWorkspaces, setupStory, openPalette)
  to reduce boilerplate across stories
- Enrich MacOSDesktop with 4 workspaces across 2 projects so the
  sidebar shows real content behind the traffic lights
- Extract createPopulatedClient() helper shared by both stories
- Add BrowserMode story showing the non-Electron title bar variant
- Use selectWorkspace + expandProjects + collapseRightSidebar for
  a lived-in app state
…stories

- Expand setupGovernorStory from 1 workspace to 5 across 2 projects
  (my-app + infra-tools) for a lived-in sidebar behind the modal
- Import expandProjects/collapseRightSidebar from storyHelpers
- Add PolicyBlocked story: policyState 'blocked' with no providers,
  no MCP, only local runtime
- Add RichPolicy story: enforced policy with 3 providers (anthropic
  with specific models, openai with forced proxy URL, google with all
  models allowed)
Replace thin 1-2 message exchanges with rich 4-6 message multi-turn
arcs in 5 screenshot stories:

- ProductHero: 5 messages with file read, file edit, bash, and status tools
- CodeReview: 4 messages with file read, bash (typecheck), and PR summary
- PlanMermaidWithCosts: 5 messages with bash (ls), propose plan, and status tools
- CostsTabRich: 6 messages with file read, file edit, bash, and status tools
- OpportunisticCompactionTooltip: 6 messages building up to the compaction
  (last message preserved with 'Replace all chat history' for play function)

The chat panes now show realistic multi-turn agent conversations with
tool calls, making screenshots look lived-in and professional.
Add scripts/capture-readme-screenshots.ts that uses Playwright + Sharp to
capture all 8 README screenshot stories from a running Storybook instance.

Features:
- Navigates to each story's iframe URL with 2x DPR viewport (1600×1171)
- Waits for network idle + stabilization before capture
- Converts PNG captures to WebP (quality 90) via Sharp
- Handles play-function stories (GitStatusPopover, ProjectSecretsModal,
  OpportunisticCompactionTooltip) by replicating interactions in Playwright
- AgentStatusSidebar: clips sidebar region and upscales to full viewport
- --storybook-url flag (default http://localhost:6006)
- --story flag to capture a single story
- Graceful error handling: logs failures but continues with remaining stories
- Summary output with success/failure count

Also adds 'capture-readme-screenshots' Makefile target.
ProjectSecretsModal: wrap querySelector in waitFor so it retries until
the sidebar renders instead of failing immediately.

OpportunisticCompactionTooltip: use findAllByRole and grab the last
'Start Here' button since multiple assistant messages each render one.
…ettings

When policyState is 'blocked', the app renders PolicyBlockedScreen instead
of the main App, so there's no settings button to click. Replace the play
function to verify the blocked screen renders with 'blocked by policy' text.
…o capture script

The opacity-0 secrets button is inside a Radix TooltipTrigger. Clicking it
in the headless test runner triggers scroll-lock (pointer-events: none on body),
preventing the modal from appearing. The capture script handles the full
interaction via Playwright directly.
…rminal

- Capture script: add TARGET_WIDTH (2400px), resize all screenshots from
  native 3200px (DPR 2) to consistent output width via lanczos3 kernel.
- GitStatusPopover: add postProcess crop (left 40%, center vertical) for
  focused divergence tooltip shot.
- AgentStatusSidebar: fix upscale to TARGET_WIDTH instead of viewport size.
- ProductHero terminal: add ANSI color codes for realistic bun test + lint
  + typecheck output with colored prompts/checkmarks.
- OpportunisticCompaction capture: use .last() for Start Here button to
  handle multiple assistant messages.
- Remove unused createCompactionRequestMessage import.
Both stories rely on Radix portaled elements (tooltip/modal) that are
unreliable in the headless test-runner environment. The capture script
replicates these interactions via Playwright instead.

Add tags: ['!test'] to exclude them from test-storybook while keeping
them available for Chromatic visual regression and interactive use.
The README hero image is now mux-demo.gif instead of product-hero.webp.
Remove ProductHero from the capture script's story list while keeping
the story itself for Storybook browsing and Chromatic regression.
Replace 1600px legacy screenshots with high-resolution 3800px WebP
images captured from Storybook stories. Also fix capture script:

- Fix GitStatusPopover: use radio role selector instead of ambiguous
  getByText('Commits')
- Fix ProjectSecretsModal: target manage-secrets button by aria-label
  with force-click (bypasses opacity-0 hover requirement)
- Fix ProjectSecretsModal: use input[value] selector for secret keys
  (they render in <input> elements, not as text nodes)
- Add retry logic (3 attempts) for stories with playInteraction to
  handle flaky Radix portal timing under sequential load
Documents the full pipeline for regenerating high-resolution README
screenshots from Storybook stories. Includes prerequisite checks,
step-by-step procedure, troubleshooting, and explicit instructions
to fail loudly if dependencies are missing.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs Improvements or additions to documentation enhancement New feature or functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant