CO

color-palette

Generates accessible 11-shade color palettes and semantic tokens from a single hex code, including WCAG compliance checks.

Install

mkdir -p .claude/skills/color-palette && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/3657" && unzip -o skill.zip -d .claude/skills/color-palette && rm skill.zip

Installs to .claude/skills/color-palette

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Generate complete, accessible colour palettes from a single brand hex. Produces 11-shade scale (50-950), semantic tokens, dark mode variants, Tailwind v4 CSS output, WCAG contrast checks. Use whenever the user supplies a brand hex and asks for a palette, mentions setting up a design system, wants Tailwind theme colours from a brand colour, or asks to check colour accessibility / contrast.
391 charsno explicit “when” triggerlonger than Claude Code's old 250-char listing cap (fine on current versions)
Beginner

Key capabilities

  • Generate 11-shade color scales from a single hex
  • Create semantic UI tokens for light and dark modes
  • Calculate WCAG contrast ratios for accessibility
  • Produce Tailwind v4 CSS output templates

How it works

The tool converts the input hex to HSL, generates a scale by varying lightness and saturation, and maps these shades to semantic tokens based on predefined light and dark mode patterns.

Inputs & outputs

You give it
A single brand hex color string
You get back
A complete Tailwind v4 CSS color system and semantic token mapping

When to use color-palette

  • Create a color scale for a design system
  • Generate dark mode variants for brand colors
  • Verify text contrast for accessibility
  • Define semantic color tokens for UI

About this skill

Colour Palette Generator

Generate a complete, accessible colour system from a single brand hex. Produces Tailwind v4 CSS ready to paste into your project.

Workflow

Step 1: Get the Brand Hex

Ask for the primary brand colour. A single hex like #0D9488 is enough.

Step 2: Generate 11-Shade Scale

Convert hex to HSL, then generate shades by varying lightness while keeping hue constant.

Hex to HSL Conversion

