Seeing what your agent broke.
npm i usephantomPhantom takes a snapshot of your DOM before an AI agent makes changes, then another after. It diffs every element's position, size, color, text, and styles, and renders ghost overlays showing exactly what moved, what broke, and what changed.
Live demo
Click "Snapshot" to capture the before state. Then click "Agent edit" to simulate changes. Phantom shows the diff.
Monthly Revenue
$124,500 — up 12%
Active Users
8,241 daily active
Seven diff types
Every change gets classified with severity (low/medium/high) based on visual impact:
Four overlay modes
Output
Four detail levels. The same diff rendered at each level:
Install
npm install usephantom -D
import { Phantom } from 'usephantom' function App() { return ( <> <YourApp /> {process.env.NODE_ENV === "development" && <Phantom />} </> ) }
- React 18+ — uses modern React features
- Client-side only — requires DOM access
- Zero dependencies — no runtime deps beyond React
- ~6.6kb gzipped — tree-shakeable ESM and CJS
Props
All optional. Works with zero configuration.
enabled | Enable/disable (default: true) |
mode | "ghost" | "heatmap" | "outline" | "xray" |
detail | "compact" | "standard" | "detailed" | "forensic" |
autoInterval | Auto-snapshot interval in ms (0 = manual) |
root | Scope selector (default: "body") |
ignore | Selectors to skip (default: []) |
moveThreshold | Min px to report as moved (default: 2) |
resizeThreshold | Min px to report as resized (default: 2) |
color | Accent color (default: "#a855f7") |
toolbar | Show toolbar (default: true) |
position | Toolbar corner (default: "bottom-right") |
onDiff | Called when diff computed (receives DiffResult) |
onCopy | Called when copied (receives markdown) |
onSnapshot | Called when snapshot taken (receives PageSnapshot) |
badge | Show diff count badge (default: true) |
shortcut | Snapshot shortcut (default: "ctrl+shift+p") |
className | Custom class for overlay |
Types
type DiffType = 'moved' | 'resized' | 'recolored' | 'added' | 'removed' | 'text-changed' | 'style-changed' type DiffEntry = { type: DiffType; selector: string; tag: string description: string; severity: 'low'|'medium'|'high' before: Partial<ElementSnapshot> | null after: Partial<ElementSnapshot> | null distance?: number; sizeDelta?: { width; height } } type DiffResult = { before: PageSnapshot; after: PageSnapshot entries: DiffEntry[] summary: { total; moved; resized; recolored; added; removed; ... } } type OverlayMode = 'ghost' | 'heatmap' | 'outline' | 'xray' type OutputDetail = 'compact' | 'standard' | 'detailed' | 'forensic'
Programmatic API
import { takeSnapshot, computeDiff, formatDiffMarkdown } from 'usephantom' // Capture before state const before = takeSnapshot() // ... agent makes changes ... // Capture after state const after = takeSnapshot() // Compute diff const diff = computeDiff(before, after) // → { entries: [...], summary: { total: 4, moved: 1, ... } } // Generate markdown const md = formatDiffMarkdown(diff, 'detailed') // → "# Phantom Diff Report\n4 changes detected..."
Exports: Phantom, takeSnapshot, computeDiff, formatDiffMarkdown, formatSummaryLine, DiffOverlay
Type exports: PhantomProps, PhantomState, PageSnapshot, ElementSnapshot, DOMRectData, StyleData, DiffResult, DiffEntry, DiffType, OverlayMode, OutputDetail
Keyboard shortcuts
| Ctrl+Shift+P | Take snapshot / compare |
| Esc | Close overlay |
~6.6kb gzipped · zero dependencies · React 18+ · MIT