@vizzly-testing/honeydiff 0.0.2 → 0.0.3

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/README.md CHANGED
@@ -5,25 +5,9 @@
5
5
  [![CI](https://github.com/vizzly-testing/honeydiff/workflows/Node.js%20Bindings/badge.svg)](https://github.com/vizzly-testing/honeydiff/actions)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](../../LICENSE)
7
7
 
8
- High-performance image diffing for Node.js - Native bindings to the Honeydiff Rust library.
9
-
10
- Blazing fast image comparison with support for anti-aliasing detection, perceptual similarity (SSIM), spatial clustering, and variable-height screenshots. Perfect for visual regression testing.
11
-
12
- ## Features
13
-
14
- - **🚀 Native Performance** - Rust-powered via Neon bindings (1.1B pixels/sec for Full HD)
15
- - **📦 Dual Input** - Works with file paths or Buffers
16
- - **⚡ Async + Sync APIs** - Choose between non-blocking promises or synchronous operations
17
- - **🎯 Full TypeScript Support** - Complete type definitions included
18
- - **🔍 Advanced Analysis**:
19
- - Anti-aliasing detection
20
- - SSIM perceptual similarity scoring
21
- - Spatial clustering of diff regions
22
- - Intensity statistics (min, max, mean, median, std dev)
23
- - Bounding box detection
24
- - **📸 Variable Height Support** - Compare scrollable screenshots with different heights
25
- - **🎨 Visual Artifacts** - Generate diff, mask, and overlay images
26
- - **⚙️ Flexible Options** - Pixel tolerance, color thresholds, custom diff colors
8
+ Fast image diffing for Node.js with native Rust performance (1.1B pixels/sec). Supports anti-aliasing detection, SSIM, clustering, and variable-height screenshots.
9
+
10
+ **Features:** File paths or Buffers • Async + sync APIs • TypeScript types • Pre-built binaries (macOS/Linux/Windows)
27
11
 
28
12
  ## Installation
29
13
 
@@ -31,25 +15,15 @@ Blazing fast image comparison with support for anti-aliasing detection, perceptu
31
15
  npm install @vizzly-testing/honeydiff
32
16
  ```
33
17
 
34
- **Requirements:**
35
- - Node.js 22+
36
-
37
- **Pre-built Binaries:**
38
- This package ships with pre-built native binaries for:
39
- - macOS (Apple Silicon arm64)
40
- - Linux (x64 and arm64)
41
- - Windows (x64)
42
-
43
- No Rust toolchain required! The correct binary is automatically loaded for your platform.
18
+ Requires Node.js 22+. Ships with pre-built binaries for macOS (ARM64), Linux (x64/ARM64), and Windows (x64). No Rust toolchain needed.
44
19
 
45
20
  ## Quick Start
46
21
 
47
- ### JavaScript (Async - Recommended)
48
-
22
+ **JavaScript**
49
23
  ```javascript
50
24
  const { compare, quickCompare } = require('@vizzly-testing/honeydiff');
51
25
 
52
- // Quick boolean check
26
+ // Quick check
53
27
  if (await quickCompare('baseline.png', 'current.png')) {
54
28
  console.log('Visual regression detected!');
55
29
  }
@@ -60,112 +34,62 @@ const result = await compare('baseline.png', 'current.png', {
60
34
  includeSSIM: true
61
35
  });
62
36
 
63
- console.log(`Diff: ${result.diffPercentage.toFixed(2)}%`);
64
- console.log(`SSIM: ${result.perceptualScore}`);
37
+ console.log(`Diff: ${result.diffPercentage.toFixed(2)}%, SSIM: ${result.perceptualScore}`);
65
38
  ```
66
39
 
67
- ### TypeScript
40
+ **TypeScript**
68
41
 
69
42
  ```typescript
70
43
  import { compare, CompareOptions, DiffResult } from '@vizzly-testing/honeydiff';
71
44
 
72
- const options: CompareOptions = {
45
+ const result: DiffResult = await compare('img1.png', 'img2.png', {
73
46
  pixelTolerance: 5,
74
47
  includeSSIM: true,
75
48
  includeClusters: true
76
- };
77
-
78
- const result: DiffResult = await compare('img1.png', 'img2.png', options);
49
+ });
79
50
 
80
51
  if (result.diffClusters) {
81
52
  console.log(`Found ${result.diffClusters.length} diff regions`);
82
53
  }
83
54
  ```
84
55
 
85
- ## API Reference
86
-
87
- ### Async API (Recommended)
88
-
89
- #### `compare(img1, img2, options?): Promise<DiffResult>`
90
-
91
- Compare two images asynchronously. Non-blocking operation.
92
-
93
- **Parameters:**
94
- - `img1`: `string | Buffer` - First image (file path or Buffer)
95
- - `img2`: `string | Buffer` - Second image (file path or Buffer)
96
- - `options`: `CompareOptions` (optional) - Comparison configuration
97
-
98
- **Returns:** `Promise<DiffResult>` - Detailed diff results
99
-
100
- **Example:**
101
- ```javascript
102
- const result = await compare('baseline.png', 'current.png', {
103
- pixelTolerance: 10,
104
- antialiasing: true,
105
- includeSSIM: true,
106
- diffPath: '/tmp/diff.png'
107
- });
108
- ```
56
+ ## API
109
57
 
110
- #### `quickCompare(img1, img2): Promise<boolean>`
58
+ **Async (recommended)**
59
+ - `compare(img1, img2, options?): Promise<DiffResult>` - Full comparison
60
+ - `quickCompare(img1, img2): Promise<boolean>` - Quick check
111
61
 
112
- Quick async comparison returning only a boolean.
62
+ **Sync (blocks event loop)**
63
+ - `compareSync(img1, img2, options?): DiffResult`
64
+ - `quickCompareSync(img1, img2): boolean`
113
65
 
114
- **Returns:** `Promise<boolean>` - `true` if different, `false` if identical
66
+ Inputs: `string` (file path) or `Buffer`
115
67
 
116
- ### Sync API
68
+ ## Options & Results
117
69
 
118
- #### `compareSync(img1, img2, options?): DiffResult`
119
-
120
- Synchronous comparison (blocks event loop). Use only when necessary.
121
-
122
- #### `quickCompareSync(img1, img2): boolean`
123
-
124
- Synchronous quick comparison returning a boolean.
125
-
126
- ## Options
70
+ <details>
71
+ <summary><strong>CompareOptions</strong></summary>
127
72
 
128
73
  ```typescript
129
74
  interface CompareOptions {
130
- /** Pixel tolerance 0-255 (default: 0) */
131
- pixelTolerance?: number;
132
-
133
- /** YIQ color threshold 0.0-1.0 (default: 0.0 = RGB mode) */
134
- colorThreshold?: number;
135
-
136
- /** Enable anti-aliasing detection (default: true) */
137
- antialiasing?: boolean;
138
-
139
- /** Ignore colors, compare brightness only (default: false) */
140
- ignoreColors?: boolean;
141
-
142
- /** Max differences to find before stopping (default: unlimited) */
143
- maxDiffs?: number;
144
-
145
- /** Include detailed pixel list (default: false) */
146
- includeDiffPixels?: boolean;
147
-
148
- /** Include spatial clusters (default: false) */
149
- includeClusters?: boolean;
150
-
151
- /** Calculate SSIM score (default: false) */
152
- includeSSIM?: boolean;
153
-
154
- /** Path to save diff image */
155
- diffPath?: string;
156
-
157
- /** Path to save binary mask */
158
- maskPath?: string;
159
-
160
- /** Path to save side-by-side overlay */
161
- overlayPath?: string;
162
-
163
- /** Overwrite existing files (default: false) */
164
- overwrite?: boolean;
75
+ pixelTolerance?: number; // 0-255 (default: 0)
76
+ colorThreshold?: number; // 0.0-1.0 for YIQ mode (default: 0.0 = RGB)
77
+ antialiasing?: boolean; // Enable AA detection (default: true)
78
+ ignoreColors?: boolean; // Brightness only (default: false)
79
+ maxDiffs?: number; // Stop after N diffs (default: unlimited)
80
+ includeDiffPixels?: boolean; // Detailed pixel list (default: false)
81
+ includeClusters?: boolean; // Spatial clusters (default: false)
82
+ includeSSIM?: boolean; // SSIM score (default: false)
83
+ diffPath?: string; // Save diff image
84
+ maskPath?: string; // Save mask image
85
+ overlayPath?: string; // Save overlay image
86
+ overwrite?: boolean; // Overwrite files (default: false)
165
87
  }
166
88
  ```
89
+ </details>
167
90
 
168
- ## Result Object
91
+ <details>
92
+ <summary><strong>DiffResult</strong></summary>
169
93
 
170
94
  ```typescript
171
95
  interface DiffResult {
@@ -180,148 +104,79 @@ interface DiffResult {
180
104
  diffPixelsList: DiffPixel[] | null;
181
105
  diffClusters: DiffCluster[] | null;
182
106
  intensityStats: IntensityStats | null;
183
- perceptualScore: number | null; // SSIM 0.0-1.0
107
+ perceptualScore: number | null; // SSIM 0.0-1.0
184
108
  }
185
109
  ```
110
+ </details>
186
111
 
187
- ## Usage Examples
188
-
189
- ### With Buffers
112
+ ## Examples
190
113
 
114
+ **Buffers**
191
115
  ```javascript
192
116
  const fs = require('fs');
193
117
  const { compare } = require('@vizzly-testing/honeydiff');
194
118
 
195
- const img1 = fs.readFileSync('image1.png');
196
- const img2 = fs.readFileSync('image2.png');
197
-
198
- const result = await compare(img1, img2, {
199
- pixelTolerance: 5
200
- });
119
+ let img1 = fs.readFileSync('image1.png');
120
+ let img2 = fs.readFileSync('image2.png');
121
+ let result = await compare(img1, img2, { pixelTolerance: 5 });
201
122
  ```
202
123
 
203
- ### Generate Diff Images
124
+ **Diff Images**
204
125
 
205
126
  ```javascript
206
- const result = await compare('baseline.png', 'current.png', {
207
- diffPath: './output/diff.png',
208
- maskPath: './output/mask.png',
209
- overlayPath: './output/overlay.png',
127
+ let result = await compare('baseline.png', 'current.png', {
128
+ diffPath: './diff.png',
129
+ maskPath: './mask.png',
130
+ overlayPath: './overlay.png',
210
131
  overwrite: true
211
132
  });
212
-
213
- console.log(`Diff images saved with ${result.diffPercentage}% difference`);
214
133
  ```
215
134
 
216
- ### Spatial Clustering
217
-
135
+ **Clustering & Metrics**
218
136
  ```javascript
219
- const result = await compare('img1.png', 'img2.png', {
220
- includeClusters: true
137
+ let result = await compare('img1.png', 'img2.png', {
138
+ includeClusters: true,
139
+ includeSSIM: true,
140
+ includeDiffPixels: true
221
141
  });
222
142
 
143
+ // Spatial clusters
223
144
  if (result.diffClusters) {
224
- result.diffClusters.forEach((cluster, i) => {
225
- console.log(`Cluster ${i + 1}:`);
226
- console.log(` Pixels: ${cluster.pixelCount}`);
227
- console.log(` Center: (${cluster.centerOfMass[0]}, ${cluster.centerOfMass[1]})`);
228
- console.log(` Bounds: ${cluster.boundingBox.width}x${cluster.boundingBox.height}`);
145
+ result.diffClusters.forEach((c, i) => {
146
+ console.log(`Region ${i + 1}: ${c.pixelCount} pixels at (${c.centerOfMass[0]}, ${c.centerOfMass[1]})`);
229
147
  });
230
148
  }
231
- ```
232
-
233
- ### Perceptual Similarity (SSIM)
234
-
235
- ```javascript
236
- const result = await compare('img1.png', 'img2.png', {
237
- includeSSIM: true
238
- });
239
149
 
150
+ // SSIM score
240
151
  if (result.perceptualScore !== null) {
241
- if (result.perceptualScore > 0.95) {
242
- console.log('Perceptually very similar');
243
- } else if (result.perceptualScore > 0.80) {
244
- console.log('Somewhat similar');
245
- } else {
246
- console.log('Perceptually different');
247
- }
152
+ console.log(`SSIM: ${result.perceptualScore.toFixed(3)}`);
248
153
  }
249
- ```
250
-
251
- ### Intensity Statistics
252
-
253
- ```javascript
254
- const result = await compare('img1.png', 'img2.png', {
255
- includeDiffPixels: true // Enables intensity stats
256
- });
257
154
 
155
+ // Intensity stats
258
156
  if (result.intensityStats) {
259
- console.log(`Intensity range: ${result.intensityStats.min}-${result.intensityStats.max}`);
260
- console.log(`Mean: ${result.intensityStats.mean.toFixed(1)}`);
261
- console.log(`Median: ${result.intensityStats.median}`);
262
- console.log(`Std Dev: ${result.intensityStats.stdDev.toFixed(1)}`);
157
+ console.log(`Range: ${result.intensityStats.min}-${result.intensityStats.max}, Mean: ${result.intensityStats.mean.toFixed(1)}`);
263
158
  }
264
159
  ```
265
160
 
266
161
  ## Performance
267
162
 
268
- Benchmarks on M-series Mac:
269
-
270
163
  | Image Size | Time | Throughput |
271
164
  |------------|------|------------|
272
165
  | 1920x1080 (Full HD) | ~2ms | 1.1B pixels/sec |
273
166
  | 3840x2160 (4K) | ~3ms | 3.0B pixels/sec |
274
167
 
275
- With diff artifact generation: ~30-35ms for Full HD images
276
-
277
- ## Variable Height Support
278
-
279
- Honeydiff can compare images with different heights (same width) - perfect for scrollable screenshots:
280
-
281
- ```javascript
282
- const result = await compare('short.png', 'tall.png');
283
-
284
- if (result.heightDiff) {
285
- console.log(`Height diff: ${result.heightDiff.height1}px vs ${result.heightDiff.height2}px`);
286
- console.log(`Extra pixels: ${result.heightDiff.extraPixels}`);
287
- }
288
- ```
168
+ With artifacts: ~30-35ms for Full HD. Benchmarked on Apple M-series Mac.
289
169
 
290
170
  ## Building from Source
291
171
 
292
- Only needed if you want to contribute or modify the native code.
293
-
294
- **Prerequisites:**
295
- - Rust toolchain (install from https://rustup.rs)
296
- - Node.js 22+
172
+ Only needed for contributing or modifying native code. Requires Rust toolchain and Node.js 22+.
297
173
 
298
174
  ```bash
299
- # Clone the repository
300
175
  git clone https://github.com/vizzly-testing/honeydiff
301
176
  cd honeydiff/crates/honeydiff-node
302
-
303
- # Install dependencies
304
- npm install
305
-
306
- # Build for your platform
307
- npm run build
308
-
309
- # Run examples
310
- node examples/basic.js
311
- ```
312
-
313
- ### Cross-Platform Builds
314
-
315
- ```bash
316
- # Build for all supported platforms (requires cross-compilation setup)
317
- npm run cross-build
177
+ npm install && npm run build
318
178
  ```
319
179
 
320
- ## Related Projects
321
-
322
- - [honeydiff](https://github.com/vizzly-testing/honeydiff) - The core Rust library
323
- - [Vizzly](https://github.com/vizzly-testing/vizzly) - Visual regression testing platform
324
-
325
180
  ## License
326
181
 
327
- MIT - See [LICENSE](../../LICENSE) for details
182
+ MIT - See [LICENSE](../../LICENSE) for details. Built for [Vizzly](https://github.com/vizzly-testing/vizzly) visual regression testing.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vizzly-testing/honeydiff",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "High-performance image diffing for Node.js - Native bindings to Honeydiff Rust library",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -45,6 +45,11 @@
45
45
  "index.d.ts",
46
46
  "load-platform.js",
47
47
  "platforms/*.node",
48
+ "README.md",
49
+ "index.js",
50
+ "index.d.ts",
51
+ "load-platform.js",
52
+ "platforms/*.node",
48
53
  "README.md"
49
54
  ],
50
55
  "engines": {