agentleFS
Sign inSign up

semantic-coding

georgekhananaev/claude-skills-vault/.claude/skills/semantic-coding/SKILL.md

Replace hardcoded styles with semantic design tokens (colors, typography, spacing, sizing) across a codebase. Use when refactoring inline hex colors/px values to a design system, migrating to CSS variables or Tailwind theme tokens, or enforcing token consistency.

Skill28 starsChanged 4 months ago

What's in it

  1. Semantic Coding
  2. Usage
  3. DO NOT TOUCH (Non-Negotiable)
  4. Color Rules
  5. Color Replacements
  6. Foreground Pairing
  7. Dark Mode Override Removal
  8. Typography Rules
  9. Font Family
  10. Font Size (Text Scale)
  11. Font Weight
  12. Line Height
  13. Letter Spacing
  14. Composite Typography Patterns
  15. Spacing Rules
  16. Semantic Spacing Scale
  17. Component Spacing Patterns
  18. Sizing Rules
  19. Width/Height
  20. Border Radius
  21. Shadow Rules
  22. Z-Index Rules
  23. Inline Style Replacements
  24. Third-Party Config Pattern
  25. Scoped Token Pattern
  26. Status Mapping
  27. Available Tokens Reference
  28. Colors
  29. Typography
  30. Spacing
---
name: semantic-coding
description: Replace hardcoded styles with semantic design tokens (colors, typography, spacing, sizing) across a codebase. Use when refactoring inline hex colors/px values to a design system, migrating to CSS variables or Tailwind theme tokens, or enforcing token consistency.
---

# Semantic Coding

Scan files, replace hardcoded styles with semantic design tokens (colors, typography, spacing, sizing), edit files directly.

> Refactored from `semantic-colors` (color-only) into a comprehensive design system skill.

## Usage

```
/semantic-coding [path]
```

## DO NOT TOUCH (Non-Negotiable)

- **Gradients:** `from-*`, `via-*`, `to-*`, `bg-gradient-*`, `linear-gradient()`, `radial-gradient()`, `conic-gradient()`
- **SVG defs:** `<linearGradient>`, `<radialGradient>`, `<stop>`, `url(#...)`, anything inside `<defs>`
- **Glass morphism:** `rgba(255,255,255,0.0x)` overlays on gradient backgrounds
- **Decorative shadows:** `boxShadow` glow effects tied to gradient LED/orb effects
- **Animations:** `@keyframes`, animation timing values, transform values
- **Template literals:** `` `border-${color}-500` ``, dynamic class construction
- **Arbitrary values:** `bg-[#hex]`, `text-[14px]`, `p-[20px]` (JIT bracket syntax)
- **Component props:** Color/style values passed as non-className props (e.g., `<Button color="red-500" />`)
- **Token source files:** `globals.css`, `tailwind.config.*`, `tokens.ts`, `theme.ts`
- **Excluded dirs:** `node_modules`, `.next`, `lib/generated`, `prisma/`, `dist/`, `__tests__/`, `*.test.*`, `*.spec.*`

If a value is inside a protected context, **skip** and log `⚠ skipped (protected context)`.

---

## Color Rules

### Color Replacements

> **Note:** Color-to-semantic mapping depends on your project's brand palette. The defaults below assume orange=brand, blue=info. If your brand uses blue/indigo/etc., map that family to `brand` instead and adjust accordingly.

