Many projects I ship have documentation, and every piece of documentation has screenshots that quietly rot. A button moves, a label gets reworded, and the image in the guide is a lie nobody notices until a reader opens an issue about it. The two usual fixes are both bad: retake everything by hand at each release, or write a bespoke Playwright script per shot and end up maintaining a small, undocumented test suite whose only job is taking pictures. Writing docs for my own projects, I got tired of both, so I built shotlist.

In shotlist a screenshot is a YAML file. You describe the state you want — click this, fill that, wait for the row to show up — then which region to clip and what to point at, and it opens your running site, drives it there, clips the region, draws the callouts on the image, and writes the file where the project expects it. There is no step that evaluates JavaScript, and there will not be one: if a screenshot cannot be described, that is a missing verb or query primitive, and it gets added to the vocabulary instead. Because a recipe is just data, a screenshot becomes something you can review in a pull request like the rest of the docs.

The part that pays for itself is --check. It re-shoots everything against the images already committed and tells you which ones have drifted, writing a before/after/changed diff when you want to look. Run it in CI and stale screenshots stop being something you find out about after publishing. It also has to be safe to run on a config you did not write, since in automation that config may come from someone else’s fork: a shot list only ever opens its own site, and never reads or writes .env, .git, .ssh and their like, in every mode, with --untrusted tightening it further. It is on npm under MIT, and shotlist.dev takes its own screenshots with it.