theme-consistency

Enforce consistent theming across all prototype mockup screens. Auto-loads theme.yaml, validates CSS variable usage, prevents hardcoded values, and maintains visual consistency session-to-session. Use during /prototype create when generating new screens.

$ Installer

git clone https://github.com/marcusgoll/Spec-Flow /tmp/Spec-Flow && cp -r /tmp/Spec-Flow/.claude/skills/theme-consistency ~/.claude/skills/Spec-Flow

// tip: Run this command in your terminal to install the skill


name: theme-consistency description: Enforce consistent theming across all prototype mockup screens. Auto-loads theme.yaml, validates CSS variable usage, prevents hardcoded values, and maintains visual consistency session-to-session. Use during /prototype create when generating new screens.

  1. Loading and enforcing theme.yaml values during mockup generation
  2. Preventing hardcoded colors, spacing, and typography values
  3. Validating new screens match established patterns
  4. Locking theme after first screen approval to ensure session-to-session consistency

This prevents the common problem where screens created in different sessions drift in style, creating an inconsistent prototype that undermines the design intent.

<quick_start> <when_to_invoke> Automatically invoke this skill when:

  • /prototype create [screen] is called and theme.yaml exists
  • Generating HTML mockup content for any screen
  • User requests a new prototype screen in any session

Do NOT invoke when:

  • Creating the very first screen (theme not yet established)
  • User explicitly requests to reset/modify theme </when_to_invoke>

<basic_workflow>

  1. Load Theme - Read design/prototype/theme.yaml
  2. Check Lock Status - If locked: true, enforce; if false, may update
  3. Load Context - Get app_type, core_goal, layout, tone, density
  4. Generate Screen - Create HTML using theme CSS variables
  5. Validate - Check for hardcoded values, fix violations </basic_workflow>

<key_rules> NEVER use:

  • Hardcoded hex colors: #3b82f6, #ffffff
  • Hardcoded RGB: rgb(59, 130, 246)
  • Hardcoded spacing: padding: 17px, margin: 32px
  • Arbitrary values: text-[15px], p-[23px]

ALWAYS use:

  • Theme CSS variables: var(--color-primary), var(--space-4)
  • Shared component classes: .btn--primary, .card, .form-input
  • Density classes: .density-compact, .density-spacious </key_rules> </quick_start>

<detailed_procedures> <theme_loading>

Loading Theme Configuration

When generating any prototype screen, FIRST load the theme:

# Read design/prototype/theme.yaml
theme:
  locked: true|false
  palette:
    primary: "oklch(55% 0.2 250)"
    # ... all colors
  typography:
    heading_font: "Inter, system-ui, sans-serif"
    # ... font settings
  spacing:
    unit: "8px"
    # ... spacing scale
  tone:
    style: "professional"  # affects content voice
    density: "comfortable" # affects spacing multipliers

Lock Status Behavior

If locked: true:

  • Theme is immutable
  • All new screens MUST use existing theme values
  • Warn if user requests theme changes
  • Suggest creating new prototype instead

If locked: false:

  • First screen is being created
  • Theme values may be refined based on user feedback
  • After user approves first mockup, set locked: true </theme_loading>

<screen_generation>

Generating Consistent Screens

HTML Structure

Every screen MUST follow base.html structure:

<!DOCTYPE html>
<html lang="en">
<head>
  <title>{{SCREEN_TITLE}} - {{APP_NAME}}</title>
  <link rel="stylesheet" href="../../theme.css">
  <link rel="stylesheet" href="../../shared.css">
  <style>/* Screen-specific overrides only */</style>
</head>
<body class="theme-{{TONE_STYLE}} density-{{DENSITY}}">
  <a href="#main-content" class="skip-link">Skip to main content</a>

  <!-- Navigation (if applicable) -->
  <nav class="nav nav--{{LAYOUT}}">...</nav>

  <!-- Main Content -->
  <main id="main-content" class="main main--{{LAYOUT}}">
    {{SCREEN_CONTENT}}
  </main>
</body>
</html>

CSS Variable Usage