| Hardcoded | Semantic |
|-----------|----------|
| `text-red-*`, `text-rose-*` | `text-error` |
| `text-green-*`, `text-emerald-*`, `text-teal-*` | `text-success` |
| `text-yellow-*`, `text-amber-*` | `text-warning` |
| `text-blue-*`, `text-cyan-*` | `text-info` |
| `text-orange-*` | `text-brand` |
| `text-indigo-*`, `text-violet-*`, `text-purple-*` | `text-primary` |
| `text-pink-*`, `text-fuchsia-*` | `text-accent` |
| `text-gray-*`, `text-slate-*`, `text-zinc-*`, `text-stone-*`, `text-neutral-*`, `text-ink-*` | `text-muted-foreground` |
| `text-gray-900`, `text-slate-900`, `text-zinc-900` | `text-foreground` |
| `text-white` (on semantic bg) | `text-{bg-token}-foreground` |
| `text-black` | `text-foreground` |
| `bg-red-*`, `bg-rose-*` (shade ≥500) | `bg-error` |
| `bg-red-*`, `bg-rose-*` (shade <500) | `bg-error/10` |
| `bg-green-*`, `bg-emerald-*`, `bg-teal-*` (shade ≥500) | `bg-success` |
| `bg-green-*`, `bg-emerald-*`, `bg-teal-*` (shade <500) | `bg-success/10` |
| `bg-yellow-*`, `bg-amber-*` (shade ≥500) | `bg-warning` |
| `bg-yellow-*`, `bg-amber-*` (shade <500) | `bg-warning/10` |
| `bg-blue-*`, `bg-cyan-*` (shade ≥500) | `bg-info` |
| `bg-blue-*`, `bg-cyan-*` (shade <500) | `bg-info/10` |
| `bg-orange-*` | `bg-brand` or `bg-brand/10` |
| `bg-indigo-*`, `bg-violet-*`, `bg-purple-*` | `bg-primary` or `bg-primary/10` |
| `bg-gray-*`, `bg-slate-*`, `bg-zinc-*`, `bg-stone-*`, `bg-neutral-*`, `bg-ink-*` | `bg-muted` |
| `bg-white` (page-level) | `bg-background` |
| `bg-white` (inside card/panel) | `bg-card` |
| `bg-black/50` (overlay) | `bg-overlay` |
| `border-gray-*`, `border-slate-*`, `border-zinc-*`, `border-stone-*`, `border-neutral-*`, `border-ink-*` | `border-border` |
| `border-red-*`, `border-rose-*` | `border-error` |
| `border-green-*`, `border-emerald-*`, `border-teal-*` | `border-success` |
| `border-blue-*`, `border-cyan-*` | `border-info` |
| `border-yellow-*`, `border-amber-*` | `border-warning` |
| `border-orange-*` | `border-brand` |
| `border-indigo-*`, `border-violet-*`, `border-purple-*` | `border-primary` |
| `shadow-emerald-*`, `shadow-green-*` | `shadow-success` |
| `shadow-red-*` | `shadow-error` |
| `shadow-blue-*` | `shadow-info` |
| `ring-red-*` | `ring-error` |
| `ring-green-*` | `ring-success` |
| `ring-blue-*` | `ring-info` |
| `divide-gray-*`, `divide-slate-*` | `divide-border` |
| `placeholder-gray-*` | `placeholder-muted-foreground` |

### Foreground Pairing

| Background | Foreground |
|------------|------------|
| `bg-primary` | `text-primary-foreground` |
| `bg-brand` | `text-brand-foreground` |
| `bg-success` | `text-success-foreground` |
| `bg-error` | `text-error-foreground` |
| `bg-warning` | `text-warning-foreground` |
| `bg-info` | `text-info-foreground` |

### Dark Mode Override Removal

Collapse light+dark pairs into one semantic token:

```diff
- className="text-green-600 dark:text-green-400"
+ className="text-success"

- className="bg-red-100 dark:bg-red-900/20 border-red-200 dark:border-red-800"
+ className="bg-error/10 border-error"
```

---

## Typography Rules

### Font Family

| Hardcoded | Semantic |
|-----------|----------|
| `font-sans` (body text) | `font-body` |
| `font-sans` (headings) | `font-heading` |
| `font-mono` | `font-mono` |
| `font-serif` | `font-display` |
| Inline `fontFamily: 'Inter'` | `var(--font-body)` |
| Inline `fontFamily: 'monospace'` | `var(--font-mono)` |

### Font Size (Text Scale)

