Skip to content
The reference

22 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 init

Nothing to install first — npx fetches it on the first run. Node 18 or newer is the whole list of requirements.

22
commands
1
config file
0
accounts to run locally
A terminal running npx norma-scope compare with the --json and --strict flags. It prints one line per frame — 0.3% aligned with 5.6% unaligned, SSIM 99 and two drifted sections for the first, 0.0% for the other two — then reports where the report and summary were saved, and that --strict is exiting 1 because one frame is above the threshold.
One real run. Every command prints like this — one line per page, the numbers that matter, and exactly where it put the files.

Grouped by what they do

Setup4Capture2Compare2Share10AI1Utility3
Start here

Answer a few questions, get the commands to run

Your answers become the choices to make in init, the commands to run after it, and a preview of the .bridge/config.json that init writes.

1 · What are you comparing against?
2 · Can Normascope reach your app?
3 · What does each screen show?
4 · What should CI do when a frame drifts?

.bridge/config.json — init writes this

{
  "source": { "type": "images", "dir": "designs" },
  "threshold": 5,
  "app": { "baseUrl": "http://localhost:3000" },
  "frames": [
    {
      "label": "pricing",
      "screenshot": "pricing.png",
      "width": 1440,
      "height": 2400,
      "viewport": { "width": 1440, "height": 900 },
      "route": "/pricing",
      "capture": "fullPage"
    }
  ]
}

init also adds a project id and one more line per screen: a short code like fr_k3m9…. They are different for every project, so they are not shown here. They are what let you rename pricing.png later without losing its history.

then run

$ npx norma-scope init # choose "A folder of PNGs", then "The whole page"

# set each screen's route in .bridge/config.json

# start your app, then:

$ npx norma-scope doctor

$ npx norma-scope check

$ open .bridge/reports/report.html

Reading these reference PNGs needs no token, network connection or account.

Every command

Pick one to see what it does

Setup
Capture
Compare
Share
AI
Utility

Before choosing whether to share usage analytics.

  • Default collection is release-gated off. Preview opt-in uses NORMA_TELEMETRY=1.
Reads
Local telemetry preference.
Writes
Nothing; does not create an installation ID.
Network
None — it makes no request at all
Can it spend money?
No
Can it fail a build?
No.
At a glance

What each one touches

Everything here runs on your machine unless the network column says otherwise, and nothing spends money unless the money column says so.

