impeccable-design
Overview
Hard QA design review checklist consisting of 50 deterministic rules covering typography (T1-T10), color systems (C1-C12), layout constraints (L1-L11), component contracts (K1-K11), and micro-animations (A1-A8).
When to Use
Activate during the REVIEW phase of all frontend tasks as a strict visual and functional QA gate before marking UI work complete.
Rules & Patterns
Based on pbakaus/impeccable — deterministic detector rules for AI-generated frontend design.
Core Principle
Every model is trained on the same SaaS templates. Skip this guidance and you get the same handful of tells on every project. Impeccable eliminates them.
Role in the Pipeline
This skill acts as a QA-designer at the /review phase. ui-ux-pro is the planning guideline; impeccable-design is the hard checklist that runs before merge.
Anti-Pattern Rules
Typography (Rules T1–T10)
| Rule |
Anti-Pattern |
Correct Approach |
| T1 |
Using Inter for all text |
Use Inter for UI body, pair with a distinct display font for headings OR with JetBrains Mono for technical/number accents (premium SaaS pattern) |
| T2 |
Using Arial or Helvetica |
Use a curated Google Font pairing |
| T3 |
All text same weight |
Use weight contrast: 700 headings, 400 body, 500 labels |
| T4 |
Line height = 1 (tight) |
Body: 1.6–1.8, Headings: 1.1–1.3 |
| T5 |
No letter-spacing on caps |
Uppercase labels: letter-spacing: 0.08em (Tailwind: tracking-widest) |
| T6 |
Text too wide |
Max line length: 60–75 characters — use max-w-prose or max-w-[65ch] |
| T7 |
Monospace only for code |
Use tabular-nums Tailwind class for number tables and data grids |
| T8 |
Random font sizing |
Use a consistent modular scale (1.25× or 1.333×) — use Tailwind's text-* scale |
| T9 |
Body text too small |
Minimum text-sm (14px) for body, never smaller than 12px |
| T10 |
Bold everywhere |
Bold is for emphasis. Diluted if overused. |
Tailwind typography utilities:
text-balance — for headlines (prevents orphan words)
text-pretty — for body paragraphs (smart line-breaks)
tabular-nums — for numerical data tables
Color (Rules C1–C12)
| Rule |
Anti-Pattern |
Correct Approach |
| C1 |
Pure black #000 |
Tint toward brand: hsl(240, 10%, 4%) |
| C2 |
Pure white #fff for surfaces |
Near-white with warmth: hsl(40, 30%, 97%) |
| C3 |
Gray on colored background |
Check contrast — likely fails WCAG. Use white/dark |
| C4 |
Purple → Blue gradient |
Clichéd AI palette. Use brand-derived gradients |
| C5 |
Neon primary colors |
Neon = accent only, never primary surface or text |
| C6 |
Too many colors |
3 colors max: primary, neutral, semantic (success/error) |
| C7 |
All links same blue #0000EE |
Style links with brand color, preserve underline |
| C8 |
Disabled state = gray only |
Disabled: opacity-40 + cursor-not-allowed |
| C9 |
Success always green, Error always red |
Check brand conflicts. Use accessible variants |
| C10 |
Dark mode = inverted light mode |
Dark mode needs separate palette — use @layer base { .dark { ... } } |
| C11 |
No hover state change |
Hover: shift lightness 8–12%, add transition-colors duration-150 |
| C12 |
Brand color on dark surface loses identity |
Adjust saturation/lightness for dark bg context |
Layout & Spacing (Rules L1–L11)
| Rule |
Anti-Pattern |
Correct Approach |
| L1 |
Cards inside cards |
One level of card depth maximum |
| L2 |
Icon tile above every heading |
Use icons inline, in context, not decoratively above text |
| L3 |
Centered long paragraphs |
text-center max 2 lines only. Use text-pretty + left-align for body |
| L4 |
Inconsistent spacing |
Use Tailwind spacing utilities only. Never arbitrary values like gap-[17px] |
| L5 |
Zero whitespace between sections |
Sections need py-16 to py-24 breathing room |
| L6 |
Content touching edges |
Always px-4 minimum on mobile |
| L7 |
Same visual weight everywhere |
Use hierarchy: primary > secondary > tertiary zones |
| L8 |
Grid breaks on tablet |
Test at 768px. Use 4-col on tablet, 12-col on desktop |
| L9 |
Full-width everything |
Max content width: max-w-7xl centered |
| L10 |
Missing grid alignment |
Use CSS Grid or Tailwind grid — not absolute positioning |
| L11 |
Arbitrary high z-indexes |
NEVER use z-[999] or z-50 manually. Rely on DOM order + Radix/shadcn Portals which already handle modal elevation correctly |
| L12 |
Default Rhythm |
Break the 'Hero → 3 Features → CTA' structure. Build structurally diverse pages tailored to the content. |
| L13 |
Symmetric card grids everywhere |
Use asymmetric layouts (e.g., bento boxes, masonry, alternating left/right) to reduce the AI-generated feel. |
Components (Rules K1–K11)
| Rule |
Anti-Pattern |
Correct Approach |
| K1 |
Two filled buttons side-by-side |
<Button variant="default"> + <Button variant="outline"> or variant="ghost" |
| K2 |
Button without loading state |
Always add spinner + disabled during async actions |
| K3 |
Modal without backdrop blur |
shadcn <Dialog> handles this. Don't override with plain divs |
| K4 |
Empty states left blank |
Always design empty states: illustration + helpful message + primary CTA |
| K5 |
No skeleton screens |
Use <Skeleton> from shadcn for content areas, not just spinners |
| K6 |
Tooltip on click (not hover) |
Tooltips on hover, modals on click — use shadcn <Tooltip> + <Dialog> |
| K7 |
Dropdown without keyboard nav |
Use shadcn <DropdownMenu> — keyboard nav is built-in |
| K8 |
Table without row hover |
shadcn <TableRow> handles hover state automatically. Do not override it |
| K9 |
Building complex UI from scratch |
Check shadcn/ui first. If the component exists, generate the CLI command: npx shadcn@latest add dialog. Never manually rewrite what shadcn already provides |
| K10 |
Native <select> or <input type="date"> in premium UI |
Native form controls cannot be styled consistently across Chrome/Safari/Firefox. Use shadcn <Select> and shadcn <DatePicker> for cross-browser consistency |
| K11 |
Form without error state styling |
Every input must have error state: red border + error message below |
Animation (Rules A1–A8)
| Rule |
Anti-Pattern |
Correct Approach |
| A1 |
CSS bounce/elastic/spring easing |
CSS spring animations are forbidden. Exception: If using Framer Motion, highly damped springs are encouraged: { type: "spring", stiffness: 400, damping: 30 } for modals and popovers — this creates a premium, physical feel like Vercel/Linear |
| A2 |
Animations that take > 400ms |
Micro: 100–150ms, Components: 200–300ms, Pages: 300–400ms |
| A3 |
Animations everywhere |
Animate max 2–3 elements simultaneously |
| A4 |
Same animation for enter and exit |
Enter: ease-out (decelerate), Exit: ease-in (accelerate) |
| A5 |
Animating expensive properties |
Only animate transform and opacity — never height, width, top |
| A6 |
No animation on mobile |
Respect prefers-reduced-motion: reduce — wrap in @media or use useReducedMotion() |
| A7 |
Scroll-triggered animations that block |
Don't block content visibility for scroll reveals |
| A8 |
Hover animations on touch devices |
Wrap hover effects in @media (hover: hover) |
Images & Icons (Rules I1–I8)
| Rule |
Anti-Pattern |
Correct Approach |
| I1 |
Decorative icons on every list item |
Icons add meaning, not decoration. Use selectively. |
| I2 |
Mix of icon styles |
Pick one icon set (e.g., Lucide for shadcn). Stick with it. |
| I3 |
Low-contrast icons |
Icons need ≥ 3:1 contrast ratio |
| I4 |
Images without aspect-ratio |
Always set aspect-video or aspect-square to prevent layout shifts |
| I5 |
No image loading state |
Use <Skeleton> placeholder or blur hash |
| I6 |
SVG icons inline without aria |
Add aria-hidden="true" or aria-label |
| I7 |
Stock photo generic humans |
Use illustrations, abstract art, or genuine brand photography |
| I8 |
Unoptimized images |
WebP/AVIF, properly sized, loading="lazy" below fold |
Design Initialization Checklist
Start every new design with:
## Design Context
**Surface type**: [brand/marketing OR product/app]
**Target audience**: [who are they? what do they value?]
**Brand tone**: [professional/playful/bold/minimal/technical]
**Anti-references**: [designs this should NOT look like]
**Primary font**: [chosen font + why + Framer Motion / shadcn pairing]
**Color palette**: [3 semantic colors + HSL values for light AND dark]
**Component library**: [shadcn/ui | radix | custom]
**Animation library**: [CSS only | Framer Motion | GSAP]
Design Review Audits
Quick Audit (before PR)
- Typography: Is there clear visual hierarchy? Are fonts intentional? Is Inter paired properly?
- Color: Any pure black/white? Contrast failures? Too many colors? Dark mode?
- Spacing: Consistent Tailwind scale? No arbitrary values? Enough whitespace?
- Animation: Any CSS bounce/elastic? Too slow (>400ms)? Too many simultaneous?
- Components: Any native
<select> or <input type="date"> that should be shadcn?
- Z-index: Any hardcoded
z-[999] or z-50?
Full Audit (before release)
- Accessibility: Run axe DevTools or Lighthouse — target 90+ score
- Responsiveness: Test at 375px, 768px, 1280px, 1440px
- Dark mode: Does the full palette hold up? No inverted-only shortcuts?
- Empty states: Does every list/table have a designed empty state?
- Edge cases: Loading states, error states, long text overflow, RTL
Premium Design Markers
These details separate premium from mediocre:
- Consistent border radius — pick one and use it everywhere (
rounded-md = 6px, rounded-lg = 8px)
- Intentional drop shadows — darker near surface, lighter for floating elements
- Micro-copy quality — button labels are verbs: "Save changes" not "Submit"
- Focus ring styling —
focus-visible:ring-2 focus-visible:ring-primary matching brand
- Smooth color transitions —
transition-colors duration-150 on all interactive elements
- Optical alignment — icon + text optically centered, not mathematically (
items-center gap-1.5)
Code Examples
See EXAMPLES.md for detailed code examples.
Validation Checklist
What to verify during the review phase before completing the task.
Common Mistakes
Anti-patterns and things to explicitly avoid. See TROUBLESHOOTING.md.
Integration Notes
How this skill interacts with other skills.
1---2name: impeccable-design-23description: Visual design quality enforcement. 50 deterministic anti-pattern rules preventing AI design slop. Bans generic fonts, pure colors, nested cards, dated animations. Adapted for Tailwind CSS v4, shadcn/ui, and Framer Motion stacks.4---56# impeccable-design78## Overview910Hard QA design review checklist consisting of 50 deterministic rules covering typography (T1-T10), color systems (C1-C12), layout constraints (L1-L11), component contracts (K1-K11), and micro-animations (A1-A8).1112## When to Use1314Activate during the REVIEW phase of all frontend tasks as a strict visual and functional QA gate before marking UI work complete.1516## Rules & Patterns1718Based on [pbakaus/impeccable](https://github.com/pbakaus/impeccable) — deterministic detector rules for AI-generated frontend design.1920## Core Principle2122> Every model is trained on the same SaaS templates. Skip this guidance and you get the same handful of tells on every project. Impeccable eliminates them.2324## Role in the Pipeline2526> **This skill acts as a QA-designer at the `/review` phase.** `ui-ux-pro` is the planning guideline; `impeccable-design` is the hard checklist that runs before merge.2728---2930## Anti-Pattern Rules3132### Typography (Rules T1–T10)3334| Rule | Anti-Pattern | Correct Approach |35| ------ | ------------- | ----------------- |36| T1 | Using Inter for all text | Use Inter for UI body, pair with a distinct display font for headings OR with `JetBrains Mono` for technical/number accents (premium SaaS pattern) |37| T2 | Using Arial or Helvetica | Use a curated Google Font pairing |38| T3 | All text same weight | Use weight contrast: 700 headings, 400 body, 500 labels |39| T4 | Line height = 1 (tight) | Body: 1.6–1.8, Headings: 1.1–1.3 |40| T5 | No letter-spacing on caps | Uppercase labels: `letter-spacing: 0.08em` (Tailwind: `tracking-widest`) |41| T6 | Text too wide | Max line length: 60–75 characters — use `max-w-prose` or `max-w-[65ch]` |42| T7 | Monospace only for code | Use `tabular-nums` Tailwind class for number tables and data grids |43| T8 | Random font sizing | Use a consistent modular scale (1.25× or 1.333×) — use Tailwind's `text-*` scale |44| T9 | Body text too small | Minimum `text-sm` (14px) for body, never smaller than 12px |45| T10 | Bold everywhere | Bold is for emphasis. Diluted if overused. |4647**Tailwind typography utilities:**4849- `text-balance` — for headlines (prevents orphan words)50- `text-pretty` — for body paragraphs (smart line-breaks)51- `tabular-nums` — for numerical data tables5253### Color (Rules C1–C12)5455| Rule | Anti-Pattern | Correct Approach |56| ------ | ------------- | ----------------- |57| C1 | Pure black `#000` | Tint toward brand: `hsl(240, 10%, 4%)` |58| C2 | Pure white `#fff` for surfaces | Near-white with warmth: `hsl(40, 30%, 97%)` |59| C3 | Gray on colored background | Check contrast — likely fails WCAG. Use white/dark |60| C4 | Purple → Blue gradient | Clichéd AI palette. Use brand-derived gradients |61| C5 | Neon primary colors | Neon = accent only, never primary surface or text |62| C6 | Too many colors | 3 colors max: primary, neutral, semantic (success/error) |63| C7 | All links same blue `#0000EE` | Style links with brand color, preserve underline |64| C8 | Disabled state = gray only | Disabled: `opacity-40` + `cursor-not-allowed` |65| C9 | Success always green, Error always red | Check brand conflicts. Use accessible variants |66| C10 | Dark mode = inverted light mode | Dark mode needs separate palette — use `@layer base { .dark { ... } }` |67| C11 | No hover state change | Hover: shift lightness 8–12%, add `transition-colors duration-150` |68| C12 | Brand color on dark surface loses identity | Adjust saturation/lightness for dark bg context |6970### Layout & Spacing (Rules L1–L11)7172| Rule | Anti-Pattern | Correct Approach |73| ------ | ------------- | ----------------- |74| L1 | Cards inside cards | One level of card depth maximum |75| L2 | Icon tile above every heading | Use icons inline, in context, not decoratively above text |76| L3 | Centered long paragraphs | `text-center` max 2 lines only. Use `text-pretty` + left-align for body |77| L4 | Inconsistent spacing | Use Tailwind spacing utilities only. **Never arbitrary values** like `gap-[17px]` |78| L5 | Zero whitespace between sections | Sections need `py-16` to `py-24` breathing room |79| L6 | Content touching edges | Always `px-4` minimum on mobile |80| L7 | Same visual weight everywhere | Use hierarchy: primary > secondary > tertiary zones |81| L8 | Grid breaks on tablet | Test at 768px. Use 4-col on tablet, 12-col on desktop |82| L9 | Full-width everything | Max content width: `max-w-7xl` centered |83| L10 | Missing grid alignment | Use CSS Grid or Tailwind `grid` — not absolute positioning |84| L11 | Arbitrary high z-indexes | **NEVER** use `z-[999]` or `z-50` manually. Rely on DOM order + Radix/shadcn Portals which already handle modal elevation correctly |85| L12 | Default Rhythm | Break the 'Hero → 3 Features → CTA' structure. Build structurally diverse pages tailored to the content. |86| L13 | Symmetric card grids everywhere | Use asymmetric layouts (e.g., bento boxes, masonry, alternating left/right) to reduce the AI-generated feel. |8788### Components (Rules K1–K11)8990| Rule | Anti-Pattern | Correct Approach |91| ------ | ------------- | ----------------- |92| K1 | Two filled buttons side-by-side | `<Button variant="default">` + `<Button variant="outline">` or `variant="ghost"` |93| K2 | Button without loading state | Always add spinner + `disabled` during async actions |94| K3 | Modal without backdrop blur | shadcn `<Dialog>` handles this. Don't override with plain divs |95| K4 | Empty states left blank | **Always** design empty states: illustration + helpful message + primary CTA |96| K5 | No skeleton screens | Use `<Skeleton>` from shadcn for content areas, not just spinners |97| K6 | Tooltip on click (not hover) | Tooltips on hover, modals on click — use shadcn `<Tooltip>` + `<Dialog>` |98| K7 | Dropdown without keyboard nav | Use shadcn `<DropdownMenu>` — keyboard nav is built-in |99| K8 | Table without row hover | shadcn `<TableRow>` handles hover state automatically. Do **not** override it |100| K9 | Building complex UI from scratch | **Check shadcn/ui first**. If the component exists, generate the CLI command: `npx shadcn@latest add dialog`. Never manually rewrite what shadcn already provides |101| K10 | Native `<select>` or `<input type="date">` in premium UI | Native form controls cannot be styled consistently across Chrome/Safari/Firefox. Use `shadcn <Select>` and `shadcn <DatePicker>` for cross-browser consistency |102| K11 | Form without error state styling | Every input must have error state: red border + error message below |103104### Animation (Rules A1–A8)105106| Rule | Anti-Pattern | Correct Approach |107| ------ | ------------- | ----------------- |108| A1 | CSS bounce/elastic/spring easing | CSS spring animations are forbidden. **Exception**: If using Framer Motion, highly damped springs are encouraged: `{ type: "spring", stiffness: 400, damping: 30 }` for modals and popovers — this creates a premium, physical feel like Vercel/Linear |109| A2 | Animations that take > 400ms | Micro: 100–150ms, Components: 200–300ms, Pages: 300–400ms |110| A3 | Animations everywhere | Animate max 2–3 elements simultaneously |111| A4 | Same animation for enter and exit | Enter: ease-out (decelerate), Exit: ease-in (accelerate) |112| A5 | Animating expensive properties | Only animate `transform` and `opacity` — never `height`, `width`, `top` |113| A6 | No animation on mobile | Respect `prefers-reduced-motion: reduce` — wrap in `@media` or use `useReducedMotion()` |114| A7 | Scroll-triggered animations that block | Don't block content visibility for scroll reveals |115| A8 | Hover animations on touch devices | Wrap hover effects in `@media (hover: hover)` |116117### Images & Icons (Rules I1–I8)118119| Rule | Anti-Pattern | Correct Approach |120| ------ | ------------- | ----------------- |121| I1 | Decorative icons on every list item | Icons add meaning, not decoration. Use selectively. |122| I2 | Mix of icon styles | Pick one icon set (e.g., Lucide for shadcn). Stick with it. |123| I3 | Low-contrast icons | Icons need ≥ 3:1 contrast ratio |124| I4 | Images without aspect-ratio | Always set `aspect-video` or `aspect-square` to prevent layout shifts |125| I5 | No image loading state | Use `<Skeleton>` placeholder or blur hash |126| I6 | SVG icons inline without aria | Add `aria-hidden="true"` or `aria-label` |127| I7 | Stock photo generic humans | Use illustrations, abstract art, or genuine brand photography |128| I8 | Unoptimized images | WebP/AVIF, properly sized, `loading="lazy"` below fold |129130---131132## Design Initialization Checklist133134Start every new design with:135136```markdown137## Design Context138139**Surface type**: [brand/marketing OR product/app]140**Target audience**: [who are they? what do they value?]141**Brand tone**: [professional/playful/bold/minimal/technical]142**Anti-references**: [designs this should NOT look like]143**Primary font**: [chosen font + why + Framer Motion / shadcn pairing]144**Color palette**: [3 semantic colors + HSL values for light AND dark]145**Component library**: [shadcn/ui | radix | custom]146**Animation library**: [CSS only | Framer Motion | GSAP]147```148149---150151## Design Review Audits152153### Quick Audit (before PR)154155- Typography: Is there clear visual hierarchy? Are fonts intentional? Is Inter paired properly?156- Color: Any pure black/white? Contrast failures? Too many colors? Dark mode?157- Spacing: Consistent Tailwind scale? No arbitrary values? Enough whitespace?158- Animation: Any CSS bounce/elastic? Too slow (>400ms)? Too many simultaneous?159- Components: Any native `<select>` or `<input type="date">` that should be shadcn?160- Z-index: Any hardcoded `z-[999]` or `z-50`?161162### Full Audit (before release)163164- Accessibility: Run axe DevTools or Lighthouse — target 90+ score165- Responsiveness: Test at 375px, 768px, 1280px, 1440px166- Dark mode: Does the full palette hold up? No inverted-only shortcuts?167- Empty states: Does every list/table have a designed empty state?168- Edge cases: Loading states, error states, long text overflow, RTL169170---171172## Premium Design Markers173174These details separate premium from mediocre:1751761. **Consistent border radius** — pick one and use it everywhere (`rounded-md` = 6px, `rounded-lg` = 8px)1772. **Intentional drop shadows** — darker near surface, lighter for floating elements1783. **Micro-copy quality** — button labels are verbs: "Save changes" not "Submit"1794. **Focus ring styling** — `focus-visible:ring-2 focus-visible:ring-primary` matching brand1805. **Smooth color transitions** — `transition-colors duration-150` on all interactive elements1816. **Optical alignment** — icon + text optically centered, not mathematically (`items-center gap-1.5`)182183184## Code Examples185186See `EXAMPLES.md` for detailed code examples.187188## Validation Checklist189190What to verify during the review phase before completing the task.191192## Common Mistakes193194Anti-patterns and things to explicitly avoid. See `TROUBLESHOOTING.md`.195196## Integration Notes197198How this skill interacts with other skills.