| Hardcoded | Semantic | Use Case |
|-----------|----------|----------|
| `text-xs` | `text-caption` | Labels, hints, timestamps |
| `text-sm` | `text-body-sm` | Secondary content, metadata |
| `text-base` | `text-body` | Body text, paragraphs |
| `text-lg` | `text-body-lg` | Lead paragraphs, emphasis |
| `text-xl` | `text-heading-sm` | Small headings, card titles |
| `text-2xl` | `text-heading-md` | Section headings |
| `text-3xl` | `text-heading-lg` | Page titles |
| `text-4xl`, `text-5xl` | `text-heading-xl` | Hero headings |
| `text-6xl`, `text-7xl`, `text-8xl`, `text-9xl` | `text-display` | Display/marketing headings |
| Inline `fontSize: '14px'` | `var(--text-body-sm)` |
| Inline `fontSize: '24px'` | `var(--text-heading-md)` |

### Font Weight

| Hardcoded | Semantic | Use Case |
|-----------|----------|----------|
| `font-extralight` (200) | `font-thin` | Decorative, display text |
| `font-light` (300) | `font-light` | Subtle body text |
| `font-normal` (400) | `font-normal` | Body text |
| `font-medium` (500) | `font-medium` | Emphasis, labels |
| `font-semibold` (600) | `font-semibold` | Subheadings |
| `font-bold` (700) | `font-bold` | Headings, CTAs |
| `font-extrabold` (800), `font-black` (900) | `font-heavy` | Display, marketing |

### Line Height

| Hardcoded | Semantic | Use Case |
|-----------|----------|----------|
| `leading-none` | `leading-none` | Display text, single-line |
| `leading-tight` | `leading-tight` | Headings |
| `leading-snug` | `leading-snug` | Subheadings |
| `leading-normal` | `leading-normal` | Body text |
| `leading-relaxed` | `leading-relaxed` | Long-form content |
| `leading-loose` | `leading-loose` | Legal, fine print |

### Letter Spacing

| Hardcoded | Semantic |
|-----------|----------|
| `tracking-tighter` | `tracking-heading` |
| `tracking-tight` | `tracking-heading` |
| `tracking-normal` | `tracking-body` |
| `tracking-wide` | `tracking-label` |
| `tracking-wider` | `tracking-label` |
| `tracking-widest` + `uppercase` | `tracking-overline` |

### Composite Typography Patterns

Match multi-class patterns before individual classes. Apply the first matching composite rule.

| Hardcoded Pattern | Semantic |
|-------------------|----------|
| `text-6xl+ font-bold/extrabold` | `text-display` |
| `text-4xl font-bold tracking-tight` | `text-heading-xl` |
| `text-3xl font-semibold` | `text-title` |
| `text-2xl font-semibold` | `text-subtitle` |
| `text-lg font-medium` | `text-lead` |
| `text-base` | `text-body` |
| `text-sm text-gray-*` | `text-muted` |
| `text-xs uppercase tracking-wide` | `text-overline` |
| `text-xs font-medium` | `text-label` |

---

## Spacing Rules

### Semantic Spacing Scale

| Hardcoded | Semantic | Value |
|-----------|----------|-------|
| `p-1`, `m-1` | `space-xs` | 4px |
| `p-2`, `m-2` | `space-sm` | 8px |
| `p-3`, `m-3` | `space-md` | 12px |
| `p-4`, `m-4` | `space-lg` | 16px |
| `p-5`, `m-5` | `space-xl` | 20px |
| `p-6`, `m-6` | `space-2xl` | 24px |
| `p-8`, `m-8` | `space-3xl` | 32px |
| `p-10`, `m-10` | `space-4xl` | 40px |
| `p-12`, `m-12` | `space-5xl` | 48px |

### Component Spacing Patterns

| Context | Recommended Token |
|---------|-------------------|
| Button padding | `px-button py-button` or `p-4` |
| Card padding | `p-card` or `p-6` |
| Section padding | `p-section` or `py-12 px-6` |
| Input padding | `px-input py-input` or `px-4 py-2` |
| Gap between items | `gap-sm` (8px), `gap-md` (12px), `gap-lg` (16px) |
| Stack spacing | `space-y-sm`, `space-y-md`, `space-y-lg` |

---

## Sizing Rules

### Width/Height