CommandReadsWritesNetworkSpends
telemetry statusLocal telemetry preference.Nothing; does not create an installation ID.NoneNothing
telemetry disableLocal telemetry preference.Persistent opt-out; removes the saved installation ID.NoneNothing
inityour answers; for Figma, the file's frame list; for a folder of PNGs, the folder.bridge/config.json, the .bridge/ folders, .gitignore entries, a pre-commit hook, and .env.local for the Figma token when it is savedFigma only, to check the token and list the framesNothing
doctorconfig, token, design file, your app URLnothing — diagnosis onlyyour design source and your running app, to check both answerNothing
captureconfig + your running app.bridge/screenshots/*.pngyour own running app, in a headless browserNothing
compare.bridge/screenshots/ + the reference your source points at.bridge/diff/, report.html, and summary.json with --json. A project that sends its reports to Cloud writes summary.json, a saved copy of the run in .bridge/pending/ and the receipt .bridge/reports/cloud.json, and no report.html once Cloud holds the runyour design source, unless a snapshot or cache already has the reference; and Normascope Cloud, for a project that sends its reports thereNothing, unless the project sends its reports to Cloud: then 1 Cloud credit per published run that measured something, as cloud publish
checkeverything capture and compare readeverything capture and compare writethe same as capture and compare — your app, your design source, and Normascope Cloud for a project that sends its reports therethe same as compare
explain --local [frame]screenshots, diffs, captured DOM context, optional source excerpts, your API keyfindings in the terminal and in the reportyour own model provider, under your own key. Nothing goes to Normascope Cloudyour own provider account
cloud publishCloud.bridge/reports/summary.json and the images it names.bridge/reports/cloud.json — the receipt, written on every run including a failed oneNormascope Cloud1 Cloud credit per published run that measured something, when credits are available. At zero credits, publishing continues and the timeline locks. Hosted analysis with --explain uses additional credits.
cloud validateCloud.bridge/config.jsonnothing — it exits 1 if it found somethingNoneNothing
cloud statusCloud.bridge/config.jsonnothingNormascope Cloud — one request with the project ID and whether the configured mode includes images; no run dataNothing
cloud loginCloud.bridge/config.json (its project ID, a digest of its bytes, and its threshold and frame names if you choose to share them). With no config, the new project an admin set up in the browserthe key, in this machine's credential store; .bridge/cloud-connection.json, which says where it is and holds no key; .bridge/config.json only if you accept a suggested name or threshold, keeping the old file as config.json.before-connect, or, with no config, only if you accept the new project's config, together with what init writes around it: the .gitignore lines, a Figma token in .env.local and the pre-commit hookNormascope Cloud — the machine's name, the project ID and the config digest, and the threshold and frame names only if you say yes, then polls until an admin answers; no run data. A new project's addresses, folders and Figma token are never sentNothing
cloud logoutCloud.bridge/cloud-connection.json and the key it names in this machine's credential storeremoves that key and that fileNormascope Cloud — one request that ends the key it is sent with; no run dataNothing
cloud pendingCloud.bridge/pending/ and .bridge/config.jsonnothingNoneNothing
cloud retry <id>Cloudthe saved run in .bridge/pending/, .bridge/config.json, and the same credential as cloud publishthe saved run's own record in .bridge/pending/; never .bridge/reports/cloud.jsonNormascope Cloud — the saved run's data, exactly as it was saved, and nothing else1 credit when the run is published for the first time and measured something, as with cloud publish. A run Cloud already has is not charged again
cloud discard <id>Cloudthe saved run in .bridge/pending/removes that run's files, and records that it was discardedNoneNothing
frames listCloud.bridge/config.jsonnothing — it just printsNoneNothing
frames adoptCloud.bridge/config.json.bridge/config.json — then commit itNoneNothing
ci comment.bridge/reports/summary.json, and .bridge/reports/cloud.json when a publish wrote onemarkdown on stdoutNoneNothing
baseline approve.bridge/screenshots/.bridge/baseline/ plus a manifest — commit itNoneNothing
design snapshotthe design file.bridge/design/ — commit ityour design sourceNothing
clean—empties screenshots/, diff/, reports/, context/ and the cache, which holds the MCP refusal logNoneNothing
What leaves your machine

The four upload modes

Set cloud.upload in .bridge/config.json, least disclosure first. This only ever applies to cloud publish — nothing else in the CLI sends anything.

ModeWhat it sends
offNothing at all. No request is made, and cloud publish becomes a no-op rather than an error.
metricsThe numbers and nothing else. No pixels leave your machine — and a run with no images cannot be explained by Cloud.
reviewFull evidence for every frame over threshold, plus one preview for each clean frame. The default.
fullFull evidence for every compared frame.
Flags

Every option, by command

Anything not on this list is refused. A misspelled flag never runs the command anyway — --dry-runn is an error, not a publish.

--jsoncompare, check
Also write summary.json (schema v11, published and validated)
--jsondoctor
Print the result as one line of JSON instead of a table, for a pipeline to read
--fullcompare, check
Embed full-resolution images in the report
--freshcompare, check
Bypass the design cache and refetch
--strictcompare, check
Exit 1 when a compared frame is over threshold or flagged by an enforced local visual check, or a configured frame was skipped because its page was the wrong one (an unexpected status or redirect); 2 when nothing was compared, as with a wrong page in zero-config compare --target
--targetcompare
Zero-config mode: the mock PNG to diff against. Requires --url
--urlcompare
The page to capture, in zero-config mode
--selectorcompare
Capture one element instead of the full page, in zero-config mode
--expect-statuscompare
The HTTP status the page must answer with, for a page that is an error on purpose. Default: any 2xx
--expect-urlcompare
Where the page must end up, for a page that redirects on purpose. A full URL or a path. Default: the same origin and path as --url
--localexplain
Required. Analyse here, on your own provider key — nothing goes to Normascope Cloud
--allexplain
Explain every compared frame, not just the flagged ones
--deepexplain
Use the stronger, more expensive model
--modecloud publish
Override the configured upload mode for one run: off, metrics, review or full
--dry-runcloud publish
List exactly what would be sent, and send none of it
--full-evidencecloud publish
Full images for every frame, not previews for the clean ones
--explaincloud publish
Ask Cloud to analyse the flagged frames after publishing. Spends Cloud credits
--no-browsercloud login
Print the link and code and open no browser, for a machine without one
--file-storecloud login
Keep the key in an owner-only file in ~/.normascope/credentials instead of the system's credential store
--urlcloud login
Which Normascope Cloud to connect to, by its address alone. Default: https://www.normascope.com
--confirmcloud retry
Send a run that may already be published. If it was deleted in Cloud since, Cloud refuses it and the saved run is removed here
--localcompare, check
Keep this run's report here, when the project's reports go to Normascope Cloud
--checkdesign snapshot
Has the live design drifted from the committed exports?
--help, -hevery command
Print what this command does and run nothing
Which do I want?

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

“Take the screenshots for me.”

capture

“Capture and compare in one go.”

check

“Nothing loaded, or it says skipped.”

doctor

“Explain it using my own provider key.”

explain --local [frame]

“Explain it using the Cloud credits I bought.”

cloud publish --explain

“Will Cloud accept my config?”

cloud validate

“There's no designer — I just don't want surprises.”

mode: "baseline", then baseline approve

“CI shouldn't need a design token.”

design snapshot, and commit .bridge/design/

“Render the PR comment.”

ci comment

“Fail the build on a regression.”

compare --strict

Worth knowing

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.

Normascope Cloudnormascopecloud

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.