design-system-generator
SKILL.md
Design System Generator
Instructions
When creating a design system:
- Define design tokens (colors, typography, spacing)
- Create base components (Button, Input, Card, etc.)
- Establish patterns (forms, navigation, layouts)
- Document usage and variants
Design Tokens
Colors
// tokens/colors.ts
export const colors = {
// Brand
primary: {
50: '#eff6ff',
100: '#dbeafe',
200: '#bfdbfe',
300: '#93c5fd',
400: '#60a5fa',
500: '#3b82f6', // Main
600: '#2563eb',
700: '#1d4ed8',
800: '#1e40af',
900: '#1e3a8a',
},
// Semantic
success: {
light: '#dcfce7',
main: '#22c55e',
dark: '#15803d',
},
warning: {
light: '#fef3c7',
main: '#f59e0b',
dark: '#b45309',
},
error: {
light: '#fee2e2',
main: '#ef4444',
dark: '#b91c1c',
},
// Neutral
gray: {
50: '#f9fafb',
100: '#f3f4f6',
200: '#e5e7eb',
300: '#d1d5db',
400: '#9ca3af',
500: '#6b7280',
600: '#4b5563',
700: '#374151',
800: '#1f2937',
900: '#111827',
},
} as const;
Typography
// tokens/typography.ts
export const typography = {
fontFamily: {
sans: ['Inter', 'system-ui', 'sans-serif'],
mono: ['JetBrains Mono', 'monospace'],
},
fontSize: {
xs: ['0.75rem', { lineHeight: '1rem' }],
sm: ['0.875rem', { lineHeight: '1.25rem' }],
base: ['1rem', { lineHeight: '1.5rem' }],
lg: ['1.125rem', { lineHeight: '1.75rem' }],
xl: ['1.25rem', { lineHeight: '1.75rem' }],
'2xl': ['1.5rem', { lineHeight: '2rem' }],
'3xl': ['1.875rem', { lineHeight: '2.25rem' }],
'4xl': ['2.25rem', { lineHeight: '2.5rem' }],
'5xl': ['3rem', { lineHeight: '1.15' }],
},
fontWeight: {
normal: '400',
medium: '500',
semibold: '600',
bold: '700',
},
} as const;
Spacing
// tokens/spacing.ts
export const spacing = {
px: '1px',
0: '0',
0.5: '0.125rem', // 2px
1: '0.25rem', // 4px
1.5: '0.375rem', // 6px
2: '0.5rem', // 8px
2.5: '0.625rem', // 10px
3: '0.75rem', // 12px
4: '1rem', // 16px
5: '1.25rem', // 20px
6: '1.5rem', // 24px
8: '2rem', // 32px
10: '2.5rem', // 40px
12: '3rem', // 48px
16: '4rem', // 64px
20: '5rem', // 80px
24: '6rem', // 96px
} as const;
Shadows & Radii
// tokens/effects.ts
export const shadows = {
sm: '0 1px 2px 0 rgb(0 0 0 / 0.05)',
DEFAULT: '0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)',
md: '0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)',
lg: '0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)',
xl: '0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)',
};
export const radii = {
none: '0',
sm: '0.125rem',
DEFAULT: '0.25rem',
md: '0.375rem',
lg: '0.5rem',
xl: '0.75rem',
'2xl': '1rem',
full: '9999px',
};
CSS Variables Setup
/* globals.css */
:root {
/* Colors */
--color-primary: 59 130 246;
--color-primary-foreground: 255 255 255;
--color-background: 255 255 255;
--color-foreground: 17 24 39;
--color-muted: 243 244 246;
--color-muted-foreground: 107 114 128;
--color-border: 229 231 235;
--color-ring: 59 130 246;
/* Spacing */
--spacing-unit: 0.25rem;
/* Typography */
--font-sans: 'Inter', system-ui, sans-serif;
--font-mono: 'JetBrains Mono', monospace;
/* Radii */
--radius: 0.5rem;
}
.dark {
--color-background: 17 24 39;
--color-foreground: 243 244 246;
--color-muted: 31 41 55;
--color-muted-foreground: 156 163 175;
--color-border: 55 65 81;
}
Base Components
Button
// components/ui/button.tsx
import { cva, type VariantProps } from 'class-variance-authority';
import { cn } from '@/lib/utils';
const buttonVariants = cva(
'inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
{
variants: {
variant: {
primary: 'bg-primary-500 text-white hover:bg-primary-600',
secondary: 'bg-gray-100 text-gray-900 hover:bg-gray-200',
outline: 'border border-gray-300 bg-transparent hover:bg-gray-50',
ghost: 'hover:bg-gray-100',
destructive: 'bg-red-500 text-white hover:bg-red-600',
link: 'text-primary-500 underline-offset-4 hover:underline',
},
size: {
sm: 'h-8 px-3 text-sm',
md: 'h-10 px-4',
lg: 'h-12 px-6 text-lg',
icon: 'h-10 w-10',
},
},
defaultVariants: {
variant: 'primary',
size: 'md',
},
}
);
interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
isLoading?: boolean;
}
export function Button({
className,
variant,
size,
isLoading,
children,
disabled,
...props
}: ButtonProps) {
return (
<button
className={cn(buttonVariants({ variant, size }), className)}
disabled={disabled || isLoading}
{...props}
>
{isLoading && <Spinner className="mr-2 h-4 w-4" />}
{children}
</button>
);
}
Input
// components/ui/input.tsx
import { cn } from '@/lib/utils';
import { forwardRef } from 'react';
interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
error?: string;
}
export const Input = forwardRef<HTMLInputElement, InputProps>(
({ className, error, ...props }, ref) => {
return (
<div className="space-y-1">
<input
ref={ref}
className={cn(
'flex h-10 w-full rounded-md border bg-white px-3 py-2 text-sm',
'placeholder:text-gray-400',
'focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-transparent',
'disabled:cursor-not-allowed disabled:opacity-50',
error ? 'border-red-500' : 'border-gray-300',
className
)}
aria-invalid={!!error}
{...props}
/>
{error && (
<p className="text-sm text-red-500" role="alert">
{error}
</p>
)}
</div>
);
}
);
Input.displayName = 'Input';
Card
// components/ui/card.tsx
import { cn } from '@/lib/utils';
interface CardProps extends React.HTMLAttributes<HTMLDivElement> {}
export function Card({ className, ...props }: CardProps) {
return (
<div
className={cn(
'rounded-lg border bg-white shadow-sm',
className
)}
{...props}
/>
);
}
export function CardHeader({ className, ...props }: CardProps) {
return <div className={cn('p-6 pb-0', className)} {...props} />;
}
export function CardTitle({ className, ...props }: CardProps) {
return <h3 className={cn('text-lg font-semibold', className)} {...props} />;
}
export function CardContent({ className, ...props }: CardProps) {
return <div className={cn('p-6', className)} {...props} />;
}
export function CardFooter({ className, ...props }: CardProps) {
return <div className={cn('p-6 pt-0 flex gap-2', className)} {...props} />;
}
Tailwind Config
// tailwind.config.js
const { colors, typography, spacing, shadows, radii } = require('./tokens');
module.exports = {
content: ['./src/**/*.{js,ts,jsx,tsx}'],
darkMode: 'class',
theme: {
extend: {
colors: {
primary: colors.primary,
gray: colors.gray,
success: colors.success,
warning: colors.warning,
error: colors.error,
},
fontFamily: typography.fontFamily,
fontSize: typography.fontSize,
spacing: spacing,
boxShadow: shadows,
borderRadius: radii,
},
},
plugins: [],
};
Utility Function
// lib/utils.ts
import { clsx, type ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge';
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
Component Index
// components/ui/index.ts
export { Button } from './button';
export { Input } from './input';
export { Card, CardHeader, CardTitle, CardContent, CardFooter } from './card';
export { Badge } from './badge';
export { Avatar } from './avatar';
export { Select } from './select';
export { Checkbox } from './checkbox';
export { Radio } from './radio';
export { Switch } from './switch';
export { Modal } from './modal';
export { Toast } from './toast';
export { Tabs } from './tabs';
export { Dropdown } from './dropdown';
Weekly Installs
16
Repository
onewave-ai/claude-skillsGitHub Stars
53
First Seen
Feb 25, 2026
Security Audits
Installed on
codex13
opencode12
gemini-cli12
github-copilot12
amp12
kimi-cli12