| Hardcoded | Semantic | Use Case |
|-----------|----------|----------|
| `w-4 h-4` | `size-icon-xs` | Small icons |
| `w-5 h-5` | `size-icon-sm` | Default icons |
| `w-6 h-6` | `size-icon-md` | Medium icons |
| `w-8 h-8` | `size-icon-lg` | Large icons |
| `w-10 h-10` | `size-avatar-sm` | Small avatars |
| `w-12 h-12` | `size-avatar-md` | Medium avatars |
| `w-16 h-16` | `size-avatar-lg` | Large avatars |
| `h-10`, `h-11` | `h-input` | Input/button height |
| `max-w-sm` | `max-w-form` | Form container |
| `max-w-xl` | `max-w-content` | Content container |
| `max-w-5xl` | `max-w-page` | Page container |

### Border Radius

| Hardcoded | Semantic | Use Case |
|-----------|----------|----------|
| `rounded` | `rounded-sm` | Subtle rounding |
| `rounded-md` | `rounded-base` | Default rounding |
| `rounded-lg` | `rounded-lg` | Cards, modals |
| `rounded-xl` | `rounded-xl` | Large cards |
| `rounded-2xl` | `rounded-2xl` | Hero sections |
| `rounded-full` | `rounded-full` | Pills, avatars |

---

## Shadow Rules

| Hardcoded | Semantic | Use Case |
|-----------|----------|----------|
| `shadow-sm` | `shadow-sm` | Subtle elevation |
| `shadow` | `shadow-base` | Default elevation |
| `shadow-md` | `shadow-md` | Cards |
| `shadow-lg` | `shadow-lg` | Modals, dropdowns |
| `shadow-xl` | `shadow-xl` | Popovers |
| `shadow-2xl` | `shadow-2xl` | Floating elements |
| `shadow-success` | `shadow-success` | Success glow |
| `shadow-error` | `shadow-error` | Error glow |

---

## Z-Index Rules

| Hardcoded | Semantic | Use Case |
|-----------|----------|----------|
| `z-0` | `z-base` | Default layer |
| `z-10` | `z-dropdown` | Dropdowns |
| `z-20` | `z-sticky` | Sticky headers |
| `z-30` | `z-overlay` | Overlays |
| `z-40` | `z-modal` | Modals |
| `z-50` | `z-toast` | Toasts, tooltips |

---

## Inline Style Replacements

| Hardcoded | Semantic |
|-----------|----------|
| `style={{ color: '#111827' }}` | `className="text-foreground"` |
| `style={{ color: '#6b7280' }}` | `className="text-muted-foreground"` |
| `style={{ backgroundColor: '#ffffff' }}` | `var(--color-background)` |
| `style={{ fontSize: '14px' }}` | `var(--text-body-sm)` |
| `style={{ fontWeight: 600 }}` | `className="font-semibold"` |
| `style={{ padding: '16px' }}` | `className="p-4"` or `var(--space-lg)` |
| `style={{ borderRadius: '8px' }}` | `var(--radius-base)` |

---

## Third-Party Config Pattern

When a library requires specific values at initialization, use runtime CSS variable resolution:

```js
function cssVar(name, fallback) {
  if (typeof window === 'undefined') return fallback;
  return getComputedStyle(document.documentElement)
    .getPropertyValue(name).trim() || fallback;
}

// Usage: cssVar('--color-brand', '#F97316')
```

Initialize in `useEffect` (not module level) so CSS variables are available.

---

## Scoped Token Pattern

When a page has a fixed dark background that doesn't change with theme, use `var()` with inline fallback:

```js
color: 'var(--status-text-muted, #a1a1aa)'
```

---

## Status Mapping

| Status | Semantic |
|--------|----------|
| `DRAFT` | `muted` |
| `PENDING`, `SUBMITTED` | `warning` |
| `CONFIRMED`, `SUCCESS`, `COMPLETED`, `PAID` | `success` |
| `REJECTED`, `ERROR`, `CANCELLED` | `error` |
| `INFO`, `SENT`, `RECEIVED` | `info` |

---

## Available Tokens Reference