function hexToHSL(hex) {
  hex = hex.replace(/^#/, '');
  const r = parseInt(hex.substring(0, 2), 16) / 255;
  const g = parseInt(hex.substring(2, 4), 16) / 255;
  const b = parseInt(hex.substring(4, 6), 16) / 255;

  const max = Math.max(r, g, b);
  const min = Math.min(r, g, b);
  const diff = max - min;

  let l = (max + min) / 2;
  let s = 0;
  if (diff !== 0) {
    s = l > 0.5 ? diff / (2 - max - min) : diff / (max + min);
  }

  let h = 0;
  if (diff !== 0) {
    if (max === r) h = ((g - b) / diff + (g < b ? 6 : 0)) / 6;
    else if (max === g) h = ((b - r) / diff + 2) / 6;
    else h = ((r - g) / diff + 4) / 6;
  }

  return { h: Math.round(h * 360), s: Math.round(s * 100), l: Math.round(l * 100) };
}

Lightness and Saturation Values

ShadeLightnessSaturation MultUse Case
5097%0.80Subtle backgrounds
10094%0.80Hover states
20087%0.85Borders, dividers
30075%0.90Disabled states
40062%0.95Placeholder text
50048%1.00Brand colour baseline
60040%1.00Primary actions (often the brand colour)
70033%1.00Hover on primary
80027%1.00Active states
90020%1.00Text on light bg
95010%1.00Darkest accents

Reduce saturation for lighter shades (50-200 by 15-20%, 300-400 by 5-10%) to prevent overly vibrant pastels. Keep full saturation for 500-950.

Complete Scale Generator

function generateShadeScale(brandHex) {
  const { h, s } = hexToHSL(brandHex);
  const shades = {
    50:  { l: 97, sMul: 0.8 },  100: { l: 94, sMul: 0.8 },
    200: { l: 87, sMul: 0.85 }, 300: { l: 75, sMul: 0.9 },
    400: { l: 62, sMul: 0.95 }, 500: { l: 48, sMul: 1.0 },
    600: { l: 40, sMul: 1.0 },  700: { l: 33, sMul: 1.0 },
    800: { l: 27, sMul: 1.0 },  900: { l: 20, sMul: 1.0 },
    950: { l: 10, sMul: 1.0 }
  };
  const result = {};
  for (const [shade, { l, sMul }] of Object.entries(shades)) {
    result[shade] = `hsl(${h}, ${Math.round(s * sMul)}%, ${l}%)`;
  }
  return result;
}

HSL to Hex Conversion

function hslToHex(h, s, l) {
  s = s / 100; l = l / 100;
  const c = (1 - Math.abs(2 * l - 1)) * s;
  const x = c * (1 - Math.abs((h / 60) % 2 - 1));
  const m = l - c / 2;
  let r = 0, g = 0, b = 0;
  if (h < 60) { r = c; g = x; }
  else if (h < 120) { r = x; g = c; }
  else if (h < 180) { g = c; b = x; }
  else if (h < 240) { g = x; b = c; }
  else if (h < 300) { r = x; b = c; }
  else { r = c; b = x; }
  r = Math.round((r + m) * 255);
  g = Math.round((g + m) * 255);
  b = Math.round((b + m) * 255);
  return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`.toUpperCase();
}

Verification

Generated shades should look like the same colour family with smooth progression. Light shades (50-300) usable for backgrounds, dark shades (700-950) usable for text. Brand colour recognisable in 500-700.


Step 3: Map Semantic Tokens

Every background token MUST have a paired foreground token. Never use a background without its pair or dark mode will break.

Light Mode Tokens

TokenShadeUse Case
backgroundwhitePage backgrounds
foreground950Body text
cardwhiteCard backgrounds
card-foreground900Card text
popoverwhiteDropdown/tooltip backgrounds
popover-foreground950Dropdown text
primary600Primary buttons, links
primary-foregroundwhiteText on primary buttons
secondary100Secondary buttons
secondary-foreground900Text on secondary buttons
muted50Disabled backgrounds, subtle sections
muted-foreground600Muted text, captions
accent100Hover states, subtle highlights
accent-foreground900Text on accent backgrounds
destructivered-600Delete buttons, errors
destructive-foregroundwhiteText on destructive buttons
border200Input borders, dividers
input200Input field borders
ring600Focus rings

Dark Mode Tokens

TokenShadeUse Case
background950Page backgrounds
foreground50Body text
card900Card backgrounds
card-foreground50Card text
popover900Dropdown backgrounds
popover-foreground50Dropdown text
primary500Primary buttons (brighter in dark)
primary-foregroundwhiteText on primary buttons
secondary800Secondary buttons
secondary-foreground50Text on secondary buttons
muted800Disabled backgrounds
muted-foreground400Muted text
accent800Hover states
accent-foreground50Text on accent backgrounds
destructivered-500Delete buttons (brighter)
destructive-foregroundwhiteText on destructive
border800Borders
input800Input borders
ring500Focus rings

Dark Mode Inversion Pattern

Dark mode inverts lightness while preserving hue and saturation. Swap extremes (50 becomes 950, 950 becomes 50), preserve middle (500 stays near 500).

Light ShadeDark EquivalentRole
50950Backgrounds
100900Subtle backgrounds
200800Borders
500500 (slightly brighter)Brand baseline
600400Primary actions
95050Text colour

Key dark mode principles:

  • Use shade 500 (not 600) for primary -- brighter for visibility on dark backgrounds
  • Use shade 50 (off-white) for text instead of pure #FFFFFF -- easier on eyes
  • Borders need ~10-15% lighter than background (e.g. 800 border on 950 background)
  • Higher elevation = lighter colour (opposite of light mode shadows)
  • Always update foreground when changing background

Step 4: Check Contrast

WCAG Minimum Ratios

Content TypeAAAAA
Normal text (<18px or <14px bold)4.5:17:1
Large text (>=18px or >=14px bold)3:14.5:1
UI components (buttons, borders)3:1Not defined
Graphical objects (icons, charts)3:1Not defined

Target AA for most projects, AAA for high-accessibility needs (government, healthcare).

Luminance and Contrast Formulas

function getLuminance(hex) {
  hex = hex.replace(/^#/, '');
  const r = parseInt(hex.substring(0, 2), 16) / 255;
  const g = parseInt(hex.substring(2, 4), 16) / 255;
  const b = parseInt(hex.substring(4, 6), 16) / 255;
  const rsRGB = r <= 0.03928 ? r / 12.92 : Math.pow((r + 0.055) / 1.055, 2.4);
  const gsRGB = g <= 0.03928 ? g / 12.92 : Math.pow((g + 0.055) / 1.055, 2.4);
  const bsRGB = b <= 0.03928 ? b / 12.92 : Math.pow((b + 0.055) / 1.055, 2.4);
  return 0.2126 * rsRGB + 0.7152 * gsRGB + 0.0722 * bsRGB;
}

function getContrastRatio(hex1, hex2) {
  const lum1 = getLuminance(hex1);
  const lum2 = getLuminance(hex2);
  const lighter = Math.max(lum1, lum2);
  const darker = Math.min(lum1, lum2);
  return (lighter + 0.05) / (darker + 0.05);
}

Quick Check Table -- Light Mode

ForegroundBackgroundRatioPass?Use Case
950white18.5:1AAABody text
900white14.2:1AAACard text
700white8.1:1AAAText
600white5.7:1AAText, buttons
500white3.9:1FailToo light for text
white6005.7:1AAButton text
white7008.1:1AAAButton text
600505.4:1AAMuted section text

Quick Check Table -- Dark Mode

ForegroundBackgroundRatioPass?Use Case
5095018.5:1AAABody text
5090014.2:1AAACard text
4009508.2:1AAAMuted text
4009006.3:1AAMuted text
white6005.7:1AAButton text

Rule of thumb: For text, aim for 50%+ lightness difference between foreground and background.

Essential Pairs to Verify

  1. Body text: foreground on background (light: 950 on white = 18.5:1, dark: 50 on 950 = 18.5:1)
  2. Primary button: primary-foreground on primary (light: white on 600 = 5.7:1, dark: white on 500 = 3.9:1 -- borderline)
  3. Muted text: muted-foreground on muted (light: 600 on 50 = 5.4:1, dark: 400 on 800 = 4.1:1 -- may fail)
  4. Card text: card-foreground on card (light: 900 on white = 14.2:1, dark: 50 on 900 = 14.2:1)

Fixing Common Contrast Failures

White on primary-500 fails (3.9:1): Use primary-600 instead (5.7:1), or use dark text on the button.

Muted text in dark mode fails (400 on 800 = 4.1:1): Use 300 on 900 = 6.8:1.

Links hard to see (500 on white = 3.9:1): Use primary-700 (8.1:1), or add underline decoration.


Step 5: Output Tailwind v4 CSS

@import "tailwindcss";

@theme {
  /* Shade scale */
  --color-primary-50: #F0FDFA;
  --color-primary-100: #CCFBF1;
  --color-primary-200: #99F6E4;
  --color-primary-300: #5EEAD4;
  --color-primary-400: #2DD4BF;
  --color-primary-500: #14B8A6;
  --color-primary-600: #0D9488;
  --color-primary-700: #0F766E;
  --color-primary-800: #115E59;
  --color-primary-900: #134E4A;
  --color-primary-950: #042F2E;

  /* Light mode semantic tokens */
  --color-background: #FFFFFF;
  --color-foreground: var(--color-primary-950);
  --color-ca

---

*Content truncated.*

When not to use it

  • When the user has not provided a brand hex code
  • When working outside of Claude Code environments

Prerequisites

A primary brand hex color

Limitations

  • Requires manual verification of contrast ratios for specific UI components
  • Does not automatically handle complex gradient or transparent color edge cases

How it compares

Unlike manual color selection, this tool automates the generation of a full accessible scale and semantic CSS tokens based on specific lightness and saturation formulas.

Compared to similar skills

color-palette side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
color-palette (this skill)23moNo flagsBeginner
tailwind-design-system342moNo flagsIntermediate
web-design-reviewer77moNo flagsIntermediate
epic-ui-guidelines36moNo flagsBeginner

Try saying

Example prompts that trigger this skill in your AI assistant.

Search skills

Search the agent skills registry