算法艺术创作
algorithmic-art
通过代码和可调参数创作生成艺术与交互式视觉效果。
frontend-design-system【设计与创意】Use this skill when the user says 'design system', 'design tokens', 'component library', 'theme', 'colors', 'typography system', 'spacing system', 'component API design', 'variant system', or when creating or extending a frontend design system. This skill enforces: three-tier token hierarchy (primitive, semantic, component), CSS custom properties as …
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
Build a three-tier design token system with CVA-based component variants and theme-aware architecture. Every visual value is a token. No hardcoded colors, spacing, or typography. Components support dark mode, responsive variants, and accessibility out of the box.
Exact user phrases: "design system", "design tokens", "component library", "theme", "colors", "typography system", "spacing system", "component API design", "variant system", "create a design system".
Before activating, verify:
No file output. Produces token definitions and component APIs as text.
Token definitions:
Primitive: --color-{scale}-{step}
Semantic: --color-{role}
Component: --{component}-{property}
Component API:
Component: {Name}
Props: {list with types}
Variants: {variant name -> options}
No preamble. No postamble. No explanations. No filler/hedging/transitions. Compress output.
Token definitions: 15 lines. Component API: 10 lines.
Existing styling stack?
|-- Tailwind CSS --> Use CVA with Tailwind classes + cn() helper
|-- CSS Modules --> Use CVA with @apply and module scoping
|-- styled-components / Emotion --> Use CSS prop or styled() + variants
|-- Vanilla CSS --> Use CSS custom properties + BEM-style classes
|-- CSS-in-JS (other) --> Use the library's variant system
Runtime theme switching needed?
|-- YES --> CSS Custom Properties + semantic tokens (themes are CSS files)
| Components reference semantic tokens, themes swap their values
|-- NO --> Build-time token generation (Style Dictionary -> Tailwind config / CSS)
| Simpler, no runtime overhead. Rebuild to change theme.
Does the component render its children?
|-- YES --> Is it a layout component?
| |-- YES --> Use React children / Vue slots
| |-- NO --> Use composition (compound components)
|-- NO --> Does it accept many optional sub-elements?
|-- YES --> Use slots pattern (leftIcon, rightIcon, subtitle)
|-- NO --> Keep props flat under 10
How many visual states does the component have?
|-- 1-3 (simple) -->
| |-- Single variant, few props --> Direct utility classes or styled()
|-- 4-10 (moderate) -->
| |-- Multiple variants (size, color) --> CVA or recipe()
|-- 10+ (complex) -->
|-- Compound component for sub-elements --> Compound + CVA
|-- Slots for optional elements --> Slot pattern + CVA
Primitive tokens (raw values):
--color-gray-50, --color-blue-500, --font-size-md, --spacing-4
These never change meaning. Direct mappings to design values.
Semantic tokens (meaning):
--color-bg-primary, --color-text-body, --color-border
These reference primitives. Meaning is stable even when theme changes.
Component tokens (scoped):
--button-bg, --card-padding, --input-border
These reference semantic tokens. Components only use these, never primitives.
:root {
/* Primitives */
--color-gray-50: #f9fafb;
--color-gray-100: #f3f4f6;
--color-blue-500: #3b82f6;
--color-blue-600: #2563eb;
--font-size-sm: 0.875rem;
--font-size-md: 1rem;
--spacing-1: 0.25rem;
--spacing-2: 0.5rem;
--spacing-4: 1rem;
/* Semantic */
--color-bg-primary: var(--color-gray-50);
--color-text-primary: #111827;
--color-text-secondary: #6b7280;
--color-border: var(--color-gray-100);
--color-brand: var(--color-blue-600);
--font-body: var(--font-size-md);
--spacing-stack: var(--spacing-4);
/* Component */
--button-bg: var(--color-brand);
--button-text: #ffffff;
--button-padding: var(--spacing-2) var(--spacing-4);
--button-radius: 0.375rem;
}
:root[data-theme="dark"] {
--color-bg-primary: #111827;
--color-text-primary: #f9fafb;
--color-text-secondary: #9ca3af;
--color-border: #374151;
/* Component tokens inherit automatically via --button-bg: var(--color-brand) */
}
Components never reference dark-mode values directly. They reference semantic tokens which change under [data-theme="dark"].
interface ButtonProps {
// Variants (use CVA)
variant: 'primary' | 'secondary' | 'ghost' | 'danger'
size: 'sm' | 'md' | 'lg'
// Behavior
type?: 'button' | 'submit'
disabled?: boolean
loading?: boolean
// Content
children: React.ReactNode
leftIcon?: React.ReactNode
rightIcon?: React.ReactNode
// Escape hatch
className?: string
// Maximum 10 props
}
import { cva, type VariantProps } from 'class-variance-authority'
const buttonVariants = cva(
'inline-flex items-center justify-center rounded-md font-medium transition-colors',
{
variants: {
variant: {
primary: 'bg-blue-600 text-white hover:bg-blue-700',
secondary: 'bg-gray-100 text-gray-900 hover:bg-gray-200',
ghost: 'text-gray-700 hover:bg-gray-100',
danger: 'bg-red-600 text-white hover:bg-red-700',
},
size: {
sm: 'h-8 px-3 text-sm',
md: 'h-10 px-4 text-base',
lg: 'h-12 px-6 text-lg',
},
},
defaultVariants: { variant: 'primary', size: 'md' },
}
)
function Card({ children, className }) {
return <div className={cn('rounded-xl border p-6', className)}>{children}</div>;
}
Card.Header = function CardHeader({ children, className }) {
return <div className={cn('mb-4', className)}>{children}</div>;
};
Card.Body = function CardBody({ children, className }) {
return <div className={cn('space-y-4', className)}>{children}</div>;
};
Card.Footer = function CardFooter({ children, className }) {
return <div className={cn('mt-4 pt-4 border-t', className)}>{children}</div>;
};
// Usage
<Card>
<Card.Header>Title</Card.Header>
<Card.Body>Content</Card.Body>
<Card.Footer>Actions</Card.Footer>
</Card>;
function Text({ as: Component = 'p', variant = 'body', children, className }) {
const styles = {
h1: 'text-3xl font-bold',
h2: 'text-2xl font-semibold',
h3: 'text-xl font-medium',
body: 'text-base',
caption: 'text-sm text-gray-500',
};
return <Component className={cn(styles[variant], className)}>{children}</Component>;
}
it('renders with correct variant classes', () => {
const { container } = render(<Button variant="primary">Click</Button>);
const button = container.querySelector('button');
expect(button.className).toContain('bg-blue-600');
expect(button.className).toContain('text-white');
});
it('applies disabled state', () => {
const { container } = render(<Button disabled>Click</Button>);
expect(container.querySelector('button')).toBeDisabled();
});
{
"color": {
"brand": {
"500": { "value": "#3b82f6" }
}
},
"spacing": {
"sm": { "value": "0.5rem" },
"md": { "value": "1rem" }
}
}
npx style-dictionary build --config style-dictionary.config.js
# Outputs: css/tokens.css, scss/_tokens.scss, js/tokens.js
Every component in the design system must:
// Base focus style mixin for all components
const focusVisible = 'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600'
const buttonVariants = cva(
`inline-flex items-center justify-center rounded-md font-medium transition-colors ${focusVisible}`,
// ...
)
/* BAD -- hardcoded color */
.button { background: #3b82f6; }
/* GOOD -- token reference */
.button { background: var(--button-bg); }
/* BAD -- component token references primitive directly */
--button-bg: var(--color-blue-500);
/* GOOD -- component token references semantic token */
--button-bg: var(--color-brand);
--color-brand: var(--color-blue-500);
This allows the theme to change --color-brand without touching component tokens.
More than 10 props on a component makes it hard to use and maintain. Prefer composition (children, slots) over configuration props.
Every interactive component must have visible focus states. Design system components that omit focus rings fail WCAG 2.4.7.
Passing theme values through component props creates tight coupling. Use CSS custom properties or React context for theming.
Every data-driven component (Table, Dropdown, Autocomplete) must handle loading, empty, and error states. These should be part of the design system.
Components should support responsive behavior at the container level, not just the page level.
| Approach | Token System | Variant System | Runtime Theming | Bundle Size |
|---|---|---|---|---|
| CSS Custom Properties + CVA | Yes (3-tier) | CVA | Yes | 0 KB runtime |
| Tailwind + CVA | Via config | CVA | Yes (CSS vars) | < 15 KB CSS |
| styled-components | Via ThemeProvider | styled() + css() | Yes | ~15 KB runtime |
| Theme UI / Stitches | Design tokens | Variant system | Yes | ~5 KB runtime |
| Material UI Theme | Theme object | sx prop | Yes | ~30 KB |
| Radix UI | Unstyled | Unstyled | Manual | 0 KB (unstyling) |
CSS custom properties are resolved at computed-value time, not cascade time. This means:
var(--color-brand) has a small performance cost on first style resolutionCVA is a function that returns a class string. It is negligible (< 0.01ms per call). The class string itself is fast because it is CSS -- no runtime style computation.
A well-designed design system component library should add:
className) for one-off overrides.references/component-api.md -- Component API Designreferences/component-architecture.md -- Component Architecturereferences/design-system-implementation.md -- Design System Implementationreferences/design-system-testing.md -- Design System Testingreferences/design-tokens.md -- Design Tokensreferences/theme-implementation.md -- Theme Implementationreferences/design-system-token-architecture.md -- Design System Token Architecturereferences/design-system-component-library.md -- Design System Component Library ArchitectureNo artifact produced. Next skill: frontend-state-management -- state architecture for the design system. Carry forward: token definitions, component API rules, dark mode strategy.
` interface EventObserver { onEvent(event: T): Promise; }
class EventBus { private observers: Set<EventObserver> = new Set(); subscribe(observer: EventObserver): void { this.observers.add(observer); } unsubscribe(observer: EventObserver): void { this.observers.delete(observer); } async emit(event: T): Promise { const results = Array.from(this.observers).map(o => o.onEvent(event)); await Promise.allSettled(results); } } `
config: defaults: timeout: 30s retryCount: 3 overrides: production: timeout: 60s retryCount: 5 development: timeout: 300s retryCount: 1
| Metric | Threshold | Severity | Action |
|---|---|---|---|
| Error rate | > 1% over 5min | Critical | Page on-call |
| p99 latency | > 2s over 5min | Warning | Investigate |
| Throughput drop | > 50% over 1min | Critical | Check upstream |
| Queue depth | > 1000 over 1min | Warning | Scale consumers |
| Disk usage | > 85% | Warning | Clean or expand |
| Memory usage | > 90% heap | Critical | Restart or scale |
| Anti-Pattern | Symptom | Root Cause | Solution |
|---|---|---|---|
| Premature optimization | Complex code for no measured benefit | Guessing instead of profiling | Measure first, optimize based on data |
| Copy-paste reuse | Duplicate code across codebase | Lack of abstraction | Extract shared logic into libraries |
| Gold-plating | Features with no current requirement | Over-engineering | YAGNI — build what's needed now |
| Magical thinking | Assumptions without validation | Skipping error handling | Handle all failure modes explicitly |
Cache hierarchy: L1 (in-memory local) → L2 (distributed Redis/Memcached) → L3 (CDN/Edge). Cache invalidation: TTL-based (simple, stale), event-based (complex, fresh), write-through (consistent, higher write latency), write-behind (fast writes, eventual consistency).
Is the component presentational or behavioral?
├── Presentational → Stateless, fully prop-driven, no internal state
└── Behavioral → Does it manage complex state?
├── Yes → Split into container (state) + presentational (render)
└── No → Single component with internal state
Does it need styling customization?
├── Yes → CSS custom properties + className prop
└── No → Fully scoped styles, no override API
Who defines the tokens?
├── Design team → Token names match Figma variables (semantic)
├── Engineering → Technology-agnostic naming with transform layer
└── Cross-functional → Design-engineering pair, token review committee
What output formats are needed?
├── CSS only → CSS custom properties in a single file
└── Multi-format → Style Dictionary with transforms (CSS, JS, Swift, Kotlin)