npx skills add ...
npx skills add osmontero/opencode-skills --skill reviewing-interface-quality
Use when asked to review, critique, audit, or improve an existing user interface — "review this UI", "why does this look generic", "make this more polished", "design feedback", "does this look AI-generated", "audit this page". Also use as the final gate before shipping any frontend work, and when a UI renders correctly but feels unfinished, cheap, or inconsistent without an obvious cause.
npx skills add osmontero/opencode-skills --skill reviewing-interface-quality
"Make it look better" is not actionable. Interface quality problems have specific causes — an unenforced spacing scale, hierarchy varying on four dimensions at once, a state that was never designed — and a review is only useful if it names the cause and the fix.
Core principle: Every finding names a location, a cause, and a concrete replacement value. "The spacing feels off" is not a finding. ".card uses padding: 14px while everything else uses the 8px scale — change to var(--space-s)" is.
Companion skills: designing-frontend-interfaces (visual), designing-user-experience (behavior), building-accessible-interfaces (access). This skill audits against all three.
Reviewing an interface means looking at it. Reading the source and inferring how it renders is not a review — it misses exactly the class of defect a review exists to catch: overflow, collapsed layouts, invisible text, layout shift, broken states.
Minimum evidence before writing a single finding: a screenshot at 1440px, a screenshot at 390px, and the computed values for anything you are about to call inconsistent.
Then read both screenshots. The distinct-value counts tell you where the system broke; the screenshots tell you what it looks like. You need both.
For a server-backed app, wrap this with testing-webapps/scripts/with_server.py.
If the UI genuinely cannot be rendered (no runtime, a fragment, a component in isolation), say so explicitly in the report and mark every visual finding PLAUSIBLE rather than CONFIRMED.
Look at the desktop screenshot for five seconds and answer before analyzing anything:
Write these answers down before proceeding. Once you start auditing details you cannot recover the naive read, and it is the read every real user has.
Highest yield. Most "looks unpolished" comes from here, and every finding is objective.
| Check | Threshold | Common cause |
|---|---|---|
Distinct font-size values | > 8 | Sizes chosen ad hoc, no ratio scale |
Distinct font-family values | > 3 | Third face crept in, or a fallback resolving differently |
Distinct border-radius values | > 2 | Mixed radii — the loudest amateur signal |
Distinct box-shadow values | > 3 | A new shadow invented per component |
| Padding values off the space scale | any | Raw px instead of tokens |
Distinct grays in color | > 5 | No ink ramp; each component picked its own |
| Accent color surface area | > 10% | Accent used as decoration rather than emphasis |
Also check: are design tokens declared but not used? A :root block with a beautiful scale and components full of raw px is a very common and very fixable finding.
tabular-numstext-wrap: balancewidth/height or aspect-ratio — no layout shift100dvh/100svh rather than 100vhCheck each against designing-user-experience. These are usually missing, not wrong — so audit the code, not just the render.
type, inputmode, autocompleteRun the automated scan, then the keyboard walk. Full detail in building-accessible-interfaces.
outline: none never appears without a replacementalt (empty for decorative)<h1>; no skipped heading levels<main>, <nav>, <header> landmarks presentprefers-reduced-motion block existstransform/opacity/filter animated — no width/height/top/lefttransition: allfont-display: swap and a metric-matched fallbackOrder findings by severity. Every finding carries a location, a cause, and a fix.
| Severity | Definition |
|---|---|
| Critical | Unusable for some users, or data loss. Keyboard traps, removed focus, failing contrast on body text, form clearing on error, horizontal overflow on mobile. |
| Important | Visibly degrades quality or blocks a real task. Inconsistent system values, missing states, unreadable measure, missing error recovery. |
| Minor | Polish. Orphaned words, a slightly-off duration, a shadow that could be tighter. |
Do not pad the report. Five real findings beat twenty that mix a keyboard trap with a 2px alignment nit — the padding buries the trap.
Reviewing the code instead of the interface. The defects a review exists to catch are the ones only visible when rendered.
"Feels off" findings. If you cannot name the cause, keep looking. Every quality problem has a mechanical cause.
Desktop only. Most defects appear at 390px. Both widths, always.
Redesigning instead of reviewing. "Rebuild this as a dashboard" is not a finding. Fix what exists unless the direction itself is the problem — and if it is, say so once, as a single top-level finding.
Severity inflation. Calling everything Critical means nothing is. Reserve it for genuinely broken.
Listing violations without fixes. "Contrast fails" is half a finding. "--ink-3 #8b857c on --base #f4f1ea is 2.9:1; darken to #6b6459 for 4.5:1" is a whole one.
Skipping the first impression. Once you are three passes deep you cannot recover the naive read, and it is the only read most users get.
# Fast static pass over source
grep -rEo '(padding|margin|gap|font-size):[^;]+' src/ | grep -E '[0-9]+px' | sort | uniq -c | sort -rn
grep -rEo 'border-radius:[^;]+' src/ | sort | uniq -cnpx @axe-core/cli http://localhost:5173 --exit## First Impression
[The 5 answers from Step 2 — the naive read, verbatim]
## Evidence
Rendered at 1440×900 and 390×844. 34 distinct font-sizes, 6 border-radii,
9 box-shadows. 2 console errors. 1 horizontal overflow.
## Critical — breaks the interface for some users
**Focus indicator removed globally**
`src/styles/base.css:12` — `*:focus { outline: none }` with no replacement.
Keyboard users cannot tell where they are; WCAG 2.4.7 failure.
Fix: delete it, add `:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px }`.
## Important — visibly degrades quality
**Spacing scale not enforced**
17 distinct padding values including `14px`, `18px`, `22px` (`Card.tsx:8`,
`Panel.tsx:22`, `Modal.tsx:41`). Tokens exist in `:root` but are unused, so
nothing aligns to a common rhythm.
Fix: replace every raw px with the nearest `--space-*` token.
## Minor — polish
**Headings orphan their last word**
`h2` in `Hero.tsx:14` wraps "started" alone onto line 2 at 1440px.
Fix: add `text-wrap: balance`.
## Strengths
[Specific, not flattery. "The type pairing carries the direction" — not "looks good".]
## Verdict
Ship / Ship with the Critical items fixed / Needs rework — plus one sentence of reasoning.