npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

screenshot-annotator

v0.5.0

Published

Capture annotated screenshots of any web UI. Annotations rendered as DOM overlays before Playwright captures. Arrows, highlights, callouts, multi-viewport, and replayable JSON specs so screenshots never go stale.

Readme

screenshot-annotator

npm version license

Capture annotated screenshots of any web UI for documentation, tutorials, and product walkthroughs. Annotations (highlight boxes, numbered callouts, text labels, arrows) are injected into the page as real DOM elements before Playwright captures the screenshot, so they render at full resolution, scale with the page, and match your design system.

Built for teams whose user-facing docs, onboarding guides, or help-center articles keep going stale because the UI ships faster than someone remembers to retake the screenshots.

Hero example

Why

Documentation screenshots usually mean:

  • Take a screenshot manually
  • Open Figma/Photoshop
  • Add arrows and labels by hand
  • Re-export
  • Repeat every time the UI changes

This tool turns all of that into a single node command. Annotations are defined in code, anchored to selectors, and re-rendered automatically when the UI changes.

Install

npm (recommended)

npm install --save-dev screenshot-annotator playwright
npx playwright install chromium

Claude skill

npx skills add arjunkai/screenshot-annotator

Then in any conversation: "Take an annotated screenshot of localhost:5173 highlighting the login button". Claude will use the skill.

30-second example

import { chromium } from 'playwright';
import { annotate } from 'screenshot-annotator';

const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://opbindr.com');

await annotate(page, [
  {
    type: 'arrow',
    fromTarget: page.getByRole('heading', { name: /collection/i }),
    toTarget: page.getByRole('button', { name: /create your first binder/i }),
  },
  {
    type: 'label',
    target: page.getByRole('button', { name: /create your first binder/i }),
    text: 'Click to begin',
    position: 'right',
  },
]);

await page.screenshot({ path: 'home.png' });
await browser.close();

That's it. The arrow and label render at the correct positions on the live page.

Default color is red (#ef4444), the docs convention for "look here." Pass color: on any annotation to match your brand:

{ type: 'arrow', fromTarget: ..., toTarget: ..., color: '#3b82f6' }  // blue
{ type: 'label', target: ..., text: 'New', color: '#10b981' }          // green

The killer feature: spec replay

Screenshots in docs go stale because the UI changes faster than people remember to retake them. This tool fixes that by saving the intent of each screenshot as a JSON sidecar:

{
  "url": "https://opbindr.com",
  "viewports": [
    { "name": "desktop", "width": 1440, "height": 900 },
    { "name": "mobile",  "width": 390,  "height": 844 }
  ],
  "setup": [
    { "action": "waitForSelector", "selector": "h1" }
  ],
  "annotations": [
    {
      "type": "label",
      "selector": "role=button[name=/create your first binder/i]",
      "text": "Click to begin",
      "position": "right",
      "color": "#ef4444"
    }
  ]
}

When the UI changes, re-render every screenshot in your docs with one command:

npx screenshot-annotator replay public/guide

For each *.spec.json it finds, you get a fresh .png next to it (one per viewport: feature.desktop.png, feature.mobile.png).

Want to point at staging or a feature branch instead of prod? Override the origin with SCREENSHOT_URL:

SCREENSHOT_URL=https://staging.myapp.com npx screenshot-annotator replay public/guide

Setup helpers for real-world pages

Scripts that run against real apps keep hitting the same four gotchas. The package exports helpers for each, so you don't have to debug them yourself:

  • hoverByMouse(page, locator) bypasses Playwright's actionability stall on re-rendering elements (virtualized lists, live data, CSS transitions)
  • waitForImagesLoaded(page, opts?) waits until ≥90% of visible images have decoded, so your screenshots aren't half-loaded grids
  • raceVisible(page, locatorMap, opts?) handles branching landing pages where a first-time user and a returning user see different buttons
  • Plus: don't use waitUntil: 'networkidle' on a dev server. HMR keeps WebSockets open and page.goto times out. Use 'domcontentloaded' instead.

Full explanation of each gotcha and how to use the helpers is in SKILL.md.

Annotation primitives

| Type | What it does | Use when | |---|---|---| | highlight | Colored rectangle with darkened backdrop around a target | "This is the thing I'm talking about" | | callout | Numbered circle at a corner of a target (1, 2, 3…) | Step-by-step sequences referenced from text | | label | Text pill anchored to a target with position: 'right' \| 'left' \| 'above' \| 'below' | Inline explanations | | step | Numbered pill with text fused inline ([1] Click here) | Tutorial steps that pair a number with a description | | arrow | SVG arrow between two locators or coordinates | Connecting two elements visually |

Each annotation accepts either Playwright Locators (page.getByRole(...), page.getByText(...)) when used in a script, or selector strings (role=button[name="Save"], text="Filters") when used in a spec.

Capturing interactive states

Hover effects, dropdowns, focus rings, and tooltips only appear when the user interacts with the page. Specs support setup actions to trigger them:

{
  "setup": [
    { "action": "hover",   "selector": ".user-avatar" },
    { "action": "focus",   "selector": "input[name='search']" },
    { "action": "type",    "selector": "input[name='search']", "text": "luffy" },
    { "action": "press",   "key": "Enter" },
    { "action": "scroll",  "selector": ".footer" }
  ]
}

Full list: click, hover, focus, fill, type, press, scroll, waitForSelector, waitForTimeout.

Quick start without writing any code

npx screenshot-annotator example     # writes a starter example.spec.json
npx screenshot-annotator replay .    # produces example.png + example.mobile.png

CLI reference

npx screenshot-annotator replay <dir>     # re-render every spec in <dir>
npx screenshot-annotator example          # write a starter spec in cwd
npx screenshot-annotator --help

Env vars:

  • SCREENSHOT_URL: override the origin of every spec (point at staging/dev)

Programmatic API

import {
  annotate, clearAnnotations,
  saveSpec, loadSpec, replaySpec,
  hoverByMouse, waitForImagesLoaded, raceVisible,
  themes,
} from 'screenshot-annotator';

themes.bright and themes.muted are color palettes you can spread into annotations to stop repeating hex literals. Each is { primary, accent, success, warning, info, text }.

See examples/example-script.js for a complete worked example that captures + saves spec + supports multi-viewport.

Requirements

  • Node 18+
  • Playwright (npm install -D playwright && npx playwright install chromium)
  • A web UI to screenshot (local dev server or production URL)

License

MIT