ElementCorrectIncorrect
Button backgroundvar(--color-primary)#3b82f6
Card paddingvar(--space-4)32px
Heading sizevar(--text-2xl)1.953rem
Border radiusvar(--radius-md)8px
Box shadowvar(--shadow-md)0 4px 6px rgba(...)
Transitionvar(--transition-base)150ms ease

Component Reuse

Use shared.css classes instead of inline styles:

<!-- CORRECT -->
<button class="btn btn--primary">Submit</button>
<div class="card card--elevated">...</div>
<input class="form-input" type="text">

<!-- INCORRECT -->
<button style="background: #3b82f6; padding: 8px 16px;">Submit</button>
<div style="background: white; box-shadow: 0 4px 6px rgba(0,0,0,0.1);">...</div>

</screen_generation>

After generating screen HTML, validate:

1. No Hardcoded Colors

# Check for hex colors
grep -E "#[0-9a-fA-F]{3,6}" screen.html

# Check for rgb/rgba
grep -E "rgb\(|rgba\(" screen.html

# Check for hsl/hsla
grep -E "hsl\(|hsla\(" screen.html

2. No Hardcoded Spacing

# Check for pixel values not in variables
grep -E "padding:\s*\d+px" screen.html
grep -E "margin:\s*\d+px" screen.html
grep -E "gap:\s*\d+px" screen.html

3. Font Usage

# Check for hardcoded font-family
grep -E "font-family:\s*[^v]" screen.html  # Should use var()

4. Theme Variable Coverage

Ensure all visual properties use theme variables:

  • Colors: var(--color-*)
  • Spacing: var(--space-*)
  • Typography: var(--text-*), var(--font-*)
  • Effects: var(--shadow-*), var(--radius-*)

<content_presentation>

Content Presentation by Screen Type

Use context from theme.yaml to guide content structure:

Entry/Auth Screens

  • Single focus, minimal distraction
  • Centered card layout
  • Clear primary CTA
  • Minimal navigation

Dashboard/Overview Screens

  • Scannable grid layout
  • Summary cards with key metrics
  • Quick action shortcuts
  • Navigation hub role

Create/Edit Screens

  • Form-focused layout
  • Progressive disclosure if complex
  • Clear validation feedback
  • Save/Cancel actions visible

Browse/List Screens

  • Table or card grid
  • Search/filter bar at top
  • Pagination or infinite scroll
  • Quick actions per item

Detail/View Screens

  • Hero section with primary info
  • Tabbed or sectioned content
  • Action buttons in header
  • Related items/navigation </content_presentation> </detailed_procedures>

<validation_output>

Validation Report Format

After screen generation, output validation status:

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
THEME CONSISTENCY CHECK
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Screen: dashboard-overview.html
Theme: [APP_NAME] Theme (locked)

CHECKLIST:
✅ Uses theme.css variables
✅ Imports shared.css
✅ No hardcoded colors
✅ No hardcoded spacing
✅ Uses shared component classes
✅ Follows base.html structure
✅ Includes skip link
✅ Matches layout pattern (sidebar)
✅ Applies density setting (comfortable)

STATUS: PASS
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

If violations found:

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
THEME CONSISTENCY CHECK
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Screen: settings-form.html
Theme: [APP_NAME] Theme (locked)

VIOLATIONS FOUND:

Line 45: Hardcoded color
  Before: background: #f3f4f6;
  After:  background: var(--color-neutral-100);

Line 67: Hardcoded spacing
  Before: padding: 24px;
  After:  padding: var(--space-3);

Line 89: Missing shared class
  Before: <button style="...">
  After:  <button class="btn btn--primary">

STATUS: FAIL (3 violations)
Auto-fixing violations...
STATUS: PASS (after fixes)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

</validation_output>

  • Theme Template: .spec-flow/templates/prototype/theme.yaml
  • CSS Variables: .spec-flow/templates/prototype/theme.css
  • Base HTML: .spec-flow/templates/prototype/base.html
  • Shared Styles: .spec-flow/templates/prototype/shared.css
  • Design Tokens: docs/project/style-guide.md