Back to skills
SkillHub ClubDesign ProductFull StackFrontendDesigner

frontend-design

Create distinctive, production-grade frontend interfaces with high design quality. Provides analysis tools for auditing existing designs and generation tools for creating color palettes, typography systems, design tokens, and component templates. Supports React, Vue, Svelte, and vanilla HTML/CSS. Use when building web components, pages, or applications. Keywords: design, UI, frontend, CSS, components, palette, typography, tokens, accessibility.

Packaged view

This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.

Stars
35
Hot score
90
Updated
March 20, 2026
Overall rating
C2.5
Composite score
2.5
Best-practice grade
N/A

Install command

npx @skill-hub/cli install jwynia-agent-skills-frontend-design
frontendUICSSdesign-systemcomponents

Repository

jwynia/agent-skills

Skill path: skills/frontend/design/frontend-design

Create distinctive, production-grade frontend interfaces with high design quality. Provides analysis tools for auditing existing designs and generation tools for creating color palettes, typography systems, design tokens, and component templates. Supports React, Vue, Svelte, and vanilla HTML/CSS. Use when building web components, pages, or applications. Keywords: design, UI, frontend, CSS, components, palette, typography, tokens, accessibility.

Open repository

Best for

Primary workflow: Design Product.

Technical facets: Full Stack, Frontend, Designer.

Target audience: everyone.

License: MIT.

Original source

Catalog source: SkillHub Club.

Repository owner: jwynia.

This is still a mirrored public skill entry. Review the repository before installing into production workflows.

What it helps with

  • Install frontend-design into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
  • Review https://github.com/jwynia/agent-skills before adding frontend-design to shared team environments
  • Use frontend-design for development workflows

Works across

Claude CodeCodex CLIGemini CLIOpenCode

Favorites: 0.

Sub-skills: 0.

Aggregator: No.

Original source / Raw SKILL.md

---
name: frontend-design
description: "Create distinctive, production-grade frontend interfaces with high design quality. Provides analysis tools for auditing existing designs and generation tools for creating color palettes, typography systems, design tokens, and component templates. Supports React, Vue, Svelte, and vanilla HTML/CSS. Use when building web components, pages, or applications. Keywords: design, UI, frontend, CSS, components, palette, typography, tokens, accessibility."
license: MIT
compatibility: Requires Deno with --allow-read, --allow-write permissions
metadata:
  author: agent-skills
  version: "1.0"
---

# Frontend Design

Create distinctive, production-grade frontend interfaces that avoid generic "AI slop" aesthetics. This skill combines design philosophy guidance with practical TypeScript tooling for analyzing existing designs and generating design system artifacts.

**Core Principle**: Choose a clear aesthetic direction and execute it with precision. Bold maximalism and refined minimalism both work - the key is intentionality, not intensity.

## When to Use This Skill

**Use when**:
- Building web components, pages, or applications
- Auditing existing CSS for design inconsistencies
- Extracting design tokens from legacy codebases
- Generating color palettes and typography systems
- Creating component templates across frameworks
- Checking accessibility compliance for design elements

**Don't use when**:
- Simple text content changes
- Backend-only work
- Non-visual functionality

## Prerequisites

- **Deno** runtime (for script execution)
- Optional: Existing CSS/design files for analysis
- Optional: Design tokens file for reference

## Quick Start

This skill operates in three modes:

### 1. Analyze Mode
Audit existing styles, extract tokens, check accessibility.

```bash
# Audit CSS for design patterns and inconsistencies
deno run --allow-read scripts/analyze-styles.ts styles.css

# Extract design tokens from existing CSS
deno run --allow-read scripts/extract-tokens.ts ./src --format css

# Check accessibility (contrast, focus states)
deno run --allow-read scripts/analyze-accessibility.ts component.tsx
```

### 2. Specify Mode
Create JSON specifications defining what to generate. See `assets/` for schema examples.

### 3. Generate Mode
Create palettes, typography systems, tokens, and components.

```bash
# Generate a color palette
deno run --allow-read --allow-write scripts/generate-palette.ts --seed "#2563eb" --theme warm

# Generate typography system
deno run --allow-read --allow-write scripts/generate-typography.ts --display "Playfair Display" --body "Source Sans Pro"

# Generate design tokens file
deno run --allow-read --allow-write scripts/generate-tokens.ts tokens-spec.json ./output/

# Generate a component
deno run --allow-read --allow-write scripts/generate-component.ts --name Button --framework react --styling tailwind
```

---

## Instructions

### Phase 1: Analysis (Optional but Recommended)

Before creating new designs, audit existing code to understand current patterns.

#### 1a. Style Analysis

Analyze CSS files to identify colors, typography, spacing, and inconsistencies:

```bash
deno run --allow-read scripts/analyze-styles.ts <input> [options]

Options:
  --tokens <file>    Compare against existing design tokens
  --pretty           Pretty-print JSON output
  --format <type>    Output format: json (default), summary
```

**Output includes**:
- Color usage inventory with hex normalization
- Typography patterns (fonts, sizes, weights)
- Spacing value distribution
- Inconsistencies and recommendations

#### 1b. Token Extraction

Extract design tokens from CSS files into standardized formats:

```bash
deno run --allow-read scripts/extract-tokens.ts <input> [options]

Options:
  --format <type>    Output: css, scss, tailwind, style-dictionary, tokens-studio
  --output-css       Also output CSS variables file
```

#### 1c. Accessibility Audit

Check design-related accessibility issues:

```bash
deno run --allow-read scripts/analyze-accessibility.ts <input> [options]

Options:
  --format <type>    Output: json, summary
  --level <AA|AAA>   WCAG conformance level (default: AA)
```

**Checks include**:
- Color contrast ratios
- Focus indicator presence
- Touch target sizes
- Motion preference respect

---

### Phase 2: Generation

#### 2a. Color Palette Generation

Generate cohesive color palettes from seed colors or themes:

```bash
deno run --allow-read --allow-write scripts/generate-palette.ts [options] <output>

Options:
  --seed <color>     Primary seed color (hex)
  --theme <type>     warm, cool, neutral, vibrant, muted, dark, light
  --style <type>     minimalist, bold, organic, corporate, playful
  --shades           Generate 50-950 shade scale
  --semantic         Generate success/warning/error colors
  --contrast <lvl>   Target contrast: AA (default), AAA
  --format <type>    css, scss, tailwind, tokens, json
```

**Example specification** (`palette-spec.json`):
```json
{
  "seedColors": {
    "primary": "#2563eb",
    "accent": "#f59e0b"
  },
  "theme": "cool",
  "generateShades": true,
  "generateSemantics": true,
  "contrastTarget": "AA",
  "outputFormat": "css"
}
```

#### 2b. Typography System Generation

Generate typography systems with font stacks and scales:

```bash
deno run --allow-read --allow-write scripts/generate-typography.ts [options] <output>

Options:
  --display <font>   Display/heading font family
  --body <font>      Body text font family
  --mono <font>      Monospace font family
  --scale <type>     minor-second, major-second, minor-third, major-third, perfect-fourth, golden-ratio
  --base <px>        Base font size (default: 16)
  --line-height      tight, normal, relaxed
  --responsive       Generate responsive breakpoints
  --format <type>    css, scss, tailwind, tokens
```

**Type scales**:
| Scale | Ratio | Character |
|-------|-------|-----------|
| minor-second | 1.067 | Subtle, conservative |
| major-second | 1.125 | Balanced, professional |
| minor-third | 1.200 | Clear hierarchy |
| major-third | 1.250 | Strong presence |
| perfect-fourth | 1.333 | Bold, impactful |
| golden-ratio | 1.618 | Dramatic, artistic |

#### 2c. Design Token Generation

Generate comprehensive design token files in multiple formats:

```bash
deno run --allow-read --allow-write scripts/generate-tokens.ts <spec> <output-dir>
```

**Specification structure**:
```json
{
  "name": "my-design-system",
  "tokens": {
    "color": { "primary": "#2563eb", "secondary": "#64748b" },
    "spacing": { "xs": "0.25rem", "sm": "0.5rem", "md": "1rem" },
    "typography": {
      "fontFamilies": { "display": "Playfair Display", "body": "Inter" },
      "fontSizes": { "sm": "0.875rem", "base": "1rem", "lg": "1.125rem" }
    },
    "shadow": { "sm": "0 1px 2px rgba(0,0,0,0.05)" },
    "border": { "radius": { "sm": "0.25rem", "md": "0.5rem" } },
    "animation": { "duration": { "fast": "150ms", "normal": "300ms" } }
  },
  "outputFormats": ["css", "scss", "tailwind", "ts"]
}
```

#### 2d. Component Generation

Generate component templates with design-focused styling:

```bash
deno run --allow-read --allow-write scripts/generate-component.ts [options] <output-dir>

Options:
  --name <name>      Component name (required)
  --type <type>      button, card, input, modal, navigation, hero, custom
  --framework <fw>   react, vue, svelte, html
  --styling <type>   css, tailwind, css-modules, styled-components, emotion
  --aesthetic <type> minimal, bold, organic, brutalist, glassmorphism, neumorphism
  --animation <lvl>  none, subtle, expressive
  --dark-mode        Include dark mode support
  --tokens <file>    Use design tokens file
```

**Framework output examples**:

React with Tailwind:
```tsx
export function Button({ variant = 'primary', children }: ButtonProps) {
  return (
    <button className="px-4 py-2 rounded-lg font-medium transition-all">
      {children}
    </button>
  );
}
```

Vue with scoped CSS:
```vue
<template>
  <button :class="['btn', `btn--${variant}`]"><slot /></button>
</template>
<script setup lang="ts">
defineProps<{ variant?: 'primary' | 'secondary' }>();
</script>
<style scoped>.btn { /* styles */ }</style>
```

Svelte:
```svelte
<script lang="ts">
  export let variant: 'primary' | 'secondary' = 'primary';
</script>
<button class="btn btn--{variant}"><slot /></button>
<style>.btn { /* styles */ }</style>
```

---

## Examples

### Example 1: Audit and Modernize Legacy CSS

```bash
# 1. Analyze existing styles
deno run --allow-read scripts/analyze-styles.ts ./legacy/styles.css --pretty > audit.json

# 2. Extract tokens from the analysis
deno run --allow-read scripts/extract-tokens.ts ./legacy/styles.css --format css > tokens.css

# 3. Generate improved palette from dominant color
deno run --allow-read --allow-write scripts/generate-palette.ts --seed "#336699" --shades --format css palette.css
```

### Example 2: Create Design System from Scratch

```bash
# 1. Generate color palette
deno run --allow-read --allow-write scripts/generate-palette.ts \
  --seed "#8b5cf6" --theme vibrant --shades --semantic --format css colors.css

# 2. Generate typography system
deno run --allow-read --allow-write scripts/generate-typography.ts \
  --display "Space Grotesk" --body "Inter" --scale major-third --responsive --format css typography.css

# 3. Generate comprehensive tokens
deno run --allow-read --allow-write scripts/generate-tokens.ts design-spec.json ./tokens/
```

### Example 3: Generate Component Library

```bash
# Generate button component for React with Tailwind
deno run --allow-read --allow-write scripts/generate-component.ts \
  --name Button --framework react --styling tailwind --aesthetic bold ./components/

# Generate card component for Vue with CSS modules
deno run --allow-read --allow-write scripts/generate-component.ts \
  --name Card --framework vue --styling css-modules --aesthetic glassmorphism ./components/

# Generate input for Svelte
deno run --allow-read --allow-write scripts/generate-component.ts \
  --name Input --framework svelte --styling css --aesthetic minimal ./components/
```

### Example 4: Accessibility Check Before Launch

```bash
# Audit all components
deno run --allow-read scripts/analyze-accessibility.ts ./src/components --level AAA --format summary
```

---

## Script Reference

| Script | Purpose | Permissions |
|--------|---------|-------------|
| `analyze-styles.ts` | Audit CSS for patterns and inconsistencies | `--allow-read` |
| `extract-tokens.ts` | Extract design tokens from CSS | `--allow-read` |
| `analyze-accessibility.ts` | Check design accessibility | `--allow-read` |
| `generate-palette.ts` | Generate color palettes | `--allow-read --allow-write` |
| `generate-typography.ts` | Generate typography systems | `--allow-read --allow-write` |
| `generate-tokens.ts` | Generate multi-format tokens | `--allow-read --allow-write` |
| `generate-component.ts` | Generate framework components | `--allow-read --allow-write` |

---

## Design Philosophy

Avoid generic "AI slop" aesthetics. See `references/design-philosophy.md` for detailed guidance.

**Key principles**:
- **Typography**: Choose distinctive fonts, not defaults (avoid Arial, Inter, Roboto)
- **Color**: Dominant colors with sharp accents, not timid palettes
- **Motion**: Orchestrated reveals over scattered micro-interactions
- **Composition**: Asymmetry, overlap, grid-breaking elements
- **Texture**: Gradients, noise, patterns - not flat solid colors

**Never converge on**:
- Purple gradients on white backgrounds
- System fonts or overused families
- Predictable card-based layouts
- Cookie-cutter Bootstrap aesthetics

---

## Common Issues

**"CSS parsing failed"**
- Ensure valid CSS syntax
- SCSS/PostCSS may need preprocessing first

**"Color contrast check failed"**
- Check for CSS variables that couldn't be resolved
- Provide the actual color values or tokens file

**"Unknown framework"**
- Supported: react, vue, svelte, html
- Check spelling and lowercase

**"Token format not supported"**
- Supported: css, scss, tailwind, style-dictionary, tokens-studio, json, ts

---

## Additional Resources

- `references/design-philosophy.md` - Detailed anti-slop aesthetics guide
- `references/token-formats.md` - Design token format specifications
- `references/framework-templates.md` - Framework-specific patterns
- `assets/*.json` - JSON schema files for specifications

---

## Related Skills

- `web-search` - Research design inspiration and trends
- `research-workflow` - Deep dive into design systems


---

## Referenced Files

> The following files are referenced in this skill and included for context.

### scripts/analyze-styles.ts

```typescript
#!/usr/bin/env -S deno run --allow-read

/**
 * analyze-styles.ts - CSS Style Auditor
 *
 * Analyzes CSS files to extract color, typography, spacing patterns
 * and identify design inconsistencies.
 */

import { parseArgs } from "jsr:@std/[email protected]/parse-args";
import { basename, extname, resolve } from "jsr:@std/[email protected]";
import { walk } from "jsr:@std/[email protected]/walk";

// === Constants ===
const VERSION = "1.0.0";
const SCRIPT_NAME = "analyze-styles";

// === Types ===
export interface ColorUsage {
  value: string;
  normalizedHex: string;
  count: number;
  locations: string[];
  suggestedTokenName?: string;
}

export interface TypographyUsage {
  property: "font-family" | "font-size" | "font-weight" | "line-height";
  value: string;
  count: number;
  locations: string[];
}

export interface SpacingUsage {
  property: string;
  value: string;
  count: number;
  locations: string[];
}

export interface StyleInconsistency {
  type: "color" | "font" | "spacing" | "z-index";
  description: string;
  values: string[];
  suggestion: string;
}

export interface StyleAuditResult {
  filename: string;
  summary: {
    totalSelectors: number;
    totalDeclarations: number;
    uniqueColors: number;
    uniqueFonts: number;
    uniqueSpacingValues: number;
  };
  colors: ColorUsage[];
  typography: TypographyUsage[];
  spacing: SpacingUsage[];
  inconsistencies: StyleInconsistency[];
  recommendations: string[];
}

interface AnalyzeOptions {
  input: string;
  tokensFile?: string;
  pretty: boolean;
  format: "json" | "summary";
}

// === Color Utilities ===

const COLOR_REGEX =
  /#(?:[0-9a-fA-F]{3}){1,2}\b|rgb\([^)]+\)|rgba\([^)]+\)|hsl\([^)]+\)|hsla\([^)]+\)|(?:transparent|currentColor|inherit)\b/gi;

const NAMED_COLORS: Record<string, string> = {
  black: "#000000",
  white: "#ffffff",
  red: "#ff0000",
  green: "#008000",
  blue: "#0000ff",
  yellow: "#ffff00",
  cyan: "#00ffff",
  magenta: "#ff00ff",
  gray: "#808080",
  grey: "#808080",
};

function normalizeColor(color: string): string {
  const lower = color.toLowerCase().trim();

  // Handle named colors
  if (NAMED_COLORS[lower]) {
    return NAMED_COLORS[lower];
  }

  // Handle hex shorthand
  if (/^#[0-9a-f]{3}$/i.test(lower)) {
    const r = lower[1];
    const g = lower[2];
    const b = lower[3];
    return `#${r}${r}${g}${g}${b}${b}`;
  }

  // Handle rgb/rgba
  const rgbMatch = lower.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);
  if (rgbMatch) {
    const r = parseInt(rgbMatch[1]).toString(16).padStart(2, "0");
    const g = parseInt(rgbMatch[2]).toString(16).padStart(2, "0");
    const b = parseInt(rgbMatch[3]).toString(16).padStart(2, "0");
    return `#${r}${g}${b}`;
  }

  // Already normalized hex or other
  return lower;
}

function suggestTokenName(hex: string, index: number): string {
  // Simple heuristic based on luminance
  const r = parseInt(hex.slice(1, 3), 16);
  const g = parseInt(hex.slice(3, 5), 16);
  const b = parseInt(hex.slice(5, 7), 16);
  const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;

  if (luminance > 0.9) return `color-light-${index}`;
  if (luminance < 0.1) return `color-dark-${index}`;
  if (r > g && r > b) return `color-red-${index}`;
  if (g > r && g > b) return `color-green-${index}`;
  if (b > r && b > g) return `color-blue-${index}`;
  return `color-neutral-${index}`;
}

// === CSS Parsing ===

interface Declaration {
  property: string;
  value: string;
  selector: string;
}

