Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Build scalable design systems with design tokens, theming infrastructure, and component architecture patterns. Use when creating design tokens, implementing theme switching, building component libraries, or establishing design system foundations.
.claude/skills/asymmetric-al-design-system-patterns/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 100% | 0% |
| case-18 | ✗→✓ | ▲ Improved | 93% | 0% |
| case-05 | ✓→✗ | ▼ Worse | 115% | 0% |
| case-02 | ✓→✓ | = Same ✓ | 63% | 0% |
| case-03 | ✓→✓ | = Same ✓ | 108% | 0% |
> Repo notice (Asymmetric-al/core): This repository is Base UI only. > Shared primitives come from @base-ui/react via the shadcn base-maia > style in packages/ui. Ignore any Radix UI guidance below — never add > radix-ui/@radix-ui/* imports or dependencies; composition uses Base > UI's render prop, not asChild. See docs/ai/rules/frontend.md.
Master design system architecture to create consistent, maintainable, and scalable UI foundations across web and mobile applications.
typescript// Design tokens with CSS custom properties const tokens = { colors: { // Primitive tokens gray: { 50: "#fafafa", 100: "#f5f5f5", 900: "#171717", }, blue: { 500: "#3b82f6", 600: "#2563eb", }, }, // Semantic tokens (reference primitives) semantic: { light: { "text-primary": "var(--color-gray-900)", "text-secondary": "var(--color-gray-600)", "surface-default": "var(--color-white)", "surface-elevated": "var(--color-gray-50)", "border-default": "var(--color-gray-200)", "interactive-primary": "var(--color-blue-500)", }, dark: { "text-primary": "var(--color-gray-50)", "text-secondary": "var(--color-gray-400)", "surface-default": "var(--color-gray-900)", "surface-elevated": "var(--color-gray-800)", "border-default": "var(--color-gray-700)", "interactive-primary": "var(--color-blue-400)", }, }, };
css/* Layer 1: Primitive tokens (raw values) */ :root { --color-blue-500: #3b82f6; --color-blue-600: #2563eb; --color-gray-50: #fafafa; --color-gray-900: #171717; --space-1: 0.25rem; --space-2: 0.5rem; --space-4: 1rem; --font-size-sm: 0.875rem; --font-size-base: 1rem; --font-size-lg: 1.125rem; --radius-sm: 0.25rem; --radius-md: 0.5rem; --radius-lg: 1rem; } /* Layer 2: Semantic tokens (meaning) */ :root { --text-primary: var(--color-gray-900); --text-secondary: var(--color-gray-600); --surface-default: white; --interactive-primary: var(--color-blue-500); --interactive-primary-hover: var(--color-blue-600); } /* Layer 3: Component tokens (specific usage) */ :root { --button-bg: var(--interactive-primary); --button-bg-hover: var(--interactive-primary-hover); --button-text: white; --button-radius: var(--radius-md); --button-padding-x: var(--space-4); --button-padding-y: var(--space-2); }
tsximport { createContext, useContext, useEffect, useState } from "react"; type Theme = "light" | "dark" | "system"; interface ThemeContextValue { theme: Theme; resolvedTheme: "light" | "dark"; setTheme: (theme: Theme) => void; } const ThemeContext = createContext<ThemeContextValue | null>(null); export function ThemeProvider({ children }: { children: React.ReactNode }) { const [theme, setTheme] = useState<Theme>(() => { if (typeof window !== "undefined") { return (localStorage.getItem("theme") as Theme) || "system"; } return "system"; }); const [resolvedTheme, setResolvedTheme] = useState<"light" | "dark">("light"); useEffect(() => { const root = document.documentElement; const applyTheme = (isDark: boolean) => { root.classList.remove("light", "dark"); root.classList.add(isDark ? "dark" : "light"); setResolvedTheme(isDark ? "dark" : "light"); }; if (theme === "system") { const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)"); applyTheme(mediaQuery.matches); const handler = (e: MediaQueryListEvent) => applyTheme(e.matches); mediaQuery.addEventListener("change", handler); return () => mediaQuery.removeEventListener("change", handler); } else { applyTheme(theme === "dark"); } }, [theme]); useEffect(() => { localStorage.setItem("theme", theme); }, [theme]); return ( <ThemeContext.Provider value={{ theme, resolvedTheme, setTheme }}> {children} </ThemeContext.Provider> ); } export const useTheme = () => { const context = useContext(ThemeContext); if (!context) throw new Error("useTheme must be used within ThemeProvider"); return context; };
tsximport { cva, type VariantProps } from "class-variance-authority"; import { cn } from "@/lib/utils"; const buttonVariants = cva( // Base styles "inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50", { variants: { variant: { default: "bg-primary text-primary-foreground hover:bg-primary/90", destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90", outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground", secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80", ghost: "hover:bg-accent hover:text-accent-foreground", link: "text-primary underline-offset-4 hover:underline", }, size: { sm: "h-9 px-3 text-sm", md: "h-10 px-4 text-sm", lg: "h-11 px-8 text-base", icon: "h-10 w-10", }, }, defaultVariants: { variant: "default", size: "md", }, }, ); interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> { asChild?: boolean; } export function Button({ className, variant, size, ...props }: ButtonProps) { return ( <button className={cn(buttonVariants({ variant, size, className }))} {...props} /> ); }
javascript// style-dictionary.config.js module.exports = { source: ["tokens/**/*.json"], platforms: { css: { transformGroup: "css", buildPath: "dist/css/", files: [ { destination: "variables.css", format: "css/variables", options: { outputReferences: true, // Preserve token references }, }, ], }, scss: { transformGroup: "scss", buildPath: "dist/scss/", files: [ { destination: "_variables.scss", format: "scss/variables", }, ], }, ios: { transformGroup: "ios-swift", buildPath: "dist/ios/", files: [ { destination: "DesignTokens.swift", format: "ios-swift/class.swift", className: "DesignTokens", }, ], }, android: { transformGroup: "android", buildPath: "dist/android/", files: [ { destination: "colors.xml", format: "android/colors", filter: { attributes: { category: "color" } }, }, ], }, }, };
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 16,979 | 19,136 | +13% | 1 | 1 | 0% | 3,255 | 6,496 | +100% | 0 | 0 | — |
case-02 | pass→pass | 14,381 | 10,339 | -28% | 1 | 1 | 0% | 2,898 | 4,715 | +63% | 0 | 0 | — |
case-03 | pass→pass | 12,230 | 8,374 | -32% | 1 | 1 | 0% | 2,010 | 4,190 | +108% | 0 | 0 | — |
case-04 | pass→pass | 15,039 | 13,008 | -14% | 1 | 1 | 0% | 3,032 | 5,425 | +79% | 0 | 0 | — |
case-09 | pass→pass | 15,884 | 15,114 | -5% | 1 | 1 | 0% | 2,435 | 5,226 | +115% | 0 | 0 | — |
case-05 | pass→fail | 12,778 | 11,928 | -7% | 1 | 1 | 0% | 2,325 | 4,997 | +115% | 0 | 0 | — |
case-06 | pass→pass | 10,426 | 11,015 | +6% | 1 | 1 | 0% | 2,221 | 4,968 | +124% | 0 | 0 | — |
case-07 | pass→pass | 13,333 | 8,644 | -35% | 1 | 1 | 0% | 2,654 | 4,519 | +70% | 0 | 0 | — |
case-08 | pass→pass | 9,857 | 8,508 | -14% | 1 | 1 | 0% | 1,845 | 4,273 | +132% | 0 | 0 | — |
case-10 | pass→pass | 16,150 | 20,454 | +27% | 1 | 1 | 0% | 3,007 | 6,735 | +124% | 0 | 0 | — |
case-11 | fail→fail | 13,832 | 14,847 | +7% | 1 | 1 | 0% | 3,008 | 6,088 | +102% | 0 | 0 | — |
case-12 | pass→pass | 14,213 | 10,298 | -28% | 1 | 1 | 0% | 2,855 | 4,968 | +74% | 0 | 0 | — |
case-13 | pass→pass | 13,680 | 17,126 | +25% | 1 | 1 | 0% | 2,591 | 5,840 | +125% | 0 | 0 | — |
case-18 | fail→pass | 12,386 | 7,868 | -36% | 1 | 1 | 0% | 2,259 | 4,349 | +93% | 0 | 0 | — |
case-14 | pass→pass | 13,976 | 12,725 | -9% | 1 | 1 | 0% | 2,764 | 5,356 | +94% | 0 | 0 | — |
case-15 | pass→pass | 8,400 | 7,896 | -6% | 1 | 1 | 0% | 1,896 | 4,728 | +149% | 0 | 0 | — |
case-16 | pass→pass | 7,854 | 5,118 | -35% | 1 | 1 | 0% | 1,714 | 3,897 | +127% | 0 | 0 | — |
case-17 | pass→pass | 12,892 | 8,042 | -38% | 1 | 1 | 0% | 2,475 | 4,394 | +78% | 0 | 0 | — |
case-19 | pass→pass | 9,677 | 9,582 | -1% | 1 | 1 | 0% | 1,549 | 4,423 | +186% | 0 | 0 | — |
case-20 | pass→pass | 10,282 | 6,762 | -34% | 1 | 1 | 0% | 2,141 | 4,207 | +96% | 0 | 0 | — |
case-21 | pass→pass | 6,524 | 5,568 | -15% | 1 | 1 | 0% | 1,201 | 4,010 | +234% | 0 | 0 | — |
case-22 | pass→pass | 8,724 | 12,391 | +42% | 1 | 1 | 0% | 1,746 | 5,278 | +202% | 0 | 0 | — |
case-23 | pass→pass | 4,618 | 4,529 | -2% | 1 | 1 | 0% | 916 | 3,553 | +288% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted. The headline lift of +4 percentage points is the difference between those two pass rates over the 23 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.