A Claude Code plugin that does a zero-tolerance audit-and-fix pass over your project: visual polish first, code quality second.
Born from a real session of building a terminal UI, where "close enough" kept not being close enough:
the % label that resizes its whole column when it ticks from 9% to 13%,
the glyph that can never truly center over an even-width bar,
the controls that drift one cell the moment a progress bar appears.
This plugin hunts exactly that class of bug, and fixes it instead of listing it.
The hard rule behind all of it: measurements, not impressions. Render it, count the cells, fix the root cause, re-measure.
- Inventory every screen and state the UI can render
- Render and measure - browser screenshot, char-frame dump, test render; never judge alignment from source
- Simulate the states - empty vs full, 0% vs 100%, shortest vs longest string; layout bugs live in the transitions
- Fix the root cause - one guard in the shared function, not a patch at the call site
- Re-measure - a fix is not done until rendered again
- Report - terse table, no essays
Visual invariants (measured against rendered output, never eyeballed from source):
- Alignment to computed anchor columns, not hardcoded offsets
- Layout shift across every dynamic state (empty vs full, 0% vs 100%, first vs last selection)
- Centering parity: odd-over-odd, manual padding, no trust in flexbox rounding
- Spacing hierarchy vs dead space
- One separator glyph, one prefix style, stable color roles
- Animations that use their full range, with floor-and-ceiling normalization for live data
Code invariants:
- Root cause over symptom: trace the callers, fix the shared function
- Reuse before writing, smallest correct diff
- Tests and typecheck green, one runnable check for new logic
- No dead code, stale comments, or debug residue
Fair skepticism: a strong model already fixes plenty of UI bugs on its own. So the skill was A/B tested - the same audit run with it and without it, scored by a script that renders the output and measures pixels, not by opinion.
The headline result is on the exact bug class this plugin exists for: a layout shift that only appears in a state the default view never shows. An agent is handed a toolbar and told only "audit this" - the bug is never named - across 8 trials per condition:
- Without the skill: 0/8 found it. Every run fixed a different, visible issue (the buttons' font) and never simulated the changing count, so the shift sailed through.
- With the skill: 8/8 found it. Its "simulate every state" rule renders the count at 3 and at 9999, sees the buttons drift, and reserves the width.
That is the skill doing the one thing a fast read cannot: catching the bug you only see when you render a state that isn't on screen.
Honest scope, because the same study measured it: when a bug is named, visible on sight, or readable in the source - even buried in a real, heavy landing page - a strong base model already fixes it, and the skill adds no correctness there while costing 2-3x more tokens.
Its edge is specifically the source-invisible, state-dependent bug.
Full write-up, all five rounds, both render-and-measure scorers, and every number including the ties: eval/ablation.
As a plugin (recommended, gets updates):
/plugin marketplace add undeemed/ocd
/plugin install ocd@ocd
Or as a standalone skill:
git clone --depth 1 https://github.com/undeemed/ocd /tmp/ocd && cp -r /tmp/ocd/skills/ocd ~/.claude/skills/ocd/ocd
Or just complain naturally: "this is triggering my OCD", "the arrows aren't aligned", "something shifted". The description is written to trigger on those.
It ends every run with a terse report:
FIXED
src/ui/progress.tsx:41 - label resizes column at 100% - padded to fixed 4-char width
src/ui/panel.tsx:12 - header centers against variable content - centered in fixed box
CLEAN
empty/full lists, 0%/100%, first/last selection, separators, color roles
The companion skill for visual verification.
The natural move after changing a button is to screenshot the button - a frame in which nothing can be verified, because alignment and spacing are relations to siblings and the crop deleted the siblings.
/wideshot computes the meaningful container (control pane, toolbar, table, modal) with a landmark-walking heuristic and screenshots that instead:
- changed a control button -> shoots the whole control pane
- changed a table cell -> the table
- changed a nav link -> the nav bar
It uses whatever browser tooling the session already has, or falls back to a bundled ~50-line puppeteer-core script that reuses your installed Chrome (no browser download, <2s per shot).
The heuristic handles shadow DOM, inner scroll containers, display:contents, and position:fixed, and returns why it picked the frame.
Those handling claims are backed by an eval + bench, not just prose - fittingly, given the skill's own "measurements, not impressions" rule.
The suite lives in skills/wideshot/scripts/test (12 correctness cases in real headless Chrome, plus a perf bench): npm test, npm run bench.
The heuristic is a container-selection step that runs before a screenshot, so the fair comparison is against the framing other tools give you. Measured on one engine (puppeteer-core + Chrome), same page and target, so the only variable is what gets framed (Apple M5, arm64 - ratios matter, not absolute ms):
| framing strategy | time (median) | output | note |
|---|---|---|---|
element-only (Playwright / shot-scraper / capture-website --element) |
25.1 ms | 40 x 30 px | no siblings -> alignment/shift unverifiable |
| wideshot | 24.5 ms | 920 x 50 px | frames the pane, same speed as element-only |
| full-page | 41.9 ms | 1280 x 4400 px | captures everything, 1.7x slower, unfocused |
The heuristic itself adds < 0.1 ms (p95), below the performance.now() floor.
So wideshot costs the same as a plain element shot but returns a frame you can actually verify in - where element-only deleted the siblings and full-page buried the change.
Every other tool screenshots exactly the selector you hand it or the whole page; only wideshot walks to the meaningful container.
Full matrix and how-to in the eval README.
.claude-plugin/
plugin.json plugin manifest
marketplace.json lets `/plugin marketplace add undeemed/ocd` work
skills/
ocd/SKILL.md the audit-and-fix pass
wideshot/SKILL.md context-framed screenshots for visual verification
wideshot/scripts/ container heuristic + fallback capture tool
wideshot/scripts/test/ eval (12 cases) + perf bench for the heuristic
Skills under skills/ are auto-discovered by the plugin.
To add one, create skills/<name>/SKILL.md with name and description frontmatter - nothing to register.
Agents (agents/*.md), commands (commands/*.md), and hooks (declared in plugin.json) slot in the same way when needed.
New invariants and verification tricks welcome - see CONTRIBUTING.md. Scope stays narrow on purpose: audit-and-fix passes only.
MIT
