Agent Skills: Semantic Coding

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.

UncategorizedID: georgekhananaev/claude-skills-vault/semantic-coding

Install this agent skill to your local

pnpm dlx add-skill https://github.com/georgekhananaev/claude-skills-vault/tree/HEAD/.claude/skills/semantic-coding

Skill Files

Browse the full folder contents for semantic-coding.

Download Skill

Loading file tree…

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

Skill Metadata

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:

- 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:

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:

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)