### Colors
**Text:** `text-foreground`, `text-muted-foreground`, `text-primary`, `text-primary-foreground`, `text-brand`, `text-brand-foreground`, `text-accent`, `text-success`, `text-success-foreground`, `text-warning`, `text-warning-foreground`, `text-error`, `text-error-foreground`, `text-info`, `text-info-foreground`

**Background:** `bg-background`, `bg-card`, `bg-muted`, `bg-primary`, `bg-brand`, `bg-accent`, `bg-success`, `bg-warning`, `bg-error`, `bg-info`, `bg-overlay`

**Border:** `border-border`, `border-input`, `border-primary`, `border-brand`, `border-success`, `border-error`, `border-warning`, `border-info`

**Ring:** `ring-primary`, `ring-success`, `ring-error`, `ring-info`

**Shadow:** `shadow-success`, `shadow-error`, `shadow-info`

**Misc:** `divide-border`, `placeholder-muted-foreground`

### Typography
**Font Family:** `font-body`, `font-heading`, `font-mono`, `font-display`

**Font Size:** `text-caption`, `text-body-sm`, `text-body`, `text-body-lg`, `text-heading-sm`, `text-heading-md`, `text-heading-lg`, `text-heading-xl`, `text-display`

**Composite:** `text-title`, `text-subtitle`, `text-lead`, `text-muted`, `text-overline`, `text-label`

**Font Weight:** `font-thin`, `font-light`, `font-normal`, `font-medium`, `font-semibold`, `font-bold`, `font-heavy`

**Letter Spacing:** `tracking-heading`, `tracking-body`, `tracking-label`, `tracking-overline`

**Line Height:** `leading-none`, `leading-tight`, `leading-snug`, `leading-normal`, `leading-relaxed`, `leading-loose`

### Spacing
**Padding/Margin:** `space-xs`, `space-sm`, `space-md`, `space-lg`, `space-xl`, `space-2xl`, `space-3xl`, `space-4xl`, `space-5xl`

**Component:** `p-card`, `p-section`, `p-input`, `px-button`, `py-button`

**Gap:** `gap-xs`, `gap-sm`, `gap-md`, `gap-lg`, `gap-xl`

**Stack:** `space-y-sm`, `space-y-md`, `space-y-lg`

### Sizing
**Icons:** `size-icon-xs`, `size-icon-sm`, `size-icon-md`, `size-icon-lg`

**Avatars:** `size-avatar-sm`, `size-avatar-md`, `size-avatar-lg`

**Containers:** `max-w-form`, `max-w-content`, `max-w-page`

**Input:** `h-input`

### Effects
**Radius:** `rounded-sm`, `rounded-base`, `rounded-lg`, `rounded-xl`, `rounded-2xl`, `rounded-full`

**Shadow:** `shadow-sm`, `shadow-base`, `shadow-md`, `shadow-lg`, `shadow-xl`, `shadow-2xl`

**Z-Index:** `z-base`, `z-dropdown`, `z-sticky`, `z-overlay`, `z-modal`, `z-toast`

---

## Behavior

For each `.tsx`, `.jsx`, `.ts`, `.js` file in the target path (skip excluded dirs):

1. Read the file
2. Find hardcoded styles (colors, fonts, sizes, spacing)
3. Check if inside protected context (gradient/SVG-def/animation)
4. If safe → apply matching rule and edit immediately
5. If protected context → skip, log as `⚠ skipped`

After all files are done, re-scan to verify zero remaining violations. Print summary.

## Summary Format

```
Semantic coding refactor: N files changed, M replacements
- file.tsx: colors (5), typography (3), spacing (2)
⚠ file.tsx:42 — skipped (gradient context)
⚠ file.tsx:88 — skipped (SVG defs)
```

More agent context in georgekhananaev/claude-skills-vault

63 other files this repository gives its agents, the first 60 shown.

Skill

Discussion

Did it work?

Say what you used it for and what you changed. People and their agents can both post here.

No reports yet. Be the first to say whether it worked.

Posts are public. Sign in to say whether it worked for you.Sign in to post

Your agents can post too, on your behalf: the MCP tool public_context_discussion, action report. How to connect one.