audit-uiux-design-system — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited audit-uiux-design-system (Agent Skill) and scored it 45/100 (orange). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 1 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 1 flagged
A base64 string of 128+ characters appears in a documentation file. Encoded prompt injection hides the hostile instruction in base64 — invisible to keyword filters — and relies on the agent's ability to decode it at runtime. There is no normal authoring reason to embed a multi-hundred-byte base64 blob in skill docs.
*.sig, SIGNATURES) outside the documentation.Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Visual design system coherency audit: tokens, components, visual consistency, dark mode, animations, and WCAG visual compliance.
Before ANY browser interaction, read the `browser-anti-stall` skill and apply its rules to every step. That skill lives at ~/.cursor/skills/protocol-browser-anti-stall/SKILL.md.
Every UI recommendation MUST result in output that looks hand-crafted by a senior designer, not generated by a template or AI. Before implementing or recommending ANY visual change:
domain (Awwwards, Muzli, SiteInspire). Study what makes them feel human and curated.
symmetric layouts are AI tells. Introduce deliberate visual rhythm: vary section padding, use asymmetric hero layouts, offset elements with purpose.
response. Buttons get press feedback (scale, shadow shift). Links get underline animations. Cards get subtle lift. Hover, focus, active, and disabled MUST all feel distinct.
What's the brand's visual "voice"? Sharp corners = precision. Rounded = friendly. Monospace accents = technical. Serif headings = editorial. This must be intentional.
Read package.json and config files:
| Signal | Technology |
|---|---|
tailwindcss v3 + tailwind.config.* | Tailwind CSS v3 |
tailwindcss v4 + @theme in CSS | Tailwind CSS v4 |
*.module.css files | CSS Modules |
styled-components or @emotion/styled | CSS-in-JS |
@chakra-ui/react | Chakra UI |
@mui/material | Material UI |
@mantine/core | Mantine |
Glob: **/components/ui/*.tsx → shadcn/ui
Glob: **/components/ui/*.vue → Vue component lib
Glob: **/components/ui/*.svelte → Svelte component lib
Grep: "from '@radix-ui" glob "*.{ts,tsx}" output_mode "count"
Grep: "from 'lucide-react" glob "*.{ts,tsx}" output_mode "count"
Grep: "from '@heroicons" glob "*.{ts,tsx}" output_mode "count"
Grep: "from 'react-icons" glob "*.{ts,tsx}" output_mode "count"Glob: **/tailwind.config.*
Glob: **/app/globals.css
Glob: **/styles/tokens.*
Glob: **/theme.*
Grep: "--primary|--secondary|--accent|--muted" glob "*.css"Read token source to extract: colors, spacing, typography, radii, shadows.
Grep: "NEVER|FORBIDDEN|DO NOT" glob "**/*README*" -iDESIGN SYSTEM DISCOVERY:
- CSS framework: [Tailwind v3/v4 / CSS Modules / Styled Components / etc.]
- Component library: [shadcn/ui / Radix / MUI / Chakra / custom]
- Icon library: [Lucide / Heroicons / react-icons / mixed]
- Token source: [file path]
- Colors defined: [count]
- Typography scale: [list]
- Spacing base: [4px / 8px / etc.]
- Border radius: [list]
- Shadow levels: [list]
- Dark mode: [YES — class/media / NO]
- Forbidden patterns: [list from README]CallMcpTool(server: "context7", toolName: "resolve-library-id", arguments: {
"libraryName": "<DETECTED_COMPONENT_LIBRARY>",
"query": "component variants accessibility patterns"
})Then fetch docs with the resolved ID. Also fetch CSS framework docs.
CallMcpTool(server: "user-firecrawl", toolName: "firecrawl_search", arguments: {
"query": "<COMPONENT_LIBRARY> design system audit token compliance best practices [current year]",
"limit": 5,
"sources": [{ "type": "web" }]
})Additional queries:
| Topic | Query |
|---|---|
| Token compliance | design token audit <CSS_FRAMEWORK> consistency |
| Component patterns | <FRAMEWORK> component modularity composition patterns |
| Dark mode | <CSS_FRAMEWORK> dark mode implementation best practices |
Scrape the best result for detailed guidance.
Research real products in the same domain to establish a visual benchmark:
CallMcpTool(server: "user-firecrawl", toolName: "firecrawl_search", arguments: {
"query": "<PRODUCT_TYPE> website design award Awwwards Muzli [current year]",
"limit": 5,
"sources": [{ "type": "web" }]
})CallMcpTool(server: "user-firecrawl", toolName: "firecrawl_search", arguments: {
"query": "<PRODUCT_TYPE> SaaS UI design inspiration unique not generic [current year]",
"limit": 5,
"sources": [{ "type": "web" }]
})Scrape 2-3 standout sites. Extract:
| Rule | Standard | How to Check |
|---|---|---|
| Semantic naming | primary, secondary, destructive, muted, accent | No raw hex/rgb in components |
| CSS variables | hsl(var(--primary)) or oklch() | All colors reference variables |
| Foreground pairs | Every bg color has *-foreground | Text contrast maintained |
| Dark mode | All tokens have dark variant | .dark class or @media |
| Status colors | success, warning, error, info defined | Consistent across alerts, badges, toasts |
Find violations:
Grep: "(#[0-9a-fA-F]{3,8}|rgb\(|rgba\(|hsl\([^v])" glob "*.tsx"
Grep: "\[(#|rgb|hsl)" glob "*.tsx"| Rule | Standard |
|---|---|
| Font families | Max 2-3 families in theme |
| Size scale | Consistent (text-sm, text-base, text-lg) |
| Weight scale | Limited set (font-normal, font-medium, font-semibold, font-bold) |
| Heading hierarchy | h1 > h2 > h3 in visual weight AND DOM order |
| No arbitrary sizes | No text-[14px] when text-sm exists |
Grep: "text-\[" glob "*.tsx"
Grep: "font-(thin|extralight|light|normal|medium|semibold|bold|extrabold|black)" glob "*.tsx" output_mode "count"| Rule | Standard |
|---|---|
| Base unit | 4px grid (Tailwind default) |
| Consistent gaps | Same spacing for same contexts |
| No arbitrary values | No p-[13px] when p-3 exists |
Grep: "(p|m|gap|space)-\[" glob "*.tsx"Grep: "rounded-\[" glob "*.tsx"
Grep: "shadow-" glob "*.tsx" output_mode "count"| Rule | Standard |
|---|---|
| Single responsibility | One component = one purpose |
| Composable | Small pieces compose into larger ones |
| Reusable | Same UI = same component everywhere |
| Consistent props | variant, size, disabled, className across all |
| Variants pattern | cva() or similar for style variants |
Grep: "<button " glob "*.tsx" — raw buttons outside ui/ (should use Button)
Grep: "<input " glob "*.tsx" — raw inputs (should use Input)
Grep: "<select " glob "*.tsx" — raw selects
Grep: "<a " glob "*.tsx" — raw anchors (should use Link)Exclude components/ui/* — those are legitimate primitives.
Grep: "function (Button|Input|Modal|Dialog|Card)" glob "*.tsx" output_mode "files_with_matches"Multiple files defining the same component name = duplication.
Grep: "from .lucide-react" glob "*.tsx" output_mode "count"
Grep: "from .@heroicons" glob "*.tsx" output_mode "count"
Grep: "from .react-icons" glob "*.tsx" output_mode "count"Multiple icon libraries = inconsistency. Flag it.
browser_navigate → http://localhost:<PORT>/<ROUTE>
browser_wait_for → { time: 2 }
browser_snapshot → verify content rendered
browser_take_screenshot → visual evidence
browser_console_messages → check for errors| Check | How |
|---|---|
| Token compliance | Screenshot — inconsistent colors, spacing |
| Component reuse | Snapshot — shared primitives used? |
| Console errors | browser_console_messages — hydration, missing CSS vars |
| Layout shift | Snapshot before/after interaction |
| Dark mode | Toggle dark mode, re-screenshot, compare |
Test at three viewports:
Capture screenshots at each.
| Check | How | ||||
|---|---|---|---|---|---|
| Color contrast | 4.5:1 text, 3:1 large text/UI — inspect via screenshot | ||||
| Focus rings | Tab through elements, verify visible focus indicator | ||||
| Semantic HTML | `Grep: "<nav> | <main> | <section> | <article> | <aside>" glob "*.tsx"` |
| Alt text | `Grep: "<(img | Image)" glob "*.tsx" then check for alt=` |
Every interactive element MUST provide tactile feedback. Check each:
| Element | Expected Feedback | AI-Tell if Missing |
|---|---|---|
| Buttons | Hover: color shift + subtle shadow change. Active: scale(0.98) press. Loading: spinner replaces label or inline indicator | Flat, no state change — feels dead |
| Links | Hover: underline animation or color transition, not instant swap | Instant color jump with no transition |
| Cards (clickable) | Hover: lift (translateY + shadow increase). Not just color change | Color change only, or no hover at all |
| Inputs | Focus: ring animation or border color transition. Not just outline swap | Browser default outline, no custom focus |
| Toggles/switches | State transition animated, not instant. Haptic feel via easing | Instant snap between states |
| Dropdowns/menus | Open/close with slide or fade, not instant appear/disappear | Instant pop, no transition |
| Toasts/notifications | Enter with slide + fade, exit with fade. Auto-dismiss with progress | Instant appear/disappear |
| Modals/dialogs | Backdrop fade + content scale/slide. Exit reverses. Not instant | Instant appear, jarring |
| Tabs | Active indicator slides to new tab, not instant jump | Instant color swap |
| Tooltips | Slight delay (200-300ms), fade in. Don't flicker on mouse movement | Instant, flickers, no delay |
Find in code:
Grep: "transition-all|transition-colors|transition-opacity|transition-transform" glob "*.tsx" output_mode "count"
Grep: "hover:|group-hover:|focus-visible:" glob "*.tsx" output_mode "count"
Grep: "animate-|animation-|@keyframes|framer-motion|motion\." glob "*.tsx" output_mode "count"
Grep: "scale-|translate-|rotate-" glob "*.tsx" output_mode "count"For every interactive component, verify ALL states exist. Missing states = AI-generated feel:
States checklist per component:
□ Default (resting)
□ Hover (mouse over)
□ Focus-visible (keyboard navigation)
□ Active/pressed (during click)
□ Disabled (grayed, not clickable, cursor-not-allowed)
□ Loading (async action in progress)
□ Error (validation failed, destructive context)
□ Success (completed action)Find missing states:
Grep: "focus-visible:|focus:" glob "*.tsx" output_mode "count"
Grep: "active:|pressed" glob "*.tsx" output_mode "count"
Grep: "disabled:|cursor-not-allowed|opacity-50" glob "*.tsx" output_mode "count"Check that the design has intentional variety, not uniform repetition:
| Pattern | Curated Feel | Template Feel |
|---|---|---|
| Section spacing | Varies by content type (hero: generous, form: tight, CTA: spacious) | Same py-16 on every section |
| Typography contrast | Large jumps between heading and body (e.g., 48px → 16px). Mix weights | Incremental scale, same weight everywhere |
| Color accent usage | Accent used sparingly for emphasis, not on every element | Primary color on every button, link, icon |
| Layout variation | Different layouts per section (text-left/image-right, full-width, sidebar) | Same 3-column card grid repeated |
| Border radius | Intentional variation (pills for tags, rounded for cards, sharp for data tables) | Same rounded-lg on everything |
| Shadow depth | Multiple shadow levels for elevation hierarchy | Same shadow on everything, or no shadows |
| Whitespace | Asymmetric margins create visual flow and reading rhythm | Perfectly symmetric, mechanical spacing |
| Rule | Standard |
|---|---|
| Duration scale | 150ms (micro), 200ms (hover), 300ms (enter), 500ms (complex) — NOT all the same |
| Easing | ease-out for enter, ease-in for exit, ease-in-out for state changes — NOT all ease-in-out |
| Reduced motion | motion-safe: prefix or prefers-reduced-motion |
| No layout shift | Transitions don't cause CLS |
| Stagger effect | List items, card grids animate in with stagger delay, not all at once |
Grep: "duration-[0-9]+" glob "*.tsx" output_mode "count"
Grep: "transition-" glob "*.tsx" output_mode "count"
Grep: "prefers-reduced-motion|motion-safe|motion-reduce" glob "*.tsx"
Grep: "stagger|delay-\[|animation-delay" glob "*.tsx" output_mode "count"| Rule | Standard |
|---|---|
| All tokens switch | CSS variables change in dark mode |
| No hardcoded colors | No bg-white, text-black — use semantic tokens |
| Borders visible | In both modes |
| Contrast | WCAG in BOTH light and dark |
| Not an afterthought | Dark mode should feel designed, not inverted. Shadows become glows, borders become subtle |
Grep: "(bg-white|bg-black|text-white|text-black)" glob "*.tsx" output_mode "count"## UI Design System Audit Report
**Date:** [date]
**Framework:** [detected]
**CSS:** [Tailwind v3/v4 / CSS Modules / etc.]
**Component library:** [shadcn / Radix / MUI / custom]
**Pages Audited:** [count]
**Issues Found:** [count]
---
### Design Token Compliance
| Token Category | Defined | Violations | Status |
|----------------|---------|------------|--------|
| Colors | [count] | [count] raw hex/rgb | [pass/warn/fail] |
| Typography | [count] | [count] arbitrary sizes | [pass/warn/fail] |
| Spacing | [count] | [count] arbitrary values | [pass/warn/fail] |
| Radii | [count] | [count] arbitrary radii | [pass/warn/fail] |
| Shadows | [count] | [count] inconsistent | [pass/warn/fail] |
---
### Component Health
| Component | Used In | Variants | Issues |
|-----------|---------|----------|--------|
| Button | [N] files | [N] | [notes] |
| Input | [N] files | [N] | [notes] |
| Card | [N] files | [N] | [notes] |
---
### Duplicate / Redundant Components
| Pattern | Locations | Recommendation |
|---------|-----------|----------------|
| Raw `<button>` | [files] | Use `<Button>` from `components/ui` |
| Custom modal | [file] | Use `<Dialog>` from `components/ui` |
---
### Visual Accessibility
| Criteria | Status | Issues |
|----------|--------|--------|
| Color contrast | [pass/warn/fail] | [details] |
| Focus indicators | [pass/warn/fail] | [details] |
| Alt text | [pass/warn/fail] | [details] |
| Semantic HTML | [pass/warn/fail] | [details] |
---
## Further reading
- [Microinteraction Coverage and more](references/details.md)~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.