Ten commands, no guesswork
Two of them do almost everything: init once, then check forever. The rest are there for the days something is wrong, or CI needs to work differently.
npx norma-scope initNothing to install first — npx fetches it on the first run. Node 18 or newer is the whole list of requirements.
- 10
- commands
- 1
- config file
- 0
- accounts

Grouped by what they do
Answer three questions,
get a working config
This writes a real .bridge/config.json and the exact commands to run with it. Copy it into your project and it works.
.bridge/config.json
{
"threshold": 5,
"source": { "type": "images", "dir": "designs" },
"app": { "baseUrl": "http://localhost:3000" },
"frames": [
{
"label": "Pricing",
"screenshot": "pricing.png",
"route": "/pricing",
"viewport": { "width": 1440, "height": 900 }
}
]
}then run
$ npx norma-scope init
$ npx norma-scope doctor
# start your app, then:
$ npx norma-scope check
$ open .bridge/reports/report.html
No token, no network, no account — the reference is already in your repo.
Pick one to see what it does
Once per project, or again if you switch design sources
- Asks for your design file and token, then lists the frames in it so you can pick the ones you care about.
- Saves each frame's real design dimensions — capturing your app at a different size than the design is the number one cause of a scary score that means nothing.
- Creates the .bridge/ folders, adds the throwaway ones to .gitignore, and installs a pre-commit hook (backing up any existing hook first).
- Prints the exact filename and pixel size it expects for every screenshot.
- Figma-first, but you can hand-edit the config afterwards to point at an image folder or a URL instead.
Once per project, or again if you switch design sources
- Asks for your design file and token, then lists the frames in it so you can pick the ones you care about.
- Saves each frame's real design dimensions — capturing your app at a different size than the design is the number one cause of a scary score that means nothing.
- Creates the .bridge/ folders, adds the throwaway ones to .gitignore, and installs a pre-commit hook (backing up any existing hook first).
- Prints the exact filename and pixel size it expects for every screenshot.
- Figma-first, but you can hand-edit the config afterwards to point at an image folder or a URL instead.
- Reads
- your answers, the design source's API
- Writes
- .bridge/config.json, the .bridge/ folders, .gitignore entries, a pre-commit hook
What each one reads and writes
| Command | Reads | Writes |
|---|---|---|
| init | your answers, the design source's API | .bridge/config.json, the .bridge/ folders, .gitignore entries, a pre-commit hook |
| doctor | config, token, design file, your app URL | nothing — diagnosis only |
| auto | config + your running app | .bridge/screenshots/*.png |
| compare | .bridge/screenshots/ + the reference your source points at | .bridge/diff/, report.html, and summary.json with --json |
| compare --target | the mock PNG and the --url you pass | screenshot, diff, report.html, and summary.json — always |
| check | — | everything auto and compare write |
| baseline | .bridge/screenshots/ | .bridge/baseline/ plus a manifest — commit it |
| snapshot | the design file | .bridge/design/ — commit it |
| comment | .bridge/reports/summary.json | markdown on stdout |
| explain | screenshots, diffs, captured DOM context, your API key | findings in the terminal and in the report |
| clean | — | empties screenshots/, diff/, reports/ and the cache |
The ones worth knowing
- --json
- Also write summary.json (schema v2, published and validated)
- --full
- Embed full-resolution images in the report
- --fresh
- Bypass the design cache and refetch
- --strict
- Exit 1 on a measured regression — the only way a job turns red
- --all
- Explain every compared frame, not just the flagged ones
- --deep
- Use the stronger, more expensive model
- --check
- On snapshot: has the live design drifted from the committed one?
- --selector
- On target mode: capture one element instead of the full page
Start from the problem
“Just tell me if this page matches this picture.”
compare --target x.png --url …
“Do that for five pages, on every commit.”
init, then check
“Nothing loaded, or it says skipped.”
doctor
“There's no designer — I just don't want surprises.”
mode: "baseline", then baseline
“CI shouldn't need a design token.”
snapshot, and commit .bridge/design/
“Fail the build on a regression.”
compare --strict
“But why did it move?”
explain
Three things that trip people up
Start your app first
Normascope photographs a running app; it doesn't start one. Run your dev server, then run the command.
Nothing is ever blocked
A bad score is information. The git hook always succeeds and CI stays green unless you explicitly ask for the opposite.
Name the file after the page
The screenshot filename is what ties your design, your capture and the difference together. Keep them the same and everything lines up.
Every command ships with --help, and doctor explains anything that’s misconfigured in your project rather than making you go and look it up.
All of that runs on one machine, for one person.
The moment a second person needs to see a result, or you need to know whether a page has been drifting, you need somewhere to put it.