ui-polish — make the UI look like a real team shipped it
When to use this skill
Trigger when the visual quality of an interface is the bottleneck. Strong signals:
- "make this look better", "polish this page", "improve the design", "this looks AI-generated"
- A screenshot in the conversation with the user pointing out spacing, alignment, or visual hierarchy issues
- A new component just landed and the user wants it to match the rest of the system
Do not trigger for: a11y-only requests (separate skill territory), pure animation work without a structural problem, or when the design system is locked and the user is asking you to break it.
The output contract
Code changes that pass this checklist:
- Type scale: at most 6 sizes in use, geometric ratio (e.g. 12, 14, 16, 20, 24, 32). No
font-size: 13px one-off.
- Spacing: every margin/padding/gap is a multiple of 4 (preferably 8). No
margin: 17px.
- Color: every color comes from a token (
color-bg-surface, color-text-muted) — not a raw hex inline.
- States covered: every interactive element has explicit
:hover, :focus-visible, :active, and :disabled. Forms have loading + error + empty + success.
- Density: deliberate. Marketing pages breathe. Dense data UIs are tight. Don't average.
- Motion: at most one purposeful transition per interaction (e.g. 150ms opacity on hover). No bouncy nonsense.
Workflow
1 — Diagnose before touching
Read the current component. Identify the actual problems, in priority order:
- Hierarchy: can the eye find the primary action in <1 second?
- Alignment: do edges line up? Is there a grid?
- Spacing: is there a rhythm, or are gaps random?
- Contrast: does text actually pass 4.5:1 against its background?
- States: what happens on hover, focus, disabled, loading, empty?
Name the top three problems out loud. Don't start editing until you can articulate what's wrong.
2 — Look at what already exists
- Is there a design system in the repo? (Tailwind config, shadcn/ui, Chakra, Radix, MUI?)
- What spacing scale is in
tailwind.config.{ts,js} or the equivalent? Use it. Don't introduce new tokens unless the user asks.
- What components already exist? Reuse
<Button> from the library before hand-rolling one.
3 — Apply the fixes in this order
- Structure first: get the layout grid and visual hierarchy right. Use flex/grid; remove ad-hoc margins.
- Spacing: replace every margin/padding with a token value. Use
gap on flex/grid containers instead of margins on children.
- Type: collapse every font size to the existing scale. Set deliberate weights — only
400, 500, 600, 700 unless the design system uses something else.
- Color: replace inline hex with tokens. If you need a new shade, add it to the config, don't sprinkle.
- States: add
:hover, :focus-visible, :disabled. Replace fade-in with a real loading skeleton or spinner. Add empty states with a one-line "why this is empty + the next action".
- Motion: one short transition per interaction.
transition: opacity 150ms ease is usually enough.
4 — Verify with the browser
If a dev server is running, use the preview tools (or Playwright via browser-qa) to:
- Screenshot the new state at desktop + mobile widths
- Tab through interactive elements and confirm focus rings are visible
- Hover over actionable items and confirm state change
Show the user the before/after screenshots. Don't just claim it looks better.
5 — Hand-off
Summarize what you changed in 5 bullets max:
- The structural fix (e.g. "switched to a 12-col grid")
- The spacing rule (e.g. "all margins now multiples of 8")
- The token usage (e.g. "replaced 6 inline hex with
color-text-* tokens")
- The new states (e.g. "added loading skeleton, empty state, error inline")
- Anything that should be promoted to the design system
Patterns and anti-patterns
✅ Do:
- Steal mercilessly from existing top-tier UIs. Linear, Vercel, Stripe, Notion — study their spacing rhythm before inventing your own.
- Default to a single accent color. Two is brave. Three is a brand crisis.
- Use
outline-offset: 2px for focus rings; never set outline: none without a replacement.
- Match line-height to font size: body 1.5x, headings 1.2x.
❌ Don't:
- Don't add shadows to fix unclear hierarchy. Fix the hierarchy.
- Don't use
transition: all. Be explicit about what animates.
- Don't reach for new fonts. The existing one almost always works with better weight + spacing choices.
- Don't center-align everything. Left-align body copy. Always.
Example invocation
User pastes a screenshot of a dashboard card: "this looks like AI slop, make it look good"
- Diagnose: hierarchy is flat (label, value, delta are all the same weight), gaps are random (12, 17, 20px), the chart has no axis labels, focus state is missing on the time-range toggle.
- Check repo — uses Tailwind with a custom scale. Spacing tokens: 1, 2, 3, 4, 6, 8, 12.
- Restructure: bigger weight on the metric value (font-semibold, text-3xl), smaller muted label above (text-xs, text-muted-foreground, uppercase tracking-wide).
- Normalize: all gaps to
gap-2 (8px) inside the card, gap-6 (24px) between cards.
- Add chart axis labels with the muted color token; add
:focus-visible ring to the time-range button.
- Add a loading skeleton (one shimmer line at the right height) for when the metric is fetching.
- Show the user before/after, list the 5 changes.
See also
code-auditor — for finding hard-coded magic numbers and inline styles at scale
browser-qa — to verify the polished UI doesn't break the user flows
refactor-master — when polishing reveals that the component needs to be split
1---2name: ui-polish3description: Upgrade a generic-looking UI into something a design-conscious team would ship. Enforces a real type scale, an 8-point spacing grid, semantic color tokens, full interaction states (hover/focus/disabled/loading/empty/error), and tasteful motion. Use when the user says "make this look good", "polish the UI", "improve the design", "this looks like AI slop", "make it look professional", or pastes a screenshot and says it looks off.4---56# ui-polish — make the UI look like a real team shipped it78## When to use this skill910Trigger when the visual quality of an interface is the bottleneck. Strong signals:1112- "make this look better", "polish this page", "improve the design", "this looks AI-generated"13- A screenshot in the conversation with the user pointing out spacing, alignment, or visual hierarchy issues14- A new component just landed and the user wants it to match the rest of the system1516Do *not* trigger for: a11y-only requests (separate skill territory), pure animation work without a structural problem, or when the design system is locked and the user is asking you to *break* it.1718## The output contract1920Code changes that pass this checklist:21221. **Type scale**: at most 6 sizes in use, geometric ratio (e.g. 12, 14, 16, 20, 24, 32). No `font-size: 13px` one-off.232. **Spacing**: every margin/padding/gap is a multiple of 4 (preferably 8). No `margin: 17px`.243. **Color**: every color comes from a token (`color-bg-surface`, `color-text-muted`) — not a raw hex inline.254. **States covered**: every interactive element has explicit `:hover`, `:focus-visible`, `:active`, and `:disabled`. Forms have loading + error + empty + success.265. **Density**: deliberate. Marketing pages breathe. Dense data UIs are tight. Don't average.276. **Motion**: at most one purposeful transition per interaction (e.g. 150ms opacity on hover). No bouncy nonsense.2829## Workflow3031### 1 — Diagnose before touching3233Read the current component. Identify the actual problems, in priority order:3435- **Hierarchy**: can the eye find the primary action in <1 second?36- **Alignment**: do edges line up? Is there a grid?37- **Spacing**: is there a rhythm, or are gaps random?38- **Contrast**: does text actually pass 4.5:1 against its background?39- **States**: what happens on hover, focus, disabled, loading, empty?4041Name the top three problems out loud. Don't start editing until you can articulate what's wrong.4243### 2 — Look at what already exists4445- Is there a design system in the repo? (Tailwind config, shadcn/ui, Chakra, Radix, MUI?)46- What spacing scale is in `tailwind.config.{ts,js}` or the equivalent? Use it. Don't introduce new tokens unless the user asks.47- What components already exist? Reuse `<Button>` from the library before hand-rolling one.4849### 3 — Apply the fixes in this order50511. **Structure first**: get the layout grid and visual hierarchy right. Use flex/grid; remove ad-hoc margins.522. **Spacing**: replace every margin/padding with a token value. Use `gap` on flex/grid containers instead of margins on children.533. **Type**: collapse every font size to the existing scale. Set deliberate weights — only `400`, `500`, `600`, `700` unless the design system uses something else.544. **Color**: replace inline hex with tokens. If you need a new shade, add it to the config, don't sprinkle.555. **States**: add `:hover`, `:focus-visible`, `:disabled`. Replace fade-in with a real loading skeleton or spinner. Add empty states with a one-line "why this is empty + the next action".566. **Motion**: one short transition per interaction. `transition: opacity 150ms ease` is usually enough.5758### 4 — Verify with the browser5960If a dev server is running, use the preview tools (or Playwright via `browser-qa`) to:61- Screenshot the new state at desktop + mobile widths62- Tab through interactive elements and confirm focus rings are visible63- Hover over actionable items and confirm state change6465Show the user the before/after screenshots. Don't just claim it looks better.6667### 5 — Hand-off6869Summarize what you changed in 5 bullets max:70- The structural fix (e.g. "switched to a 12-col grid")71- The spacing rule (e.g. "all margins now multiples of 8")72- The token usage (e.g. "replaced 6 inline hex with `color-text-*` tokens")73- The new states (e.g. "added loading skeleton, empty state, error inline")74- Anything that should be promoted to the design system7576## Patterns and anti-patterns7778✅ **Do**:79- Steal mercilessly from existing top-tier UIs. Linear, Vercel, Stripe, Notion — study their spacing rhythm before inventing your own.80- Default to a single accent color. Two is brave. Three is a brand crisis.81- Use `outline-offset: 2px` for focus rings; never set `outline: none` without a replacement.82- Match line-height to font size: body 1.5x, headings 1.2x.8384❌ **Don't**:85- Don't add shadows to fix unclear hierarchy. Fix the hierarchy.86- Don't use `transition: all`. Be explicit about what animates.87- Don't reach for new fonts. The existing one almost always works with better weight + spacing choices.88- Don't center-align everything. Left-align body copy. Always.8990## Example invocation9192> User pastes a screenshot of a dashboard card: "this looks like AI slop, make it look good"93941. Diagnose: hierarchy is flat (label, value, delta are all the same weight), gaps are random (12, 17, 20px), the chart has no axis labels, focus state is missing on the time-range toggle.952. Check repo — uses Tailwind with a custom scale. Spacing tokens: 1, 2, 3, 4, 6, 8, 12.963. Restructure: bigger weight on the metric value (font-semibold, text-3xl), smaller muted label above (text-xs, text-muted-foreground, uppercase tracking-wide).974. Normalize: all gaps to `gap-2` (8px) inside the card, `gap-6` (24px) between cards.985. Add chart axis labels with the muted color token; add `:focus-visible` ring to the time-range button.996. Add a loading skeleton (one shimmer line at the right height) for when the metric is fetching.1007. Show the user before/after, list the 5 changes.101102## See also103104- `code-auditor` — for finding hard-coded magic numbers and inline styles at scale105- `browser-qa` — to verify the polished UI doesn't break the user flows106- `refactor-master` — when polishing reveals that the component needs to be split