You know that moment. You're proud of your docs - clean VitePress site, nice code examples, helpful screenshots showing exactly how your app works.
Six months later someone opens an issue: "The screenshot on the getting started page doesn't match the actual UI."
You check. They're right. The button moved. The modal got redesigned. Half your screenshots are lying.
The Problem With Manual Screenshots
Here's what updating screenshots manually looks like:
- Open browser, navigate to the page
- Log in (dig up those test credentials)
- Find the exact element
- Take screenshot, crop it
- Save with the right filename in the right folder
- Rebuild docs, check it looks right
- Commit, push
Multiply by 20 screenshots. Do this every release.
Nobody does this. The screenshots rot.
The Fix: Define Once, Regenerate Forever
What if you could run one command and every screenshot in your VitePress site updates automatically?
npx heroshot
That's the goal. Let me show you how to set it up.
Step 1: Install
npm install heroshot
Step 2: Define Your Screenshots
Run the visual picker:
npx heroshot config
This opens an interactive browser. Navigate to the page you want to screenshot. Click the element. Name it "dashboard". Done.
Heroshot creates .heroshot/config.json:
{
"baseUrl": "http://localhost:3000",
"outputDirectory": "public/heroshots",
"screenshots": [
{
"name": "dashboard",
"url": "/app/dashboard",
"selector": ".dashboard-container"
}
]
}
Repeat for each screenshot. Click, name, next.
Step 3: Add the Vite Plugin
Heroshot has a Vite plugin that auto-loads your screenshot config:
// .vitepress/config.ts
import { defineConfig } from 'vitepress';
import { heroshot } from 'heroshot/plugins/vite';
export default defineConfig({
vite: {
plugins: [heroshot()],
},
});
Step 4: Register the Component
Heroshot provides a <Heroshot> component that handles light/dark mode and responsive variants automatically:
// .vitepress/theme/index.ts
import DefaultTheme from 'vitepress/theme';
import type { Theme } from 'vitepress';
import { Heroshot } from 'heroshot/vitepress';
import 'virtual:heroshot-manifest';
export default {
extends: DefaultTheme,
enhanceApp({ app }) {
app.component('Heroshot', Heroshot);
},
} satisfies Theme;
The virtual:heroshot-manifest import auto-registers your screenshot config.
Step 5: Use It in Markdown
Now in any markdown file:
<Heroshot name="dashboard" alt="Dashboard overview" />
That's it. The component:
- Finds the screenshot by name from your config
- Shows light version in light mode, dark in dark mode
- Handles responsive variants with srcset
- Lazy loads for performance
No manual {.light-only} gymnastics.
Step 6: Regenerate Anytime
When your UI changes, regenerate all screenshots:
npx heroshot
One command. Every screenshot updates. The <Heroshot> component picks up the new images automatically.
Step 7: Handle Auth
Most apps need login. When you run heroshot config, log in manually in the browser. Heroshot saves your session.
Future runs reuse it - even headless.
Automate It
Once this works locally, automate it in CI. Screenshots update on every push.
See the CI/CD integration docs for GitHub Actions setup.
The Result
Before: Screenshots rot. Manual updates. Light/dark mode headaches.
After: One component, one command. Screenshots that stay honest.
heroshot - point, click, capture.
Top comments (0)