AVAILABLE FOR WORK·SUWANEE, GA
15Y+ IN & AROUND AZURELAST SHIP THIS WEEK
Work / design-doctor
◐ IN PROGRESS Open source · developer tool

design-doctor

A configurable design-quality compiler for React UI — shadcn/ui, Tailwind v4, motion, design tokens, and accessibility. It scans a project, scores it, governs motion and token drift, and ships as an installable agent skill so AI assistants stop writing UI slop.

TypeScript Node 20+ React Tailwind v4
pnpm + TurborepoOxlintVitestmotion/reactSARIFGitHub Action

Not a prettier linter for Tailwind. It's a configurable design-quality compiler for React, shadcn/ui, Tailwind v4, motion, accessibility, and production SaaS UX.

// Why it exists

Most tools catch broken code. Very few catch design entropy.

Linters tell you the code parses. They don't tell you a card hover is jittering your dashboard, that a status color skipped the token system, that a dialog is missing an accessible title, or that three files quietly drifted off the motion easing curve. That's the gap design-doctor lives in.

It owns the product-aware rules, a transparent scoring model, autofix safety, and reports — and it lints itself with its own internal rules. The whole point is to read like a serious open-source compiler with taste, not an AI that dumped regexes into a scripts folder.

// The terminal

Premium in a TTY, boring in CI.

A Bloomberg terminal that went to design school. Deterministic plain output when piped or in CI.

design-doctor scan
╭────────────────────────────────────────────────────────────╮
 ◈ Design Doctor                                              
 shadcn/ui + Tailwind v4 + motion + design-system scanner    
╰────────────────────────────────────────────────────────────╯

  UI Health   87/100  B+
  Policy      operator-console · compact · strict motion
  Files       214 scanned · 18 changed · 1.9s

  Scan lens
  tokens       ███████████████████░ 94
  a11y         █████████████████░░░ 88
  motion       ███████████████░░░░░ 79  drift
  shadcn       ██████████████████░░ 91
  tailwind     ███████████████████░ 96
  data-ux      ████████████████░░░░ 82
  polish       █████████████████░░░ 86

  Critical fixes
  ✖ motion/no-transition-all      src/components/card.tsx:44:12
    Use named transition properties with global motion tokens.
  ✖ shadcn/dialog-title-required  src/features/orders/ApproveOrderDialog.tsx:31:4
    DialogContent must include a DialogTitle (or visually hidden title).

  Best next move
   design-doctor fix --safe
   design-doctor explain motion/no-transition-all
// The point system

A transparent, configurable, PR-delta-aware score.

100 points across seven weighted categories. Fails on regressions in changed files, not on legacy warnings.

Design tokens
20 pts
Accessibility
20 pts
Motion
15 pts
shadcn composition
15 pts
Tailwind v4 hygiene
10 pts
Data UX
10 pts
Production polish
10 pts
// What sets it apart

Opinions with receipts.

MOTION

Motion governance

Enforces duration/easing tokens, press-scale, reduced-motion, and a hard "no card hover movement" rule. Catches motion-design entropy almost nothing else does.

COLOR

Contrast role-ranges

Beyond WCAG floors: defines an intended hierarchy range per role pair, flagging "too low" separately from "outside intended range."

AGENT

Installable skill

npx design-doctor install-skill drops a compact SKILL.md + references so Codex/Cursor/Claude follow the project's design policy before and after editing UI.

CI

PR-delta action

GitHub Action with sticky PR comment, score/grade outputs, inline review comments, and "fail on regression" — so teams don't hate it by day two.

RULES

Fixture-heavy & self-linting

Every rule needs docs, config schema, score impact, and pass/fail fixtures. There's an internal ESLint plugin that lints the linter.

SAFETY

Suppression hygiene

Disables require a reason and an expiry date — no broad file-level silencing, no expired suppressions left rotting in the codebase.

// The rule contract

Every rule is typed, documented, and scored.

packages/rules/src/motion/no-card-hover-movement.ts
export const noCardHoverMovement = createRule({
  id: "motion/no-card-hover-movement",
  category: "motion",
  defaultSeverity: "error",
  meta: {
    rationale: "Card hover movement creates spatial noise in dense UIs.",
    autofix: "none",          // requires design judgment
    subjective: true,
  },
  schema: z.object({
    allowedFeedback: z.array(z.enum(["border","shadow","tint","focus-ring"])),
  }),
  create(ctx) {
    return { CssRule(rule) { /* flag translate/scale/float on :hover */ } };
  },
});
◐ Status & open source

design-doctor is in active development and will be open-sourced when it's ready — monorepo scaffold, core engine, scoring, the rule packs, the agent skill, and the GitHub Action. This page will grow into the real docs hub (rule catalog, recipes, the "wall of shame" before/after fixtures). Want early access or to compare notes on design tooling? Reach out →