Scan complete · 63ms · 146 code files

Design System Diagnosis

vercel/ai-chatbot · scanned 2026-08-22
Health score
75/100
nextTypeScriptTailwind CSSCVAshadcn/ui.cursor/rules
Summary
103 arbitrary values like [13px] punched through the Tailwind scale, each one a precedent your agent will follow. 2 references in your agent rules point at things this scan can no longer find.
Written by Claude from this scan · 2026-08-22 · not part of the measurement

What the numbers mean

The 75 is real, but read it carefully: the tiles are green because shadcn carries them. All 61 colours are oklch tokens with zero hex strays — the token architecture is doing its job, and the score credits it. What the score can only partly price is where this repo's mess actually lives: 103 arbitrary bracket values punched through the Tailwind scale. [13px] alone appears 26 times, led by components/chat/sidebar-user-nav.tsx, with [10px], [0.12em] and [3px] close behind. Each one is a precedent: an agent reading this code learns that when the scale doesn't fit, you punch through it.

The quieter finding is worse: the agent rules are stale. .cursor/rules/ultracite.mdc references pages/_document.jsx and pages/_document.js — files this scan cannot find, remnants of a pages-router past in an app-router repo. A rule the agent obeys is worse than no rule when the repo has moved on.

The component layer is disciplined at the top and fraying at the edges: MessageActions is defined in two files, and the button family has grown six members — Button, SubmitButton, ArtifactCloseButton, CodeBlockCopyButton, ConversationScrollButton, PromptInputButton. Most are legitimate specialisations, but nothing in the repo says which are canonical, so the next agent adds a seventh.

The fix, calmly: the bracket values are decisions without names. [13px] used 26 times is a font-size step this design wants and the scale doesn't have — add the step, then fold the brackets in as files get touched. Delete the two dead references from ultracite.mdc today; it is a two-line fix and the cheapest win on this page. And one line in the rules naming Button as the base others wrap would close the family to accidental growth.

Where to start

One tweak · 75 → 80

01
Give your repeated bracket values names
+5
[13px] appears 26 times, which reads as a decision, not drift. If it is one, name it in app/globals.css so the next component (and your agent) can reach for it; 5 more repeated values deserve the same look. The 14 values used once are worth a pass: keep the deliberate ones (optical nudges like the 4 under 4px, one-off layout widths) and round the accidents to a neighbouring step.

You sat through the roast

so you get a present.

Agent trap. [13px] appears 26 times. An agent looking for how this repo does spacing reads repetition as intent, so it will write occurrence 27. The most copied pattern here is the one you least want copied.
61
distinct colours
Ideal Design System~24
Avg Design System130 · cleaner than 65%
Reputable systems24
0
shades of grey
Ideal Design System~13
Avg Design System17 · cleaner than 88%
Reputable systems5
6
off-scale spacing values
Ideal Design System~12
Avg Design System34 · cleaner than 79%
Reputable systems6 =
0
duplicated components
Ideal Design System0 =
Avg Design System20 · cleaner than 85%
Reputable systems12
7
inline style blocks
Ideal Design System0
Avg Design System49 · cleaner than 76%
Reputable systems12
0
near-identical colour pairs
Ideal Design System0 =
Avg Design System13 · cleaner than 71%
Reputable systems1
9
!important declarations
Ideal Design System0
Avg Design System7
Reputable systems3
0
components never imported
Ideal Design System0 =
Avg Design System14
Reputable systems0 =
103
arbitrary bracket values
Ideal Design System~20
Avg Design System70
Reputable systems0

What your AI agent sees today

Your agent reads .cursor/rules. But none of it points at a single source of truth for components and tokens, because there isn't one yet. The numbers below are what your agent actually works from.

.cursor/rules · Cursor
2 rule references gone stale · a rule your agent obeys is worse than no rule when the repo has moved on
pages/_document.jsx named in .cursor/rules/ultracite.mdc, but the path no longer exists
pages/_document.js named in .cursor/rules/ultracite.mdc, but the path no longer exists

Rules rot quietly: nobody edits them when a component is renamed or a file moves. Regenerate them from a fresh scan, or fix the lines by hand.

Palette
61colours

A healthy product palette is up to ~24 colours: one brand hue with a few tints, one accent, up to 13 greys, and status colours.

