@testivai/witness 1.0.1 → 1.0.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.
Files changed (88) hide show
  1. package/README.md +44 -13
  2. package/dist/baselines/index.d.ts +6 -0
  3. package/dist/baselines/index.d.ts.map +1 -0
  4. package/dist/baselines/index.js +9 -0
  5. package/dist/baselines/index.js.map +1 -0
  6. package/dist/baselines/store.d.ts +79 -0
  7. package/dist/baselines/store.d.ts.map +1 -0
  8. package/dist/baselines/store.js +234 -0
  9. package/dist/baselines/store.js.map +1 -0
  10. package/dist/bin/testivai.js +2 -0
  11. package/dist/bin/testivai.js.map +1 -1
  12. package/dist/browser/binding.d.ts.map +1 -1
  13. package/dist/browser/binding.js +173 -42
  14. package/dist/browser/binding.js.map +1 -1
  15. package/dist/browser/capture.d.ts.map +1 -1
  16. package/dist/browser/capture.js +7 -4
  17. package/dist/browser/capture.js.map +1 -1
  18. package/dist/commands/approve.d.ts +3 -0
  19. package/dist/commands/approve.d.ts.map +1 -0
  20. package/dist/commands/approve.js +94 -0
  21. package/dist/commands/approve.js.map +1 -0
  22. package/dist/commands/init.d.ts.map +1 -1
  23. package/dist/commands/init.js +53 -0
  24. package/dist/commands/init.js.map +1 -1
  25. package/dist/commands/run.d.ts.map +1 -1
  26. package/dist/commands/run.js +98 -0
  27. package/dist/commands/run.js.map +1 -1
  28. package/dist/config/index.d.ts +6 -0
  29. package/dist/config/index.d.ts.map +1 -0
  30. package/dist/config/index.js +14 -0
  31. package/dist/config/index.js.map +1 -0
  32. package/dist/config/local-config.d.ts +54 -0
  33. package/dist/config/local-config.d.ts.map +1 -0
  34. package/dist/config/local-config.js +130 -0
  35. package/dist/config/local-config.js.map +1 -0
  36. package/dist/diff/diff.d.ts +27 -0
  37. package/dist/diff/diff.d.ts.map +1 -0
  38. package/dist/diff/diff.js +216 -0
  39. package/dist/diff/diff.js.map +1 -0
  40. package/dist/diff/ignore.d.ts +22 -0
  41. package/dist/diff/ignore.d.ts.map +1 -0
  42. package/dist/diff/ignore.js +43 -0
  43. package/dist/diff/ignore.js.map +1 -0
  44. package/dist/diff/index.d.ts +16 -0
  45. package/dist/diff/index.d.ts.map +1 -0
  46. package/dist/diff/index.js +23 -0
  47. package/dist/diff/index.js.map +1 -0
  48. package/dist/diff/minimap.d.ts +23 -0
  49. package/dist/diff/minimap.d.ts.map +1 -0
  50. package/dist/diff/minimap.js +43 -0
  51. package/dist/diff/minimap.js.map +1 -0
  52. package/dist/diff/regions.d.ts +23 -0
  53. package/dist/diff/regions.d.ts.map +1 -0
  54. package/dist/diff/regions.js +129 -0
  55. package/dist/diff/regions.js.map +1 -0
  56. package/dist/diff/resize.d.ts +27 -0
  57. package/dist/diff/resize.d.ts.map +1 -0
  58. package/dist/diff/resize.js +82 -0
  59. package/dist/diff/resize.js.map +1 -0
  60. package/dist/diff/types.d.ts +79 -0
  61. package/dist/diff/types.d.ts.map +1 -0
  62. package/dist/diff/types.js +10 -0
  63. package/dist/diff/types.js.map +1 -0
  64. package/dist/index.d.ts +8 -0
  65. package/dist/index.d.ts.map +1 -1
  66. package/dist/index.js +23 -2
  67. package/dist/index.js.map +1 -1
  68. package/dist/report/compare.d.ts +18 -0
  69. package/dist/report/compare.d.ts.map +1 -0
  70. package/dist/report/compare.js +163 -0
  71. package/dist/report/compare.js.map +1 -0
  72. package/dist/report/generator.d.ts +31 -0
  73. package/dist/report/generator.d.ts.map +1 -0
  74. package/dist/report/generator.js +123 -0
  75. package/dist/report/generator.js.map +1 -0
  76. package/dist/report/index.d.ts +10 -0
  77. package/dist/report/index.d.ts.map +1 -0
  78. package/dist/report/index.js +13 -0
  79. package/dist/report/index.js.map +1 -0
  80. package/dist/report/results.d.ts +35 -0
  81. package/dist/report/results.d.ts.map +1 -0
  82. package/dist/report/results.js +8 -0
  83. package/dist/report/results.js.map +1 -0
  84. package/dist/report/template.d.ts +14 -0
  85. package/dist/report/template.d.ts.map +1 -0
  86. package/dist/report/template.js +229 -0
  87. package/dist/report/template.js.map +1 -0
  88. package/package.json +58 -15
