Package Exports
- visual-regression-engine
- visual-regression-engine/src/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (visual-regression-engine) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
Visual Regression Engine
A modular visual comparison engine specifically designed for Processing and p5.js regression testing. This engine provides advanced clustering analysis to detect significant visual differences while filtering out minor rendering variations.
Features
- 🎨 Creative Coding Focused: Built specifically for Processing and p5.js visual testing
- 🔍 Smart Difference Detection: Advanced clustering analysis to distinguish significant changes from noise
- 📏 Configurable Thresholds: Customizable sensitivity and tolerance settings
- 🚀 High Performance: Efficient image processing with optimized algorithms
- 🧩 Modular Architecture: Clean, extensible codebase with separate concerns
- 📊 Detailed Analytics: Comprehensive reporting on detected differences
Installation
npm install visual-regression-engine
Quick Start
const VisualComparisonEngine = require('visual-regression-engine');
const { loadImage } = require('canvas');
const engine = new VisualComparisonEngine({
threshold: 0.1, // Pixel difference threshold (0-1)
maxTotalDiffPixels: 100, // Maximum allowed different pixels
minClusterSize: 5, // Minimum cluster size to be considered significant
maxSignificantClusters: 3, // Maximum allowed significant clusters
maxSide: 800, // Resize images to max dimension
backgroundColor: [255, 255, 255, 255] // Background color for standardization
});
async function compareImages() {
const actualImage = await loadImage('path/to/actual.png');
const expectedImage = await loadImage('path/to/expected.png');
const result = await engine.compare(actualImage, expectedImage);
if (result.ok) {
console.log('✅ Images match within tolerance');
} else {
console.log('❌ Images differ significantly');
console.log(`Total different pixels: ${result.diffCount}`);
console.log(`Significant different pixels: ${result.details.significantDiffPixels}`);
console.log(`Significant clusters: ${result.details.analysis.significantClusters}`);
}
}
compareImages();
API Reference
VisualComparisonEngine
Constructor Options
Option | Type | Default | Description |
---|---|---|---|
threshold |
number | 0.1 | Pixel color difference threshold (0-1) |
maxTotalDiffPixels |
number | 100 | Maximum allowed different pixels for test to pass |
minClusterSize |
number | 5 | Minimum cluster size to be considered significant |
maxSignificantClusters |
number | 3 | Maximum allowed significant clusters |
maxSide |
number | 800 | Maximum dimension for image resizing |
backgroundColor |
array | [255,255,255,255] | RGBA background color |
includeAA |
boolean | false | Include anti-aliasing differences |
alpha |
number | 0.1 | Alpha threshold for transparency |
lineShiftThreshold |
number | 0.8 | Threshold for detecting line shifts |
Methods
compare(actualImage, expectedImage, options?)
Compares two images and returns a detailed analysis.
Parameters:
actualImage
- Image object, Canvas, Buffer, or ImageDataexpectedImage
- Image object, Canvas, Buffer, or ImageDataoptions
- Optional override options for this comparison
Returns: Promise
{
ok: boolean, // Whether images match within tolerance
diffCount: number, // Total number of different pixels
diffImageData: ImageData, // Visual diff highlighting differences
details: {
totalDiffPixels: number, // Same as diffCount
significantDiffPixels: number,// Pixels in significant clusters only
clusters: Array, // Array of detected clusters
analysis: { // Detailed cluster analysis
clusters: Array,
significantClusters: number,
significantPixels: number,
totalClusters: number
}
}
}
Advanced Usage
Folder Comparison
const VisualComparisonEngine = require('visual-regression-engine');
const { loadImage, createCanvas } = require('canvas');
const fs = require('fs').promises;
const path = require('path');
class TestSuite {
constructor() {
this.engine = new VisualComparisonEngine({
threshold: 0.1,
maxTotalDiffPixels: 50,
minClusterSize: 4,
});
}
async runTests() {
const referenceDir = './test/reference';
const actualDir = './test/actual';
const diffOutputDir = './test/diff-output';
await fs.mkdir(diffOutputDir, { recursive: true });
const files = await fs.readdir(referenceDir);
const results = [];
for (const file of files.filter(f => /\.(png|jpg)$/i.test(f))) {
const refImage = await loadImage(path.join(referenceDir, file));
const actualImage = await loadImage(path.join(actualDir, file));
const result = await this.engine.compare(refImage, actualImage);
results.push({ file, ...result });
if (!result.ok) {
await this.saveDiffImage(result.diffImageData,
path.join(diffOutputDir, `diff-${file}`));
}
}
return results;
}
async saveDiffImage(imageData, outputPath) {
const canvas = createCanvas(imageData.width, imageData.height);
const ctx = canvas.getContext('2d');
ctx.putImageData(imageData, 0, 0);
const buffer = canvas.toBuffer('image/png');
await fs.writeFile(outputPath, buffer);
}
}
Custom Configuration for Different Test Types
// High precision for critical UI elements
const strictEngine = new VisualComparisonEngine({
threshold: 0.05,
maxTotalDiffPixels: 10,
minClusterSize: 2
});
// Relaxed settings for creative/generative content
const creativeEngine = new VisualComparisonEngine({
threshold: 0.2,
maxTotalDiffPixels: 500,
minClusterSize: 10,
lineShiftThreshold: 0.9 // More tolerant of line shifts
});
Understanding the Results
Cluster Analysis
The engine groups different pixels into clusters and analyzes their significance:
- Line Shifts: Detected when >80% of pixels in a cluster have ≤2 neighbors (indicates text/line movement)
- Significant Clusters: Clusters that meet the minimum size requirement and aren't classified as line shifts
- Total vs Significant Pixels: Total includes all different pixels; significant only includes those in meaningful clusters
Typical Workflow
- Set appropriate thresholds based on your content type
- Run initial comparison to understand difference patterns
- Adjust settings based on false positives/negatives
- Integrate into CI/CD pipeline for automated testing
Contributing
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature
- Commit changes:
git commit -m 'Add amazing feature'
- Push to branch:
git push origin feature/amazing-feature
- Open a Pull Request
License
This project is licensed under the MIT License - see the LICENSE file for details.
Changelog
v1.0.0
- Initial release
- Core comparison engine with clustering analysis
- Support for multiple image formats
- Configurable thresholds and options