
Product
Microsoft Teams Notifications Are Now Available in Socket
Socket can now send alerts and supply chain attack notifications to Microsoft Teams, with filters that route the right updates to each channel.
@tyroneross/interface-built-right
Advanced tools
Visual regression testing for Claude Code - capture baselines, compare changes, iterate automatically
Visual regression testing for Claude Code. Capture baselines, compare changes, iterate automatically.
import { compare } from '@tyroneross/interface-built-right';
const result = await compare({
url: 'http://localhost:3000/dashboard',
baselinePath: './baselines/dashboard.png',
});
if (result.verdict !== 'MATCH') {
console.log('Visual changes detected:', result.summary);
}
# 1. Install
npm install github:tyroneross/interface-built-right
# 2. Capture baseline of your app
npx ibr start http://localhost:3000/dashboard --name my-feature
# 3. Make UI changes...
# 4. Compare against baseline
npx ibr check
# 5. View visual diff in browser
npx ibr serve
When to use IBR vs Playwright? See WHEN-TO-USE.md for guidance.
From GitHub:
npm install github:tyroneross/interface-built-right
From local path:
npm install /path/to/interface-built-right
After install, verify it works:
npx ibr --help
Add .ibr/ to your .gitignore:
echo ".ibr/" >> .gitignore
IBR stores sessions, screenshots, and browser state in .ibr/. This folder should not be committed.
| Command | Description |
|---|---|
npx ibr start <url> | Capture baseline screenshot |
npx ibr check [sessionId] | Compare current state against baseline |
npx ibr serve | Open web UI at localhost:4200 |
npx ibr list | List all sessions |
npx ibr update [sessionId] | Update baseline with current screenshot |
npx ibr clean --older-than 7d | Clean old sessions |
npx ibr login <url> | Save auth state for protected pages |
npx ibr logout | Clear saved auth state |
For step-by-step UI testing:
| Command | Description |
|---|---|
npx ibr session:start <url> | Start interactive browser session |
npx ibr session:click <id> <selector> | Click an element |
npx ibr session:type <id> <selector> <text> | Type into an element |
npx ibr session:type <id> <selector> <text> --submit | Type and press Enter |
npx ibr session:press <id> <key> | Press keyboard key (Enter, Tab, Escape, etc.) |
npx ibr session:screenshot <id> | Take screenshot and audit elements |
npx ibr session:navigate <id> <url> | Navigate to new URL |
npx ibr session:wait <id> <selectorOrMs> | Wait for element or duration |
npx ibr session:close <id> | Close session (use "all" to stop server) |
# 1. Start your app
cd my-app && npm run dev # → localhost:3000
# 2. Capture baseline before making changes
npx ibr start http://localhost:3000/settings --name settings-redesign
# → Session started: sess_Hk8mN2pQ
# 3. Make your UI changes (edit components, styles, etc.)
# 4. Compare against baseline
npx ibr check
# → Shows diff percentage and verdict
# 5. View in web UI
npx ibr serve
# → Opens http://localhost:4200 with side-by-side comparison
# 6. If changes look good, update baseline
npx ibr update
For pages behind login:
# 1. Save auth state (opens browser for manual login)
npx ibr login http://localhost:3000/login
# → Log in manually, then close browser
# 2. Now captures will use your auth session
npx ibr start http://localhost:3000/dashboard
# → 🔐 Using saved authentication state
# 3. Clear auth when done
npx ibr logout
Security notes:
auth.{username}.json).ibr/ to your .gitignoreAdd to your project's .claude/settings.json:
{
"plugins": [
"node_modules/interface-built-right/plugin"
]
}
Then restart Claude Code. You'll have these commands:
| Command | Description |
|---|---|
/ibr:ui | Launch web UI dashboard |
/ibr:snapshot | Capture baseline (prompts for URL) |
/ibr:compare | Compare against baseline |
import { compare, compareAll } from '@tyroneross/interface-built-right';
// Simple one-line comparison
const result = await compare({
url: 'http://localhost:3000/dashboard',
baselinePath: './baselines/dashboard.png',
});
console.log(result.verdict);
// → "MATCH" | "EXPECTED_CHANGE" | "UNEXPECTED_CHANGE" | "LAYOUT_BROKEN"
console.log(result.diffPercent); // e.g., 2.5
console.log(result.summary); // Human-readable description
// Compare two existing images
const result2 = await compare({
baselinePath: './baselines/old.png',
currentPath: './screenshots/new.png',
});
// Batch comparison of all sessions
const results = await compareAll('./.ibr');
import { InterfaceBuiltRight } from '@tyroneross/interface-built-right';
const ibr = new InterfaceBuiltRight({
baseUrl: 'http://localhost:3000',
outputDir: './.ibr',
threshold: 1.0, // % diff allowed
});
// Capture baseline
const { sessionId } = await ibr.startSession('/dashboard', {
name: 'dashboard-update',
});
// After making changes, compare
const report = await ibr.check(sessionId);
console.log(report.analysis.verdict);
// → "MATCH" | "EXPECTED_CHANGE" | "UNEXPECTED_CHANGE" | "LAYOUT_BROKEN"
// Cleanup
await ibr.close();
Hide timestamps, spinners, and other dynamic content for stable comparisons:
const result = await compare({
url: 'http://localhost:3000/dashboard',
baselinePath: './baselines/dashboard.png',
mask: {
hideDynamicContent: true, // Auto-hide timestamps, loaders, etc.
selectors: ['[data-testid="live-count"]'], // Additional elements
hideAnimations: true, // Default: true
},
});
Create .ibrrc.json in your project root:
{
"baseUrl": "http://localhost:3000",
"outputDir": "./.ibr",
"viewport": "desktop",
"threshold": 1.0,
"fullPage": true,
"retention": {
"maxSessions": 20,
"maxAgeDays": 7,
"keepFailed": true,
"autoClean": true
}
}
Automatic session cleanup prevents accumulation of old sessions:
| Option | Description |
|---|---|
maxSessions | Keep only the N most recent sessions |
maxAgeDays | Delete sessions older than N days |
keepFailed | Preserve sessions with LAYOUT_BROKEN or UNEXPECTED_CHANGE verdicts |
autoClean | Run cleanup automatically when creating new sessions |
# Manual cleanup
npx ibr clean --older-than 7d
npx ibr clean --keep-last 20
Reports are structured for Claude to read and act on:
{
"sessionId": "sess_abc123",
"comparison": {
"match": false,
"diffPercent": 8.2,
"diffPixels": 6560
},
"analysis": {
"verdict": "EXPECTED_CHANGE",
"summary": "Header background changed. Layout intact."
}
}
Verdicts:
MATCH - No visual changes (within threshold)EXPECTED_CHANGE - Changes detected, appear intentionalUNEXPECTED_CHANGE - Changes in unexpected areasLAYOUT_BROKEN - Significant structural issuesSessions are stored in .ibr/sessions/:
.ibr/
├── auth.{username}.json # Auth state (per-user)
└── sessions/
└── sess_abc123/
├── session.json # Session metadata
├── baseline.png # Original screenshot
├── current.png # After-changes screenshot
└── diff.png # Visual diff
"Command not found: ibr"
# Use npx or run from source
npx ibr --help
# OR
npm run ibr -- --help
"Playwright browsers not installed"
npx playwright install chromium
"Auth state expired"
npx ibr login http://localhost:3000/login
"Session not found"
# List available sessions
npx ibr list
MIT
FAQs
End-to-end design tool for AI coding agents. Guided UI builds, iOS/macOS/web design guidance, Calm Precision principles, visual validation, interaction testing, mockup matching, cross-browser. Custom CDP engine.
The npm package @tyroneross/interface-built-right receives a total of 29 weekly downloads. As such, @tyroneross/interface-built-right popularity was classified as not popular.
We found that @tyroneross/interface-built-right demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Product
Socket can now send alerts and supply chain attack notifications to Microsoft Teams, with filters that route the right updates to each channel.

Security News
pnpm 12 rewrites the package manager in Rust, cutting install times by up to 90% while preserving pnpm 11 workflows and lockfiles.

Security News
Socket CTO Ahmad Nassri joins AppSec leaders at Black Hat to discuss active malware, package manager risks, and software supply chain defense.