visual-regression-engine
v1.0.1
Published
A modular visual comparison engine for Processing and p5.js regression testing
Downloads
14
Maintainers
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-engineQuick 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