function parseCSS(css: string): Declaration[] {
  const declarations: Declaration[] = [];
  let currentSelector = "";

  // Remove comments
  const cleaned = css.replace(/\/\*[\s\S]*?\*\//g, "");

  // Simple regex-based parser (handles most common cases)
  const ruleRegex = /([^{]+)\{([^}]+)\}/g;
  let match;

  while ((match = ruleRegex.exec(cleaned)) !== null) {
    currentSelector = match[1].trim();
    const body = match[2];

    // Parse declarations
    const declRegex = /([a-z-]+)\s*:\s*([^;]+);?/gi;
    let declMatch;

    while ((declMatch = declRegex.exec(body)) !== null) {
      declarations.push({
        property: declMatch[1].toLowerCase().trim(),
        value: declMatch[2].trim(),
        selector: currentSelector,
      });
    }
  }

  return declarations;
}

// === Analysis Functions ===

function analyzeColors(declarations: Declaration[]): ColorUsage[] {
  const colorMap = new Map<string, ColorUsage>();

  const colorProperties = [
    "color",
    "background-color",
    "background",
    "border-color",
    "border",
    "border-top-color",
    "border-right-color",
    "border-bottom-color",
    "border-left-color",
    "outline-color",
    "box-shadow",
    "text-shadow",
    "fill",
    "stroke",
  ];

  for (const decl of declarations) {
    if (colorProperties.some((p) => decl.property.includes(p))) {
      const colors = decl.value.match(COLOR_REGEX) || [];

      for (const color of colors) {
        if (color === "transparent" || color === "currentColor" || color === "inherit") {
          continue;
        }

        const normalized = normalizeColor(color);
        const location = `${decl.selector}:${decl.property}`;

        if (colorMap.has(normalized)) {
          const existing = colorMap.get(normalized)!;
          existing.count++;
          if (!existing.locations.includes(location)) {
            existing.locations.push(location);
          }
        } else {
          colorMap.set(normalized, {
            value: color,
            normalizedHex: normalized,
            count: 1,
            locations: [location],
          });
        }
      }
    }
  }

  // Add suggested token names
  const colors = Array.from(colorMap.values()).sort((a, b) => b.count - a.count);
  colors.forEach((c, i) => {
    c.suggestedTokenName = suggestTokenName(c.normalizedHex, i + 1);
  });

  return colors;
}

function analyzeTypography(declarations: Declaration[]): TypographyUsage[] {
  const typoMap = new Map<string, TypographyUsage>();
  const typoProperties = ["font-family", "font-size", "font-weight", "line-height"];

  for (const decl of declarations) {
    if (typoProperties.includes(decl.property)) {
      const key = `${decl.property}:${decl.value}`;
      const location = `${decl.selector}:${decl.property}`;

      if (typoMap.has(key)) {
        const existing = typoMap.get(key)!;
        existing.count++;
        if (!existing.locations.includes(location)) {
          existing.locations.push(location);
        }
      } else {
        typoMap.set(key, {
          property: decl.property as TypographyUsage["property"],
          value: decl.value,
          count: 1,
          locations: [location],
        });
      }
    }
  }

  return Array.from(typoMap.values()).sort((a, b) => b.count - a.count);
}

function analyzeSpacing(declarations: Declaration[]): SpacingUsage[] {
  const spacingMap = new Map<string, SpacingUsage>();
  const spacingProperties = [
    "margin",
    "margin-top",
    "margin-right",
    "margin-bottom",
    "margin-left",
    "padding",
    "padding-top",
    "padding-right",
    "padding-bottom",
    "padding-left",
    "gap",
    "row-gap",
    "column-gap",
  ];

  for (const decl of declarations) {
    if (spacingProperties.includes(decl.property)) {
      const key = `${decl.property}:${decl.value}`;
      const location = `${decl.selector}:${decl.property}`;

      if (spacingMap.has(key)) {
        const existing = spacingMap.get(key)!;
        existing.count++;
        if (!existing.locations.includes(location)) {
          existing.locations.push(location);
        }
      } else {
        spacingMap.set(key, {
          property: decl.property,
          value: decl.value,
          count: 1,
          locations: [location],
        });
      }
    }
  }

  return Array.from(spacingMap.values()).sort((a, b) => b.count - a.count);
}

function findInconsistencies(
  colors: ColorUsage[],
  typography: TypographyUsage[],
  spacing: SpacingUsage[]
): StyleInconsistency[] {
  const inconsistencies: StyleInconsistency[] = [];

  // Check for similar but different colors
  const hexColors = colors.map((c) => c.normalizedHex);
  for (let i = 0; i < hexColors.length; i++) {
    for (let j = i + 1; j < hexColors.length; j++) {
      const c1 = hexColors[i];
      const c2 = hexColors[j];
      if (c1 && c2 && areColorsSimilar(c1, c2)) {
        inconsistencies.push({
          type: "color",
          description: `Similar colors found that could be consolidated`,
          values: [c1, c2],
          suggestion: `Consider using a single color token for these similar values`,
        });
      }
    }
  }

  // Check for too many unique font families
  const fontFamilies = typography.filter((t) => t.property === "font-family");
  if (fontFamilies.length > 3) {
    inconsistencies.push({
      type: "font",
      description: `Too many font families (${fontFamilies.length}) - consider limiting to 2-3`,
      values: fontFamilies.map((f) => f.value),
      suggestion: "Use a display font, body font, and optionally a monospace font",
    });
  }

  // Check for inconsistent spacing values
  const spacingValues = [...new Set(spacing.map((s) => s.value))];
  if (spacingValues.length > 10) {
    inconsistencies.push({
      type: "spacing",
      description: `Many unique spacing values (${spacingValues.length}) - consider a consistent scale`,
      values: spacingValues.slice(0, 10),
      suggestion: "Use a spacing scale (4px, 8px, 12px, 16px, 24px, 32px, etc.)",
    });
  }

  return inconsistencies;
}

function areColorsSimilar(hex1: string, hex2: string): boolean {
  if (!hex1.startsWith("#") || !hex2.startsWith("#")) return false;

  const r1 = parseInt(hex1.slice(1, 3), 16);
  const g1 = parseInt(hex1.slice(3, 5), 16);
  const b1 = parseInt(hex1.slice(5, 7), 16);

  const r2 = parseInt(hex2.slice(1, 3), 16);
  const g2 = parseInt(hex2.slice(3, 5), 16);
  const b2 = parseInt(hex2.slice(5, 7), 16);

  const distance = Math.sqrt(
    Math.pow(r1 - r2, 2) + Math.pow(g1 - g2, 2) + Math.pow(b1 - b2, 2)
  );

  // Colors within distance of 30 are considered similar
  return distance > 0 && distance < 30;
}

function generateRecommendations(
  result: Omit<StyleAuditResult, "recommendations">
): string[] {
  const recommendations: string[] = [];

  // Color recommendations
  if (result.colors.length > 15) {
    recommendations.push(
      `Consider reducing color palette from ${result.colors.length} to 10-15 colors with a design token system`
    );
  }

  // Typography recommendations
  const genericFonts = result.typography.filter(
    (t) =>
      t.property === "font-family" &&
      /arial|helvetica|roboto|inter|system-ui/i.test(t.value)
  );
  if (genericFonts.length > 0) {
    recommendations.push(
      "Replace generic fonts (Arial, Helvetica, Roboto, Inter) with distinctive alternatives"
    );
  }

  // Spacing recommendations
  const pixelSpacing = result.spacing.filter((s) => /^\d+px$/.test(s.value));
  if (pixelSpacing.length > 5) {
    recommendations.push(
      "Convert pixel-based spacing to rem units for better accessibility"
    );
  }

  // Inconsistency-based recommendations
  if (result.inconsistencies.length > 0) {
    recommendations.push(
      `Address ${result.inconsistencies.length} design inconsistencies identified in the audit`
    );
  }

  return recommendations;
}

// === Core Analysis Function ===

export async function analyzeStyles(options: AnalyzeOptions): Promise<StyleAuditResult[]> {
  const results: StyleAuditResult[] = [];
  const inputPath = resolve(options.input);

  // Collect CSS files
  const cssFiles: string[] = [];

  try {
    const stat = await Deno.stat(inputPath);

    if (stat.isDirectory) {
      for await (const entry of walk(inputPath, {
        exts: [".css"],
        includeDirs: false,
      })) {
        cssFiles.push(entry.path);
      }
    } else if (stat.isFile && extname(inputPath) === ".css") {
      cssFiles.push(inputPath);
    } else {
      throw new Error(`Input must be a CSS file or directory: ${inputPath}`);
    }
  } catch (error) {
    if (error instanceof Deno.errors.NotFound) {
      throw new Error(`File or directory not found: ${inputPath}`);
    }
    throw error;
  }

  if (cssFiles.length === 0) {
    throw new Error(`No CSS files found in: ${inputPath}`);
  }

  // Analyze each file
  for (const file of cssFiles) {
    const css = await Deno.readTextFile(file);
    const declarations = parseCSS(css);

    const colors = analyzeColors(declarations);
    const typography = analyzeTypography(declarations);
    const spacing = analyzeSpacing(declarations);
    const inconsistencies = findInconsistencies(colors, typography, spacing);

    const uniqueSelectors = new Set(declarations.map((d) => d.selector));

    const partialResult = {
      filename: basename(file),
      summary: {
        totalSelectors: uniqueSelectors.size,
        totalDeclarations: declarations.length,
        uniqueColors: colors.length,
        uniqueFonts: typography.filter((t) => t.property === "font-family").length,
        uniqueSpacingValues: spacing.length,
      },
      colors,
      typography,
      spacing,
      inconsistencies,
    };

    results.push({
      ...partialResult,
      recommendations: generateRecommendations(partialResult),
    });
  }

  return results;
}

// === Output Formatting ===

function formatSummary(results: StyleAuditResult[]): string {
  const lines: string[] = [];

  for (const result of results) {
    lines.push(`\n${"=".repeat(60)}`);
    lines.push(`FILE: ${result.filename}`);
    lines.push("=".repeat(60));

    lines.push("\nSUMMARY:");
    lines.push(`  Selectors: ${result.summary.totalSelectors}`);
    lines.push(`  Declarations: ${result.summary.totalDeclarations}`);
    lines.push(`  Unique Colors: ${result.summary.uniqueColors}`);
    lines.push(`  Unique Fonts: ${result.summary.uniqueFonts}`);
    lines.push(`  Unique Spacing: ${result.summary.uniqueSpacingValues}`);

    if (result.colors.length > 0) {
      lines.push("\nTOP COLORS:");
      result.colors.slice(0, 5).forEach((c) => {
        lines.push(`  ${c.normalizedHex} (${c.count}x) → ${c.suggestedTokenName}`);
      });
    }

    if (result.typography.length > 0) {
      lines.push("\nTYPOGRAPHY:");
      result.typography
        .filter((t) => t.property === "font-family")
        .slice(0, 3)
        .forEach((t) => {
          lines.push(`  ${t.value} (${t.count}x)`);
        });
    }

    if (result.inconsistencies.length > 0) {
      lines.push("\nINCONSISTENCIES:");
      result.inconsistencies.forEach((i) => {
        lines.push(`  [${i.type.toUpperCase()}] ${i.description}`);
      });
    }

    if (result.recommendations.length > 0) {
      lines.push("\nRECOMMENDATIONS:");
      result.recommendations.forEach((r) => {
        lines.push(`  • ${r}`);
      });
    }
  }

  return lines.join("\n");
}

// === Help Text ===

function printHelp(): void {
  console.log(`
${SCRIPT_NAME} v${VERSION} - CSS Style Auditor

Analyzes CSS files to extract color, typography, spacing patterns
and identify design inconsistencies.

Usage:
  deno run --allow-read scripts/${SCRIPT_NAME}.ts <input> [options]

Arguments:
  <input>              CSS file or directory containing CSS files

Options:
  -h, --help           Show this help message
  -v, --version        Show version
  --tokens <file>      Compare against existing design tokens file
  --pretty             Pretty-print JSON output
  --format <type>      Output format: json (default), summary

Examples:
  # Analyze a single CSS file
  deno run --allow-read scripts/${SCRIPT_NAME}.ts styles.css

  # Analyze all CSS in a directory with pretty output
  deno run --allow-read scripts/${SCRIPT_NAME}.ts ./src --pretty

  # Get a human-readable summary
  deno run --allow-read scripts/${SCRIPT_NAME}.ts ./src --format summary

  # Compare against existing tokens
  deno run --allow-read scripts/${SCRIPT_NAME}.ts styles.css --tokens tokens.json
`);
}

// === Main CLI Handler ===

async function main(args: string[]): Promise<void> {
  const parsed = parseArgs(args, {
    boolean: ["help", "version", "pretty"],
    string: ["tokens", "format"],
    alias: { h: "help", v: "version" },
    default: { format: "json", pretty: false },
  });

  if (parsed.help) {
    printHelp();
    Deno.exit(0);
  }

  if (parsed.version) {
    console.log(`${SCRIPT_NAME} v${VERSION}`);
    Deno.exit(0);
  }

  const input = parsed._[0] as string;

  if (!input) {
    console.error("Error: Input file or directory required");
    console.error("Use --help for usage information");
    Deno.exit(1);
  }

  const options: AnalyzeOptions = {
    input,
    tokensFile: parsed.tokens,
    pretty: parsed.pretty,
    format: parsed.format as "json" | "summary",
  };

  try {
    const results = await analyzeStyles(options);

    if (options.format === "summary") {
      console.log(formatSummary(results));
    } else {
      const output = options.pretty
        ? JSON.stringify(results, null, 2)
        : JSON.stringify(results);
      console.log(output);
    }
  } catch (error) {
    console.error(`Error: ${(error as Error).message}`);
    Deno.exit(1);
  }
}

// === Entry Point ===

if (import.meta.main) {
  main(Deno.args);
}

```

### scripts/extract-tokens.ts

```typescript
#!/usr/bin/env -S deno run --allow-read

/**
 * extract-tokens.ts - Design Token Extractor
 *
 * Extracts design tokens from CSS files containing CSS custom properties
 * and outputs in various standardized formats.
 */

import { parseArgs } from "jsr:@std/[email protected]/parse-args";
import { basename, extname, resolve } from "jsr:@std/[email protected]";
import { walk } from "jsr:@std/[email protected]/walk";

// === Constants ===
const VERSION = "1.0.0";
const SCRIPT_NAME = "extract-tokens";

type OutputFormat = "css" | "scss" | "tailwind" | "style-dictionary" | "tokens-studio" | "json";

// === Types ===
export interface TokenValue {
  value: string;
  type: string;
  description?: string;
  usageCount?: number;
}

export interface ExtractedTokens {
  source: string;
  format: OutputFormat;
  tokens: {
    color: Record<string, TokenValue>;
    typography: Record<string, TokenValue>;
    spacing: Record<string, TokenValue>;
    shadow: Record<string, TokenValue>;
    border: Record<string, TokenValue>;
    animation: Record<string, TokenValue>;
    other: Record<string, TokenValue>;
  };
  unmapped: Array<{
    property: string;
    value: string;
    count: number;
    suggestion: string;
  }>;
}

interface ExtractOptions {
  input: string;
  format: OutputFormat;
  outputCss: boolean;
  pretty: boolean;
}

// === Token Classification ===

const TOKEN_PATTERNS: Record<string, RegExp[]> = {
  color: [
    /color/i,
    /background/i,
    /border-color/i,
    /fill/i,
    /stroke/i,
    /shadow/i,
    /bg/i,
    /fg/i,
    /text(?!-)/i,
  ],
  typography: [
    /font/i,
    /text-/i,
    /line-height/i,
    /letter-spacing/i,
    /word-spacing/i,
  ],
  spacing: [
    /space/i,
    /gap/i,
    /margin/i,
    /padding/i,
    /inset/i,
  ],
  shadow: [
    /shadow/i,
    /elevation/i,
  ],
  border: [
    /border/i,
    /radius/i,
    /outline/i,
  ],
  animation: [
    /duration/i,
    /timing/i,
    /easing/i,
    /delay/i,
    /transition/i,
    /animation/i,
  ],
};

function classifyToken(name: string, value: string): string {
  // Check name patterns
  for (const [category, patterns] of Object.entries(TOKEN_PATTERNS)) {
    if (patterns.some((p) => p.test(name))) {
      return category;
    }
  }

  // Check value patterns
  if (/^#|^rgb|^hsl|^oklch|transparent|currentColor/i.test(value)) {
    return "color";
  }
  if (/^\d+(\.\d+)?(px|rem|em|%)$/.test(value)) {
    if (/radius/i.test(name)) return "border";
    return "spacing";
  }
  if (/^\d+(\.\d+)?(ms|s)$/.test(value)) {
    return "animation";
  }
  if (/^(sans-serif|serif|monospace|cursive|fantasy|system-ui)/i.test(value)) {
    return "typography";
  }

  return "other";
}

function inferTokenType(category: string, value: string): string {
  if (category === "color") return "color";
  if (category === "typography") {
    if (/^\d/.test(value)) return "dimension";
    return "fontFamily";
  }
  if (category === "spacing") return "dimension";
  if (category === "shadow") return "shadow";
  if (category === "border") return "dimension";
  if (category === "animation") return "duration";
  return "other";
}

// === CSS Parsing ===

interface CSSVariable {
  name: string;
  value: string;
  count: number;
}

function extractCSSVariables(css: string): CSSVariable[] {
  const variables = new Map<string, CSSVariable>();

  // Remove comments
  const cleaned = css.replace(/\/\*[\s\S]*?\*\//g, "");

  // Find variable definitions (--name: value)
  const varDefRegex = /(--[\w-]+)\s*:\s*([^;]+);/g;
  let match;

  while ((match = varDefRegex.exec(cleaned)) !== null) {
    const name = match[1].trim();
    const value = match[2].trim();

    if (variables.has(name)) {
      variables.get(name)!.count++;
    } else {
      variables.set(name, { name, value, count: 1 });
    }
  }

  return Array.from(variables.values());
}

function extractRepeatedValues(css: string): Map<string, number> {
  const valueCount = new Map<string, number>();

  // Remove comments
  const cleaned = css.replace(/\/\*[\s\S]*?\*\//g, "");

  // Find all property values
  const declRegex = /[a-z-]+\s*:\s*([^;{}]+);/gi;
  let match;

  while ((match = declRegex.exec(cleaned)) !== null) {
    const value = match[1].trim();
    // Skip var() references and very short values
    if (!value.startsWith("var(") && value.length > 2) {
      valueCount.set(value, (valueCount.get(value) || 0) + 1);
    }
  }

  return valueCount;
}

// === Token Extraction ===

export async function extractTokens(options: ExtractOptions): Promise<ExtractedTokens> {
  const inputPath = resolve(options.input);

  // Collect CSS files
  const cssContents: string[] = [];
  let sourceName = "";

  try {
    const stat = await Deno.stat(inputPath);

    if (stat.isDirectory) {
      sourceName = basename(inputPath);
      for await (const entry of walk(inputPath, {
        exts: [".css"],
        includeDirs: false,
      })) {
        cssContents.push(await Deno.readTextFile(entry.path));
      }
    } else if (stat.isFile && extname(inputPath) === ".css") {
      sourceName = basename(inputPath);
      cssContents.push(await Deno.readTextFile(inputPath));
    } else {
      throw new Error(`Input must be a CSS file or directory: ${inputPath}`);
    }
  } catch (error) {
    if (error instanceof Deno.errors.NotFound) {
      throw new Error(`File or directory not found: ${inputPath}`);
    }
    throw error;
  }

  if (cssContents.length === 0) {
    throw new Error(`No CSS files found in: ${inputPath}`);
  }

  const combinedCSS = cssContents.join("\n");

  // Extract CSS variables
  const cssVariables = extractCSSVariables(combinedCSS);

  // Extract repeated values that could become tokens
  const repeatedValues = extractRepeatedValues(combinedCSS);

  // Classify tokens
  const tokens: ExtractedTokens["tokens"] = {
    color: {},
    typography: {},
    spacing: {},
    shadow: {},
    border: {},
    animation: {},
    other: {},
  };

  for (const variable of cssVariables) {
    const category = classifyToken(variable.name, variable.value);
    const tokenName = variable.name.replace(/^--/, "");

    tokens[category as keyof typeof tokens][tokenName] = {
      value: variable.value,
      type: inferTokenType(category, variable.value),
      usageCount: variable.count,
    };
  }

  // Find unmapped repeated values
  const unmapped: ExtractedTokens["unmapped"] = [];
  for (const [value, count] of repeatedValues) {
    if (count >= 3) {
      // Value used 3+ times
      const category = classifyToken("", value);
      const suggestion = `--${category}-${unmapped.length + 1}`;

      // Check if this value is already a token
      const isTokenized = Object.values(tokens).some((cat) =>
        Object.values(cat).some((t) => t.value === value)
      );

      if (!isTokenized) {
        unmapped.push({
          property: category,
          value,
          count,
          suggestion,
        });
      }
    }
  }

  return {
    source: sourceName,
    format: options.format,
    tokens,
    unmapped: unmapped.sort((a, b) => b.count - a.count).slice(0, 20),
  };
}

// === Output Formatting ===

function formatAsCSS(tokens: ExtractedTokens): string {
  const lines: string[] = ["/* Design Tokens - Generated by extract-tokens */", "", ":root {"];

  for (const [category, categoryTokens] of Object.entries(tokens.tokens)) {
    const entries = Object.entries(categoryTokens);
    if (entries.length === 0) continue;

    lines.push(`  /* ${category} */`);
    for (const [name, token] of entries) {
      lines.push(`  --${name}: ${token.value};`);
    }
    lines.push("");
  }

  lines.push("}");
  return lines.join("\n");
}

function formatAsSCSS(tokens: ExtractedTokens): string {
  const lines: string[] = ["// Design Tokens - Generated by extract-tokens", ""];

  for (const [category, categoryTokens] of Object.entries(tokens.tokens)) {
    const entries = Object.entries(categoryTokens);
    if (entries.length === 0) continue;

    lines.push(`// ${category}`);
    for (const [name, token] of entries) {
      const scssName = name.replace(/-/g, "_");
      lines.push(`$${scssName}: ${token.value};`);
    }
    lines.push("");
  }

  return lines.join("\n");
}

function formatAsTailwind(tokens: ExtractedTokens): string {
  const config: Record<string, Record<string, string>> = {
    colors: {},
    spacing: {},
    fontFamily: {},
    fontSize: {},
    boxShadow: {},
    borderRadius: {},
    transitionDuration: {},
  };

  for (const [name, token] of Object.entries(tokens.tokens.color)) {
    config.colors[name] = token.value;
  }

  for (const [name, token] of Object.entries(tokens.tokens.spacing)) {
    config.spacing[name] = token.value;
  }

  for (const [name, token] of Object.entries(tokens.tokens.typography)) {
    if (token.type === "fontFamily") {
      config.fontFamily[name] = token.value;
    } else {
      config.fontSize[name] = token.value;
    }
  }

  for (const [name, token] of Object.entries(tokens.tokens.shadow)) {
    config.boxShadow[name] = token.value;
  }

  for (const [name, token] of Object.entries(tokens.tokens.border)) {
    config.borderRadius[name] = token.value;
  }

  for (const [name, token] of Object.entries(tokens.tokens.animation)) {
    config.transitionDuration[name] = token.value;
  }

  // Remove empty categories
  for (const key of Object.keys(config)) {
    if (Object.keys(config[key]).length === 0) {
      delete config[key];
    }
  }

  return `// Tailwind Config Extension - Generated by extract-tokens
// Add this to your tailwind.config.js theme.extend

module.exports = {
  theme: {
    extend: ${JSON.stringify(config, null, 6).replace(/"([^"]+)":/g, "$1:")}
  }
};`;
}

function formatAsStyleDictionary(tokens: ExtractedTokens): string {
  const sdTokens: Record<string, unknown> = {};

  for (const [category, categoryTokens] of Object.entries(tokens.tokens)) {
    if (Object.keys(categoryTokens).length === 0) continue;

    sdTokens[category] = {};
    for (const [name, token] of Object.entries(categoryTokens)) {
      (sdTokens[category] as Record<string, unknown>)[name] = {
        value: token.value,
        type: token.type,
      };
    }
  }

  return JSON.stringify(sdTokens, null, 2);
}

function formatAsTokensStudio(tokens: ExtractedTokens): string {
  const tsTokens: Record<string, unknown> = {};

  for (const [category, categoryTokens] of Object.entries(tokens.tokens)) {
    if (Object.keys(categoryTokens).length === 0) continue;

    tsTokens[category] = {};
    for (const [name, token] of Object.entries(categoryTokens)) {
      (tsTokens[category] as Record<string, unknown>)[name] = {
        value: token.value,
        type: token.type,
        $extensions: {
          "studio.tokens": {
            modify: {},
          },
        },
      };
    }
  }

  return JSON.stringify(tsTokens, null, 2);
}

function formatOutput(tokens: ExtractedTokens, options: ExtractOptions): string {
  switch (options.format) {
    case "css":
      return formatAsCSS(tokens);
    case "scss":
      return formatAsSCSS(tokens);
    case "tailwind":
      return formatAsTailwind(tokens);
    case "style-dictionary":
      return formatAsStyleDictionary(tokens);
    case "tokens-studio":
      return formatAsTokensStudio(tokens);
    case "json":
    default:
      return options.pretty
        ? JSON.stringify(tokens, null, 2)
        : JSON.stringify(tokens);
  }
}

// === Help Text ===

function printHelp(): void {
  console.log(`
${SCRIPT_NAME} v${VERSION} - Design Token Extractor

Extracts design tokens from CSS files containing CSS custom properties
and outputs in various standardized formats.

Usage:
  deno run --allow-read scripts/${SCRIPT_NAME}.ts <input> [options]

Arguments:
  <input>              CSS file or directory containing CSS files

Options:
  -h, --help           Show this help message
  -v, --version        Show version
  --format <type>      Output format: css, scss, tailwind, style-dictionary,
                       tokens-studio, json (default: json)
  --output-css         Also output CSS variables (with json format)
  --pretty             Pretty-print JSON output

Formats:
  css              CSS custom properties (:root { --token: value; })
  scss             SCSS variables ($token: value;)
  tailwind         Tailwind config extension object
  style-dictionary Style Dictionary JSON format
  tokens-studio    Tokens Studio JSON format
  json             Raw JSON with all metadata

Examples:
  # Extract tokens as CSS variables
  deno run --allow-read scripts/${SCRIPT_NAME}.ts styles.css --format css

  # Extract to Tailwind config
  deno run --allow-read scripts/${SCRIPT_NAME}.ts ./src --format tailwind

  # Extract to Style Dictionary format
  deno run --allow-read scripts/${SCRIPT_NAME}.ts ./src --format style-dictionary

  # Get raw JSON with unmapped values
  deno run --allow-read scripts/${SCRIPT_NAME}.ts styles.css --pretty
`);
}

// === Main CLI Handler ===

async function main(args: string[]): Promise<void> {
  const parsed = parseArgs(args, {
    boolean: ["help", "version", "pretty", "output-css"],
    string: ["format"],
    alias: { h: "help", v: "version" },
    default: { format: "json", pretty: false },
  });

  if (parsed.help) {
    printHelp();
    Deno.exit(0);
  }

  if (parsed.version) {
    console.log(`${SCRIPT_NAME} v${VERSION}`);
    Deno.exit(0);
  }

  const input = parsed._[0] as string;

  if (!input) {
    console.error("Error: Input file or directory required");
    console.error("Use --help for usage information");
    Deno.exit(1);
  }

  const validFormats: OutputFormat[] = [
    "css",
    "scss",
    "tailwind",
    "style-dictionary",
    "tokens-studio",
    "json",
  ];

  if (!validFormats.includes(parsed.format as OutputFormat)) {
    console.error(`Error: Invalid format '${parsed.format}'`);
    console.error(`Valid formats: ${validFormats.join(", ")}`);
    Deno.exit(1);
  }

  const options: ExtractOptions = {
    input,
    format: parsed.format as OutputFormat,
    outputCss: parsed["output-css"],
    pretty: parsed.pretty,
  };

  try {
    const tokens = await extractTokens(options);
    console.log(formatOutput(tokens, options));
  } catch (error) {
    console.error(`Error: ${(error as Error).message}`);
    Deno.exit(1);
  }
}

// === Entry Point ===

if (import.meta.main) {
  main(Deno.args);
}

```

### scripts/analyze-accessibility.ts

```typescript
#!/usr/bin/env -S deno run --allow-read

/**
 * analyze-accessibility.ts - Design Accessibility Auditor
 *
 * Checks HTML/component files for design-related accessibility issues
 * including color contrast, focus states, touch targets, and motion.
 */

import { parseArgs } from "jsr:@std/[email protected]/parse-args";
import { basename, extname, resolve } from "jsr:@std/[email protected]";
import { walk } from "jsr:@std/[email protected]/walk";

// === Constants ===
const VERSION = "1.0.0";
const SCRIPT_NAME = "analyze-accessibility";

// WCAG contrast ratios
const CONTRAST_AA_NORMAL = 4.5;
const CONTRAST_AA_LARGE = 3.0;
const CONTRAST_AAA_NORMAL = 7.0;
const CONTRAST_AAA_LARGE = 4.5;

// === Types ===
export interface A11yIssue {
  severity: "error" | "warning" | "info";
  category: "contrast" | "focus" | "motion" | "touch-target" | "semantics" | "images";
  element: string;
  line?: number;
  description: string;
  wcagCriteria: string;
  suggestion: string;
}

export interface A11yCheck {
  category: string;
  description: string;
  passed: boolean;
}

export interface AccessibilityAuditResult {
  filename: string;
  issues: A11yIssue[];
  warnings: A11yIssue[];
  passed: A11yCheck[];
  score: number;
}

interface AnalyzeOptions {
  input: string;
  level: "AA" | "AAA";
  format: "json" | "summary";
  pretty: boolean;
}

// === Color Utilities ===

function hexToRgb(hex: string): { r: number; g: number; b: number } | null {
  const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
  if (!result) {
    // Try short hex
    const short = /^#?([a-f\d])([a-f\d])([a-f\d])$/i.exec(hex);
    if (short) {
      return {
        r: parseInt(short[1] + short[1], 16),
        g: parseInt(short[2] + short[2], 16),
        b: parseInt(short[3] + short[3], 16),
      };
    }
    return null;
  }
  return {
    r: parseInt(result[1], 16),
    g: parseInt(result[2], 16),
    b: parseInt(result[3], 16),
  };
}

function getLuminance(r: number, g: number, b: number): number {
  const [rs, gs, bs] = [r, g, b].map((c) => {
    c = c / 255;
    return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
  });
  return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
}

function getContrastRatio(color1: string, color2: string): number | null {
  const rgb1 = hexToRgb(color1);
  const rgb2 = hexToRgb(color2);

  if (!rgb1 || !rgb2) return null;

  const l1 = getLuminance(rgb1.r, rgb1.g, rgb1.b);
  const l2 = getLuminance(rgb2.r, rgb2.g, rgb2.b);

  const lighter = Math.max(l1, l2);
  const darker = Math.min(l1, l2);

  return (lighter + 0.05) / (darker + 0.05);
}

// === Analysis Patterns ===

interface AnalysisPattern {
  pattern: RegExp;
  check: (match: RegExpMatchArray, content: string, lineNum: number) => A11yIssue | null;
}

const HTML_PATTERNS: AnalysisPattern[] = [
  // Missing alt text on images
  {
    pattern: /<img[^>]*(?!alt=)[^>]*>/gi,
    check: (match, _content, lineNum) => {
      if (!match[0].includes("alt=")) {
        return {
          severity: "error",
          category: "images",
          element: match[0].substring(0, 50) + "...",
          line: lineNum,
          description: "Image missing alt attribute",
          wcagCriteria: "1.1.1 Non-text Content",
          suggestion: 'Add alt="" for decorative images or descriptive alt text for informative images',
        };
      }
      return null;
    },
  },
  // Empty alt text should be intentional (for decorative images)
  {
    pattern: /<img[^>]*alt=""[^>]*>/gi,
    check: (match, _content, lineNum) => {
      // Check if it has role="presentation" or aria-hidden
      if (!match[0].includes('role="presentation"') && !match[0].includes("aria-hidden")) {
        return {
          severity: "info",
          category: "images",
          element: match[0].substring(0, 50) + "...",
          line: lineNum,
          description: "Image has empty alt - ensure this is decorative",
          wcagCriteria: "1.1.1 Non-text Content",
          suggestion: 'For decorative images, also add role="presentation" or aria-hidden="true"',
        };
      }
      return null;
    },
  },
  // Links without accessible names
  {
    pattern: /<a[^>]*>[\s]*<\/a>/gi,
    check: (match, _content, lineNum) => ({
      severity: "error",
      category: "semantics",
      element: match[0],
      line: lineNum,
      description: "Empty link - no accessible name",
      wcagCriteria: "2.4.4 Link Purpose",
      suggestion: "Add text content or aria-label to the link",
    }),
  },
  // Buttons without accessible names
  {
    pattern: /<button[^>]*>[\s]*<\/button>/gi,
    check: (match, _content, lineNum) => ({
      severity: "error",
      category: "semantics",
      element: match[0],
      line: lineNum,
      description: "Empty button - no accessible name",
      wcagCriteria: "4.1.2 Name, Role, Value",
      suggestion: "Add text content or aria-label to the button",
    }),
  },
  // Form inputs without labels
  {
    pattern: /<input[^>]*type=["'](?:text|email|password|tel|url|search|number)[^>]*>/gi,
    check: (match, content, lineNum) => {
      const idMatch = match[0].match(/id=["']([^"']+)["']/);
      if (idMatch) {
        const labelPattern = new RegExp(`for=["']${idMatch[1]}["']`);
        if (labelPattern.test(content)) {
          return null;
        }
      }
      if (match[0].includes("aria-label") || match[0].includes("aria-labelledby")) {
        return null;
      }
      return {
        severity: "error",
        category: "semantics",
        element: match[0].substring(0, 50) + "...",
        line: lineNum,
        description: "Form input missing associated label",
        wcagCriteria: "1.3.1 Info and Relationships",
        suggestion: "Add a <label> with matching for attribute, or use aria-label",
      };
    },
  },
  // Check for outline:none without alternative focus styles
  {
    pattern: /outline:\s*(?:none|0);?/gi,
    check: (match, _content, lineNum) => ({
      severity: "warning",
      category: "focus",
      element: "CSS rule",
      line: lineNum,
      description: "outline:none detected - ensure alternative focus indicator exists",
      wcagCriteria: "2.4.7 Focus Visible",
      suggestion: "Replace with visible focus styles (box-shadow, border, etc.)",
    }),
  },
  // Check for :focus without styles
  {
    pattern: /:focus\s*\{[^}]*\}/gi,
    check: (match, _content, lineNum) => {
      // Check if focus rule has meaningful styles
      const rule = match[0];
      if (
        rule.includes("outline") ||
        rule.includes("box-shadow") ||
        rule.includes("border") ||
        rule.includes("background")
      ) {
        return null; // Has focus styling
      }
      return {
        severity: "info",
        category: "focus",
        element: ":focus rule",
        line: lineNum,
        description: "Focus rule may lack visible indicator",
        wcagCriteria: "2.4.7 Focus Visible",
        suggestion: "Ensure :focus includes visible changes (outline, shadow, border)",
      };
    },
  },
  // Check for animations without reduced motion support
  {
    pattern: /@keyframes\s+[\w-]+/gi,
    check: (match, content, _lineNum) => {
      if (!content.includes("prefers-reduced-motion")) {
        return {
          severity: "warning",
          category: "motion",
          element: match[0],
          line: undefined,
          description: "Animation detected without prefers-reduced-motion support",
          wcagCriteria: "2.3.3 Animation from Interactions",
          suggestion:
            "Add @media (prefers-reduced-motion: reduce) to disable/reduce animations",
        };
      }
      return null;
    },
  },
  // Check for small touch targets
  {
    pattern: /(?:width|height|min-width|min-height):\s*(\d+)(px|rem)/gi,
    check: (match, _content, lineNum) => {
      const value = parseInt(match[1]);
      const unit = match[2];

      // Convert to px for comparison
      let pxValue = value;
      if (unit === "rem") {
        pxValue = value * 16;
      }

      // Only flag if it looks like a button/link target
      if (pxValue < 44) {
        return {
          severity: "info",
          category: "touch-target",
          element: `size: ${match[0]}`,
          line: lineNum,
          description: `Small dimension (${pxValue}px) - verify touch target is at least 44x44px`,
          wcagCriteria: "2.5.5 Target Size",
          suggestion: "Ensure interactive elements have at least 44x44px touch target",
        };
      }
      return null;
    },
  },
  // Check for text in SVGs without title/desc
  {
    pattern: /<svg[^>]*>[\s\S]*?<\/svg>/gi,
    check: (match, _content, lineNum) => {
      const svg = match[0];
      if (svg.includes("<text") && !svg.includes("<title") && !svg.includes("aria-label")) {
        return {
          severity: "warning",
          category: "images",
          element: "SVG with text",
          line: lineNum,
          description: "SVG with text content but no accessible name",
          wcagCriteria: "1.1.1 Non-text Content",
          suggestion: "Add <title> element or aria-label to SVG",
        };
      }
      return null;
    },
  },
  // Check for autoplay on video/audio
  {
    pattern: /<(?:video|audio)[^>]*autoplay[^>]*>/gi,
    check: (match, _content, lineNum) => {
      if (!match[0].includes("muted")) {
        return {
          severity: "error",
          category: "motion",
          element: match[0].substring(0, 50) + "...",
          line: lineNum,
          description: "Autoplay media without muted attribute",
          wcagCriteria: "1.4.2 Audio Control",
          suggestion: 'Add muted attribute or provide pause controls',
        };
      }
      return null;
    },
  },
];

// === Analysis Functions ===

function getLineNumber(content: string, index: number): number {
  return content.substring(0, index).split("\n").length;
}

function analyzeContent(content: string, filename: string): A11yIssue[] {
  const issues: A11yIssue[] = [];

  for (const { pattern, check } of HTML_PATTERNS) {
    // Reset regex
    pattern.lastIndex = 0;
    let match;

    while ((match = pattern.exec(content)) !== null) {
      const lineNum = getLineNumber(content, match.index);
      const issue = check(match, content, lineNum);
      if (issue) {
        issues.push(issue);
      }
    }
  }

  return issues;
}

function analyzeColorContrast(
  content: string,
  level: "AA" | "AAA"
): A11yIssue[] {
  const issues: A11yIssue[] = [];

  // Extract color pairs from inline styles
  const colorPairs: Array<{ fg: string; bg: string; context: string }> = [];

  // Look for color and background-color in same rule
  const ruleRegex = /\{([^}]+)\}/g;
  let match;

  while ((match = ruleRegex.exec(content)) !== null) {
    const rule = match[1];
    const colorMatch = rule.match(/(?:^|;)\s*color:\s*(#[a-f0-9]{3,6})/i);
    const bgMatch = rule.match(/background(?:-color)?:\s*(#[a-f0-9]{3,6})/i);

    if (colorMatch && bgMatch) {
      colorPairs.push({
        fg: colorMatch[1],
        bg: bgMatch[1],
        context: match[0].substring(0, 50),
      });
    }
  }

  // Check contrast for each pair
  const minRatio = level === "AAA" ? CONTRAST_AAA_NORMAL : CONTRAST_AA_NORMAL;

  for (const pair of colorPairs) {
    const ratio = getContrastRatio(pair.fg, pair.bg);
    if (ratio && ratio < minRatio) {
      issues.push({
        severity: "error",
        category: "contrast",
        element: pair.context,
        description: `Insufficient contrast ratio: ${ratio.toFixed(2)}:1 (requires ${minRatio}:1 for ${level})`,
        wcagCriteria: "1.4.3 Contrast (Minimum)",
        suggestion: `Increase contrast between ${pair.fg} and ${pair.bg}`,
      });
    }
  }

  return issues;
}

function generatePassedChecks(issues: A11yIssue[]): A11yCheck[] {
  const checks: A11yCheck[] = [];
  const categories = ["contrast", "focus", "motion", "touch-target", "semantics", "images"];

  for (const category of categories) {
    const categoryIssues = issues.filter((i) => i.category === category);
    const hasErrors = categoryIssues.some((i) => i.severity === "error");

    if (!hasErrors) {
      checks.push({
        category,
        description: `No ${category} errors detected`,
        passed: true,
      });
    }
  }

  return checks;
}

function calculateScore(issues: A11yIssue[]): number {
  // Start with 100, deduct points for issues
  let score = 100;

  for (const issue of issues) {
    switch (issue.severity) {
      case "error":
        score -= 15;
        break;
      case "warning":
        score -= 5;
        break;
      case "info":
        score -= 1;
        break;
    }
  }

  return Math.max(0, Math.min(100, score));
}

// === Core Analysis Function ===

export async function analyzeAccessibility(
  options: AnalyzeOptions
): Promise<AccessibilityAuditResult[]> {
  const results: AccessibilityAuditResult[] = [];
  const inputPath = resolve(options.input);

  // Supported extensions
  const exts = [".html", ".htm", ".tsx", ".jsx", ".vue", ".svelte", ".css"];

  // Collect files
  const files: string[] = [];

  try {
    const stat = await Deno.stat(inputPath);

    if (stat.isDirectory) {
      for await (const entry of walk(inputPath, {
        exts: exts.map((e) => e.slice(1)),
        includeDirs: false,
      })) {
        files.push(entry.path);
      }
    } else if (stat.isFile && exts.includes(extname(inputPath))) {
      files.push(inputPath);
    } else {
      throw new Error(`Input must be a supported file or directory: ${inputPath}`);
    }
  } catch (error) {
    if (error instanceof Deno.errors.NotFound) {
      throw new Error(`File or directory not found: ${inputPath}`);
    }
    throw error;
  }

  if (files.length === 0) {
    throw new Error(`No supported files found in: ${inputPath}`);
  }

  // Analyze each file
  for (const file of files) {
    const content = await Deno.readTextFile(file);

    const issues = [
      ...analyzeContent(content, basename(file)),
      ...analyzeColorContrast(content, options.level),
    ];

    const errors = issues.filter((i) => i.severity === "error");
    const warnings = issues.filter((i) => i.severity === "warning" || i.severity === "info");
    const passed = generatePassedChecks(issues);
    const score = calculateScore(issues);

    results.push({
      filename: basename(file),
      issues: errors,
      warnings,
      passed,
      score,
    });
  }

  return results;
}

// === Output Formatting ===

function formatSummary(results: AccessibilityAuditResult[]): string {
  const lines: string[] = [];

  for (const result of results) {
    lines.push(`\n${"=".repeat(60)}`);
    lines.push(`FILE: ${result.filename}`);
    lines.push(`SCORE: ${result.score}/100`);
    lines.push("=".repeat(60));

    if (result.issues.length > 0) {
      lines.push("\nERRORS:");
      for (const issue of result.issues) {
        lines.push(`  [${issue.category.toUpperCase()}] ${issue.description}`);
        if (issue.line) lines.push(`    Line: ${issue.line}`);
        lines.push(`    WCAG: ${issue.wcagCriteria}`);
        lines.push(`    Fix: ${issue.suggestion}`);
      }
    }

    if (result.warnings.length > 0) {
      lines.push("\nWARNINGS:");
      for (const warning of result.warnings) {
        lines.push(`  [${warning.category.toUpperCase()}] ${warning.description}`);
        if (warning.line) lines.push(`    Line: ${warning.line}`);
        lines.push(`    Fix: ${warning.suggestion}`);
      }
    }

    if (result.passed.length > 0) {
      lines.push("\nPASSED:");
      for (const check of result.passed) {
        lines.push(`  [OK] ${check.description}`);
      }
    }
  }

  // Summary
  const totalErrors = results.reduce((sum, r) => sum + r.issues.length, 0);
  const totalWarnings = results.reduce((sum, r) => sum + r.warnings.length, 0);
  const avgScore = results.reduce((sum, r) => sum + r.score, 0) / results.length;

  lines.push(`\n${"=".repeat(60)}`);
  lines.push("SUMMARY");
  lines.push("=".repeat(60));
  lines.push(`Files analyzed: ${results.length}`);
  lines.push(`Total errors: ${totalErrors}`);
  lines.push(`Total warnings: ${totalWarnings}`);
  lines.push(`Average score: ${avgScore.toFixed(1)}/100`);

  return lines.join("\n");
}

// === Help Text ===

function printHelp(): void {
  console.log(`
${SCRIPT_NAME} v${VERSION} - Design Accessibility Auditor

Checks HTML/component files for design-related accessibility issues
including color contrast, focus states, touch targets, and motion.

Usage:
  deno run --allow-read scripts/${SCRIPT_NAME}.ts <input> [options]

Arguments:
  <input>              HTML/component file or directory

Options:
  -h, --help           Show this help message
  -v, --version        Show version
  --level <AA|AAA>     WCAG conformance level (default: AA)
  --format <type>      Output format: json (default), summary
  --pretty             Pretty-print JSON output

Supported Files:
  .html, .htm, .tsx, .jsx, .vue, .svelte, .css

Checks Performed:
  - Color contrast ratios
  - Focus indicator presence
  - Touch target sizes
  - Motion and animation accessibility
  - Image alt text
  - Form label associations
  - Semantic structure

Examples:
  # Audit a component file
  deno run --allow-read scripts/${SCRIPT_NAME}.ts Button.tsx

  # Audit all components with AAA level
  deno run --allow-read scripts/${SCRIPT_NAME}.ts ./src/components --level AAA

  # Get a human-readable summary
  deno run --allow-read scripts/${SCRIPT_NAME}.ts ./src --format summary
`);
}

// === Main CLI Handler ===

async function main(args: string[]): Promise<void> {
  const parsed = parseArgs(args, {
    boolean: ["help", "version", "pretty"],
    string: ["level", "format"],
    alias: { h: "help", v: "version" },
    default: { level: "AA", format: "json", pretty: false },
  });

  if (parsed.help) {
    printHelp();
    Deno.exit(0);
  }

  if (parsed.version) {
    console.log(`${SCRIPT_NAME} v${VERSION}`);
    Deno.exit(0);
  }

  const input = parsed._[0] as string;

  if (!input) {
    console.error("Error: Input file or directory required");
    console.error("Use --help for usage information");
    Deno.exit(1);
  }

  if (!["AA", "AAA"].includes(parsed.level)) {
    console.error(`Error: Invalid level '${parsed.level}'. Use AA or AAA.`);
    Deno.exit(1);
  }

  const options: AnalyzeOptions = {
    input,
    level: parsed.level as "AA" | "AAA",
    format: parsed.format as "json" | "summary",
    pretty: parsed.pretty,
  };

  try {
    const results = await analyzeAccessibility(options);

    if (options.format === "summary") {
      console.log(formatSummary(results));
    } else {
      const output = options.pretty
        ? JSON.stringify(results, null, 2)
        : JSON.stringify(results);
      console.log(output);
    }

    // Exit with error code if there are issues
    const hasErrors = results.some((r) => r.issues.length > 0);
    if (hasErrors) {
      Deno.exit(1);
    }
  } catch (error) {
    console.error(`Error: ${(error as Error).message}`);
    Deno.exit(1);
  }
}

// === Entry Point ===

if (import.meta.main) {
  main(Deno.args);
}

```

### scripts/generate-palette.ts

```typescript
#!/usr/bin/env -S deno run --allow-read --allow-write

/**
 * generate-palette.ts - Color Palette Generator
 *
 * Generates cohesive color palettes from seed colors or themes,
 * with shade scales and semantic color variants.
 */

import { parseArgs } from "jsr:@std/[email protected]/parse-args";
import { resolve } from "jsr:@std/[email protected]";

// === Constants ===
const VERSION = "1.0.0";
const SCRIPT_NAME = "generate-palette";

type Theme = "warm" | "cool" | "neutral" | "vibrant" | "muted" | "dark" | "light";
type Style = "minimalist" | "bold" | "organic" | "corporate" | "playful";
type OutputFormat = "css" | "scss" | "tailwind" | "tokens" | "json";

// === Types ===
export interface PaletteSpec {
  seedColors?: {
    primary?: string;
    secondary?: string;
    accent?: string;
  };
  theme?: Theme;
  style?: Style;
  generateShades?: boolean;
  generateSemantics?: boolean;
  contrastTarget?: "AA" | "AAA";
  outputFormat: OutputFormat;
}

export interface GeneratedPalette {
  primary: Record<string, string>;
  secondary?: Record<string, string>;
  accent?: Record<string, string>;
  neutral: Record<string, string>;
  semantic?: {
    success: Record<string, string>;
    warning: Record<string, string>;
    error: Record<string, string>;
    info: Record<string, string>;
  };
}

interface GenerateOptions {
  specFile?: string;
  seed?: string;
  theme?: Theme;
  style?: Style;
  shades: boolean;
  semantic: boolean;
  contrast: "AA" | "AAA";
  format: OutputFormat;
  output?: string;
}

// === Color Utilities ===

interface HSL {
  h: number;
  s: number;
  l: number;
}

interface RGB {
  r: number;
  g: number;
  b: number;
}

function hexToRgb(hex: string): RGB {
  const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
  if (!result) {
    // Handle shorthand
    const short = /^#?([a-f\d])([a-f\d])([a-f\d])$/i.exec(hex);
    if (short) {
      return {
        r: parseInt(short[1] + short[1], 16),
        g: parseInt(short[2] + short[2], 16),
        b: parseInt(short[3] + short[3], 16),
      };
    }
    throw new Error(`Invalid hex color: ${hex}`);
  }
  return {
    r: parseInt(result[1], 16),
    g: parseInt(result[2], 16),
    b: parseInt(result[3], 16),
  };
}

function rgbToHex(rgb: RGB): string {
  const toHex = (n: number) =>
    Math.round(Math.max(0, Math.min(255, n)))
      .toString(16)
      .padStart(2, "0");
  return `#${toHex(rgb.r)}${toHex(rgb.g)}${toHex(rgb.b)}`;
}

function rgbToHsl(rgb: RGB): HSL {
  const r = rgb.r / 255;
  const g = rgb.g / 255;
  const b = rgb.b / 255;

  const max = Math.max(r, g, b);
  const min = Math.min(r, g, b);
  const l = (max + min) / 2;

  if (max === min) {
    return { h: 0, s: 0, l };
  }

  const d = max - min;
  const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);

  let h = 0;
  switch (max) {
    case r:
      h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
      break;
    case g:
      h = ((b - r) / d + 2) / 6;
      break;
    case b:
      h = ((r - g) / d + 4) / 6;
      break;
  }

  return { h: h * 360, s, l };
}

function hslToRgb(hsl: HSL): RGB {
  const { h, s, l } = hsl;

  if (s === 0) {
    const gray = Math.round(l * 255);
    return { r: gray, g: gray, b: gray };
  }

  const hue2rgb = (p: number, q: number, t: number) => {
    if (t < 0) t += 1;
    if (t > 1) t -= 1;
    if (t < 1 / 6) return p + (q - p) * 6 * t;
    if (t < 1 / 2) return q;
    if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
    return p;
  };

  const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
  const p = 2 * l - q;
  const hNorm = h / 360;

  return {
    r: Math.round(hue2rgb(p, q, hNorm + 1 / 3) * 255),
    g: Math.round(hue2rgb(p, q, hNorm) * 255),
    b: Math.round(hue2rgb(p, q, hNorm - 1 / 3) * 255),
  };
}

function adjustHsl(hex: string, hDelta: number, sDelta: number, lDelta: number): string {
  const rgb = hexToRgb(hex);
  const hsl = rgbToHsl(rgb);

  hsl.h = (hsl.h + hDelta + 360) % 360;
  hsl.s = Math.max(0, Math.min(1, hsl.s + sDelta));
  hsl.l = Math.max(0, Math.min(1, hsl.l + lDelta));

  return rgbToHex(hslToRgb(hsl));
}

// === Shade Generation ===

function generateShadeScale(baseColor: string): Record<string, string> {
  const rgb = hexToRgb(baseColor);
  const hsl = rgbToHsl(rgb);

  const shades: Record<string, string> = {};

  // Generate shades from 50 (lightest) to 950 (darkest)
  const levels = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950];
  const baseLightness = hsl.l;

  for (const level of levels) {
    // Map level to lightness: 50 -> ~0.97, 500 -> base, 950 -> ~0.05
    let targetL: number;
    if (level <= 500) {
      // Lighter shades
      targetL = baseLightness + ((1 - baseLightness) * (500 - level)) / 500 * 0.9;
    } else {
      // Darker shades
      targetL = baseLightness - (baseLightness * (level - 500)) / 500 * 0.9;
    }

    // Adjust saturation slightly - more saturated in mid-tones
    const satAdjust = level >= 300 && level <= 700 ? 0.05 : -0.05;

    const newHsl = {
      h: hsl.h,
      s: Math.max(0, Math.min(1, hsl.s + satAdjust)),
      l: Math.max(0.03, Math.min(0.97, targetL)),
    };

    shades[level.toString()] = rgbToHex(hslToRgb(newHsl));
  }

  return shades;
}

// === Theme-based Color Generation ===

function generateThemeColors(theme: Theme): { primary: string; hueShift: number } {
  const themeSeeds: Record<Theme, { primary: string; hueShift: number }> = {
    warm: { primary: "#e07020", hueShift: 30 },
    cool: { primary: "#2563eb", hueShift: -20 },
    neutral: { primary: "#64748b", hueShift: 0 },
    vibrant: { primary: "#8b5cf6", hueShift: 40 },
    muted: { primary: "#78716c", hueShift: 15 },
    dark: { primary: "#1e293b", hueShift: 10 },
    light: { primary: "#f1f5f9", hueShift: 5 },
  };

  return themeSeeds[theme];
}

function applyStyle(color: string, style?: Style): string {
  if (!style) return color;

  const adjustments: Record<Style, { h: number; s: number; l: number }> = {
    minimalist: { h: 0, s: -0.2, l: 0.1 },
    bold: { h: 0, s: 0.15, l: -0.05 },
    organic: { h: 15, s: -0.1, l: 0.05 },
    corporate: { h: 0, s: -0.1, l: 0 },
    playful: { h: 10, s: 0.1, l: 0.05 },
  };

  const adj = adjustments[style];
  return adjustHsl(color, adj.h, adj.s, adj.l);
}

// === Semantic Colors ===

function generateSemanticColors(): GeneratedPalette["semantic"] {
  return {
    success: generateShadeScale("#22c55e"),
    warning: generateShadeScale("#f59e0b"),
    error: generateShadeScale("#ef4444"),
    info: generateShadeScale("#3b82f6"),
  };
}

// === Neutral Colors ===

function generateNeutralScale(primary: string): Record<string, string> {
  const rgb = hexToRgb(primary);
  const hsl = rgbToHsl(rgb);

  // Use a desaturated version of primary hue for neutrals
  const neutralHsl: HSL = {
    h: hsl.h,
    s: 0.05, // Very low saturation
    l: 0.5,
  };

  const base = rgbToHex(hslToRgb(neutralHsl));
  return generateShadeScale(base);
}

// === Complementary Colors ===

function generateSecondaryColor(primary: string): string {
  // Analogous color (30 degrees)
  return adjustHsl(primary, 30, 0, 0);
}

function generateAccentColor(primary: string): string {
  // Complementary color (180 degrees) with adjusted saturation
  return adjustHsl(primary, 180, 0.1, 0.05);
}

// === Core Generation Function ===

export async function generatePalette(options: GenerateOptions): Promise<GeneratedPalette> {
  let spec: PaletteSpec;

  if (options.specFile) {
    const specContent = await Deno.readTextFile(resolve(options.specFile));
    spec = JSON.parse(specContent);
  } else {
    spec = {
      seedColors: options.seed ? { primary: options.seed } : undefined,
      theme: options.theme,
      style: options.style,
      generateShades: options.shades,
      generateSemantics: options.semantic,
      contrastTarget: options.contrast,
      outputFormat: options.format,
    };
  }

  // Determine primary color
  let primaryColor: string;

  if (spec.seedColors?.primary) {
    primaryColor = spec.seedColors.primary;
  } else if (spec.theme) {
    primaryColor = generateThemeColors(spec.theme).primary;
  } else {
    primaryColor = "#2563eb"; // Default blue
  }

  // Apply style adjustments
  if (spec.style) {
    primaryColor = applyStyle(primaryColor, spec.style);
  }

  // Generate palette
  const palette: GeneratedPalette = {
    primary: spec.generateShades
      ? generateShadeScale(primaryColor)
      : { DEFAULT: primaryColor },
    neutral: generateNeutralScale(primaryColor),
  };

  // Secondary color
  const secondaryColor = spec.seedColors?.secondary || generateSecondaryColor(primaryColor);
  if (spec.style) {
    palette.secondary = spec.generateShades
      ? generateShadeScale(applyStyle(secondaryColor, spec.style))
      : { DEFAULT: applyStyle(secondaryColor, spec.style) };
  } else {
    palette.secondary = spec.generateShades
      ? generateShadeScale(secondaryColor)
      : { DEFAULT: secondaryColor };
  }

  // Accent color
  const accentColor = spec.seedColors?.accent || generateAccentColor(primaryColor);
  if (spec.style) {
    palette.accent = spec.generateShades
      ? generateShadeScale(applyStyle(accentColor, spec.style))
      : { DEFAULT: applyStyle(accentColor, spec.style) };
  } else {
    palette.accent = spec.generateShades
      ? generateShadeScale(accentColor)
      : { DEFAULT: accentColor };
  }

  // Semantic colors
  if (spec.generateSemantics) {
    palette.semantic = generateSemanticColors();
  }

  return palette;
}

// === Output Formatting ===

function formatAsCSS(palette: GeneratedPalette): string {
  const lines: string[] = [
    "/* Color Palette - Generated by generate-palette */",
    "",
    ":root {",
  ];

  const formatColor = (name: string, colors: Record<string, string>) => {
    for (const [shade, hex] of Object.entries(colors)) {
      if (shade === "DEFAULT") {
        lines.push(`  --color-${name}: ${hex};`);
      } else {
        lines.push(`  --color-${name}-${shade}: ${hex};`);
      }
    }
  };

  formatColor("primary", palette.primary);
  lines.push("");
  if (palette.secondary) formatColor("secondary", palette.secondary);
  lines.push("");
  if (palette.accent) formatColor("accent", palette.accent);
  lines.push("");
  formatColor("neutral", palette.neutral);

  if (palette.semantic) {
    lines.push("");
    lines.push("  /* Semantic */");
    formatColor("success", palette.semantic.success);
    formatColor("warning", palette.semantic.warning);
    formatColor("error", palette.semantic.error);
    formatColor("info", palette.semantic.info);
  }

  lines.push("}");
  return lines.join("\n");
}

function formatAsSCSS(palette: GeneratedPalette): string {
  const lines: string[] = ["// Color Palette - Generated by generate-palette", ""];

  const formatColor = (name: string, colors: Record<string, string>) => {
    for (const [shade, hex] of Object.entries(colors)) {
      if (shade === "DEFAULT") {
        lines.push(`$color-${name}: ${hex};`);
      } else {
        lines.push(`$color-${name}-${shade}: ${hex};`);
      }
    }
  };

  formatColor("primary", palette.primary);
  lines.push("");
  if (palette.secondary) formatColor("secondary", palette.secondary);
  lines.push("");
  if (palette.accent) formatColor("accent", palette.accent);
  lines.push("");
  formatColor("neutral", palette.neutral);

  if (palette.semantic) {
    lines.push("");
    lines.push("// Semantic");
    formatColor("success", palette.semantic.success);
    formatColor("warning", palette.semantic.warning);
    formatColor("error", palette.semantic.error);
    formatColor("info", palette.semantic.info);
  }

  return lines.join("\n");
}

function formatAsTailwind(palette: GeneratedPalette): string {
  const config: Record<string, unknown> = {
    primary: palette.primary,
    secondary: palette.secondary,
    accent: palette.accent,
    neutral: palette.neutral,
  };

  if (palette.semantic) {
    Object.assign(config, {
      success: palette.semantic.success,
      warning: palette.semantic.warning,
      error: palette.semantic.error,
      info: palette.semantic.info,
    });
  }

  return `// Tailwind Color Config - Generated by generate-palette
// Add to tailwind.config.js theme.extend.colors

module.exports = {
  theme: {
    extend: {
      colors: ${JSON.stringify(config, null, 8).replace(/"([^"]+)":/g, "$1:")}
    }
  }
};`;
}

function formatAsTokens(palette: GeneratedPalette): string {
  const tokens: Record<string, unknown> = {
    color: {
      primary: {},
      secondary: {},
      accent: {},
      neutral: {},
    },
  };

  const formatTokens = (name: string, colors: Record<string, string>) => {
    for (const [shade, hex] of Object.entries(colors)) {
      (tokens.color as Record<string, Record<string, unknown>>)[name][shade] = {
        value: hex,
        type: "color",
      };
    }
  };

  formatTokens("primary", palette.primary);
  if (palette.secondary) formatTokens("secondary", palette.secondary);
  if (palette.accent) formatTokens("accent", palette.accent);
  formatTokens("neutral", palette.neutral);

  if (palette.semantic) {
    (tokens.color as Record<string, unknown>).semantic = {};
    for (const [name, colors] of Object.entries(palette.semantic)) {
      (tokens.color as Record<string, Record<string, unknown>>).semantic[name] = {};
      for (const [shade, hex] of Object.entries(colors)) {
        ((tokens.color as Record<string, Record<string, unknown>>).semantic[name] as Record<string, unknown>)[shade] = {
          value: hex,
          type: "color",
        };
      }
    }
  }

  return JSON.stringify(tokens, null, 2);
}

function formatOutput(palette: GeneratedPalette, format: OutputFormat): string {
  switch (format) {
    case "css":
      return formatAsCSS(palette);
    case "scss":
      return formatAsSCSS(palette);
    case "tailwind":
      return formatAsTailwind(palette);
    case "tokens":
      return formatAsTokens(palette);
    case "json":
    default:
      return JSON.stringify(palette, null, 2);
  }
}

// === Help Text ===

function printHelp(): void {
  console.log(`
${SCRIPT_NAME} v${VERSION} - Color Palette Generator

Generates cohesive color palettes from seed colors or themes,
with shade scales and semantic color variants.

Usage:
  deno run --allow-read --allow-write scripts/${SCRIPT_NAME}.ts [options] [output]

Arguments:
  [output]             Output file path (optional, prints to stdout if omitted)

Options:
  -h, --help           Show this help message
  -v, --version        Show version
  --spec <file>        JSON specification file
  --seed <color>       Primary seed color (hex)
  --theme <type>       Theme: warm, cool, neutral, vibrant, muted, dark, light
  --style <type>       Style: minimalist, bold, organic, corporate, playful
  --shades             Generate 50-950 shade scale
  --semantic           Generate semantic colors (success, warning, error, info)
  --contrast <level>   Target contrast: AA (default), AAA
  --format <type>      Output: css, scss, tailwind, tokens, json (default: css)

Examples:
  # Generate from seed color with shades
  deno run --allow-read --allow-write scripts/${SCRIPT_NAME}.ts --seed "#2563eb" --shades

  # Generate warm theme with semantic colors
  deno run --allow-read --allow-write scripts/${SCRIPT_NAME}.ts --theme warm --semantic --format css

  # Generate from spec file
  deno run --allow-read --allow-write scripts/${SCRIPT_NAME}.ts --spec palette-spec.json palette.css

  # Generate Tailwind config
  deno run --allow-read --allow-write scripts/${SCRIPT_NAME}.ts --seed "#8b5cf6" --shades --format tailwind
`);
}

// === Main CLI Handler ===

async function main(args: string[]): Promise<void> {
  const parsed = parseArgs(args, {
    boolean: ["help", "version", "shades", "semantic"],
    string: ["spec", "seed", "theme", "style", "contrast", "format"],
    alias: { h: "help", v: "version" },
    default: { contrast: "AA", format: "css", shades: false, semantic: false },
  });

  if (parsed.help) {
    printHelp();
    Deno.exit(0);
  }

  if (parsed.version) {
    console.log(`${SCRIPT_NAME} v${VERSION}`);
    Deno.exit(0);
  }

  const validThemes: Theme[] = ["warm", "cool", "neutral", "vibrant", "muted", "dark", "light"];
  const validStyles: Style[] = ["minimalist", "bold", "organic", "corporate", "playful"];
  const validFormats: OutputFormat[] = ["css", "scss", "tailwind", "tokens", "json"];

  if (parsed.theme && !validThemes.includes(parsed.theme as Theme)) {
    console.error(`Error: Invalid theme '${parsed.theme}'`);
    console.error(`Valid themes: ${validThemes.join(", ")}`);
    Deno.exit(1);
  }

  if (parsed.style && !validStyles.includes(parsed.style as Style)) {
    console.error(`Error: Invalid style '${parsed.style}'`);
    console.error(`Valid styles: ${validStyles.join(", ")}`);
    Deno.exit(1);
  }

  if (!validFormats.includes(parsed.format as OutputFormat)) {
    console.error(`Error: Invalid format '${parsed.format}'`);
    console.error(`Valid formats: ${validFormats.join(", ")}`);
    Deno.exit(1);
  }

  if (!parsed.spec && !parsed.seed && !parsed.theme) {
    console.error("Error: Provide --spec, --seed, or --theme");
    console.error("Use --help for usage information");
    Deno.exit(1);
  }

  const options: GenerateOptions = {
    specFile: parsed.spec,
    seed: parsed.seed,
    theme: parsed.theme as Theme | undefined,
    style: parsed.style as Style | undefined,
    shades: parsed.shades,
    semantic: parsed.semantic,
    contrast: parsed.contrast as "AA" | "AAA",
    format: parsed.format as OutputFormat,
    output: parsed._[0] as string | undefined,
  };

  try {
    const palette = await generatePalette(options);
    const output = formatOutput(palette, options.format);

    if (options.output) {
      await Deno.writeTextFile(resolve(options.output), output);
      console.log(`Palette written to: ${options.output}`);
    } else {
      console.log(output);
    }
  } catch (error) {
    console.error(`Error: ${(error as Error).message}`);
    Deno.exit(1);
  }
}

// === Entry Point ===

if (import.meta.main) {
  main(Deno.args);
}

```

### scripts/generate-typography.ts

```typescript
#!/usr/bin/env -S deno run --allow-read --allow-write

/**
 * generate-typography.ts - Typography System Generator
 *
 * Generates typography systems with font stacks, scales, and responsive sizing.
 */

import { parseArgs } from "jsr:@std/[email protected]/parse-args";
import { resolve } from "jsr:@std/[email protected]";

// === Constants ===
const VERSION = "1.0.0";
const SCRIPT_NAME = "generate-typography";

type Scale = "minor-second" | "major-second" | "minor-third" | "major-third" | "perfect-fourth" | "golden-ratio";
type LineHeight = "tight" | "normal" | "relaxed";
type OutputFormat = "css" | "scss" | "tailwind" | "tokens";

const SCALE_RATIOS: Record<Scale, number> = {
  "minor-second": 1.067,
  "major-second": 1.125,
  "minor-third": 1.2,
  "major-third": 1.25,
  "perfect-fourth": 1.333,
  "golden-ratio": 1.618,
};

const LINE_HEIGHTS: Record<LineHeight, number> = {
  tight: 1.25,
  normal: 1.5,
  relaxed: 1.75,
};

// === Types ===
export interface TypographySpec {
  fonts: {
    display?: string;
    body?: string;
    mono?: string;
  };
  scale?: Scale;
  baseSize?: number;
  lineHeights?: LineHeight;
  responsive?: boolean;
  outputFormat: OutputFormat;
  includeUtilities?: boolean;
}

export interface GeneratedTypography {
  fontFamilies: {
    display: string;
    body: string;
    mono: string;
  };
  fontSizes: Record<string, { size: string; lineHeight: string }>;
  fontWeights: Record<string, number>;
  letterSpacing: Record<string, string>;
  responsive?: {
    sm: Record<string, string>;
    md: Record<string, string>;
    lg: Record<string, string>;
  };
}

interface GenerateOptions {
  specFile?: string;
  display?: string;
  body?: string;
  mono?: string;
  scale: Scale;
  base: number;
  lineHeight: LineHeight;
  responsive: boolean;
  format: OutputFormat;
  output?: string;
}

// === Font Stacks ===

const FALLBACK_STACKS = {
  serif: "Georgia, Cambria, 'Times New Roman', Times, serif",
  sansSerif: "system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif",
  mono: "ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace",
};

function createFontStack(font: string | undefined, type: "display" | "body" | "mono"): string {
  if (!font) {
    if (type === "mono") return FALLBACK_STACKS.mono;
    return FALLBACK_STACKS.sansSerif;
  }

  // Wrap font name in quotes if it contains spaces
  const fontName = font.includes(" ") ? `'${font}'` : font;

  // Determine fallback based on font characteristics
  const isSerif = /serif|georgia|times|garamond|palatino|baskerville/i.test(font);
  const isMono = /mono|code|courier|consolas/i.test(font);

  if (isMono || type === "mono") {
    return `${fontName}, ${FALLBACK_STACKS.mono}`;
  }
  if (isSerif) {
    return `${fontName}, ${FALLBACK_STACKS.serif}`;
  }
  return `${fontName}, ${FALLBACK_STACKS.sansSerif}`;
}

// === Scale Generation ===

function generateFontSizes(baseSize: number, ratio: number, lineHeight: number): Record<string, { size: string; lineHeight: string }> {
  const sizes: Record<string, { size: string; lineHeight: string }> = {};

  // Generate sizes from xs to 6xl
  const steps = [
    { name: "xs", step: -2 },
    { name: "sm", step: -1 },
    { name: "base", step: 0 },
    { name: "lg", step: 1 },
    { name: "xl", step: 2 },
    { name: "2xl", step: 3 },
    { name: "3xl", step: 4 },
    { name: "4xl", step: 5 },
    { name: "5xl", step: 6 },
    { name: "6xl", step: 7 },
  ];

  for (const { name, step } of steps) {
    const size = baseSize * Math.pow(ratio, step);
    // Larger text needs tighter line height
    const adjustedLineHeight = step >= 3 ? lineHeight * 0.85 : lineHeight;

    sizes[name] = {
      size: `${(size / 16).toFixed(3)}rem`,
      lineHeight: adjustedLineHeight.toFixed(2),
    };
  }

  return sizes;
}

function generateFontWeights(): Record<string, number> {
  return {
    thin: 100,
    extralight: 200,
    light: 300,
    normal: 400,
    medium: 500,
    semibold: 600,
    bold: 700,
    extrabold: 800,
    black: 900,
  };
}

function generateLetterSpacing(): Record<string, string> {
  return {
    tighter: "-0.05em",
    tight: "-0.025em",
    normal: "0",
    wide: "0.025em",
    wider: "0.05em",
    widest: "0.1em",
  };
}

function generateResponsiveSizes(
  fontSizes: Record<string, { size: string; lineHeight: string }>
): GeneratedTypography["responsive"] {
  const responsive: GeneratedTypography["responsive"] = {
    sm: {},
    md: {},
    lg: {},
  };

  // At smaller screens, reduce large text sizes
  for (const [name, { size }] of Object.entries(fontSizes)) {
    const remValue = parseFloat(size);

    if (remValue > 2) {
      // Large text scales down on smaller screens
      responsive!.sm[name] = `${(remValue * 0.7).toFixed(3)}rem`;
      responsive!.md[name] = `${(remValue * 0.85).toFixed(3)}rem`;
      responsive!.lg[name] = size;
    } else if (remValue > 1.5) {
      responsive!.sm[name] = `${(remValue * 0.85).toFixed(3)}rem`;
      responsive!.md[name] = `${(remValue * 0.92).toFixed(3)}rem`;
      responsive!.lg[name] = size;
    } else {
      // Smaller text stays consistent
      responsive!.sm[name] = size;
      responsive!.md[name] = size;
      responsive!.lg[name] = size;
    }
  }

  return responsive;
}

// === Core Generation Function ===

export async function generateTypography(options: GenerateOptions): Promise<GeneratedTypography> {
  let spec: TypographySpec;

  if (options.specFile) {
    const specContent = await Deno.readTextFile(resolve(options.specFile));
    spec = JSON.parse(specContent);
  } else {
    spec = {
      fonts: {
        display: options.display,
        body: options.body,
        mono: options.mono,
      },
      scale: options.scale,
      baseSize: options.base,
      lineHeights: options.lineHeight,
      responsive: options.responsive,
      outputFormat: options.format,
    };
  }

  const ratio = SCALE_RATIOS[spec.scale || "major-third"];
  const baseSize = spec.baseSize || 16;
  const lineHeight = LINE_HEIGHTS[spec.lineHeights || "normal"];

  const typography: GeneratedTypography = {
    fontFamilies: {
      display: createFontStack(spec.fonts.display, "display"),
      body: createFontStack(spec.fonts.body, "body"),
      mono: createFontStack(spec.fonts.mono, "mono"),
    },
    fontSizes: generateFontSizes(baseSize, ratio, lineHeight),
    fontWeights: generateFontWeights(),
    letterSpacing: generateLetterSpacing(),
  };

  if (spec.responsive) {
    typography.responsive = generateResponsiveSizes(typography.fontSizes);
  }

  return typography;
}

// === Output Formatting ===

function formatAsCSS(typography: GeneratedTypography, responsive: boolean): string {
  const lines: string[] = [
    "/* Typography System - Generated by generate-typography */",
    "",
    ":root {",
    "  /* Font Families */",
    `  --font-display: ${typography.fontFamilies.display};`,
    `  --font-body: ${typography.fontFamilies.body};`,
    `  --font-mono: ${typography.fontFamilies.mono};`,
    "",
    "  /* Font Sizes */",
  ];

  for (const [name, { size, lineHeight }] of Object.entries(typography.fontSizes)) {
    lines.push(`  --text-${name}: ${size};`);
    lines.push(`  --leading-${name}: ${lineHeight};`);
  }

  lines.push("");
  lines.push("  /* Font Weights */");
  for (const [name, weight] of Object.entries(typography.fontWeights)) {
    lines.push(`  --font-${name}: ${weight};`);
  }

  lines.push("");
  lines.push("  /* Letter Spacing */");
  for (const [name, spacing] of Object.entries(typography.letterSpacing)) {
    lines.push(`  --tracking-${name}: ${spacing};`);
  }

  lines.push("}");

  if (responsive && typography.responsive) {
    lines.push("");
    lines.push("/* Responsive Font Sizes */");

    lines.push("@media (max-width: 640px) {");
    lines.push("  :root {");
    for (const [name, size] of Object.entries(typography.responsive.sm)) {
      lines.push(`    --text-${name}: ${size};`);
    }
    lines.push("  }");
    lines.push("}");

    lines.push("");
    lines.push("@media (min-width: 641px) and (max-width: 1024px) {");
    lines.push("  :root {");
    for (const [name, size] of Object.entries(typography.responsive.md)) {
      lines.push(`    --text-${name}: ${size};`);
    }
    lines.push("  }");
    lines.push("}");
  }

  // Add utility classes
  lines.push("");
  lines.push("/* Utility Classes */");
  lines.push(".font-display { font-family: var(--font-display); }");
  lines.push(".font-body { font-family: var(--font-body); }");
  lines.push(".font-mono { font-family: var(--font-mono); }");

  return lines.join("\n");
}

function formatAsSCSS(typography: GeneratedTypography): string {
  const lines: string[] = [
    "// Typography System - Generated by generate-typography",
    "",
    "// Font Families",
    `$font-display: ${typography.fontFamilies.display};`,
    `$font-body: ${typography.fontFamilies.body};`,
    `$font-mono: ${typography.fontFamilies.mono};`,
    "",
    "// Font Sizes",
  ];

  for (const [name, { size, lineHeight }] of Object.entries(typography.fontSizes)) {
    lines.push(`$text-${name}: ${size};`);
    lines.push(`$leading-${name}: ${lineHeight};`);
  }

  lines.push("");
  lines.push("// Font Weights");
  for (const [name, weight] of Object.entries(typography.fontWeights)) {
    lines.push(`$font-${name}: ${weight};`);
  }

  lines.push("");
  lines.push("// Letter Spacing");
  for (const [name, spacing] of Object.entries(typography.letterSpacing)) {
    lines.push(`$tracking-${name}: ${spacing};`);
  }

  lines.push("");
  lines.push("// Maps for iteration");
  lines.push("$font-sizes: (");
  for (const [name, { size }] of Object.entries(typography.fontSizes)) {
    lines.push(`  '${name}': ${size},`);
  }
  lines.push(");");

  return lines.join("\n");
}

function formatAsTailwind(typography: GeneratedTypography): string {
  const fontFamily = {
    display: [typography.fontFamilies.display.split(",")[0].replace(/['"]/g, "").trim()],
    body: [typography.fontFamilies.body.split(",")[0].replace(/['"]/g, "").trim()],
    mono: [typography.fontFamilies.mono.split(",")[0].replace(/['"]/g, "").trim()],
  };

  const fontSize: Record<string, [string, { lineHeight: string }]> = {};
  for (const [name, { size, lineHeight }] of Object.entries(typography.fontSizes)) {
    fontSize[name] = [size, { lineHeight }];
  }

  const config = {
    fontFamily,
    fontSize,
    fontWeight: typography.fontWeights,
    letterSpacing: typography.letterSpacing,
  };

  return `// Tailwind Typography Config - Generated by generate-typography
// Add to tailwind.config.js theme.extend

module.exports = {
  theme: {
    extend: ${JSON.stringify(config, null, 6).replace(/"([^"]+)":/g, "$1:")}
  }
};`;
}

function formatAsTokens(typography: GeneratedTypography): string {
  const tokens = {
    typography: {
      fontFamilies: {
        display: { value: typography.fontFamilies.display, type: "fontFamilies" },
        body: { value: typography.fontFamilies.body, type: "fontFamilies" },
        mono: { value: typography.fontFamilies.mono, type: "fontFamilies" },
      },
      fontSize: {} as Record<string, { value: string; type: string }>,
      lineHeight: {} as Record<string, { value: string; type: string }>,
      fontWeight: {} as Record<string, { value: number; type: string }>,
      letterSpacing: {} as Record<string, { value: string; type: string }>,
    },
  };

  for (const [name, { size, lineHeight }] of Object.entries(typography.fontSizes)) {
    tokens.typography.fontSize[name] = { value: size, type: "fontSizes" };
    tokens.typography.lineHeight[name] = { value: lineHeight, type: "lineHeights" };
  }

  for (const [name, weight] of Object.entries(typography.fontWeights)) {
    tokens.typography.fontWeight[name] = { value: weight, type: "fontWeights" };
  }

  for (const [name, spacing] of Object.entries(typography.letterSpacing)) {
    tokens.typography.letterSpacing[name] = { value: spacing, type: "letterSpacing" };
  }

  return JSON.stringify(tokens, null, 2);
}

function formatOutput(typography: GeneratedTypography, options: GenerateOptions): string {
  switch (options.format) {
    case "css":
      return formatAsCSS(typography, options.responsive);
    case "scss":
      return formatAsSCSS(typography);
    case "tailwind":
      return formatAsTailwind(typography);
    case "tokens":
      return formatAsTokens(typography);
    default:
      return JSON.stringify(typography, null, 2);
  }
}

// === Help Text ===

function printHelp(): void {
  console.log(`
${SCRIPT_NAME} v${VERSION} - Typography System Generator

Generates typography systems with font stacks, scales, and responsive sizing.

Usage:
  deno run --allow-read --allow-write scripts/${SCRIPT_NAME}.ts [options] [output]

Arguments:
  [output]             Output file path (optional, prints to stdout if omitted)

Options:
  -h, --help           Show this help message
  -v, --version        Show version
  --spec <file>        JSON specification file
  --display <font>     Display/heading font family
  --body <font>        Body text font family
  --mono <font>        Monospace font family
  --scale <type>       Type scale (see below)
  --base <px>          Base font size in px (default: 16)
  --line-height <type> Line height: tight, normal, relaxed (default: normal)
  --responsive         Generate responsive breakpoints
  --format <type>      Output: css, scss, tailwind, tokens (default: css)

Type Scales:
  minor-second   1.067  Subtle, conservative
  major-second   1.125  Balanced, professional
  minor-third    1.200  Clear hierarchy
  major-third    1.250  Strong presence (default)
  perfect-fourth 1.333  Bold, impactful
  golden-ratio   1.618  Dramatic, artistic

Examples:
  # Generate with custom fonts
  deno run --allow-read --allow-write scripts/${SCRIPT_NAME}.ts \\
    --display "Playfair Display" --body "Inter" --scale major-third

  # Generate responsive system
  deno run --allow-read --allow-write scripts/${SCRIPT_NAME}.ts \\
    --display "Space Grotesk" --responsive --format css typography.css

  # Generate Tailwind config
  deno run --allow-read --allow-write scripts/${SCRIPT_NAME}.ts \\
    --display "DM Sans" --body "DM Sans" --format tailwind
`);
}

// === Main CLI Handler ===

async function main(args: string[]): Promise<void> {
  const parsed = parseArgs(args, {
    boolean: ["help", "version", "responsive"],
    string: ["spec", "display", "body", "mono", "scale", "base", "line-height", "format"],
    alias: { h: "help", v: "version" },
    default: {
      scale: "major-third",
      base: "16",
      "line-height": "normal",
      format: "css",
      responsive: false,
    },
  });

  if (parsed.help) {
    printHelp();
    Deno.exit(0);
  }

  if (parsed.version) {
    console.log(`${SCRIPT_NAME} v${VERSION}`);
    Deno.exit(0);
  }

  const validScales: Scale[] = [
    "minor-second",
    "major-second",
    "minor-third",
    "major-third",
    "perfect-fourth",
    "golden-ratio",
  ];

  const validLineHeights: LineHeight[] = ["tight", "normal", "relaxed"];
  const validFormats: OutputFormat[] = ["css", "scss", "tailwind", "tokens"];

  if (!validScales.includes(parsed.scale as Scale)) {
    console.error(`Error: Invalid scale '${parsed.scale}'`);
    console.error(`Valid scales: ${validScales.join(", ")}`);
    Deno.exit(1);
  }

  if (!validLineHeights.includes(parsed["line-height"] as LineHeight)) {
    console.error(`Error: Invalid line-height '${parsed["line-height"]}'`);
    console.error(`Valid line-heights: ${validLineHeights.join(", ")}`);
    Deno.exit(1);
  }

  if (!validFormats.includes(parsed.format as OutputFormat)) {
    console.error(`Error: Invalid format '${parsed.format}'`);
    console.error(`Valid formats: ${validFormats.join(", ")}`);
    Deno.exit(1);
  }

  const baseSize = parseInt(parsed.base, 10);
  if (isNaN(baseSize) || baseSize < 10 || baseSize > 32) {
    console.error("Error: Base size must be between 10 and 32");
    Deno.exit(1);
  }

  const options: GenerateOptions = {
    specFile: parsed.spec,
    display: parsed.display,
    body: parsed.body,
    mono: parsed.mono,
    scale: parsed.scale as Scale,
    base: baseSize,
    lineHeight: parsed["line-height"] as LineHeight,
    responsive: parsed.responsive,
    format: parsed.format as OutputFormat,
    output: parsed._[0] as string | undefined,
  };

  try {
    const typography = await generateTypography(options);
    const output = formatOutput(typography, options);

    if (options.output) {
      await Deno.writeTextFile(resolve(options.output), output);
      console.log(`Typography written to: ${options.output}`);
    } else {
      console.log(output);
    }
  } catch (error) {
    console.error(`Error: ${(error as Error).message}`);
    Deno.exit(1);
  }
}

// === Entry Point ===

if (import.meta.main) {
  main(Deno.args);
}

```

### scripts/generate-tokens.ts

```typescript
#!/usr/bin/env -S deno run --allow-read --allow-write

/**
 * generate-tokens.ts - Design Token Generator
 *
 * Generates comprehensive design token files in multiple formats
 * from a JSON specification.
 */

import { parseArgs } from "jsr:@std/[email protected]/parse-args";
import { resolve, join } from "jsr:@std/[email protected]";
import { ensureDir } from "jsr:@std/[email protected]/ensure-dir";

// === Constants ===
const VERSION = "1.0.0";
const SCRIPT_NAME = "generate-tokens";

type OutputFormat = "css" | "scss" | "json" | "js" | "ts" | "tailwind" | "style-dictionary";

// === Types ===
export interface TokenSpec {
  name: string;
  description?: string;
  tokens: {
    color?: Record<string, string | Record<string, string>>;
    spacing?: Record<string, string>;
    typography?: {
      fontFamilies?: Record<string, string>;
      fontSizes?: Record<string, string>;
      fontWeights?: Record<string, number>;
      lineHeights?: Record<string, string>;
      letterSpacing?: Record<string, string>;
    };
    shadow?: Record<string, string>;
    border?: {
      radius?: Record<string, string>;
      width?: Record<string, string>;
    };
    animation?: {
      duration?: Record<string, string>;
      easing?: Record<string, string>;
    };
    zIndex?: Record<string, number>;
  };
  outputFormats: OutputFormat[];
}

interface GenerateOptions {
  specFile: string;
  outputDir: string;
}

// === Token Flattening ===

function flattenTokens(
  obj: Record<string, unknown>,
  prefix = ""
): Record<string, string | number> {
  const result: Record<string, string | number> = {};

  for (const [key, value] of Object.entries(obj)) {
    const newKey = prefix ? `${prefix}-${key}` : key;

    if (typeof value === "object" && value !== null && !Array.isArray(value)) {
      Object.assign(result, flattenTokens(value as Record<string, unknown>, newKey));
    } else if (typeof value === "string" || typeof value === "number") {
      result[newKey] = value;
    }
  }

  return result;
}

// === Format Generators ===

function generateCSS(spec: TokenSpec): string {
  const lines: string[] = [
    `/* ${spec.name} Design Tokens */`,
    `/* ${spec.description || "Generated by generate-tokens"} */`,
    "",
    ":root {",
  ];

  const allTokens = flattenTokens(spec.tokens);

  // Group by category
  const categories = new Map<string, Record<string, string | number>>();

  for (const [key, value] of Object.entries(allTokens)) {
    const category = key.split("-")[0];
    if (!categories.has(category)) {
      categories.set(category, {});
    }
    categories.get(category)![key] = value;
  }

  for (const [category, tokens] of categories) {
    lines.push(`  /* ${category} */`);
    for (const [key, value] of Object.entries(tokens)) {
      lines.push(`  --${key}: ${value};`);
    }
    lines.push("");
  }

  lines.push("}");
  return lines.join("\n");
}

function generateSCSS(spec: TokenSpec): string {
  const lines: string[] = [
    `// ${spec.name} Design Tokens`,
    `// ${spec.description || "Generated by generate-tokens"}`,
    "",
  ];

  const allTokens = flattenTokens(spec.tokens);

  // Group by category
  const categories = new Map<string, Record<string, string | number>>();

  for (const [key, value] of Object.entries(allTokens)) {
    const category = key.split("-")[0];
    if (!categories.has(category)) {
      categories.set(category, {});
    }
    categories.get(category)![key] = value;
  }

  for (const [category, tokens] of categories) {
    lines.push(`// ${category}`);
    for (const [key, value] of Object.entries(tokens)) {
      const scssKey = key.replace(/-/g, "_");
      lines.push(`$${scssKey}: ${value};`);
    }
    lines.push("");
  }

  // Generate maps
  lines.push("// Token Maps");
  for (const [category, tokens] of categories) {
    const mapName = category.replace(/-/g, "_");
    lines.push(`$${mapName}_tokens: (`);
    for (const [key, value] of Object.entries(tokens)) {
      const shortKey = key.replace(`${category}-`, "");
      lines.push(`  '${shortKey}': ${value},`);
    }
    lines.push(");");
    lines.push("");
  }

  return lines.join("\n");
}

function generateJSON(spec: TokenSpec): string {
  const output = {
    name: spec.name,
    description: spec.description,
    tokens: spec.tokens,
  };
  return JSON.stringify(output, null, 2);
}

function generateJS(spec: TokenSpec): string {
  const lines: string[] = [
    `/**`,
    ` * ${spec.name} Design Tokens`,
    ` * ${spec.description || "Generated by generate-tokens"}`,
    ` */`,
    "",
    "export const tokens = " + JSON.stringify(spec.tokens, null, 2) + ";",
    "",
    "// Flattened tokens for direct access",
    "export const flatTokens = " + JSON.stringify(flattenTokens(spec.tokens), null, 2) + ";",
    "",
    "export default tokens;",
  ];

  return lines.join("\n");
}

function generateTS(spec: TokenSpec): string {
  const lines: string[] = [
    `/**`,
    ` * ${spec.name} Design Tokens`,
    ` * ${spec.description || "Generated by generate-tokens"}`,
    ` */`,
    "",
  ];

  // Generate type definitions
  lines.push("export interface DesignTokens {");

  if (spec.tokens.color) {
    lines.push("  color: {");
    for (const [key, value] of Object.entries(spec.tokens.color)) {
      if (typeof value === "string") {
        lines.push(`    ${key}: string;`);
      } else {
        lines.push(`    ${key}: Record<string, string>;`);
      }
    }
    lines.push("  };");
  }

  if (spec.tokens.spacing) {
    lines.push("  spacing: Record<string, string>;");
  }

  if (spec.tokens.typography) {
    lines.push("  typography: {");
    if (spec.tokens.typography.fontFamilies) {
      lines.push("    fontFamilies: Record<string, string>;");
    }
    if (spec.tokens.typography.fontSizes) {
      lines.push("    fontSizes: Record<string, string>;");
    }
    if (spec.tokens.typography.fontWeights) {
      lines.push("    fontWeights: Record<string, number>;");
    }
    if (spec.tokens.typography.lineHeights) {
      lines.push("    lineHeights: Record<string, string>;");
    }
    if (spec.tokens.typography.letterSpacing) {
      lines.push("    letterSpacing: Record<string, string>;");
    }
    lines.push("  };");
  }

  if (spec.tokens.shadow) {
    lines.push("  shadow: Record<string, string>;");
  }

  if (spec.tokens.border) {
    lines.push("  border: {");
    if (spec.tokens.border.radius) {
      lines.push("    radius: Record<string, string>;");
    }
    if (spec.tokens.border.width) {
      lines.push("    width: Record<string, string>;");
    }
    lines.push("  };");
  }

  if (spec.tokens.animation) {
    lines.push("  animation: {");
    if (spec.tokens.animation.duration) {
      lines.push("    duration: Record<string, string>;");
    }
    if (spec.tokens.animation.easing) {
      lines.push("    easing: Record<string, string>;");
    }
    lines.push("  };");
  }

  if (spec.tokens.zIndex) {
    lines.push("  zIndex: Record<string, number>;");
  }

  lines.push("}");
  lines.push("");

  // Generate the token object
  lines.push("export const tokens: DesignTokens = " + JSON.stringify(spec.tokens, null, 2) + " as const;");
  lines.push("");

  // Generate flattened tokens with type
  lines.push("export type FlatToken = string | number;");
  lines.push("export const flatTokens: Record<string, FlatToken> = " + JSON.stringify(flattenTokens(spec.tokens), null, 2) + ";");
  lines.push("");
  lines.push("export default tokens;");

  return lines.join("\n");
}

function generateTailwind(spec: TokenSpec): string {
  const config: Record<string, unknown> = {};

  if (spec.tokens.color) {
    config.colors = spec.tokens.color;
  }

  if (spec.tokens.spacing) {
    config.spacing = spec.tokens.spacing;
  }

  if (spec.tokens.typography) {
    if (spec.tokens.typography.fontFamilies) {
      config.fontFamily = {};
      for (const [key, value] of Object.entries(spec.tokens.typography.fontFamilies)) {
        (config.fontFamily as Record<string, string[]>)[key] = [value];
      }
    }
    if (spec.tokens.typography.fontSizes) {
      config.fontSize = spec.tokens.typography.fontSizes;
    }
    if (spec.tokens.typography.fontWeights) {
      config.fontWeight = spec.tokens.typography.fontWeights;
    }
    if (spec.tokens.typography.lineHeights) {
      config.lineHeight = spec.tokens.typography.lineHeights;
    }
    if (spec.tokens.typography.letterSpacing) {
      config.letterSpacing = spec.tokens.typography.letterSpacing;
    }
  }

  if (spec.tokens.shadow) {
    config.boxShadow = spec.tokens.shadow;
  }

  if (spec.tokens.border) {
    if (spec.tokens.border.radius) {
      config.borderRadius = spec.tokens.border.radius;
    }
    if (spec.tokens.border.width) {
      config.borderWidth = spec.tokens.border.width;
    }
  }

  if (spec.tokens.animation) {
    if (spec.tokens.animation.duration) {
      config.transitionDuration = spec.tokens.animation.duration;
    }
    if (spec.tokens.animation.easing) {
      config.transitionTimingFunction = spec.tokens.animation.easing;
    }
  }

  if (spec.tokens.zIndex) {
    config.zIndex = spec.tokens.zIndex;
  }

  return `/**
 * ${spec.name} - Tailwind Config
 * ${spec.description || "Generated by generate-tokens"}
 *
 * Add to tailwind.config.js:
 * const tokens = require('./tokens.tailwind.js');
 * module.exports = { theme: { extend: tokens } };
 */

module.exports = ${JSON.stringify(config, null, 2).replace(/"([^"]+)":/g, "$1:")};
`;
}

function generateStyleDictionary(spec: TokenSpec): string {
  const sdTokens: Record<string, unknown> = {};

  function convertToSD(obj: unknown, category: string): unknown {
    if (typeof obj === "string" || typeof obj === "number") {
      return { value: obj };
    }
    if (typeof obj === "object" && obj !== null) {
      const result: Record<string, unknown> = {};
      for (const [key, value] of Object.entries(obj)) {
        result[key] = convertToSD(value, category);
      }
      return result;
    }
    return obj;
  }

  for (const [category, tokens] of Object.entries(spec.tokens)) {
    sdTokens[category] = convertToSD(tokens, category);
  }

  return JSON.stringify(sdTokens, null, 2);
}

// === File Extension Mapping ===

function getFileExtension(format: OutputFormat): string {
  switch (format) {
    case "css":
      return "css";
    case "scss":
      return "scss";
    case "json":
    case "style-dictionary":
      return "json";
    case "js":
      return "js";
    case "ts":
      return "ts";
    case "tailwind":
      return "tailwind.js";
    default:
      return "txt";
  }
}

function getFileName(name: string, format: OutputFormat): string {
  const baseName = name.toLowerCase().replace(/\s+/g, "-");
  const ext = getFileExtension(format);

  if (format === "style-dictionary") {
    return `${baseName}.tokens.json`;
  }

  return `${baseName}.${ext}`;
}

// === Core Generation Function ===

export async function generateTokens(options: GenerateOptions): Promise<Map<string, string>> {
  const specPath = resolve(options.specFile);
  const specContent = await Deno.readTextFile(specPath);
  const spec: TokenSpec = JSON.parse(specContent);

  if (!spec.name) {
    throw new Error("Token specification must include a 'name' field");
  }

  if (!spec.tokens) {
    throw new Error("Token specification must include a 'tokens' field");
  }

  if (!spec.outputFormats || spec.outputFormats.length === 0) {
    throw new Error("Token specification must include at least one output format");
  }

  const outputs = new Map<string, string>();

  for (const format of spec.outputFormats) {
    let content: string;

    switch (format) {
      case "css":
        content = generateCSS(spec);
        break;
      case "scss":
        content = generateSCSS(spec);
        break;
      case "json":
        content = generateJSON(spec);
        break;
      case "js":
        content = generateJS(spec);
        break;
      case "ts":
        content = generateTS(spec);
        break;
      case "tailwind":
        content = generateTailwind(spec);
        break;
      case "style-dictionary":
        content = generateStyleDictionary(spec);
        break;
      default:
        console.warn(`Unknown format: ${format}, skipping`);
        continue;
    }

    const fileName = getFileName(spec.name, format);
    outputs.set(fileName, content);
  }

  return outputs;
}

// === Help Text ===

function printHelp(): void {
  console.log(`
${SCRIPT_NAME} v${VERSION} - Design Token Generator

Generates comprehensive design token files in multiple formats
from a JSON specification.

Usage:
  deno run --allow-read --allow-write scripts/${SCRIPT_NAME}.ts <spec> <output-dir>

Arguments:
  <spec>               JSON specification file (see assets/token-schema.json)
  <output-dir>         Directory for output files

Options:
  -h, --help           Show this help message
  -v, --version        Show version

Supported Output Formats (specified in spec file):
  css              CSS custom properties
  scss             SCSS variables and maps
  json             Raw JSON
  js               JavaScript module
  ts               TypeScript module with types
  tailwind         Tailwind config extension
  style-dictionary Style Dictionary format

Example Specification:
  {
    "name": "my-design-system",
    "tokens": {
      "color": { "primary": "#2563eb" },
      "spacing": { "sm": "0.5rem", "md": "1rem" }
    },
    "outputFormats": ["css", "scss", "tailwind", "ts"]
  }

Examples:
  # Generate from specification
  deno run --allow-read --allow-write scripts/${SCRIPT_NAME}.ts design-tokens.json ./tokens/

  # Using the schema for validation
  See assets/token-schema.json for full specification format
`);
}

// === Main CLI Handler ===

async function main(args: string[]): Promise<void> {
  const parsed = parseArgs(args, {
    boolean: ["help", "version"],
    alias: { h: "help", v: "version" },
  });

  if (parsed.help) {
    printHelp();
    Deno.exit(0);
  }

  if (parsed.version) {
    console.log(`${SCRIPT_NAME} v${VERSION}`);
    Deno.exit(0);
  }

  const specFile = parsed._[0] as string;
  const outputDir = parsed._[1] as string;

  if (!specFile) {
    console.error("Error: Specification file required");
    console.error("Use --help for usage information");
    Deno.exit(1);
  }

  if (!outputDir) {
    console.error("Error: Output directory required");
    console.error("Use --help for usage information");
    Deno.exit(1);
  }

  const options: GenerateOptions = {
    specFile,
    outputDir,
  };

  try {
    const outputs = await generateTokens(options);
    const outPath = resolve(outputDir);

    await ensureDir(outPath);

    for (const [fileName, content] of outputs) {
      const filePath = join(outPath, fileName);
      await Deno.writeTextFile(filePath, content);
      console.log(`Generated: ${filePath}`);
    }

    console.log(`\nSuccessfully generated ${outputs.size} token files`);
  } catch (error) {
    console.error(`Error: ${(error as Error).message}`);
    Deno.exit(1);
  }
}

// === Entry Point ===

if (import.meta.main) {
  main(Deno.args);
}

```

### scripts/generate-component.ts

```typescript
#!/usr/bin/env -S deno run --allow-read --allow-write

/**
 * generate-component.ts - Component Template Generator
 *
 * Generates component templates with design-focused styling
 * for multiple frameworks (React, Vue, Svelte, HTML).
 */

import { parseArgs } from "jsr:@std/[email protected]/parse-args";
import { resolve, join } from "jsr:@std/[email protected]";
import { ensureDir } from "jsr:@std/[email protected]/ensure-dir";

// === Constants ===
const VERSION = "1.0.0";
const SCRIPT_NAME = "generate-component";

type Framework = "react" | "vue" | "svelte" | "html";
type Styling = "css" | "tailwind" | "css-modules" | "styled-components" | "emotion";
type Aesthetic = "minimal" | "bold" | "organic" | "brutalist" | "glassmorphism" | "neumorphism";
type Animation = "none" | "subtle" | "expressive";
type ComponentType = "button" | "card" | "input" | "modal" | "navigation" | "hero" | "custom";

// === Types ===
export interface ComponentSpec {
  name: string;
  type: ComponentType;
  framework: Framework;
  styling: Styling;
  aesthetic?: {
    style?: Aesthetic;
    animation?: Animation;
    darkMode?: boolean;
  };
  tokens?: string;
  props?: Record<string, { type: string; default?: string; required?: boolean }>;
  slots?: string[];
  variants?: string[];
}

interface GenerateOptions {
  specFile?: string;
  name: string;
  type: ComponentType;
  framework: Framework;
  styling: Styling;
  aesthetic?: Aesthetic;
  animation: Animation;
  darkMode: boolean;
  tokens?: string;
  outputDir: string;
}

// === Style Templates ===

const AESTHETIC_STYLES: Record<Aesthetic, Record<string, string>> = {
  minimal: {
    base: "border border-gray-200 bg-white text-gray-900",
    hover: "hover:border-gray-300",
    focus: "focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2",
    active: "active:bg-gray-50",
    transition: "transition-colors duration-150",
  },
  bold: {
    base: "bg-gradient-to-r from-purple-600 to-pink-600 text-white font-bold",
    hover: "hover:from-purple-700 hover:to-pink-700 hover:scale-105",
    focus: "focus:outline-none focus:ring-4 focus:ring-purple-300",
    active: "active:scale-95",
    transition: "transition-all duration-200 transform",
  },
  organic: {
    base: "bg-amber-50 text-amber-900 border-2 border-amber-200 rounded-3xl",
    hover: "hover:bg-amber-100 hover:border-amber-300",
    focus: "focus:outline-none focus:ring-2 focus:ring-amber-400",
    active: "active:bg-amber-200",
    transition: "transition-all duration-300 ease-out",
  },
  brutalist: {
    base: "bg-black text-white border-4 border-black font-mono uppercase tracking-wider",
    hover: "hover:bg-white hover:text-black",
    focus: "focus:outline-none focus:ring-0 focus:border-yellow-400",
    active: "active:translate-x-1 active:translate-y-1",
    transition: "transition-all duration-100",
  },
  glassmorphism: {
    base: "bg-white/20 backdrop-blur-lg border border-white/30 text-white shadow-xl",
    hover: "hover:bg-white/30",
    focus: "focus:outline-none focus:ring-2 focus:ring-white/50",
    active: "active:bg-white/40",
    transition: "transition-all duration-200",
  },
  neumorphism: {
    base: "bg-gray-100 text-gray-700 rounded-xl shadow-[8px_8px_16px_#d1d1d1,-8px_-8px_16px_#ffffff]",
    hover: "hover:shadow-[4px_4px_8px_#d1d1d1,-4px_-4px_8px_#ffffff]",
    focus: "focus:outline-none focus:shadow-[inset_4px_4px_8px_#d1d1d1,inset_-4px_-4px_8px_#ffffff]",
    active: "active:shadow-[inset_4px_4px_8px_#d1d1d1,inset_-4px_-4px_8px_#ffffff]",
    transition: "transition-shadow duration-200",
  },
};

const ANIMATION_STYLES: Record<Animation, string> = {
  none: "",
  subtle: "transition-all duration-200 ease-out",
  expressive: "transition-all duration-300 ease-out hover:scale-105 active:scale-95",
};

// === Component Templates ===

function getButtonTemplate(options: GenerateOptions): { styles: string; component: string } {
  const aesthetic = options.aesthetic || "minimal";
  const styles = AESTHETIC_STYLES[aesthetic];
  const animation = ANIMATION_STYLES[options.animation];

  const cssClasses = [
    "px-4 py-2 rounded-lg font-medium",
    styles.base,
    styles.hover,
    styles.focus,
    styles.active,
    animation || styles.transition,
  ].join(" ");

  if (options.styling === "tailwind") {
    return {
      styles: "",
      component: cssClasses,
    };
  }

  // CSS version
  const cssStyles = `
.btn {
  padding: 0.5rem 1rem;
  border-radius: 0.5rem;
  font-weight: 500;
  cursor: pointer;
  ${aesthetic === "minimal" ? `
  border: 1px solid #e5e7eb;
  background: white;
  color: #111827;
  ` : ""}
  ${aesthetic === "bold" ? `
  background: linear-gradient(to right, #9333ea, #ec4899);
  color: white;
  font-weight: 700;
  border: none;
  ` : ""}
  transition: all 0.2s ease-out;
}

.btn:hover {
  transform: translateY(-1px);
}

.btn:focus {
  outline: none;
  box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.5);
}

.btn:active {
  transform: translateY(0);
}
${options.darkMode ? `
.dark .btn {
  background: #1f2937;
  color: white;
  border-color: #374151;
}
` : ""}`;

  return { styles: cssStyles, component: "btn" };
}

function getCardTemplate(options: GenerateOptions): { styles: string; component: string } {
  const aesthetic = options.aesthetic || "minimal";

  if (options.styling === "tailwind") {
    const classes: Record<Aesthetic, string> = {
      minimal: "bg-white border border-gray-200 rounded-lg shadow-sm p-6",
      bold: "bg-gradient-to-br from-indigo-500 to-purple-600 text-white rounded-2xl p-8 shadow-2xl",
      organic: "bg-amber-50 border-2 border-amber-200 rounded-3xl p-8",
      brutalist: "bg-white border-4 border-black p-6",
      glassmorphism: "bg-white/20 backdrop-blur-lg border border-white/30 rounded-2xl p-6 shadow-xl",
      neumorphism: "bg-gray-100 rounded-2xl p-6 shadow-[8px_8px_16px_#d1d1d1,-8px_-8px_16px_#ffffff]",
    };
    return { styles: "", component: classes[aesthetic] };
  }

  const cssStyles = `
.card {
  padding: 1.5rem;
  border-radius: 0.5rem;
  background: white;
  border: 1px solid #e5e7eb;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}

.card-header {
  margin-bottom: 1rem;
  padding-bottom: 1rem;
  border-bottom: 1px solid #e5e7eb;
}

.card-body {
  color: #374151;
}

.card-footer {
  margin-top: 1rem;
  padding-top: 1rem;
  border-top: 1px solid #e5e7eb;
}
${options.darkMode ? `
.dark .card {
  background: #1f2937;
  border-color: #374151;
  color: white;
}
` : ""}`;

  return { styles: cssStyles, component: "card" };
}

function getInputTemplate(options: GenerateOptions): { styles: string; component: string } {
  if (options.styling === "tailwind") {
    return {
      styles: "",
      component: "w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent",
    };
  }

  const cssStyles = `
.input-wrapper {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.input-label {
  font-size: 0.875rem;
  font-weight: 500;
  color: #374151;
}

.input {
  width: 100%;
  padding: 0.5rem 1rem;
  border: 1px solid #d1d5db;
  border-radius: 0.5rem;
  font-size: 1rem;
  transition: border-color 0.2s, box-shadow 0.2s;
}

.input:focus {
  outline: none;
  border-color: #3b82f6;
  box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
}

.input-error {
  border-color: #ef4444;
}

.input-error-message {
  font-size: 0.875rem;
  color: #ef4444;
}
${options.darkMode ? `
.dark .input {
  background: #1f2937;
  border-color: #4b5563;
  color: white;
}
` : ""}`;

  return { styles: cssStyles, component: "input" };
}

// === Framework Generators ===

function generateReact(options: GenerateOptions, template: { styles: string; component: string }): string {
  const { name } = options;
  const propsInterface = `export interface ${name}Props {
  children?: React.ReactNode;
  className?: string;
  variant?: 'primary' | 'secondary' | 'ghost';
  size?: 'sm' | 'md' | 'lg';
  disabled?: boolean;
  onClick?: () => void;
}`;

  if (options.styling === "tailwind") {
    return `import React from 'react';

${propsInterface}

const variants = {
  primary: '${template.component}',
  secondary: 'bg-gray-100 text-gray-900 hover:bg-gray-200',
  ghost: 'bg-transparent hover:bg-gray-100',
};

const sizes = {
  sm: 'px-3 py-1.5 text-sm',
  md: 'px-4 py-2 text-base',
  lg: 'px-6 py-3 text-lg',
};

export function ${name}({
  children,
  className = '',
  variant = 'primary',
  size = 'md',
  disabled = false,
  onClick,
}: ${name}Props) {
  return (
    <button
      className={\`\${variants[variant]} \${sizes[size]} \${className} \${disabled ? 'opacity-50 cursor-not-allowed' : ''}\`}
      disabled={disabled}
      onClick={onClick}
    >
      {children}
    </button>
  );
}

export default ${name};
`;
  }

  if (options.styling === "css-modules") {
    return `import React from 'react';
import styles from './${name}.module.css';

${propsInterface}

export function ${name}({
  children,
  className = '',
  variant = 'primary',
  size = 'md',
  disabled = false,
  onClick,
}: ${name}Props) {
  const classes = [
    styles.${template.component},
    styles[variant],
    styles[size],
    disabled ? styles.disabled : '',
    className,
  ].filter(Boolean).join(' ');

  return (
    <button className={classes} disabled={disabled} onClick={onClick}>
      {children}
    </button>
  );
}

export default ${name};
`;
  }

  // Default CSS
  return `import React from 'react';
import './${name}.css';

${propsInterface}

export function ${name}({
  children,
  className = '',
  variant = 'primary',
  size = 'md',
  disabled = false,
  onClick,
}: ${name}Props) {
  const classes = [
    '${template.component}',
    \`${template.component}--\${variant}\`,
    \`${template.component}--\${size}\`,
    disabled ? '${template.component}--disabled' : '',
    className,
  ].filter(Boolean).join(' ');

  return (
    <button className={classes} disabled={disabled} onClick={onClick}>
      {children}
    </button>
  );
}

export default ${name};
`;
}

function generateVue(options: GenerateOptions, template: { styles: string; component: string }): string {
  const { name } = options;

  if (options.styling === "tailwind") {
    return `<template>
  <button
    :class="[
      '${template.component}',
      variants[variant],
      sizes[size],
      { 'opacity-50 cursor-not-allowed': disabled }
    ]"
    :disabled="disabled"
    @click="$emit('click')"
  >
    <slot />
  </button>
</template>

<script setup lang="ts">
defineProps<{
  variant?: 'primary' | 'secondary' | 'ghost';
  size?: 'sm' | 'md' | 'lg';
  disabled?: boolean;
}>();

defineEmits<{
  click: [];
}>();

const variants = {
  primary: '',
  secondary: 'bg-gray-100 text-gray-900 hover:bg-gray-200',
  ghost: 'bg-transparent hover:bg-gray-100',
};

const sizes = {
  sm: 'px-3 py-1.5 text-sm',
  md: 'px-4 py-2 text-base',
  lg: 'px-6 py-3 text-lg',
};
</script>
`;
  }

  return `<template>
  <button
    :class="[
      '${template.component}',
      '${template.component}--' + variant,
      '${template.component}--' + size,
      { '${template.component}--disabled': disabled }
    ]"
    :disabled="disabled"
    @click="$emit('click')"
  >
    <slot />
  </button>
</template>

<script setup lang="ts">
defineProps<{
  variant?: 'primary' | 'secondary' | 'ghost';
  size?: 'sm' | 'md' | 'lg';
  disabled?: boolean;
}>();

defineEmits<{
  click: [];
}>();
</script>

<style scoped>
${template.styles}

.${template.component}--secondary {
  background: #f3f4f6;
  color: #111827;
}

.${template.component}--ghost {
  background: transparent;
  border: none;
}

.${template.component}--sm {
  padding: 0.375rem 0.75rem;
  font-size: 0.875rem;
}

.${template.component}--lg {
  padding: 0.75rem 1.5rem;
  font-size: 1.125rem;
}

.${template.component}--disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
</style>
`;
}

function generateSvelte(options: GenerateOptions, template: { styles: string; component: string }): string {
  const { name: _name } = options;

  if (options.styling === "tailwind") {
    return `<script lang="ts">
  export let variant: 'primary' | 'secondary' | 'ghost' = 'primary';
  export let size: 'sm' | 'md' | 'lg' = 'md';
  export let disabled = false;

  const variants = {
    primary: '${template.component}',
    secondary: 'bg-gray-100 text-gray-900 hover:bg-gray-200',
    ghost: 'bg-transparent hover:bg-gray-100',
  };

  const sizes = {
    sm: 'px-3 py-1.5 text-sm',
    md: 'px-4 py-2 text-base',
    lg: 'px-6 py-3 text-lg',
  };
</script>

<button
  class="{variants[variant]} {sizes[size]} {disabled ? 'opacity-50 cursor-not-allowed' : ''}"
  {disabled}
  on:click
>
  <slot />
</button>
`;
  }

  return `<script lang="ts">
  export let variant: 'primary' | 'secondary' | 'ghost' = 'primary';
  export let size: 'sm' | 'md' | 'lg' = 'md';
  export let disabled = false;
</script>

<button
  class="${template.component} ${template.component}--{variant} ${template.component}--{size}"
  class:${template.component}--disabled={disabled}
  {disabled}
  on:click
>
  <slot />
</button>

<style>
${template.styles}

.${template.component}--secondary {
  background: #f3f4f6;
  color: #111827;
}

.${template.component}--ghost {
  background: transparent;
  border: none;
}

.${template.component}--sm {
  padding: 0.375rem 0.75rem;
  font-size: 0.875rem;
}

.${template.component}--lg {
  padding: 0.75rem 1.5rem;
  font-size: 1.125rem;
}

.${template.component}--disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
</style>
`;
}

function generateHTML(options: GenerateOptions, template: { styles: string; component: string }): string {
  const { name } = options;

  if (options.styling === "tailwind") {
    return `<!-- ${name} Component -->
<!-- Add Tailwind CSS to your project for these styles to work -->

<button class="${template.component}">
  Button Text
</button>

<!-- Variants -->
<button class="${template.component}">Primary</button>
<button class="bg-gray-100 text-gray-900 hover:bg-gray-200 px-4 py-2 rounded-lg">Secondary</button>
<button class="bg-transparent hover:bg-gray-100 px-4 py-2 rounded-lg">Ghost</button>
`;
  }

  return `<!-- ${name} Component -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>${name} Component</title>
  <style>
${template.styles}

    .${template.component}--secondary {
      background: #f3f4f6;
      color: #111827;
    }

    .${template.component}--ghost {
      background: transparent;
      border: none;
    }

    .${template.component}--sm {
      padding: 0.375rem 0.75rem;
      font-size: 0.875rem;
    }

    .${template.component}--lg {
      padding: 0.75rem 1.5rem;
      font-size: 1.125rem;
    }

    .${template.component}--disabled {
      opacity: 0.5;
      cursor: not-allowed;
    }
  </style>
</head>
<body>
  <button class="${template.component}">Primary Button</button>
  <button class="${template.component} ${template.component}--secondary">Secondary Button</button>
  <button class="${template.component} ${template.component}--ghost">Ghost Button</button>
</body>
</html>
`;
}

// === File Extension Mapping ===

function getFileExtension(framework: Framework, styling: Styling): string {
  switch (framework) {
    case "react":
      return styling === "styled-components" || styling === "emotion" ? "tsx" : "tsx";
    case "vue":
      return "vue";
    case "svelte":
      return "svelte";
    case "html":
      return "html";
    default:
      return "txt";
  }
}

// === Core Generation Function ===

export async function generateComponent(options: GenerateOptions): Promise<Map<string, string>> {
  const outputs = new Map<string, string>();

  // Get template based on component type
  let template: { styles: string; component: string };

  switch (options.type) {
    case "button":
      template = getButtonTemplate(options);
      break;
    case "card":
      template = getCardTemplate(options);
      break;
    case "input":
      template = getInputTemplate(options);
      break;
    default:
      template = getButtonTemplate(options); // Default to button
  }

  // Generate component based on framework
  let componentCode: string;

  switch (options.framework) {
    case "react":
      componentCode = generateReact(options, template);
      break;
    case "vue":
      componentCode = generateVue(options, template);
      break;
    case "svelte":
      componentCode = generateSvelte(options, template);
      break;
    case "html":
      componentCode = generateHTML(options, template);
      break;
    default:
      throw new Error(`Unknown framework: ${options.framework}`);
  }

  const ext = getFileExtension(options.framework, options.styling);
  const fileName = `${options.name}.${ext}`;
  outputs.set(fileName, componentCode);

  // Generate separate CSS file if needed
  if (options.styling === "css" && template.styles && options.framework !== "html") {
    outputs.set(`${options.name}.css`, template.styles);
  }

  if (options.styling === "css-modules" && template.styles) {
    outputs.set(`${options.name}.module.css`, template.styles);
  }

  return outputs;
}

// === Help Text ===

function printHelp(): void {
  console.log(`
${SCRIPT_NAME} v${VERSION} - Component Template Generator

Generates component templates with design-focused styling
for multiple frameworks (React, Vue, Svelte, HTML).

Usage:
  deno run --allow-read --allow-write scripts/${SCRIPT_NAME}.ts [options] <output-dir>

Arguments:
  <output-dir>         Directory for output files

Options:
  -h, --help           Show this help message
  -v, --version        Show version
  --spec <file>        JSON specification file
  --name <name>        Component name (PascalCase)
  --type <type>        Component type: button, card, input, modal, navigation, hero
  --framework <fw>     Framework: react, vue, svelte, html
  --styling <type>     Styling: css, tailwind, css-modules, styled-components, emotion
  --aesthetic <type>   Aesthetic: minimal, bold, organic, brutalist, glassmorphism, neumorphism
  --animation <level>  Animation: none, subtle, expressive
  --dark-mode          Include dark mode support
  --tokens <file>      Use design tokens file

Examples:
  # Generate React button with Tailwind
  deno run --allow-read --allow-write scripts/${SCRIPT_NAME}.ts \\
    --name Button --framework react --styling tailwind --aesthetic bold ./components/

  # Generate Vue card with CSS modules
  deno run --allow-read --allow-write scripts/${SCRIPT_NAME}.ts \\
    --name Card --type card --framework vue --styling css-modules ./components/

  # Generate Svelte input with minimal aesthetic
  deno run --allow-read --allow-write scripts/${SCRIPT_NAME}.ts \\
    --name Input --type input --framework svelte --aesthetic minimal ./components/

  # Generate from spec file
  deno run --allow-read --allow-write scripts/${SCRIPT_NAME}.ts \\
    --spec component-spec.json ./components/
`);
}

// === Main CLI Handler ===

async function main(args: string[]): Promise<void> {
  const parsed = parseArgs(args, {
    boolean: ["help", "version", "dark-mode"],
    string: ["spec", "name", "type", "framework", "styling", "aesthetic", "animation", "tokens"],
    alias: { h: "help", v: "version" },
    default: {
      type: "button",
      framework: "react",
      styling: "css",
      animation: "subtle",
      "dark-mode": false,
    },
  });

  if (parsed.help) {
    printHelp();
    Deno.exit(0);
  }

  if (parsed.version) {
    console.log(`${SCRIPT_NAME} v${VERSION}`);
    Deno.exit(0);
  }

  const outputDir = parsed._[0] as string;

  if (!outputDir) {
    console.error("Error: Output directory required");
    console.error("Use --help for usage information");
    Deno.exit(1);
  }

  if (!parsed.spec && !parsed.name) {
    console.error("Error: Component name required (--name or --spec)");
    console.error("Use --help for usage information");
    Deno.exit(1);
  }

  const validFrameworks: Framework[] = ["react", "vue", "svelte", "html"];
  const validStyling: Styling[] = ["css", "tailwind", "css-modules", "styled-components", "emotion"];
  const validAesthetics: Aesthetic[] = ["minimal", "bold", "organic", "brutalist", "glassmorphism", "neumorphism"];
  const validTypes: ComponentType[] = ["button", "card", "input", "modal", "navigation", "hero", "custom"];
  const validAnimations: Animation[] = ["none", "subtle", "expressive"];

  if (!validFrameworks.includes(parsed.framework as Framework)) {
    console.error(`Error: Invalid framework '${parsed.framework}'`);
    console.error(`Valid frameworks: ${validFrameworks.join(", ")}`);
    Deno.exit(1);
  }

  if (!validStyling.includes(parsed.styling as Styling)) {
    console.error(`Error: Invalid styling '${parsed.styling}'`);
    console.error(`Valid styling options: ${validStyling.join(", ")}`);
    Deno.exit(1);
  }

  if (parsed.aesthetic && !validAesthetics.includes(parsed.aesthetic as Aesthetic)) {
    console.error(`Error: Invalid aesthetic '${parsed.aesthetic}'`);
    console.error(`Valid aesthetics: ${validAesthetics.join(", ")}`);
    Deno.exit(1);
  }

  if (!validTypes.includes(parsed.type as ComponentType)) {
    console.error(`Error: Invalid type '${parsed.type}'`);
    console.error(`Valid types: ${validTypes.join(", ")}`);
    Deno.exit(1);
  }

  if (!validAnimations.includes(parsed.animation as Animation)) {
    console.error(`Error: Invalid animation '${parsed.animation}'`);
    console.error(`Valid animations: ${validAnimations.join(", ")}`);
    Deno.exit(1);
  }

  const options: GenerateOptions = {
    specFile: parsed.spec,
    name: parsed.name || "Component",
    type: parsed.type as ComponentType,
    framework: parsed.framework as Framework,
    styling: parsed.styling as Styling,
    aesthetic: parsed.aesthetic as Aesthetic | undefined,
    animation: parsed.animation as Animation,
    darkMode: parsed["dark-mode"],
    tokens: parsed.tokens,
    outputDir,
  };

  try {
    const outputs = await generateComponent(options);
    const outPath = resolve(outputDir);

    await ensureDir(outPath);

    for (const [fileName, content] of outputs) {
      const filePath = join(outPath, fileName);
      await Deno.writeTextFile(filePath, content);
      console.log(`Generated: ${filePath}`);
    }

    console.log(`\nSuccessfully generated ${outputs.size} file(s)`);
  } catch (error) {
    console.error(`Error: ${(error as Error).message}`);
    Deno.exit(1);
  }
}

// === Entry Point ===

if (import.meta.main) {
  main(Deno.args);
}

```

### references/design-philosophy.md

```markdown
# Design Philosophy: Avoiding AI Slop

This document provides detailed guidance on creating distinctive, production-grade frontend interfaces that avoid generic "AI-generated" aesthetics.

## Core Principle

**Choose a clear aesthetic direction and execute it with precision.** Bold maximalism and refined minimalism both work - the key is intentionality, not intensity.

## Design Thinking Process

Before writing any code, understand the context and commit to a BOLD aesthetic direction:

### 1. Purpose
- What problem does this interface solve?
- Who uses it and in what context?
- What emotions should it evoke?

### 2. Aesthetic Tone

Pick a distinctive direction. Here are examples for inspiration:

| Tone | Characteristics |
|------|-----------------|
| **Brutally Minimal** | Stark contrast, maximum whitespace, single accent color |
| **Maximalist Chaos** | Dense information, layered textures, vibrant palettes |
| **Retro-Futuristic** | Neon accents, dark backgrounds, geometric shapes |
| **Organic/Natural** | Soft curves, earthy tones, flowing animations |
| **Luxury/Refined** | Subtle typography, muted palettes, premium spacing |
| **Playful/Toy-like** | Rounded corners, bright colors, bouncy animations |
| **Editorial/Magazine** | Strong typography hierarchy, asymmetric layouts |
| **Brutalist/Raw** | Exposed structure, stark fonts, visible grids |
| **Art Deco/Geometric** | Bold patterns, metallic accents, symmetry |
| **Soft/Pastel** | Gentle gradients, light shadows, calming colors |
| **Industrial/Utilitarian** | Monospace fonts, muted colors, functional density |

### 3. Differentiation
What makes this interface UNFORGETTABLE? What's the one thing someone will remember?

---

## The Five Pillars of Distinctive Design

### 1. Typography

**Do**:
- Choose fonts that are beautiful, unique, and characterful
- Pair a distinctive display font with a refined body font
- Use unexpected, personality-rich choices
- Consider the context and audience

**Don't**:
- Default to Arial, Inter, Roboto, or system fonts
- Use the same fonts across every project
- Ignore font pairing harmony
- Over-rely on weight for hierarchy

**Distinctive Font Examples**:
| Category | Options |
|----------|---------|
| Display | Playfair Display, Fraunces, Libre Baskerville, Cormorant |
| Sans-Serif | Space Grotesk, DM Sans, Plus Jakarta Sans, Outfit |
| Mono | JetBrains Mono, Fira Code, IBM Plex Mono |
| Unique | Anybody, Instrument Serif, Cabinet Grotesk |

### 2. Color & Theme

**Do**:
- Commit to a cohesive aesthetic
- Use CSS variables for consistency
- Choose dominant colors with sharp accents
- Consider context (brand, mood, accessibility)

**Don't**:
- Default to purple gradients on white
- Use timid, evenly-distributed palettes
- Ignore contrast requirements
- Copy trending palettes without adaptation

**Palette Strategies**:
- **Monochromatic**: Single hue with varied saturation/lightness
- **Complementary**: Opposite colors for high contrast
- **Analogous**: Adjacent colors for harmony
- **Split-Complementary**: Main color + two adjacent to its complement
- **Triadic**: Three evenly-spaced colors

### 3. Motion

**Do**:
- Focus on high-impact moments
- Create orchestrated page load reveals with staggered animation-delay
- Use scroll-triggered animations that surprise
- Implement hover states with personality

**Don't**:
- Add motion for motion's sake
- Create scattered, uncoordinated micro-interactions
- Ignore reduced-motion preferences
- Use jarring or disorienting effects

**Motion Hierarchy**:
1. **Page transitions**: Most impactful, highest attention
2. **Scroll reveals**: Content appearing as user explores
3. **Hover states**: Feedback and delight
4. **Micro-interactions**: Subtle polish (buttons, toggles)

**CSS-First Approach**:
```css
/* Staggered reveal */
.item { animation: fadeIn 0.5s ease-out forwards; opacity: 0; }
.item:nth-child(1) { animation-delay: 0.1s; }
.item:nth-child(2) { animation-delay: 0.2s; }
.item:nth-child(3) { animation-delay: 0.3s; }

/* Respect preferences */
@media (prefers-reduced-motion: reduce) {
  .item { animation: none; opacity: 1; }
}
```

### 4. Spatial Composition

**Do**:
- Create unexpected layouts
- Use asymmetry intentionally
- Allow elements to overlap
- Employ diagonal flow and grid-breaking elements
- Balance generous negative space OR controlled density

**Don't**:
- Default to symmetric card grids
- Treat every element equally
- Fear whitespace (or density, if that's your direction)
- Ignore visual rhythm

**Layout Techniques**:
- **Broken grid**: Elements that break the expected grid
- **Overlap**: Layered elements creating depth
- **Scale contrast**: Large elements next to small
- **Negative space**: Breathing room as a design element
- **Asymmetric balance**: Visual weight distributed unevenly

### 5. Backgrounds & Visual Details

**Do**:
- Create atmosphere and depth
- Use contextual effects that match the aesthetic
- Layer transparencies for dimension
- Add texture where appropriate

**Don't**:
- Default to solid white backgrounds
- Use generic gradient presets
- Forget about dark mode considerations
- Over-apply effects

**Visual Effects Palette**:
- Gradient meshes
- Noise and grain textures
- Geometric patterns
- Layered transparencies
- Dramatic shadows (soft or hard)
- Decorative borders
- Custom cursors
- Glassmorphism (used intentionally)
- Neumorphism (used sparingly)

---

## What to Avoid: The "AI Slop" Checklist

### Typography Anti-Patterns
- [ ] Inter everywhere
- [ ] Roboto as the only choice
- [ ] Arial or system fonts
- [ ] Identical font usage across projects

### Color Anti-Patterns
- [ ] Purple-to-blue gradient on white
- [ ] Generic "modern" teal
- [ ] Desaturated "safe" palettes
- [ ] Unrelated accent colors

### Layout Anti-Patterns
- [ ] 3-column card grids
- [ ] Identical padding everywhere
- [ ] Symmetric hero sections
- [ ] Predictable section patterns

### Effect Anti-Patterns
- [ ] Subtle gray shadows on everything
- [ ] Generic rounded corners (8px everywhere)
- [ ] Smooth but meaningless transitions
- [ ] Glass effects without purpose

---

## Implementation Complexity Matching

**Critical**: Match implementation complexity to aesthetic vision.

### Maximalist Designs
- Elaborate code with extensive animations
- Multiple layered effects
- Complex state management for interactions
- Rich color variations

### Minimalist Designs
- Restraint and precision
- Careful attention to spacing
- Perfect typography
- Subtle, meaningful details
- "Less" requires more care, not less code

---

## Quality Checklist

Before considering a design complete:

- [ ] Typography is distinctive and intentional
- [ ] Colors support the aesthetic direction
- [ ] Motion is orchestrated, not scattered
- [ ] Layout has visual interest and hierarchy
- [ ] Details add atmosphere without clutter
- [ ] Accessibility is preserved (contrast, motion preferences)
- [ ] The design is memorable - someone would recognize it

---

## Remember

> "Claude is capable of extraordinary creative work. Don't hold back, show what can truly be created when thinking outside the box and committing fully to a distinctive vision."

No two designs should look the same. Vary themes, fonts, aesthetics. The goal is intentional, memorable, production-grade interfaces.

```

### references/token-formats.md

```markdown
# Design Token Formats Reference

This document describes the various design token output formats supported by the frontend-design skill tools.

## Overview

Design tokens are the atomic values of a design system - colors, typography, spacing, etc. stored in a format that can be consumed by different platforms and tools.

## Supported Formats

### 1. CSS Custom Properties

**File extension**: `.css`

Standard CSS variables that work in any modern browser.

```css
:root {
  /* Colors */
  --color-primary-500: #2563eb;
  --color-primary-600: #1d4ed8;

  /* Spacing */
  --spacing-sm: 0.5rem;
  --spacing-md: 1rem;

  /* Typography */
  --font-body: Inter, sans-serif;
  --text-base: 1rem;
}
```

**Usage**:
```css
.button {
  background: var(--color-primary-500);
  padding: var(--spacing-sm) var(--spacing-md);
  font-family: var(--font-body);
}
```

**Pros**:
- Native browser support
- Runtime theming (dark mode, etc.)
- No build step required

**Cons**:
- No type safety
- Limited IDE support

---

### 2. SCSS Variables

**File extension**: `.scss`

SCSS/Sass variables with maps for iteration.

```scss
// Colors
$color-primary-500: #2563eb;
$color-primary-600: #1d4ed8;

// Spacing
$spacing-sm: 0.5rem;
$spacing-md: 1rem;

// Maps for iteration
$colors: (
  'primary-500': #2563eb,
  'primary-600': #1d4ed8,
);

$spacing: (
  'sm': 0.5rem,
  'md': 1rem,
);
```

**Usage**:
```scss
.button {
  background: $color-primary-500;
  padding: $spacing-sm $spacing-md;
}

// Generate utility classes
@each $name, $value in $spacing {
  .p-#{$name} { padding: $value; }
}
```

**Pros**:
- Compile-time optimization
- Programmatic generation with loops
- Mature ecosystem

**Cons**:
- Requires build step
- No runtime theming without CSS vars

---

### 3. Tailwind Config

**File extension**: `.tailwind.js`

Extension object for Tailwind CSS configuration.

```javascript
module.exports = {
  colors: {
    primary: {
      500: '#2563eb',
      600: '#1d4ed8',
    },
  },
  spacing: {
    sm: '0.5rem',
    md: '1rem',
  },
  fontFamily: {
    body: ['Inter', 'sans-serif'],
  },
};
```

**Usage** (in `tailwind.config.js`):
```javascript
const tokens = require('./tokens.tailwind.js');

module.exports = {
  theme: {
    extend: tokens,
  },
};
```

**Pros**:
- Direct Tailwind integration
- Utility class generation
- PurgeCSS optimization

**Cons**:
- Tailwind-specific
- Requires Tailwind setup

---

### 4. JSON

**File extension**: `.json`

Raw JSON format for maximum portability.

```json
{
  "name": "my-design-system",
  "tokens": {
    "color": {
      "primary": {
        "500": "#2563eb",
        "600": "#1d4ed8"
      }
    },
    "spacing": {
      "sm": "0.5rem",
      "md": "1rem"
    }
  }
}
```

**Usage**:
- Import in any language
- Transform with custom tools
- Use as source of truth

**Pros**:
- Universal format
- Easy to parse
- Platform agnostic

**Cons**:
- Requires transformation for use
- No direct runtime usage

---

### 5. JavaScript Module

**File extension**: `.js`

ES module with exports.

```javascript
export const tokens = {
  color: {
    primary: {
      500: '#2563eb',
      600: '#1d4ed8',
    },
  },
  spacing: {
    sm: '0.5rem',
    md: '1rem',
  },
};

export const flatTokens = {
  'color-primary-500': '#2563eb',
  'color-primary-600': '#1d4ed8',
  'spacing-sm': '0.5rem',
  'spacing-md': '1rem',
};

export default tokens;
```

**Usage**:
```javascript
import { tokens, flatTokens } from './tokens.js';

const primaryColor = tokens.color.primary[500];
```

**Pros**:
- Direct JavaScript import
- Tree-shakeable
- Works with any bundler

**Cons**:
- JavaScript only
- No type information

---

### 6. TypeScript Module

**File extension**: `.ts`

TypeScript module with full type definitions.

```typescript
export interface DesignTokens {
  color: {
    primary: Record<string, string>;
  };
  spacing: Record<string, string>;
}

export const tokens: DesignTokens = {
  color: {
    primary: {
      500: '#2563eb',
      600: '#1d4ed8',
    },
  },
  spacing: {
    sm: '0.5rem',
    md: '1rem',
  },
} as const;

export type FlatToken = string | number;
export const flatTokens: Record<string, FlatToken> = {
  'color-primary-500': '#2563eb',
  'spacing-sm': '0.5rem',
};

export default tokens;
```

**Usage**:
```typescript
import tokens, { DesignTokens } from './tokens';

// Full type safety
const color: string = tokens.color.primary[500];
```

**Pros**:
- Full type safety
- IDE autocomplete
- Compile-time validation

**Cons**:
- TypeScript only
- Requires compilation

---

### 7. Style Dictionary

**File extension**: `.tokens.json`

Format compatible with Amazon's Style Dictionary tool.

```json
{
  "color": {
    "primary": {
      "500": { "value": "#2563eb" },
      "600": { "value": "#1d4ed8" }
    }
  },
  "spacing": {
    "sm": { "value": "0.5rem" },
    "md": { "value": "1rem" }
  }
}
```

**Usage**:
Use with Style Dictionary to generate platform-specific outputs (iOS, Android, CSS, etc.).

**Pros**:
- Multi-platform support
- Powerful transformation system
- Industry standard

**Cons**:
- Requires Style Dictionary setup
- Additional tooling

---

## Format Selection Guide

| Use Case | Recommended Format |
|----------|-------------------|
| Web-only, runtime theming | CSS |
| Sass/SCSS project | SCSS |
| Tailwind CSS project | Tailwind |
| Multi-platform design system | Style Dictionary |
| React/JS application | TypeScript |
| Universal source of truth | JSON |
| Quick prototyping | CSS |

## Token Categories

All formats support these token categories:

| Category | Examples |
|----------|----------|
| `color` | Primary, secondary, semantic colors |
| `spacing` | Margins, paddings, gaps |
| `typography` | Font families, sizes, weights, line heights |
| `shadow` | Box shadows, text shadows |
| `border` | Radius, width |
| `animation` | Duration, easing functions |
| `zIndex` | Stacking layers |

## Best Practices

1. **Use semantic names** - `color-primary` not `color-blue`
2. **Maintain consistency** - Same structure across all formats
3. **Include metadata** - Name, description, version
4. **Version control** - Track token changes
5. **Single source of truth** - Generate all formats from one spec

```

### references/framework-templates.md

```markdown
# Framework Templates Reference

This document provides framework-specific patterns and best practices for generating components with the frontend-design skill.

## React

### File Structure

```
components/
├── Button/
│   ├── Button.tsx        # Component
│   ├── Button.css        # Styles (if using CSS)
│   ├── Button.module.css # Styles (if using CSS Modules)
│   ├── Button.test.tsx   # Tests
│   └── index.ts          # Re-export
```

### Component Pattern

```tsx
import React from 'react';

export interface ButtonProps {
  children: React.ReactNode;
  variant?: 'primary' | 'secondary' | 'ghost';
  size?: 'sm' | 'md' | 'lg';
  disabled?: boolean;
  onClick?: () => void;
}

export function Button({
  children,
  variant = 'primary',
  size = 'md',
  disabled = false,
  onClick,
}: ButtonProps) {
  return (
    <button
      className={`btn btn--${variant} btn--${size}`}
      disabled={disabled}
      onClick={onClick}
    >
      {children}
    </button>
  );
}

export default Button;
```

### Styling Options

**CSS Modules**:
```tsx
import styles from './Button.module.css';

<button className={styles.button} />
```

**Tailwind**:
```tsx
<button className="px-4 py-2 bg-blue-500 text-white rounded-lg" />
```

**Styled Components**:
```tsx
import styled from 'styled-components';

const StyledButton = styled.button`
  padding: 0.5rem 1rem;
  background: var(--color-primary);
`;
```

**Emotion**:
```tsx
import { css } from '@emotion/react';

const buttonStyle = css`
  padding: 0.5rem 1rem;
  background: var(--color-primary);
`;
```

---

## Vue 3

### File Structure

```
components/
├── Button.vue           # Single File Component
└── __tests__/
    └── Button.spec.ts   # Tests
```

### Component Pattern (Composition API)

```vue
<template>
  <button
    :class="[
      'btn',
      `btn--${variant}`,
      `btn--${size}`,
      { 'btn--disabled': disabled }
    ]"
    :disabled="disabled"
    @click="emit('click')"
  >
    <slot />
  </button>
</template>

<script setup lang="ts">
interface Props {
  variant?: 'primary' | 'secondary' | 'ghost';
  size?: 'sm' | 'md' | 'lg';
  disabled?: boolean;
}

const props = withDefaults(defineProps<Props>(), {
  variant: 'primary',
  size: 'md',
  disabled: false,
});

const emit = defineEmits<{
  click: [];
}>();
</script>

<style scoped>
.btn {
  padding: 0.5rem 1rem;
  border-radius: 0.5rem;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.2s;
}

.btn--primary {
  background: var(--color-primary);
  color: white;
}

.btn--disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
</style>
```

### Styling Options

**Scoped CSS** (default):
```vue
<style scoped>
.button { /* styles */ }
</style>
```

**CSS Modules**:
```vue
<style module>
.button { /* styles */ }
</style>

<template>
  <button :class="$style.button" />
</template>
```

**Tailwind**:
```vue
<template>
  <button class="px-4 py-2 bg-blue-500 text-white rounded-lg" />
</template>
```

---

## Svelte

### File Structure

```
components/
├── Button.svelte        # Component
└── Button.test.ts       # Tests
```

### Component Pattern

```svelte
<script lang="ts">
  export let variant: 'primary' | 'secondary' | 'ghost' = 'primary';
  export let size: 'sm' | 'md' | 'lg' = 'md';
  export let disabled = false;
</script>

<button
  class="btn btn--{variant} btn--{size}"
  class:btn--disabled={disabled}
  {disabled}
  on:click
>
  <slot />
</button>

<style>
  .btn {
    padding: 0.5rem 1rem;
    border-radius: 0.5rem;
    font-weight: 500;
    cursor: pointer;
    transition: all 0.2s;
  }

  .btn--primary {
    background: var(--color-primary);
    color: white;
  }

  .btn--disabled {
    opacity: 0.5;
    cursor: not-allowed;
  }
</style>
```

### Styling Options

**Component Styles** (default):
```svelte
<style>
  /* Scoped by default */
  .button { /* styles */ }
</style>
```

**Global Styles**:
```svelte
<style global>
  .button { /* global styles */ }
</style>
```

**Tailwind**:
```svelte
<button class="px-4 py-2 bg-blue-500 text-white rounded-lg" />
```

---

## HTML (Vanilla)

### File Structure

```
components/
├── button.html          # Component HTML
├── button.css           # Component CSS
└── button.js            # Optional JavaScript
```

### Component Pattern

```html
<!-- button.html -->
<button class="btn btn--primary btn--md">
  Button Text
</button>
```

```css
/* button.css */
.btn {
  padding: 0.5rem 1rem;
  border-radius: 0.5rem;
  font-weight: 500;
  cursor: pointer;
  border: none;
  transition: all 0.2s;
}

.btn--primary {
  background: var(--color-primary, #2563eb);
  color: white;
}

.btn--primary:hover {
  background: var(--color-primary-dark, #1d4ed8);
}

.btn--secondary {
  background: var(--color-gray-100, #f3f4f6);
  color: var(--color-gray-900, #111827);
}

.btn--ghost {
  background: transparent;
  color: var(--color-gray-700, #374151);
}

.btn--sm {
  padding: 0.375rem 0.75rem;
  font-size: 0.875rem;
}

.btn--md {
  padding: 0.5rem 1rem;
  font-size: 1rem;
}

.btn--lg {
  padding: 0.75rem 1.5rem;
  font-size: 1.125rem;
}

.btn:disabled,
.btn--disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
```

---

## Common Patterns

### Variant Classes

All frameworks use a consistent variant pattern:

```
.component--variant
.component--size
.component--state
```

Examples:
- `.btn--primary`, `.btn--secondary`, `.btn--ghost`
- `.btn--sm`, `.btn--md`, `.btn--lg`
- `.btn--disabled`, `.btn--loading`

### Prop/Attribute Naming

| Concept | React | Vue | Svelte |
|---------|-------|-----|--------|
| Style variant | `variant` | `variant` | `variant` |
| Size | `size` | `size` | `size` |
| Disabled | `disabled` | `disabled` | `disabled` |
| Click handler | `onClick` | `@click` | `on:click` |
| Children | `children` | `<slot />` | `<slot />` |

### Accessibility

All generated components include:

1. **Proper semantics** - Use native elements (`<button>`, `<input>`)
2. **Keyboard support** - Focus styles, keyboard handlers
3. **ARIA attributes** - When native semantics insufficient
4. **Focus management** - Visible focus indicators

### Dark Mode Support

When `--dark-mode` is enabled:

```css
/* Light mode (default) */
.btn {
  background: white;
  color: #111827;
}

/* Dark mode */
.dark .btn,
[data-theme="dark"] .btn {
  background: #1f2937;
  color: white;
}

/* Or using media query */
@media (prefers-color-scheme: dark) {
  .btn {
    background: #1f2937;
    color: white;
  }
}
```

### Animation Levels

| Level | Description | Usage |
|-------|-------------|-------|
| `none` | No animations | Accessibility, performance |
| `subtle` | Micro-interactions | Most components |
| `expressive` | Bold animations | Hero sections, CTAs |

```css
/* Subtle */
.btn {
  transition: all 0.2s ease-out;
}

/* Expressive */
.btn {
  transition: all 0.3s ease-out;
}
.btn:hover {
  transform: scale(1.05);
}
.btn:active {
  transform: scale(0.95);
}
```

---

## Best Practices

1. **Use semantic HTML** - `<button>` for buttons, `<a>` for links
2. **Include TypeScript types** - For React and Vue
3. **Support variants** - Primary, secondary, ghost at minimum
4. **Include sizes** - sm, md, lg
5. **Handle disabled state** - Visual and functional
6. **Add focus styles** - Visible focus indicators
7. **Respect motion preferences** - `prefers-reduced-motion`
8. **Use CSS custom properties** - For theming flexibility

```