@vizzly-testing/honeydiff 0.13.1 → 0.14.0

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.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.14.0] - 2026-07-24
11
+
12
+ ### Added
13
+ - Added opt-in, versioned `diffMaskEvidence` with a native analysis
14
+ identity, bitmap dimensions, completeness, and exact 8-connected component
15
+ facts derived from the retained pixels used by mask artifacts.
16
+
17
+ ### Changed
18
+ - Named retained mask facts consistently around Honeydiff's diff-mask artifact:
19
+ `diffMaskPixels`, `diffMaskComplete`, `diffMaskEvidence`, and
20
+ `includeDiffMaskEvidence`.
21
+ - Diff-mask artifact generation reuses requested native evidence instead
22
+ of repeating the comparison to recover filtered coordinates.
23
+
24
+ **Full Changelog**: https://github.com/vizzly-testing/honeydiff/compare/v0.13.1...v0.14.0
25
+
10
26
  ## [0.13.1] - 2026-07-23
11
27
 
12
28
  ### Changed
@@ -18,14 +34,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
18
34
  ## [0.13.0] - 2026-07-23
19
35
 
20
36
  ### Added
21
- - Exposed `effectiveDiffPixels`, `effectiveMaskComplete`,
22
- `maskSemanticsVersion`, and the installed package `version` for auditable
23
- mask consumers.
37
+ - Exposed retained mask pixel count, completeness, semantics version, and the
38
+ installed package version for auditable mask consumers.
24
39
 
25
40
  ### Fixed
26
41
  - Kept binary mask alpha opaque even when a transparent display diff color is
27
42
  requested.
28
- - Kept requested pixel and cluster diagnostics from changing the effective mask
43
+ - Kept requested pixel and cluster diagnostics from changing the diff mask
29
44
  or variable-height classification.
30
45
 
31
46
  **Full Changelog**: https://github.com/vizzly-testing/honeydiff/compare/v0.12.0...v0.13.0
package/README.md CHANGED
@@ -121,6 +121,25 @@ for (let cluster of result.diffClusters ?? []) {
121
121
  }
122
122
  ```
123
123
 
124
+ ### Persist Authoritative Mask Evidence
125
+
126
+ Use diff-mask evidence when another system needs durable spatial facts
127
+ without decoding the generated PNG:
128
+
129
+ ```js
130
+ let result = await compare('baseline.png', 'current.png', {
131
+ includeDiffMaskEvidence: true,
132
+ maskPath: 'artifacts/mask.png',
133
+ });
134
+
135
+ console.log(result.diffMaskEvidence?.analysisContractHash);
136
+ console.log(result.diffMaskEvidence?.components);
137
+ ```
138
+
139
+ The components are exact 8-connected groups of retained mask pixels. They are
140
+ separate from `diffClusters`, whose optional merge heuristics are intended for
141
+ diagnostic presentation.
142
+
124
143
  ### Add Perceptual Metrics
125
144
 
126
145
  ```js
