@vizzly-testing/honeydiff 0.17.0 → 0.18.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,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.18.0] - 2026-11-11
11
+
12
+ ### Added
13
+
14
+ - You know when one small tweak to a shared nav or footer shows up as a diff in every single
15
+ screenshot? Honeydiff can now spot those repeats for you. Pass `changeBlocks: true` to `compare`
16
+ and you'll get `difference.changeBlocks` back.
17
+
18
+ Each block groups nearby changed regions into what a person would call one change, then gives it
19
+ a `signature` based on its pixels instead of where it sits on the page. So the same change gets the
20
+ same signature on a short page, a tall page, or below a banner that pushed everything down. Group
21
+ by signature and you can review a repeated change once instead of fifty times.
22
+
23
+ Matching is exact on purpose. Two blocks only share a signature when every pixel in them is the
24
+ same, because a fuzzy match can't tell a one-letter edit apart from text that moved half a pixel.
25
+ The same edit on a different background, or right next to another change, gets its own signature.
26
+
27
+ It's off by default, since hashing a big changed area takes real time on full-page diffs. On a real
28
+ build with 148 changed screenshots it added about 4%, and leaving it off costs nothing at all.
29
+
30
+ **Full Changelog**: https://github.com/vizzly-testing/honeydiff/compare/v0.17.0...v0.18.0
31
+
10
32
  ## [0.17.0] - 2026-09-06
11
33
 
12
34
  ### Added
package/README.md CHANGED
@@ -56,6 +56,8 @@ pieces visual regression systems usually need once screenshots get real:
56
56
  - Variable-height screenshot support for full-page comparisons.
57
57
  - Diff, mask, and side-by-side image artifacts for debugging failures.
58
58
  - Exact region data, Delta E summaries, SSIM, MS-SSIM, GMSD, and diff fingerprints.
59
+ - Change blocks that identify each change by its pixels, so the same change matches across
60
+ screenshots at any position and page height.
59
61
  - WCAG contrast screening and color vision deficiency simulation.
60
62
  - Async and sync APIs with TypeScript definitions included.
61
63
 
@@ -150,6 +152,28 @@ configureThreads(4);
150
152
  Repeating the same value is safe. Changing it after Honeydiff work starts
151
153
  throws instead of silently creating an oversubscribed pool.
152
154
 
155
+ ### Find The Same Change Across Screenshots
156
+
157
+ ```js
158
+ let result = await compare('baseline.png', 'current.png', {
159
+ alignHeightChanges: true,
160
+ changeBlocks: true,
161
+ });
162
+
163
+ for (let block of result.difference.changeBlocks) {
164
+ console.log(block.signature, block.bounds);
165
+ }
166
+ ```
167
+
168
+ A block is a group of regions within 16px of each other, which is usually what a person would call
169
+ one change. Two blocks with the same `signature` have byte-identical baseline and current pixels in
170
+ their whole rectangle, wherever they sit on the page and however tall the page is. Group by
171
+ signature to review a repeated change once.
172
+
173
+ Matching is exact on purpose. The same edit on a different background, at a fractional position, or
174
+ next to another change within the gap gets a different signature. Only compare signatures whose
175
+ `cb1:` version prefix matches.
176
+
153
177
  ### Align One Added Or Removed Block
154
178
 
155
179
  ```js
@@ -198,8 +222,10 @@ await saveColorBlindnessSimulation(
198
222
  | `antialiasing` | `true` | Suppress conservative raster-coverage movement. |
199
223
  | `minimumRegionPixels` | `2` | Suppress smaller 8-connected visual regions. |
200
224
  | `alignHeightChanges` | `false` | Align one unambiguous inserted or removed row block. |
225
+ | `changeBlocks` | `false` | Merge nearby regions into blocks identified by their pixels. |
201
226
 
202
- There are no include flags. `compare` always returns its complete data.
227
+ `compare` always returns its complete data. `changeBlocks` is the one opt-in, because hashing a
228
+ large changed area adds real time to a full-page diff.
203
229
 
204
230
  ## Result Shape
205
231
 
package/index.d.ts CHANGED
@@ -77,6 +77,16 @@ export interface DiffRegion {
77
77
  appearance: DeltaESummary | null;
78
78
  }
79
79
 
80
+ export interface ChangeBlock {
81
+ /** Canvas-coordinate rectangle containing the merged regions. */
82
+ bounds: BoundingBox;
83
+ /**
84
+ * Exact identity of every baseline and current pixel in `bounds`, independent of position.
85
+ * Only compare signatures whose version prefix matches.
86
+ */
87
+ signature: string;
88
+ }
89
+
80
90
  export interface DiffAnalysis {
81
91
  different: boolean;
82
92
  settings: {
@@ -96,6 +106,8 @@ export interface DiffAnalysis {
96
106
  spatial: SpatialSummary | null;
97
107
  appearance: DeltaESummary | null;
98
108
  regions: DiffRegion[];
109
+ /** Present when the `changeBlocks` option is set. */
110
+ changeBlocks: ChangeBlock[] | null;
99
111
  };
100
112
  heightChange: {
101
113
  direction: 'added' | 'removed';
@@ -131,6 +143,8 @@ export interface CompareOptions {
131
143
  minimumRegionPixels?: number;
132
144
  /** Detect and align one unambiguous inserted or removed row block. Default: false. */
133
145
  alignHeightChanges?: boolean;
146
+ /** Merge nearby regions into blocks identified by their pixels. Default: false. */
147
+ changeBlocks?: boolean;
134
148
  }
135
149
 
136
150
  export interface ArtifactOutput {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vizzly-testing/honeydiff",
3
- "version": "0.17.0",
3
+ "version": "0.18.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",