I was putting together docs for a feature last week. Screenshot looked good, but the button I was documenting was buried in a busy toolbar. Without an arrow pointing at it, the screenshot was useless.
So I opened Figma. Drew an arrow. Exported. Realized the arrow was slightly off. Re-opened Figma. Fixed it. Re-exported. Committed.
Next sprint, the UI changed. Screenshot was stale. Had to redo the whole thing - including that damn arrow.
There has to be a better way.
Screenshots That Annotate Themselves
Heroshot has a visual editor built in. You pick what to screenshot, then draw annotations - arrows, rectangles, ellipses - right there on the page. When you regenerate screenshots, the annotations come with them.
Here is how it works:
One command to set it up:
npx heroshot config
A browser opens. That's your visual editor.
Pick What to Capture
Click the crosshair icon, hover over any element, click. Done - you just defined a screenshot. No CSS selectors to write. Heroshot figures it out.
Want just a card? Click the card. Want the whole nav? Click the nav. The sidebar shows everything you've picked.
Now Draw On It
This is the part I actually got excited about. Select an annotation tool from the toolbar:
- Arrow - point at the thing that matters
- Rectangle - highlight a section or group
- Ellipse - circle something important
Draw directly on the screenshot preview. Adjust the color, stroke width, opacity. The annotations are saved in your config and redrawn every time you regenerate.
No Figma. No Photoshop. No re-exporting when the UI changes.
Edit Text Too
Say your app shows real user data - emails, names, timestamps. You don't want that in your docs.
Click any text element and change it:
{
"textOverrides": {
".user-name": "Sarah Chen",
".email": "sarah@example.com",
".timestamp": "2 hours ago"
}
}
Or do it visually - click the text tool, click the element, type the replacement. Clean, professional screenshots with realistic-but-safe data.
The Config It Generates
All of this - the element selection, padding, annotations, text overrides - ends up in a simple JSON file:
{
"screenshots": [
{
"name": "Dashboard Settings",
"url": "https://myapp.com/settings",
"selector": ".settings-panel",
"padding": { "top": 20, "right": 20, "bottom": 20, "left": 20 },
"paddingFill": "solid",
"textOverrides": {
".user-email": "team@example.com"
},
"annotations": [
{
"type": "arrow",
"points": [200, 50, 300, 120],
"style": { "stroke": "#ff0000", "stroke-width": "3" }
}
]
}
]
}
You never have to write this by hand. The visual editor generates it. But it's just JSON - you can tweak it if you want.
Regenerate Anytime
UI changed? New styles? Just:
npx heroshot
Headless. No browser opens. Every screenshot regenerates with its annotations intact. The arrow still points at the right button, even if that button moved 20 pixels to the left.
Light mode AND dark mode? Both captured automatically. One config entry, two annotated screenshots.
What Else It Does
Since we're here:
- Multiple viewports - desktop, tablet, mobile from one config
- Actions before capture - click buttons, fill forms, dismiss cookie banners, open dropdowns
- Session persistence - log in once, capture headlessly forever
- Border radius and styling - rounded corners, borders, background fills
- Hide elements - remove chat widgets, dev toolbars, anything distracting
- CI/CD ready - runs headlessly in GitHub Actions, no display needed
Try It
npx heroshot config
Pick some elements. Draw some arrows. Close the browser. Check the heroshots/ folder.
That's it. Your screenshots now have annotations that survive redesigns.
Heroshot is free and open source. Star it on GitHub if this saved you a trip to Figma.
Top comments (0)