49 tokens12 strays
Colour usage
Sized by how often each is used
token stray
+1

6 off-scale spacing values

a disciplined repo keeps these around a dozen · on-scale Tailwind steps (·) shown for context · off-scale in coral

·2
115
·3
69
·4
61
·1
51
·0
49
·1.5
32
·2.5
21
·0.5
15
·8
14
·6
11
·20
5
·9.5
5
·12
4
·px
4
·5
4
·3.5
4
·16
3
·10
3
103 arbitrary values punched through the scale, one bracket at a time
[13px] ×26[10px] ×12[0.12em] ×9[3px] ×9[12px] ×7[200px] ×5[11px] ×4[24px] ×4[257px] ×4[450px] ×3+17 more

Typography & shape

3
typefaces
Ideal Design System~3 =
Avg Design System3 =
Reputable systems1
12
font sizes
Ideal Design System~10
Avg Design System20 · cleaner than 62%
Reputable systems6
14
border radii
Ideal Design System~10
Avg Design System13
Reputable systems2
4
shadow styles
Ideal Design System~6
Avg Design System2
Reputable systems1
the font sizes, by use
·sm ×44·xs ×29·[13px] ×25·[10px] ×12·[12px] ×5·[11px] ×4·base ×4·2xl ×3·3xl ×2·lg ×2·[var(--shiki-dark)] ×1·xl ×1
the radii, by use
·md ×31·lg ×30·2xl ×18·xl ×18·full ×17·default ×13·none ×3·sm ×2·[12px] ×22px ×19999px ×1·3xl ×1·[inherit] ×1·[2px] ×1
the elevations, cast, 2 of 4 · on the light surface they were drawn for
0 0 0 0 oklch(0.55 … ×1
0 0 0 3px oklch(0.5… ×1

3 typefaces, declared 3 different ways

every distinct declaration is a chance for the next one to be wrong

"SF Mono", "Cascadia Code", "Fira Code", "JetBrains Mono", ui-monospac×1
Geist×1
Geist Mono×1

Where it hurts most

the 5 files carrying the most off-system styling

Duplicated components

an agent asking which one is canonical gets several plausible answers. Paths open in VS Code

<MessageActions> · defined twice, one wraps the other
button family · 6 variants
<Button>
components/ui/button.tsx
used 25×
<SubmitButton>
components/chat/submit-button.tsx
used 2×
<ArtifactCloseButton>
components/chat/artifact-close-button.tsx
used 1×
<CodeBlockCopyButton>
components/ai-elements/code-block.tsx
<ConversationScrollButton>
components/ai-elements/conversation.tsx
<PromptInputButton>
components/ai-elements/prompt-input.tsx
sidebar family · 5 variants
<Sidebar>
components/ui/sidebar.tsx
used 1×
<AppSidebar>
components/chat/app-sidebar.tsx
used 1×
<SidebarHistory>
components/chat/sidebar-history.tsx
used 1×
<SidebarLeftIcon>
components/chat/icons.tsx
used 1×
<SidebarToggle>
components/chat/sidebar-toggle.tsx
spinner family · 2 variants
<Spinner>
components/ui/spinner.tsx
used 3×
<LoaderIcon>
components/chat/icons.tsx
used 8×
modal family · 2 variants
<Dialog>
components/ui/dialog.tsx
used 1×
<SuggestionDialog>
components/chat/suggestion.tsx
used 1×

7 inline style blocks

styling no system can see

9 !important declarations · the cascade admitting defeat
globals.css ×9

What you actually use

315 components defined · top by adoption · the real system, buried in here

componentuseddefined inprops
<Button> 25× components/ui/button.tsx variant size asChild
<Tooltip> 10× components/ui/tooltip.tsx none
<TooltipContent> 10× components/ui/tooltip.tsx sideOffset
<TooltipTrigger> 10× components/ui/tooltip.tsx none
<DropdownMenuItem> components/ui/dropdown-menu.tsx inset variant
<LoaderIcon> components/chat/icons.tsx size
<SidebarMenuButton> components/ui/sidebar.tsx asChild isActive variant size tooltip
<CopyIcon> components/chat/icons.tsx size
<SparklesIcon> components/chat/icons.tsx size
<ChatItem> components/chat/sidebar-history-item.tsx PureChatItem prevProps