New:Socket for Asana Is Now Available.Learn more
Get Started

@tyroneross/interface-built-right

Package Overview
Dependencies
Maintainers
1
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@tyroneross/interface-built-right

Visual regression testing for Claude Code - capture baselines, compare changes, iterate automatically

Source
npmnpm
Version
0.4.5
Version published
Weekly downloads
30
-48.28%
Maintainers
1
Weekly downloads
 
Created
Source

interface-built-right

Visual regression testing for Claude Code. Capture baselines, compare changes, iterate automatically.

Quick Start

One-Line Comparison (Programmatic)

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);
}

CLI Workflow

# 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.

Installation

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.

CLI Commands

CommandDescription
npx ibr start <url>Capture baseline screenshot
npx ibr check [sessionId]Compare current state against baseline
npx ibr serveOpen web UI at localhost:4200
npx ibr listList all sessions
npx ibr update [sessionId]Update baseline with current screenshot
npx ibr clean --older-than 7dClean old sessions
npx ibr login <url>Save auth state for protected pages
npx ibr logoutClear saved auth state

Interactive Session Commands

For step-by-step UI testing:

CommandDescription
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> --submitType 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)

Workflow Example

# 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

Authenticated Pages

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 state is stored per-user (auth.{username}.json)
  • 7-day expiration with auto-cleanup
  • Blocked in CI/CD and deployed environments
  • Add .ibr/ to your .gitignore

Claude Code Plugin

Add to your project's .claude/settings.json:

{
  "plugins": [
    "node_modules/interface-built-right/plugin"
  ]
}

Then restart Claude Code. You'll have these commands:

CommandDescription
/ibr:uiLaunch web UI dashboard
/ibr:snapshotCapture baseline (prompts for URL)
/ibr:compareCompare against baseline

Programmatic API

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');

Session-Based Workflow

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();

Dynamic Content Masking

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
  },
});

Configuration

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
  }
}

Retention Policy

Automatic session cleanup prevents accumulation of old sessions:

OptionDescription
maxSessionsKeep only the N most recent sessions
maxAgeDaysDelete sessions older than N days
keepFailedPreserve sessions with LAYOUT_BROKEN or UNEXPECTED_CHANGE verdicts
autoCleanRun cleanup automatically when creating new sessions
# Manual cleanup
npx ibr clean --older-than 7d
npx ibr clean --keep-last 20

Comparison Report

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 intentional
  • UNEXPECTED_CHANGE - Changes in unexpected areas
  • LAYOUT_BROKEN - Significant structural issues

File Structure

Sessions 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

Troubleshooting

"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

Requirements

  • Node.js 18+
  • Playwright (installed automatically)

License

MIT

Keywords

visual-regression

FAQs

Package last updated on 01 Feb 2026

Related posts