[ ] No hardcoded px spacing in Tailwind (use p-6 not p-[24px])
[ ] Pattern geometry/elevation uses the selected recipe or explicit semantic variables
[ ] No hardcoded universal rounded-2xl + shadow + mx-6 language across unrelated recipes
2. Component Conventions
[ ] Uses data-slot attribute
[ ] Uses cn() for className merging
[ ] Props typed with React.ComponentProps<>
[ ] Supports className prop override
[ ] Named export (not default export for components)
[ ] No wrapper components that only add a className
3. Accessibility (a11y)
[ ] Touch targets >= 44x44px for interactive elements
[ ] focus-visible styles on all interactive elements
[ ] Proper aria-* attributes where needed
[ ] Color contrast meets WCAG AA (4.5:1 for text, 3:1 for large text)
[ ] Animations respect prefers-reduced-motion
[ ] Images have alt text
[ ] Form inputs have associated labels
4. Surface Best Practices
[ ] No horizontal overflow
[ ] Touch-friendly spacing between interactive elements
[ ] Mobile safe area insets handled when the adapter requires them
[ ] Desktop density/type and non-web canvas/export rules follow the selected adapter
[ ] Text sizes >= 12px for readability
[ ] Scrollable containers have -webkit-overflow-scrolling: touch
5. Performance
[ ] No unnecessary re-renders (stable references, memoization where needed)
[ ] Images are lazy-loaded
[ ] Heavy components are code-split
6. Typography
[ ] Uses the locked type family and recipe-fit type roles
[ ] Font sizes from the 14-step scale (10-48px, see CLAUDE.md)
[ ] Proper font weights (400, 500, 600, 700)
[ ] Display text (36-48px): leading-none + tracking-[-0.02em]
[ ] Heading text (18-24px): leading-snug + tracking-[-0.01em]
[ ] Body text (14-17px): leading-normal (no custom tracking)
[ ] Caption uppercase (10-13px): tracking-[0.05em] or tracking-wide
[ ] No line-height: 1.5 on display/heading text (too loose)
7. Spacing Consistency
[ ] Spacing uses one maintained token scale and the selected recipe's major rhythm
[ ] Off-scale values have an optical, canvas, or platform reason
[ ] Uses size-* shorthand instead of w-* h-*
[ ] Uses ms-*/me-* instead of ml-*/mr-* (logical properties)
[ ] Motion transitions use design tokens (duration-[var(--duration-fast)])
8. Coherence (VISUAL-CRAFT.md §C0 — the "one choice per axis" laws)
> The biggest reason a UI reads as "AI-generated" isn't ugly parts — it's *mixed*
> parts. Check that each axis below uses ONE value system-wide; flag a mix as a real
> issue, not a nitpick.
[ ] One radius personality — sharp (0-4px) OR soft (8-12px) OR pill, applied to every card/button/input/modal. No mixing (e.g. a rounded-none panel with rounded-full buttons).
[ ] One identifiable primary action plus only the selected grammar's stable semantic,
categorical, or brand roles — no competing decorative emphasis hues.
[ ] No emoji as UI icons (🚗🧺⭐ as list/nav/status/category markers) — they inject many uncontrolled hues; use one line-icon set in currentColor.
[ ] Status color = severity, not decoration — a normal/OK/"보통" state is neutral grey (not colored); color marks only the minority of rows that need attention; same value → same color.
[ ] No decorative hues — favorite stars, category dots, avatars use the accent or grey, not a new color each.
[ ] One shadow language — same light direction, same scale/tint; not some black + some tinted, some up-lit + some down-lit.
[ ] One icon family / fill mode / stroke weight across the file.
[ ] Nested-radius law — an element inside a rounded container uses inner = outer − padding, not the same radius (which bulges).
[ ] Consistent control heights — buttons, inputs, selects share a height set (e.g. 40px).
[ ] Errors/states never rely on color alone (icon + text too).
Output Format
Provide:
Score: Pass / Needs Improvement / Fail
Issues: List each violation with file:line reference
Fixes: Concrete code changes for each issue
How to use it
Copy the folder
Take bitjaru/ss-review from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
Check the name does not clash
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.