@vizzly-testing/cli 0.35.3-beta.0 → 0.35.3-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -19,7 +19,7 @@ let defaultTimers = {
19
19
  /**
20
20
  * Read and parse JSON from disk, returning null on missing or invalid files.
21
21
  */
22
- export function readJsonFile(path) {
22
+ function readJsonFile(path) {
23
23
  if (!existsSync(path)) {
24
24
  return null;
25
25
  }
@@ -33,7 +33,7 @@ export function readJsonFile(path) {
33
33
  /**
34
34
  * Read report data and attach baseline metadata for the stats view.
35
35
  */
36
- export function readReportDataFile({
36
+ function readReportDataFile({
37
37
  reportDataPath,
38
38
  baselineMetadataPath
39
39
  }) {
@@ -84,7 +84,7 @@ function summaryChanged(oldData, newData) {
84
84
  /**
85
85
  * Build incremental SSE events by diffing old vs new report data.
86
86
  */
87
- export function buildReportDataEvents(oldData, newData) {
87
+ function buildReportDataEvents(oldData, newData) {
88
88
  if (!oldData) {
89
89
  return [{
90
90
  type: 'reportData',
@@ -129,7 +129,7 @@ export function buildReportDataEvents(oldData, newData) {
129
129
  /**
130
130
  * Watch report-data.json with fs.watch plus a lightweight mtime fallback.
131
131
  */
132
- export function watchReportDataFile({
132
+ function watchReportDataFile({
133
133
  workingDir,
134
134
  reportDataPath,
135
135
  onReportDataChanged,
@@ -4,7 +4,7 @@
4
4
  * Wraps honeydiff for image comparison and builds comparison result objects.
5
5
  */
6
6
 
7
- import { compare } from '@vizzly-testing/honeydiff';
7
+ import { analyze } from '@vizzly-testing/honeydiff';
8
8
  import { calculateHotspotCoverage } from '../core/hotspot-coverage.js';
9
9
  import { calculateRegionCoverage, shouldAutoApproveFromRegions } from '../core/region-coverage.js';
10
10
  import { generateComparisonId } from '../core/signature.js';
@@ -26,17 +26,41 @@ export async function compareImages(baselinePath, currentPath, diffPath, options
26
26
  threshold = 2.0,
27
27
  minClusterSize = 2
28
28
  } = options;
29
- return compare(baselinePath, currentPath, {
29
+ let analysis = await analyze(baselinePath, currentPath, {
30
30
  threshold,
31
31
  antialiasing: true,
32
+ minimumRegionPixels: minClusterSize
33
+ }, {
32
34
  diffPath,
33
- overwrite: true,
34
- includeClusters: true,
35
- includeSSIM: true,
36
- includeGMSD: true,
37
- clusterMerge: true,
38
- minClusterSize
35
+ overwrite: true
39
36
  });
37
+ let comparison = analysis.comparison;
38
+ let perception = analysis.perception;
39
+ let changedPixels = comparison.pixels.changed.total;
40
+ let totalPixels = comparison.pixels.total;
41
+ let heightChange = comparison.heightChange;
42
+ return {
43
+ isDifferent: comparison.different,
44
+ diffPercentage: totalPixels > 0 ? changedPixels / totalPixels * 100 : 0,
45
+ diffPixels: changedPixels,
46
+ totalPixels,
47
+ aaPixelsIgnored: comparison.pixels.suppressed.antialiasing.count,
48
+ aaPercentage: totalPixels > 0 ? comparison.pixels.suppressed.antialiasing.count / totalPixels * 100 : 0,
49
+ boundingBox: comparison.difference.spatial?.bounds || null,
50
+ heightDiff: heightChange ? heightChange.direction === 'added' ? heightChange.rowCount : -heightChange.rowCount : 0,
51
+ intensityStats: comparison.difference.appearance,
52
+ diffClusters: comparison.difference.regions.map(region => ({
53
+ boundingBox: region.spatial.bounds,
54
+ pixelCount: region.spatial.pixelCount,
55
+ visualPixels: region.visualPixels,
56
+ addedPixels: region.addedPixels,
57
+ removedPixels: region.removedPixels,
58
+ appearance: region.appearance
59
+ })),
60
+ perceptualScore: perception?.ssim,
61
+ ssimScore: perception?.ssim,
62
+ gmsdScore: perception?.gmsd
63
+ };
40
64
  }
41
65
 
42
66
  /**
@@ -145,9 +145,11 @@ function getBaselineScreenshot(comparison = {}) {
145
145
  /**
146
146
  * Project compact Honeydiff facts without making raw geometry the default.
147
147
  *
148
- * Agents need stable counts, fingerprints, URLs, and the API projection for
149
- * first-pass diagnosis. Raw regions and scoring details stay behind an
150
- * explicit include because they can dominate an otherwise bounded handoff.
148
+ * Agents need stable counts, fingerprints, URLs, the API projection, and the
149
+ * server's authoritative artifact manifest for first-pass diagnosis. Keeping
150
+ * that manifest intact prevents the CLI from becoming less authoritative than
151
+ * the API. Raw regions and scoring details stay behind an explicit include
152
+ * because they can dominate an otherwise bounded handoff.
151
153
  *
152
154
  * @param {Object} comparison - Comparison record from the API.
153
155
  * @param {boolean} includeDiffs - Whether to include raw Honeydiff diagnostics.
@@ -158,6 +160,7 @@ function getComparisonDiff(comparison = {}, includeDiffs = false) {
158
160
  let analysis = comparison.analysis || {};
159
161
  let regions = diff.regions || diff.diff_regions || analysis.diff_regions || comparison.diff_regions;
160
162
  let projection = diff.projection || diff.analysis_projection || analysis.projection || analysis.analysis_projection || comparison.analysis_projection || comparison.projection || null;
163
+ let artifacts = diff.artifacts ?? analysis.artifacts ?? comparison.artifacts ?? null;
161
164
  let compact = {
162
165
  percentage: diff.percentage ?? analysis.percentage ?? analysis.diff_percentage ?? comparison.diff_percentage ?? null,
163
166
  changed_pixels: diff.changed_pixels ?? analysis.changed_pixels ?? comparison.changed_pixels ?? null,
@@ -168,6 +171,12 @@ function getComparisonDiff(comparison = {}, includeDiffs = false) {
168
171
  projection,
169
172
  image_url: diff.image_url || diff.url || analysis.diff_image_url || comparison.diff_url || comparison.diff_image_url || null
170
173
  };
174
+
175
+ // Preserve server-owned evidence exactly so agents can verify and download
176
+ // artifacts without the CLI recreating identities, digests, or availability.
177
+ if (artifacts != null) {
178
+ compact.artifacts = artifacts;
179
+ }
171
180
  if (includeDiffs) {
172
181
  compact.regions = regions || [];
173
182
  compact.cluster_metadata = diff.cluster_metadata || analysis.cluster_metadata || comparison.cluster_metadata || null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vizzly-testing/cli",
3
- "version": "0.35.3-beta.0",
3
+ "version": "0.35.3-beta.2",
4
4
  "description": "Visual regression testing from your terminal",
5
5
  "keywords": [
6
6
  "llm-context",
@@ -60,7 +60,8 @@
60
60
  "LICENSE"
61
61
  ],
62
62
  "scripts": {
63
- "cli": "source .envrc && node bin/vizzly.js",
63
+ "cli": "node scripts/run-development-cli.js production",
64
+ "cli:local": "node scripts/run-development-cli.js local",
64
65
  "start": "node src/index.js",
65
66
  "build": "pnpm run clean && pnpm run compile && pnpm run build:reporter && pnpm run build:reporter-ssr && pnpm run copy-types",
66
67
  "clean": "rimraf dist",
@@ -93,7 +94,7 @@
93
94
  },
94
95
  "dependencies": {
95
96
  "@vizzly-testing/bear-den": "0.1.4",
96
- "@vizzly-testing/honeydiff": "^0.11.1",
97
+ "@vizzly-testing/honeydiff": "^0.16.0",
97
98
  "ansis": "^4.2.0",
98
99
  "commander": "^15.0.0",
99
100
  "cosmiconfig": "^9.0.0",
@@ -115,18 +116,18 @@
115
116
  }
116
117
  },
117
118
  "devDependencies": {
118
- "@babel/cli": "^7.28.0",
119
- "@babel/core": "^7.23.6",
120
- "@babel/preset-env": "^7.23.6",
121
- "@babel/preset-react": "^7.27.1",
122
- "@babel/preset-typescript": "^7.23.6",
123
- "@biomejs/biome": "^2.3.8",
119
+ "@babel/cli": "^8.0.1",
120
+ "@babel/core": "^8.0.1",
121
+ "@babel/preset-env": "^8.0.2",
122
+ "@babel/preset-react": "^8.0.1",
123
+ "@babel/preset-typescript": "^8.0.1",
124
+ "@biomejs/biome": "^2.5.10",
124
125
  "@heroicons/react": "^2.2.0",
125
126
  "@modelcontextprotocol/sdk": "^1.0.4",
126
127
  "@playwright/test": "^1.55.1",
127
128
  "@tailwindcss/postcss": "^4.1.13",
128
129
  "@tanstack/react-query": "^5.90.11",
129
- "@types/node": "^25.0.2",
130
+ "@types/node": "^26.0.0",
130
131
  "@vitejs/plugin-react": "^6.0.1",
131
132
  "autoprefixer": "^10.4.21",
132
133
  "babel-plugin-react-compiler": "^1.0.0",
@@ -136,8 +137,8 @@
136
137
  "tailwindcss": "^4.1.13",
137
138
  "tsd": "^0.33.0",
138
139
  "tui-driver": "github:vizzly-testing/tui-driver",
139
- "typescript": "^6.0.3",
140
- "vite": "^8.0.0",
140
+ "typescript": "^7.0.2",
141
+ "vite": "^8.2.2",
141
142
  "wouter": "^3.7.1"
142
143
  }
143
144
  }
@@ -1,74 +1,64 @@
1
1
  ---
2
2
  name: vizzly
3
- description: "Inspect, explain, and debug Vizzly visual regression evidence; use an existing Vizzly workflow before and after UI changes; add or adjust screenshot capture; troubleshoot local TDD or cloud builds; or configure Vizzly CI. Use when a task mentions Vizzly, screenshot baselines, comparisons, Honeydiff, visual review, dynamic regions, or a repository's Vizzly setup."
3
+ description: Inspect and explain Vizzly visual regression evidence, verify UI changes, troubleshoot local or cloud builds, adjust screenshot capture, or configure Vizzly CI. Use when a task mentions Vizzly, screenshot baselines, comparisons, Honeydiff, visual review, dynamic regions, or an existing Vizzly workflow.
4
4
  ---
5
5
 
6
6
  # Vizzly
7
7
 
8
- Use Vizzly as visual evidence for user-facing changes. Keep the repository's
9
- existing test workflow in charge of how the UI is exercised.
8
+ Use Vizzly as evidence for user-facing changes. Keep the repository's existing
9
+ test workflow in charge of how the UI is exercised.
10
10
 
11
- ## Start From The Repository
11
+ ## Prepare
12
12
 
13
- 1. Confirm that the repository uses Vizzly by checking its configuration,
14
- dependencies, scripts, or existing `.vizzly` data.
15
- 2. Use the repository's established CLI invocation. The examples in this skill
16
- use `vizzly`; substitute its package script, `pnpm exec vizzly`, or
17
- `npx vizzly` when that is how the repository runs local binaries.
18
- 3. Do not install, initialize, log in, or change credentials unless the task
19
- explicitly includes setup. Never print or persist a token.
13
+ 1. Confirm the repository uses Vizzly by checking its config, dependencies,
14
+ scripts, or `.vizzly` data.
15
+ 2. Use the repository's established CLI invocation exactly. Otherwise, replace
16
+ `vizzly` in these examples with `pnpm exec vizzly`; use `npx vizzly` when the
17
+ repository uses npm.
18
+ 3. Do not install, initialize, log in, or change credentials unless setup is in
19
+ scope. Never print or persist a token.
20
20
 
21
- ## Follow The Evidence Loop
21
+ ## Inspect And Verify
22
22
 
23
- 1. Choose the most relevant source:
24
- - Use a supplied cloud build or comparison ID when the task names one.
25
- - Use existing local context when `.vizzly` contains the run under review.
26
- - Generate fresh evidence through the repository's existing visual test
27
- workflow when stored evidence may be stale or absent.
28
- 2. Request the bounded, machine-readable build context:
23
+ 1. Choose the supplied cloud build or comparison when one is named. Otherwise,
24
+ use current local evidence or find the relevant cloud build.
25
+ 2. Request bounded JSON:
29
26
 
30
27
  ```bash
31
28
  vizzly context build current --source local --agent --json
32
29
  vizzly context build <build-id> --source cloud --agent --json
33
30
  ```
34
31
 
35
- 3. Check the build identity, source, branch, timestamps, baseline selection,
36
- review state, and truncation fields before interpreting the evidence. Treat
37
- omitted fields as unknown.
38
- 4. Inspect the current, baseline, and diff images together using whatever
39
- image, browser, URL, or local-file capability is available. If an image is
40
- inaccessible, say so and do not infer its visual contents from metadata.
41
- 5. Read viewport, browser, screenshot metadata, review state, and Honeydiff
42
- facts alongside the images. Follow the returned `suggested_commands` for
43
- exact comparison or screenshot drill-downs. Request raw diff regions only
44
- when the compact summary is insufficient.
45
- 6. Separate observations from explanations. State what the evidence shows,
46
- then label any proposed cause with appropriate confidence.
47
- 7. Make the smallest justified UI or test change, rerun the owning user
48
- workflow, and inspect the resulting evidence again.
32
+ 3. Confirm the build, source, branch, timestamps, baseline, review state, and
33
+ pagination before drawing conclusions. If `has_more` is true, run the
34
+ returned next-page command before concluding. Missing fields remain unknown.
35
+ 4. Follow `suggested_commands` to inspect a comparison. View its baseline,
36
+ current, and diff images together. If an image cannot be opened, label the
37
+ result metadata-only; do not call it visual verification.
38
+ 5. Read image dimensions, viewport, browser, diff regions, fingerprint, and
39
+ relevant history alongside the images. A prior approval is supporting
40
+ evidence, not permission to approve the current comparison.
41
+ 6. State observations before possible causes. Make the smallest justified
42
+ change, rerun the owning workflow, and inspect the new evidence.
49
43
 
50
44
  ## Guardrails
51
45
 
52
- - Treat an approved baseline as the accepted reference for that comparison,
53
- not infallible truth. Check its identity and selection reason.
54
- - Do not invent progress, counts, review state, visual causes, or missing API
46
+ - Do not invent progress, ranking, review state, visual causes, or missing API
55
47
  values.
56
- - Do not approve, reject, comment on, publish, or replace visual evidence
57
- unless the user explicitly asks for that mutation.
58
- - Preserve existing thresholds, cluster sizes, signature properties, and
59
- dynamic-region behavior unless the task and evidence justify changing them.
60
- - Prefer deterministic fixtures and existing end-to-end journeys over hiding a
61
- diff with broader tolerances or a new screenshot-only test.
62
- - Report the screenshot or comparison identity, the relevant build or link,
63
- the observed evidence, any access limitations, and the command used.
48
+ - Do not approve, reject, comment on, publish, or replace evidence unless the
49
+ task explicitly asks for that mutation.
50
+ - Preserve thresholds, cluster sizes, signature properties, and dynamic-region
51
+ behavior unless repeated evidence justifies a change.
52
+ - Prefer deterministic fixtures and existing user journeys over hiding a diff
53
+ with broader tolerances or a new screenshot-only test.
54
+ - Report the comparison or screenshot identity, observed evidence, access
55
+ limitations, and the command or link used.
64
56
 
65
- ## Load References Only When Needed
57
+ ## Load A Reference When Needed
66
58
 
67
- - Read [references/cli-context.md](references/cli-context.md) for local and
68
- cloud inspection commands, TDD lifecycle, and evidence drill-downs.
69
- - Read [references/sdks.md](references/sdks.md) only when adding or changing
70
- screenshot capture code.
71
- - Read [references/dynamic-content.md](references/dynamic-content.md) when a
72
- diff may involve unstable content, hotspots, or confirmed regions.
73
- - Read [references/setup-ci.md](references/setup-ci.md) only when the task asks
74
- to initialize Vizzly, change CI, or troubleshoot configuration.
59
+ - [CLI context](references/cli-context.md): local and cloud evidence, build
60
+ discovery, drill-downs, images, and TDD lifecycle.
61
+ - [SDK capture](references/sdks.md): add or change screenshot capture code.
62
+ - [Dynamic content](references/dynamic-content.md): investigate unstable
63
+ content, hotspots, or confirmed regions.
64
+ - [Setup and CI](references/setup-ci.md): initialize Vizzly or change CI.
@@ -1,16 +1,25 @@
1
- # CLI And Context
1
+ # CLI Context
2
2
 
3
- Use the repository's existing CLI invocation. The examples use `vizzly` for
4
- brevity; substitute the repository's package script or package-manager command
5
- when needed.
3
+ Use the repository's established CLI invocation and existing authentication.
4
+ If cloud authentication is unavailable, report the blocker. Do not start an
5
+ interactive login unless setup is in scope.
6
6
 
7
- Use existing authentication and project configuration. If cloud authentication
8
- is missing, report the blocker. Do not start an interactive login or change
9
- credentials unless the task includes setup.
7
+ ## Choose The Evidence
10
8
 
11
- ## Inspect Existing Local Evidence
9
+ Use an ID supplied by the task. If no cloud build is supplied, list recent
10
+ builds and select the one matching the branch, commit, or pull request:
12
11
 
13
- Request structured local evidence with both `--agent` and `--json`:
12
+ ```bash
13
+ vizzly builds --branch <branch> --limit 5 --json
14
+ vizzly status <build-id> --json
15
+ vizzly context build <build-id> --source cloud --agent --json
16
+ ```
17
+
18
+ Use status for lifecycle facts and build context for visual evidence. Do not
19
+ assume the first returned comparison is the most important; preserve API order
20
+ and inspect the records relevant to the task.
21
+
22
+ For saved local evidence:
14
23
 
15
24
  ```bash
16
25
  vizzly context build current --source local --agent --json
@@ -18,79 +27,71 @@ vizzly context screenshot "<screenshot-name>" --source local --json
18
27
  vizzly context review-queue --source local --json
19
28
  ```
20
29
 
21
- Pin hand-written local drill-downs with `--source local`. Without it, automatic
22
- source resolution may fall back to cloud data when a local item is unavailable.
30
+ Confirm the stored build, branch, timestamp, and baseline are current enough
31
+ for the task.
23
32
 
24
- Local context reads persisted `.vizzly` artifacts. Confirm that their build,
25
- branch, timestamp, and baseline match the task before treating them as current.
33
+ ## Generate Fresh Evidence
26
34
 
27
- ## Generate Fresh Local Evidence
28
-
29
- For a one-off run, let Vizzly own the complete local session:
35
+ For one run, let Vizzly own the local session:
30
36
 
31
37
  ```bash
32
38
  vizzly tdd run "<existing visual test command>" --no-open
33
- vizzly context build current --source local --agent --json
34
39
  ```
35
40
 
36
- For repeated test runs, start the detached daemon once:
41
+ For repeated runs, start the detached daemon once:
37
42
 
38
43
  ```bash
39
44
  vizzly tdd start --json
40
45
  vizzly tdd status --json
41
46
  <existing visual test command>
42
- vizzly context build current --source local --agent --json
43
47
  vizzly tdd stop --json
44
48
  ```
45
49
 
46
- Treat `tdd run` and `tdd start` as alternatives. Do not shell-background
47
- `tdd start`; it already launches a detached daemon. Stop only a server started
48
- for the current task, and reuse the printed port for status or stop commands
49
- when Vizzly selects a non-default port.
50
-
51
- ## Inspect Cloud Evidence
50
+ `tdd run` and `tdd start` are alternatives. Stop only a daemon started for the
51
+ current task.
52
52
 
53
- When the task already has a build ID:
53
+ When a cloud build is in scope:
54
54
 
55
55
  ```bash
56
- vizzly status <build-id> --json
56
+ vizzly run "<existing visual test command>" --wait --json
57
57
  vizzly context build <build-id> --source cloud --agent --json
58
58
  ```
59
59
 
60
- Use status for server-owned lifecycle, processing, comparison, and review
61
- facts. Use build context for visual debugging.
60
+ ## Inspect A Comparison
62
61
 
63
- When creating a cloud build is in scope, wrap the repository's existing test
64
- command:
62
+ Follow the build response's `suggested_commands`. The direct form is:
65
63
 
66
64
  ```bash
67
- vizzly run "<existing visual test command>" --wait --json
68
- vizzly context build <build-id> --source cloud --agent --json
65
+ vizzly context comparison <comparison-id> --source <local-or-cloud> --agent --json
66
+ vizzly context comparison <comparison-id> --source <local-or-cloud> --agent --include diffs --json
69
67
  ```
70
68
 
71
- ## Read And Drill Into Evidence
69
+ Open all three images together. Prefer `original_url` and fall back to `url`:
72
70
 
73
- For each evidence record:
71
+ - Current: `comparison.screenshot.original_url` or
72
+ `comparison.screenshot.url`
73
+ - Baseline: `comparison.baseline.original_url` or `comparison.baseline.url`
74
+ - Diff: `comparison.analysis.diff_image_url`
74
75
 
75
- 1. Inspect the current, baseline, and diff images with an available harness
76
- capability. State the limitation if an image cannot be accessed.
77
- 2. Read render metadata, review state, and compact Honeydiff diagnostics next
78
- to the images.
79
- 3. Run the returned `suggested_commands` instead of reconstructing identifiers
80
- or URLs.
81
- 4. Add `--include diffs` only when raw Honeydiff region geometry is needed.
82
- Request comments only when human review context matters.
76
+ Then compare the visible change with diff regions, fingerprint, and the
77
+ separate `similar_by_fingerprint` and `recent_by_name` history streams.
78
+ Previous review decisions help explain recurring evidence but do not decide the
79
+ current review.
83
80
 
84
- Useful manual drill-downs are:
81
+ Useful supporting commands:
85
82
 
86
83
  ```bash
87
- vizzly context comparison <comparison-id> --source <local-or-cloud> --json
88
84
  vizzly context screenshot "<screenshot-name>" --source <local-or-cloud> --json
89
85
  vizzly context similar <fingerprint-hash> --source cloud --json
90
86
  vizzly context review-queue --source <local-or-cloud> --json
91
87
  ```
92
88
 
93
- Use the source from the evidence you are inspecting in place of
94
- `<local-or-cloud>`. `context similar` is cloud-only. Keep missing values
95
- unknown, and do not turn metadata into a visual conclusion when the underlying
96
- images are unavailable.
89
+ Use `--include diffs` only when compact diagnostics are insufficient. Request
90
+ comments only when human review context matters.
91
+
92
+ ## Continue Without Guessing
93
+
94
+ Run returned `suggested_commands` rather than reconstructing IDs, sources, or
95
+ pagination. When more evidence exists, the next-page command carries the API's
96
+ opaque `--cursor`; do not edit or interpret it. Keep follow-up commands pinned
97
+ to the source that produced the evidence.
@@ -1,39 +1,28 @@
1
1
  # Dynamic Content
2
2
 
3
- Treat dates, timers, randomized data, API-backed content, generated images, and
4
- responsive text as possible causes of change, not automatic explanations.
3
+ Dates, timers, random data, API content, generated images, and responsive text
4
+ can cause a diff. They are possible explanations, not conclusions.
5
5
 
6
6
  ## Diagnose Before Tuning
7
7
 
8
- 1. Inspect screenshot history and the actual image evidence:
8
+ 1. Inspect the actual images and screenshot history:
9
9
 
10
10
  ```bash
11
11
  vizzly context screenshot "<screenshot-name>" --source <local-or-cloud> --json
12
12
  ```
13
13
 
14
- 2. Replace `<local-or-cloud>` with the source of the evidence being diagnosed.
15
- Record the observed region, recurrence, render metadata, and whether the
16
- same change appears across builds or variants.
17
- 3. Check whether deterministic fixtures can remove irrelevant variation.
18
- 4. Treat hotspots and confirmed regions as server- or user-owned evidence.
19
- They can affect comparison results, but this CLI exposes them for inspection
20
- rather than authoring.
21
- 5. Preserve existing per-screenshot `threshold` and `minClusterSize` values
22
- unless the task and repeated evidence justify a change. Do not invent new
23
- tolerance values from one diff.
24
-
25
- ## Avoid
26
-
27
- - Raising a global threshold for one unstable area.
28
- - Masking a whole page when only a small region changes.
29
- - Assuming a recurring change is harmless without inspecting it.
30
- - Ignoring structural movement because a region contains dynamic content.
31
- - Claiming a cause when only metadata, rather than images or history, is
32
- available.
33
-
34
- ## Report Findings
35
-
36
- State the observed change first. Then distinguish a likely explanation—such as
37
- fixture drift, content disappearance, layout shift, capture timing, or baseline
38
- mismatch—from unresolved alternatives. Include the screenshot identity and the
39
- context command or link used.
14
+ 2. Record the visible region, recurrence, render metadata, and whether the same
15
+ change appears across builds or variants.
16
+ 3. Prefer deterministic fixtures when they can remove irrelevant variation.
17
+ 4. Treat hotspots and confirmed regions as server- or user-authored evidence.
18
+ This CLI exposes them for inspection, not authoring.
19
+ 5. Preserve `threshold` and `minClusterSize` unless repeated evidence
20
+ justifies a change.
21
+
22
+ Avoid broad masks, global threshold changes for one region, and claims based on
23
+ metadata alone. A recurring change can still be a bug, especially when content
24
+ movement affects nearby layout.
25
+
26
+ Report the observed change first. Label fixture drift, layout shift, capture
27
+ timing, or baseline mismatch as a possible cause until the evidence establishes
28
+ it.
@@ -1,9 +1,10 @@
1
- # SDK Capture Patterns
1
+ # SDK Capture
2
2
 
3
- Prefer the repository's existing Vizzly integration and user journey. Add a new
4
- capture path only when the task requires it.
3
+ Use the repository's existing Vizzly integration and user journey. The
4
+ JavaScript example applies only when no framework-specific capture path already
5
+ owns the workflow.
5
6
 
6
- ## JavaScript Client
7
+ ## JavaScript
7
8
 
8
9
  ```javascript
9
10
  import { vizzlyScreenshot } from '@vizzly-testing/cli/client';
@@ -13,37 +14,28 @@ await vizzlyScreenshot('settings-profile-edit-mode', screenshot);
13
14
  ```
14
15
 
15
16
  `vizzlyScreenshot(name, image, options)` accepts PNG bytes or a file path.
16
- Available options include:
17
+ Options include `properties`, `threshold`, `minClusterSize`, and
18
+ `fullPage`. Preserve existing tuning unless visual evidence justifies changing
19
+ it.
17
20
 
18
- - `properties`: metadata attached to the screenshot.
19
- - `threshold`: per-screenshot CIEDE2000 Delta E tolerance.
20
- - `minClusterSize`: minimum changed-pixel cluster size.
21
- - `fullPage`: whether the screenshot represents a full-page capture.
21
+ ## Keep Identity Stable
22
22
 
23
- Do not add arbitrary tuning values. Preserve the repository's existing values
24
- unless visual evidence justifies changing them.
23
+ Use a descriptive name. Identity always includes the name, viewport width, and
24
+ browser. Configured `signatureProperties` add custom identity fields; other
25
+ properties are metadata.
25
26
 
26
- ## Screenshot Identity
27
+ Do not assume theme, locale, or state creates a separate baseline unless the
28
+ configuration says so. Avoid generic names such as `screenshot1` and names
29
+ with slashes.
27
30
 
28
- Use a stable, descriptive name. Vizzly's signature always includes the name,
29
- viewport width, and browser. Only properties named in the project's
30
- `signatureProperties` configuration participate in baseline identity.
31
+ ## Follow Existing Integrations
31
32
 
32
- Treat other `properties` as metadata. Do not assume values such as theme,
33
- locale, or state create separate baselines unless the configuration says so.
34
-
35
- ## Existing Integrations
36
-
37
- - Use the Vizzly Vitest matcher when the project already configures the plugin:
33
+ - Keep the Vizzly Vitest matcher when it is already configured:
38
34
 
39
35
  ```javascript
40
36
  await expect(page).toMatchScreenshot('hero-section.png');
41
37
  ```
42
38
 
43
- - Prefer existing Storybook, static-site, or Ember capture flows over adding a
44
- parallel Playwright path.
45
- - For Swift/XCTest, inspect the repository's Vizzly Swift package documentation
46
- and existing `VizzlyXCTest` usage before changing capture code.
47
-
48
- Use properties for searchable metadata and configured variants. Avoid generic
49
- names such as `screenshot1` or `test`, and avoid names with slashes.
39
+ - Prefer existing Storybook, static-site, Ember, or Swift capture flows over a
40
+ parallel test path.
41
+ - Inspect the repository's integration setup before changing capture code.