@@ -0,0 +1,216 @@
1
+ "use strict";
2
+ /**
3
+ * TestivAI Diff Engine — Core comparison loop
4
+ *
5
+ * Originally forked from pixel-buffer-diff (Pbd) by @p01, licensed under MIT.
6
+ * https://github.com/p01/pixel-buffer-diff
7
+ *
8
+ * The core pixel comparison algorithm is preserved exactly.
9
+ * Extended with: ignore regions, size mismatch handling, region detection,
10
+ * and enriched DiffResult.
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.diff = diff;
14
+ const ignore_1 = require("./ignore");
15
+ const resize_1 = require("./resize");
16
+ const regions_1 = require("./regions");
17
+ const minimap_1 = require("./minimap");
18
+ // ── Pbd constants (unchanged) ───────────────────────────────────────────────
19
+ const MINIMAP_SCALE = 128;
20
+ const COLOR32_ADDED = 0x03f00cc00;
21
+ const COLOR32_REMOVED = 0x03f0000ff;
22
+ const COLOR32_MINIMAP = 0x0207f0000;
23
+ const HASH_SPREAD = 0x0f0731337;
24
+ // ── Default options ─────────────────────────────────────────────────────────
25
+ const DEFAULT_OPTIONS = {
26
+ threshold: 0.1,
27
+ cumulatedThreshold: 0.5,
28
+ enableMinimap: false,
29
+ detectRegions: false,
30
+ };
31
+ /**
32
+ * Compare two pixel buffers and produce a diff image.
33
+ *
34
+ * Drop-in compatible with pixelmatch when called as:
35
+ * diff(img1, img2, output, w, h) → returns DiffResult
36
+ *
37
+ * @param baseline8 - Baseline image pixel data (RGBA, 4 bytes per pixel)
38
+ * @param candidate8 - Candidate image pixel data (RGBA, 4 bytes per pixel)
39
+ * @param diff8 - Output buffer for the diff image (same size as inputs)
40
+ * @param width - Width of the images in pixels
41
+ * @param height - Height of the images in pixels
42
+ * @param options - Comparison options
43
+ * @returns DiffResult with counts, percentages, and optional regions
44
+ */
45
+ function diff(baseline8, candidate8, diff8, width, height, options = {}) {
46
+ const opts = { ...DEFAULT_OPTIONS, ...options };
47
+ // ── Size mismatch handling ──────────────────────────────────────────────
48
+ let sizeMismatch;
49
+ let effectiveWidth = width;
50
+ let effectiveHeight = height;
51
+ let effectiveBaseline = baseline8;
52
+ let effectiveCandidate = candidate8;
53
+ // If caller provided handleSizeMismatch and dimensions were embedded,
54
+ // we need external width/height per buffer. For the simple API the caller
55
+ // is expected to have already normalized — but we expose normalizeDimensions
56
+ // as a public utility. Here we just validate.
57
+ const expectedLen = width * height * 4;
58
+ if (baseline8.length !== expectedLen || candidate8.length !== expectedLen) {
59
+ if (opts.handleSizeMismatch) {
60
+ // Infer baseline dimensions from baseline8.length and supplied width
61
+ const baselineHeight = baseline8.length / (width * 4);
62
+ const candidateHeight = candidate8.length / (width * 4);
63
+ // If widths differ, we need both dimensions — use normalizeDimensions
64
+ const bw = width;
65
+ const bh = Math.round(baselineHeight);
66
+ const cw = width;
67
+ const ch = Math.round(candidateHeight);
68
+ const normalized = (0, resize_1.normalizeDimensions)(baseline8, bw, bh, candidate8, cw, ch, opts.handleSizeMismatch);
69
+ effectiveBaseline = normalized.normalizedBaseline;
70
+ effectiveCandidate = normalized.normalizedCandidate;
71
+ effectiveWidth = normalized.width;
72
+ effectiveHeight = normalized.height;
73
+ sizeMismatch = normalized.sizeMismatch;
74
+ // Re-create diff buffer if size changed
75
+ if (diff8.length !== effectiveWidth * effectiveHeight * 4) {
76
+ diff8 = new Uint8ClampedArray(effectiveWidth * effectiveHeight * 4);
77
+ }
78
+ }
79
+ else {
80
+ throw new Error(`Buffer size mismatch: expected ${expectedLen} bytes (${width}×${height}×4), ` +
81
+ `got baseline=${baseline8.length}, candidate=${candidate8.length}. ` +
82
+ `Set handleSizeMismatch option to 'pad', 'crop', or 'error'.`);
83
+ }
84
+ }
85
+ // ── Ignore regions ──────────────────────────────────────────────────────
86
+ if (opts.ignoreRegions && opts.ignoreRegions.length > 0) {
87
+ // Clone buffers so we don't mutate originals
88
+ effectiveBaseline = new Uint8ClampedArray(effectiveBaseline);
89
+ effectiveCandidate = new Uint8ClampedArray(effectiveCandidate);
90
+ (0, ignore_1.applyIgnoreRegions)(effectiveBaseline, effectiveCandidate, effectiveWidth, effectiveHeight, opts.ignoreRegions);
91
+ }
92
+ // ── Core Pbd diff loop (basic mode — pixel-level YIQ comparison) ──────
93
+ const raw = pbdDiffCore(effectiveBaseline, effectiveCandidate, diff8, effectiveWidth, effectiveHeight, opts.threshold, opts.cumulatedThreshold, opts.enableMinimap);
94
+ // ── Compute extended result ─────────────────────────────────────────────
95
+ const totalPixels = effectiveWidth * effectiveHeight;
96
+ const diffPercent = totalPixels > 0 ? (raw.diff / totalPixels) * 100 : 0;
97
+ const isIdentical = raw.diff === 0;
98
+ const result = {
99
+ diffCount: raw.diff,
100
+ cumulatedDiff: raw.cumulatedDiff,
101
+ hash: raw.hash,
102
+ diffPercent,
103
+ totalPixels,
104
+ isIdentical,
105
+ };
106
+ if (sizeMismatch) {
107
+ result.sizeMismatch = sizeMismatch;
108
+ }
109
+ // ── Region detection ────────────────────────────────────────────────────
110
+ if (opts.detectRegions && !isIdentical) {
111
+ result.regions = (0, regions_1.detectRegions)(diff8, effectiveWidth, effectiveHeight);
112
+ }
113
+ return result;
114
+ }
115
+ /**
116
+ * Core Pbd diff loop — pixel-level YIQ comparison.
117
+ * Algorithm is preserved exactly from pixel-buffer-diff.
118
+ * @internal
119
+ */
120
+ function pbdDiffCore(baseline8, candidate8, diff8, width, height, threshold, cumulatedThreshold, enableMinimap) {
121
+ const area = width * height;
122
+ const b8l = baseline8.length;
123
+ // Maximum acceptable square distance between two colors;
124
+ // 35215 is the maximum possible value for the YIQ difference metric
125
+ const deltaThreshold = threshold * threshold * 35215;
126
+ // Use ArrayBuffer views for 32-bit access
127
+ const bBuffer = baseline8.buffer;
128
+ const bOffset = baseline8.byteOffset;
129
+ const cBuffer = candidate8.buffer;
130
+ const cOffset = candidate8.byteOffset;
131
+ const dBuffer = diff8.buffer;
132
+ const dOffset = diff8.byteOffset;
133
+ const baseline32 = new Uint32Array(bBuffer, bOffset, area);
134
+ const candidate32 = new Uint32Array(cBuffer, cOffset, area);
135
+ const diff32 = new Uint32Array(dBuffer, dOffset, area);
136
+ let b8i = 0;
137
+ let b32i = 0;
138
+ let d32i = 0;
139
+ let diffCount = 0;
140
+ let hash = 0;
141
+ let hashStart = 0;
142
+ let cumulatedDiff = 0;
143
+ // Quick approx of color theme to figure if "new" pixels should be dark or light
144
+ let averageBrightness = 0;
145
+ const brightnessSamples = Math.ceil(Math.sqrt(area) / 128);
146
+ const b8iStep = (b8l / brightnessSamples) & -4;
147
+ let sampleIdx = 0;
148
+ for (let i = 0; i < brightnessSamples; i++) {
149
+ averageBrightness +=
150
+ (0.299 * (baseline8[sampleIdx] + candidate8[sampleIdx]) +
151
+ 0.587 * (baseline8[sampleIdx + 1] + candidate8[sampleIdx + 1]) +
152
+ 0.114 * (baseline8[sampleIdx + 2] + candidate8[sampleIdx + 2])) /
153
+ brightnessSamples /
154
+ 2;
155
+ sampleIdx += b8iStep;
156
+ }
157
+ const isDarkTheme = averageBrightness < 128;
158
+ const color32Added = isDarkTheme ? COLOR32_ADDED : COLOR32_REMOVED;
159
+ const color32Removed = isDarkTheme ? COLOR32_REMOVED : COLOR32_ADDED;
160
+ // Minimap tracking
161
+ const miniHeight = Math.ceil(height / MINIMAP_SCALE);
162
+ const miniWidth = Math.ceil(width / MINIMAP_SCALE);
163
+ const miniMap = new Uint8ClampedArray(miniWidth * miniHeight);
164
+ const maxDimension = Math.max(width, height);
165
+ const maxMiniDimension = Math.max(miniWidth, miniHeight);
166
+ const axisMiniIndex = new Uint32Array(maxDimension);
167
+ let miniIndex = 0;
168
+ for (let i = 0; i < maxMiniDimension; i++) {
169
+ axisMiniIndex.fill(i, miniIndex, Math.min(miniIndex + MINIMAP_SCALE, maxDimension));
170
+ miniIndex += MINIMAP_SCALE;
171
+ }
172
+ // ── Per-pixel comparison ────────────────────────────────────────────────
173
+ for (let y = 0; y < height; y++) {
174
+ const miniIndexY = axisMiniIndex[y] * miniWidth;
175
+ let hashIndex = (y ^ HASH_SPREAD) * HASH_SPREAD;
176
+ for (let x = 0; x < width; x++, d32i++, b32i++, b8i += 4, hashIndex++) {
177
+ // Quick check against the Uint32
178
+ if (baseline32[b32i] === candidate32[b32i]) {
179
+ continue;
180
+ }
181
+ // Get the r,g,b -> y,i,q => YIQ square delta
182
+ const dr = candidate8[b8i] - baseline8[b8i];
183
+ const dg = candidate8[b8i + 1] - baseline8[b8i + 1];
184
+ const db = candidate8[b8i + 2] - baseline8[b8i + 2];
185
+ const dy = dr * 0.29889531 + dg * 0.58662247 + db * 0.11448223;
186
+ const di = dr * 0.59597799 - dg * 0.27417610 - db * 0.32180189;
187
+ const dq = dr * 0.21147017 - dg * 0.52261711 + db * 0.31114694;
188
+ const delta = dy * dy * 0.5053 + di * di * 0.299 + dq * dq * 0.1957;
189
+ if (delta > deltaThreshold) {
190
+ miniMap[miniIndexY + axisMiniIndex[x]]++;
191
+ diffCount++;
192
+ const dyAbs = Math.abs(dy);
193
+ cumulatedDiff += dyAbs;
194
+ diff32[d32i] =
195
+ (dy > 0 ? color32Added : color32Removed) +
196
+ (Math.min(192, dyAbs * 8) << 24);
197
+ if (hash === 0) {
198
+ hashStart = hashIndex;
199
+ }
200
+ hash += hashIndex;
201
+ }
202
+ }
203
+ }
204
+ hash -= hashStart;
205
+ cumulatedDiff /= 256;
206
+ // Apply minimap overlay
207
+ if (enableMinimap) {
208
+ (0, minimap_1.applyMinimap)(diff32, miniMap, miniWidth, miniHeight, width, height, MINIMAP_SCALE, COLOR32_MINIMAP);
209
+ }
210
+ // If cumulated diff is within threshold, treat as identical
211
+ if (cumulatedDiff <= cumulatedThreshold) {
212
+ return { diff: 0, cumulatedDiff: 0, hash: 0 };
213
+ }
214
+ return { diff: diffCount, cumulatedDiff, hash };
215
+ }
216
+ //# sourceMappingURL=diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/diff/diff.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * TestivAI Diff Engine — Ignore regions
3
+ *
4
+ * Before the diff loop runs, copy candidate pixel values into the
5
+ * baseline buffer for ignored regions. This makes ignored areas
6
+ * appear identical to the differ.
7
+ */
8
+ import { IgnoreRegion } from './types';
9
+ /**
10
+ * Mask ignored regions by copying candidate pixels into baseline.
11
+ * After this, the diff loop will see no difference in those areas.
12
+ *
13
+ * Mutates `baseline` in place.
14
+ *
15
+ * @param baseline - Baseline pixel buffer (will be mutated)
16
+ * @param candidate - Candidate pixel buffer
17
+ * @param width - Image width
18
+ * @param height - Image height
19
+ * @param regions - Regions to ignore
20
+ */
21
+ export declare function applyIgnoreRegions(baseline: Uint8Array | Uint8ClampedArray, candidate: Uint8Array | Uint8ClampedArray, width: number, height: number, regions: IgnoreRegion[]): void;
22
+ //# sourceMappingURL=ignore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ignore.d.ts","sourceRoot":"","sources":["../../src/diff/ignore.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,UAAU,GAAG,iBAAiB,EACxC,SAAS,EAAE,UAAU,GAAG,iBAAiB,EACzC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,YAAY,EAAE,GACtB,IAAI,CAoBN"}
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ /**
3
+ * TestivAI Diff Engine — Ignore regions
4
+ *
5
+ * Before the diff loop runs, copy candidate pixel values into the
6
+ * baseline buffer for ignored regions. This makes ignored areas
7
+ * appear identical to the differ.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.applyIgnoreRegions = applyIgnoreRegions;
11
+ /**
12
+ * Mask ignored regions by copying candidate pixels into baseline.
13
+ * After this, the diff loop will see no difference in those areas.
14
+ *
15
+ * Mutates `baseline` in place.
16
+ *
17
+ * @param baseline - Baseline pixel buffer (will be mutated)
18
+ * @param candidate - Candidate pixel buffer
19
+ * @param width - Image width
20
+ * @param height - Image height
21
+ * @param regions - Regions to ignore
22
+ */
23
+ function applyIgnoreRegions(baseline, candidate, width, height, regions) {
24
+ for (const region of regions) {
25
+ // Clamp to image bounds
26
+ const x0 = Math.max(0, Math.min(region.x, width));
27
+ const y0 = Math.max(0, Math.min(region.y, height));
28
+ const x1 = Math.max(0, Math.min(region.x + region.width, width));
29
+ const y1 = Math.max(0, Math.min(region.y + region.height, height));
30
+ for (let y = y0; y < y1; y++) {
31
+ const rowOffset = y * width * 4;
32
+ for (let x = x0; x < x1; x++) {
33
+ const pixelOffset = rowOffset + x * 4;
34
+ // Copy RGBA from candidate to baseline
35
+ baseline[pixelOffset] = candidate[pixelOffset];
36
+ baseline[pixelOffset + 1] = candidate[pixelOffset + 1];
37
+ baseline[pixelOffset + 2] = candidate[pixelOffset + 2];
38
+ baseline[pixelOffset + 3] = candidate[pixelOffset + 3];
39
+ }
40
+ }
41
+ }
42
+ }
43
+ //# sourceMappingURL=ignore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ignore.js","sourceRoot":"","sources":["../../src/diff/ignore.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;AAgBH,gDA0BC;AAtCD;;;;;;;;;;;GAWG;AACH,SAAgB,kBAAkB,CAChC,QAAwC,EACxC,SAAyC,EACzC,KAAa,EACb,MAAc,EACd,OAAuB;IAEvB,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,wBAAwB;QACxB,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;QAClD,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;QACnD,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;QACjE,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;QAEnE,KAAK,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;YAC7B,MAAM,SAAS,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC;YAChC,KAAK,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC7B,MAAM,WAAW,GAAG,SAAS,GAAG,CAAC,GAAG,CAAC,CAAC;gBACtC,uCAAuC;gBACvC,QAAQ,CAAC,WAAW,CAAC,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC;gBAC/C,QAAQ,CAAC,WAAW,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC;gBACvD,QAAQ,CAAC,WAAW,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC;gBACvD,QAAQ,CAAC,WAAW,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC;YACzD,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * TestivAI Diff Engine
3
+ *
4
+ * Pixel-level visual comparison engine forked from pixel-buffer-diff (Pbd)
5
+ * by @p01 (MIT license). Extended with ignore regions, size mismatch
6
+ * handling, region detection, and TypeScript support.
7
+ *
8
+ * @see https://github.com/p01/pixel-buffer-diff
9
+ */
10
+ export { diff } from './diff';
11
+ export { applyIgnoreRegions } from './ignore';
12
+ export { applyMinimap } from './minimap';
13
+ export { normalizeDimensions } from './resize';
14
+ export { detectRegions } from './regions';
15
+ export type { DiffOptions, DiffResult, DiffRegion, IgnoreRegion, SizeMismatch, PbdRawResult, } from './types';
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/diff/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,YAAY,EACV,WAAW,EACX,UAAU,EACV,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,YAAY,GACb,MAAM,SAAS,CAAC"}
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ /**
3
+ * TestivAI Diff Engine
4
+ *
5
+ * Pixel-level visual comparison engine forked from pixel-buffer-diff (Pbd)
6
+ * by @p01 (MIT license). Extended with ignore regions, size mismatch
7
+ * handling, region detection, and TypeScript support.
8
+ *
9
+ * @see https://github.com/p01/pixel-buffer-diff
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.detectRegions = exports.normalizeDimensions = exports.applyMinimap = exports.applyIgnoreRegions = exports.diff = void 0;
13
+ var diff_1 = require("./diff");
14
+ Object.defineProperty(exports, "diff", { enumerable: true, get: function () { return diff_1.diff; } });
15
+ var ignore_1 = require("./ignore");
16
+ Object.defineProperty(exports, "applyIgnoreRegions", { enumerable: true, get: function () { return ignore_1.applyIgnoreRegions; } });
17
+ var minimap_1 = require("./minimap");
18
+ Object.defineProperty(exports, "applyMinimap", { enumerable: true, get: function () { return minimap_1.applyMinimap; } });
19
+ var resize_1 = require("./resize");
20
+ Object.defineProperty(exports, "normalizeDimensions", { enumerable: true, get: function () { return resize_1.normalizeDimensions; } });
21
+ var regions_1 = require("./regions");
22
+ Object.defineProperty(exports, "detectRegions", { enumerable: true, get: function () { return regions_1.detectRegions; } });
23
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/diff/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;;AAEH,+BAA8B;AAArB,4FAAA,IAAI,OAAA;AACb,mCAA8C;AAArC,4GAAA,kBAAkB,OAAA;AAC3B,qCAAyC;AAAhC,uGAAA,YAAY,OAAA;AACrB,mCAA+C;AAAtC,6GAAA,mBAAmB,OAAA;AAC5B,qCAA0C;AAAjC,wGAAA,aAAa,OAAA"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * TestivAI Diff Engine — Minimap overlay
3
+ *
4
+ * Applies a low-resolution overlay on the diff buffer to help
5
+ * spot isolated pixel changes at a glance.
6
+ *
7
+ * Ported from pixel-buffer-diff by @p01, licensed under MIT.
8
+ */
9
+ /**
10
+ * Apply minimap overlay to the diff buffer.
11
+ * Regions with any changed pixels get a colored tint.
12
+ *
13
+ * @param diff32 - Diff image as Uint32Array
14
+ * @param miniMap - Minimap cell hit counts
15
+ * @param miniWidth - Number of minimap columns
16
+ * @param miniHeight - Number of minimap rows
17
+ * @param width - Full image width
18
+ * @param height - Full image height
19
+ * @param scale - Pixels per minimap cell (e.g. 128)
20
+ * @param color - 32-bit ABGR color to OR into diff pixels
21
+ */
22
+ export declare function applyMinimap(diff32: Uint32Array, miniMap: Uint8ClampedArray, miniWidth: number, miniHeight: number, width: number, height: number, scale: number, color: number): void;
23
+ //# sourceMappingURL=minimap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"minimap.d.ts","sourceRoot":"","sources":["../../src/diff/minimap.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,WAAW,EACnB,OAAO,EAAE,iBAAiB,EAC1B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,GACZ,IAAI,CAkBN"}
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ /**
3
+ * TestivAI Diff Engine — Minimap overlay
4
+ *
5
+ * Applies a low-resolution overlay on the diff buffer to help
6
+ * spot isolated pixel changes at a glance.
7
+ *
8
+ * Ported from pixel-buffer-diff by @p01, licensed under MIT.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.applyMinimap = applyMinimap;
12
+ /**
13
+ * Apply minimap overlay to the diff buffer.
14
+ * Regions with any changed pixels get a colored tint.
15
+ *
16
+ * @param diff32 - Diff image as Uint32Array
17
+ * @param miniMap - Minimap cell hit counts
18
+ * @param miniWidth - Number of minimap columns
19
+ * @param miniHeight - Number of minimap rows
20
+ * @param width - Full image width
21
+ * @param height - Full image height
22
+ * @param scale - Pixels per minimap cell (e.g. 128)
23
+ * @param color - 32-bit ABGR color to OR into diff pixels
24
+ */
25
+ function applyMinimap(diff32, miniMap, miniWidth, miniHeight, width, height, scale, color) {
26
+ for (let i = 0; i < miniWidth * miniHeight; i++) {
27
+ if (miniMap[i] > 0) {
28
+ const miniX = i % miniWidth;
29
+ const miniY = (i / miniWidth) | 0;
30
+ const x0 = miniX * scale;
31
+ const x1 = Math.min(x0 + scale, width);
32
+ const y0 = miniY * scale;
33
+ const y1 = Math.min(y0 + scale, height);
34
+ for (let y = y0; y < y1; y++) {
35
+ let d32i = x0 + y * width;
36
+ for (let x = x0; x < x1; x++) {
37
+ diff32[d32i++] |= color;
38
+ }
39
+ }
40
+ }
41
+ }
42
+ }
43
+ //# sourceMappingURL=minimap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"minimap.js","sourceRoot":"","sources":["../../src/diff/minimap.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;AAeH,oCA2BC;AAxCD;;;;;;;;;;;;GAYG;AACH,SAAgB,YAAY,CAC1B,MAAmB,EACnB,OAA0B,EAC1B,SAAiB,EACjB,UAAkB,EAClB,KAAa,EACb,MAAc,EACd,KAAa,EACb,KAAa;IAEb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,GAAG,UAAU,EAAE,CAAC,EAAE,EAAE,CAAC;QAChD,IAAI,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;YACnB,MAAM,KAAK,GAAG,CAAC,GAAG,SAAS,CAAC;YAC5B,MAAM,KAAK,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;YAClC,MAAM,EAAE,GAAG,KAAK,GAAG,KAAK,CAAC;YACzB,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,KAAK,EAAE,KAAK,CAAC,CAAC;YACvC,MAAM,EAAE,GAAG,KAAK,GAAG,KAAK,CAAC;YACzB,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,KAAK,EAAE,MAAM,CAAC,CAAC;YAExC,KAAK,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC7B,IAAI,IAAI,GAAG,EAAE,GAAG,CAAC,GAAG,KAAK,CAAC;gBAC1B,KAAK,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;oBAC7B,MAAM,CAAC,IAAI,EAAE,CAAC,IAAI,KAAK,CAAC;gBAC1B,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * TestivAI Diff Engine — Region bounding box detection
3
+ *
4
+ * Scans the diff output buffer for non-zero (changed) pixels
5
+ * and groups them into rectangular bounding boxes using a simple
6
+ * connected-component labeling approach.
7
+ */
8
+ import { DiffRegion } from './types';
9
+ /**
10
+ * Detect regions of change in the diff buffer.
11
+ *
12
+ * Scans for non-transparent pixels (any pixel with alpha > 0 in
13
+ * the diff output), groups adjacent changed pixels into rectangular
14
+ * bounding boxes, and filters out regions smaller than minSize.
15
+ *
16
+ * @param diff8 - Diff image pixel buffer (RGBA)
17
+ * @param width - Image width
18
+ * @param height - Image height
19
+ * @param minSize - Minimum pixels to include a region (default: 10)
20
+ * @returns Array of DiffRegion bounding boxes
21
+ */
22
+ export declare function detectRegions(diff8: Uint8Array | Uint8ClampedArray, width: number, height: number, minSize?: number): DiffRegion[];
23
+ //# sourceMappingURL=regions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"regions.d.ts","sourceRoot":"","sources":["../../src/diff/regions.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,UAAU,GAAG,iBAAiB,EACrC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,MAAW,GACnB,UAAU,EAAE,CAkHd"}
@@ -0,0 +1,129 @@
1
+ "use strict";
2
+ /**
3
+ * TestivAI Diff Engine — Region bounding box detection
4
+ *
5
+ * Scans the diff output buffer for non-zero (changed) pixels
6
+ * and groups them into rectangular bounding boxes using a simple
7
+ * connected-component labeling approach.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.detectRegions = detectRegions;
11
+ /**
12
+ * Detect regions of change in the diff buffer.
13
+ *
14
+ * Scans for non-transparent pixels (any pixel with alpha > 0 in
15
+ * the diff output), groups adjacent changed pixels into rectangular
16
+ * bounding boxes, and filters out regions smaller than minSize.
17
+ *
18
+ * @param diff8 - Diff image pixel buffer (RGBA)
19
+ * @param width - Image width
20
+ * @param height - Image height
21
+ * @param minSize - Minimum pixels to include a region (default: 10)
22
+ * @returns Array of DiffRegion bounding boxes
23
+ */
24
+ function detectRegions(diff8, width, height, minSize = 10) {
25
+ // Build a binary grid: 1 = changed pixel, 0 = unchanged
26
+ const changed = new Uint8Array(width * height);
27
+ for (let y = 0; y < height; y++) {
28
+ for (let x = 0; x < width; x++) {
29
+ const idx = (y * width + x) * 4;
30
+ // A pixel is considered "changed" if it has any non-zero alpha
31
+ // in the diff buffer (the diff engine writes colored pixels for changes)
32
+ if (diff8[idx + 3] > 0) {
33
+ changed[y * width + x] = 1;
34
+ }
35
+ }
36
+ }
37
+ // Connected-component labeling using union-find
38
+ const labels = new Int32Array(width * height).fill(-1);
39
+ const parent = [];
40
+ let nextLabel = 0;
41
+ function find(x) {
42
+ while (parent[x] !== x) {
43
+ parent[x] = parent[parent[x]]; // path compression
44
+ x = parent[x];
45
+ }
46
+ return x;
47
+ }
48
+ function union(a, b) {
49
+ const ra = find(a);
50
+ const rb = find(b);
51
+ if (ra !== rb) {
52
+ parent[rb] = ra;
53
+ }
54
+ }
55
+ // First pass: assign labels
56
+ for (let y = 0; y < height; y++) {
57
+ for (let x = 0; x < width; x++) {
58
+ const idx = y * width + x;
59
+ if (!changed[idx])
60
+ continue;
61
+ const neighbors = [];
62
+ // Check left
63
+ if (x > 0 && labels[idx - 1] >= 0) {
64
+ neighbors.push(labels[idx - 1]);
65
+ }
66
+ // Check above
67
+ if (y > 0 && labels[idx - width] >= 0) {
68
+ neighbors.push(labels[idx - width]);
69
+ }
70
+ if (neighbors.length === 0) {
71
+ // New label
72
+ labels[idx] = nextLabel;
73
+ parent.push(nextLabel);
74
+ nextLabel++;
75
+ }
76
+ else {
77
+ // Use the smallest label
78
+ const minLabel = Math.min(...neighbors.map(find));
79
+ labels[idx] = minLabel;
80
+ // Union all neighbor labels
81
+ for (const n of neighbors) {
82
+ union(minLabel, n);
83
+ }
84
+ }
85
+ }
86
+ }
87
+ // Second pass: collect bounding boxes per component
88
+ const boxes = new Map();
89
+ for (let y = 0; y < height; y++) {
90
+ for (let x = 0; x < width; x++) {
91
+ const idx = y * width + x;
92
+ if (labels[idx] < 0)
93
+ continue;
94
+ const root = find(labels[idx]);
95
+ const box = boxes.get(root);
96
+ if (box) {
97
+ box.x0 = Math.min(box.x0, x);
98
+ box.y0 = Math.min(box.y0, y);
99
+ box.x1 = Math.max(box.x1, x);
100
+ box.y1 = Math.max(box.y1, y);
101
+ box.count++;
102
+ }
103
+ else {
104
+ boxes.set(root, { x0: x, y0: y, x1: x, y1: y, count: 1 });
105
+ }
106
+ }
107
+ }
108
+ // Convert to DiffRegion array, filtering by minSize
109
+ const regions = [];
110
+ for (const box of boxes.values()) {
111
+ if (box.count < minSize)
112
+ continue;
113
+ const regionWidth = box.x1 - box.x0 + 1;
114
+ const regionHeight = box.y1 - box.y0 + 1;
115
+ const regionArea = regionWidth * regionHeight;
116
+ regions.push({
117
+ x: box.x0,
118
+ y: box.y0,
119
+ width: regionWidth,
120
+ height: regionHeight,
121
+ diffPixels: box.count,
122
+ diffPercent: regionArea > 0 ? (box.count / regionArea) * 100 : 0,
123
+ });
124
+ }
125
+ // Sort by position (top-left first)
126
+ regions.sort((a, b) => a.y - b.y || a.x - b.x);
127
+ return regions;
128
+ }
129
+ //# sourceMappingURL=regions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"regions.js","sourceRoot":"","sources":["../../src/diff/regions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * TestivAI Diff Engine — Size mismatch handling
3
+ *
4
+ * When baseline and candidate have different dimensions,
5
+ * normalize them before diffing.
6
+ */
7
+ import { SizeMismatch } from './types';
8
+ export interface NormalizeResult {
9
+ normalizedBaseline: Uint8ClampedArray;
10
+ normalizedCandidate: Uint8ClampedArray;
11
+ width: number;
12
+ height: number;
13
+ sizeMismatch: SizeMismatch;
14
+ }
15
+ /**
16
+ * Normalize two pixel buffers to the same dimensions.
17
+ *
18
+ * @param baseline - Baseline pixel buffer (RGBA)
19
+ * @param bw - Baseline width
20
+ * @param bh - Baseline height
21
+ * @param candidate - Candidate pixel buffer (RGBA)
22
+ * @param cw - Candidate width
23
+ * @param ch - Candidate height
24
+ * @param mode - 'pad' (fill with transparent), 'crop' (use min dims), or 'error'
25
+ */
26
+ export declare function normalizeDimensions(baseline: Uint8Array | Uint8ClampedArray, bw: number, bh: number, candidate: Uint8Array | Uint8ClampedArray, cw: number, ch: number, mode: 'pad' | 'crop' | 'error'): NormalizeResult;
27
+ //# sourceMappingURL=resize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resize.d.ts","sourceRoot":"","sources":["../../src/diff/resize.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,MAAM,WAAW,eAAe;IAC9B,kBAAkB,EAAE,iBAAiB,CAAC;IACtC,mBAAmB,EAAE,iBAAiB,CAAC;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,YAAY,CAAC;CAC5B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,UAAU,GAAG,iBAAiB,EACxC,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,SAAS,EAAE,UAAU,GAAG,iBAAiB,EACzC,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,GAC7B,eAAe,CA0EjB"}