@@ -170,6 +189,7 @@ await saveColorBlindnessSimulation(
170
189
  | `maxDiffs` | unlimited | Stop after a maximum number of differing pixels. Capped results classify from the pixels observed before early exit, without cluster filtering. |
171
190
  | `includeDiffPixels` | `false` | Return individual differing pixel positions and intensities. |
172
191
  | `includeClusters` | `false` | Return connected regions of visual change. |
192
+ | `includeDiffMaskEvidence` | `false` | Return authoritative diff-mask identity, dimensions, and exact components. |
173
193
  | `minClusterSize` | `2` | Filter tiny isolated clusters as noise. |
174
194
  | `clusterMerge` | disabled | Merge nearby clusters into logical text-like regions. |
175
195
  | `includeSSIM` | `false` | Calculate structural similarity. More expensive on large images. |
@@ -187,9 +207,10 @@ interface DiffResult {
187
207
  diffPercentage: number;
188
208
  totalPixels: number;
189
209
  diffPixels: number;
190
- effectiveDiffPixels: number;
191
- effectiveMaskComplete: boolean;
210
+ diffMaskPixels: number;
211
+ diffMaskComplete: boolean;
192
212
  maskSemanticsVersion: string;
213
+ diffMaskEvidence: DiffMaskEvidence | null;
193
214
  aaPixelsIgnored: number;
194
215
  aaPercentage: number;
195
216
  boundingBox: BoundingBox | null;
@@ -203,11 +224,14 @@ interface DiffResult {
203
224
  ```
204
225
 
205
226
  `diffPixels` is the raw post-threshold/anti-aliasing count.
206
- `effectiveDiffPixels` is the retained count represented by the binary mask after
227
+ `diffMaskPixels` is the retained count represented by the binary mask after
207
228
  `minClusterSize` filtering. It always matches the mask's nontransparent pixel
208
- count. If `effectiveMaskComplete` is `false`, `maxDiffs` stopped the scan early;
229
+ count. If `diffMaskComplete` is `false`, `maxDiffs` stopped the scan early;
209
230
  the partial mask is useful for diagnostics but not complete spatial proof.
210
231
  Requesting `diffPixelsList` or `diffClusters` never changes that retained result.
232
+ `diffMaskEvidence` is returned only when `includeDiffMaskEvidence` is enabled. Its
233
+ native analysis hash covers every normalized option that can change retained
234
+ pixels, and its component pixel counts sum to `diffMaskPixels`.
211
235
 
212
236
  The package also exports `version` from its installed manifest and
213
237
  `maskSemanticsVersion` from the native comparison engine.
package/index.d.ts CHANGED
@@ -60,6 +60,36 @@ export interface DiffCluster {
60
60
  boundingBox: BoundingBox;
61
61
  }
62
62
 
63
+ export interface DiffMaskComponent {
64
+ /** Number of retained pixels in this exact 8-connected component */
65
+ pixelCount: number;
66
+ /** Bitmap-pixel bounds around the component */
67
+ boundingBox: BoundingBox;
68
+ }
69
+
70
+ export interface DiffMaskEvidence {
71
+ /** Version of this evidence result shape */
72
+ contractVersion: string;
73
+ /** Native identity of normalized options that can change retained pixels */
74
+ analysisContractHash: string;
75
+ /** Version of Honeydiff's retained-pixel semantics */
76
+ semanticsVersion: string;
77
+ /** Version of the connected-component semantics */
78
+ componentSemanticsVersion: string;
79
+ /** Bitmap coordinate-space version */
80
+ coordinateSpaceVersion: string;
81
+ /** Diff-mask width in bitmap pixels */
82
+ width: number;
83
+ /** Diff-mask height in bitmap pixels */
84
+ height: number;
85
+ /** Number of retained pixels represented by the mask */
86
+ pixelCount: number;
87
+ /** False when maxDiffs stopped the comparison early */
88
+ complete: boolean;
89
+ /** Deterministically ordered exact connected components */
90
+ components: DiffMaskComponent[];
91
+ }
92
+
63
93
  export interface DiffResult {
64
94
  /**
65
95
  * Whether the images are different based on the comparison threshold
@@ -75,12 +105,14 @@ export interface DiffResult {
75
105
  * Note: This may be > 0 even when isDifferent is false if small clusters were filtered as noise
76
106
  */
77
107
  diffPixels: number;
78
- /** Number of retained pixels represented by the effective diff mask */
79
- effectiveDiffPixels: number;
108
+ /** Number of retained pixels represented by the diff mask */
109
+ diffMaskPixels: number;
80
110
  /** False when maxDiffs stopped the scan before the full image was evaluated */
81
- effectiveMaskComplete: boolean;
82
- /** Version of the pixel-retention semantics used by the effective mask */
111
+ diffMaskComplete: boolean;
112
+ /** Version of the pixel-retention semantics used by the diff mask */
83
113
  maskSemanticsVersion: string;
114
+ /** Authoritative diff-mask evidence (null unless includeDiffMaskEvidence is enabled) */
115
+ diffMaskEvidence: DiffMaskEvidence | null;
84
116
  /** Number of pixels ignored due to anti-aliasing detection */
85
117
  aaPixelsIgnored: number;
86
118
  /** Percentage of pixels ignored as anti-aliasing (0.0 - 100.0) */
@@ -108,7 +140,7 @@ export interface DiffResult {
108
140
  /** Installed @vizzly-testing/honeydiff package version */
109
141
  export const version: string;
110
142
 
111
- /** Native effective-mask semantics implemented by this package */
143
+ /** Native diff-mask semantics implemented by this package */
112
144
  export const maskSemanticsVersion: string;
113
145
 
114
146
  // ============================================================================
@@ -209,6 +241,13 @@ export interface CompareOptions {
209
241
  */
210
242
  includeClusters?: boolean;
211
243
 
244
+ /**
245
+ * Include authoritative diff-mask dimensions, identity, and exact
246
+ * connected-component facts.
247
+ * @default false
248
+ */
249
+ includeDiffMaskEvidence?: boolean;
250
+
212
251
  /**
213
252
  * Calculate SSIM (Structural Similarity Index) perceptual score
214
253
  * This metric measures the source images independently of threshold and AA
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vizzly-testing/honeydiff",
3
- "version": "0.13.1",
3
+ "version": "0.14.0",
4
4
  "description": "High-performance image diffing for Node.js - Native bindings to Honeydiff Rust library",
5
5
  "type": "module",
6
6
  "main": "index.js",