PluginBench
Skill
Pass
Audit score 90

color-palette

jezweb/claude-skills

Generate accessible 11-shade colour palettes and Tailwind themes from a single brand hex.

What is color-palette?

Creates complete colour systems from a brand hex code, including 11-shade scales (50–950), semantic tokens for light and dark modes, WCAG contrast verification, and Tailwind v4 CSS output. Use this when a user provides a brand colour and needs a design system, wants Tailwind theme colours, or needs accessibility checks.

  • Convert brand hex to HSL and generate 11-shade scale with optimized lightness and saturation
  • Map semantic tokens (background, foreground, primary, secondary, destructive, etc.) for light and dark modes
  • Apply dark mode inversion pattern that preserves hue while inverting lightness
  • Calculate WCAG contrast ratios for text and UI components against backgrounds
  • Output Tailwind v4 CSS ready to paste into projects
  • Verify colour progression is smooth and brand colour is recognizable in mid-range shades

How to install color-palette

npx skills add https://github.com/jezweb/claude-skills --skill color-palette
Claude Code
Cursor
Windsurf
Cline

How to use color-palette

  1. 1.Provide the primary brand colour as a hex code (e.g. #0D9488)
  2. 2.The skill generates an 11-shade scale by converting hex to HSL and varying lightness while keeping hue constant
  3. 3.Review the generated shades to ensure smooth progression and brand recognition in the 500–700 range
  4. 4.Map semantic tokens to shades for light mode (e.g. primary: 600, background: white, foreground: 950)
  5. 5.Generate dark mode tokens using the inversion pattern (e.g. background: 950, foreground: 50, primary: 500)
  6. 6.Run WCAG contrast checks on text/background pairs to verify AA or AAA compliance
  7. 7.Copy the Tailwind v4 CSS output into your project's theme configuration

Use cases

Good for
  • Design system setup: convert a brand colour into a complete palette with semantic tokens
  • Tailwind theme generation: produce CSS variables or theme config from a single hex
  • Accessibility audit: check contrast ratios between text colours and backgrounds against WCAG AA/AAA standards
  • Dark mode implementation: generate inverted palette that maintains readability and brand recognition
  • UI component theming: map colours to buttons, inputs, cards, and other semantic roles
Who it's for
  • Product designers setting up design systems
  • Frontend developers building Tailwind-based projects
  • Design system maintainers
  • Accessibility-focused teams
  • Developers needing quick colour theme generation

color-palette FAQ

What if my brand colour is too light or too dark?

The skill adjusts saturation multipliers for lighter shades (50–400 reduced by 5–20%) to prevent overly vibrant pastels, and keeps full saturation for darker shades (500–950). If the result doesn't match your brand, you can manually adjust the base hue or saturation before generating the scale.

Do I need to provide dark mode colours separately?

No. The skill automatically generates dark mode tokens using an inversion pattern: light shades (50) become dark (950), mid-range (500) stays similar but slightly brighter, and text colours flip (950 becomes 50). Every background token is paired with a foreground token to prevent dark mode breakage.

How do I know if my palette meets accessibility standards?

The skill calculates WCAG contrast ratios using the luminance formula. Target 4.5:1 for normal text (AA), 7:1 for AAA. Large text (≥18px or ≥14px bold) needs 3:1 (AA) or 4.5:1 (AAA). The skill flags pairs that fall short.

Can I use this palette in non-Tailwind projects?

Yes. The skill outputs HSL values and hex codes for each shade, plus semantic token names. You can map these to CSS variables, SCSS, or any other format your project uses.

What's the difference between shade 500 and 600?

Shade 500 is the brand colour baseline (48% lightness, full saturation). Shade 600 (40% lightness) is typically used for primary actions in light mode. In dark mode, use shade 500 for primary buttons because it's brighter and more visible on dark backgrounds.

Full instructions (SKILL.md)

Source of truth, from jezweb/claude-skills.


name: color-palette description: "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." compatibility: claude-code-only

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-card: #FFFFFF;
  --color-card-foreground: var(--color-primary-900);
  --color-popover: #FFFFFF;
  --color-popover-foreground: var(--color-primary-950);
  --color-primary: var(--color-primary-600);
  --color-primary-foreground: #FFFFFF;
  --color-secondary: var(--color-primary-100);
  --color-secondary-foreground: var(--color-primary-900);
  --color-muted: var(--color-primary-50);
  --color-muted-foreground: var(--color-primary-600);
  --color-accent: var(--color-primary-100);
  --color-accent-foreground: var(--color-primary-900);
  --color-destructive: #DC2626;
  --color-destructive-foreground: #FFFFFF;
  --color-border: var(--color-primary-200);
  --color-input: var(--color-primary-200);
  --color-ring: var(--color-primary-600);
  --radius: 0.5rem;
}

/* Dark mode overrides */
.dark {
  --color-background: var(--color-primary-950);
  --color-foreground: var(--color-primary-50);
  --color-card: var(--color-primary-900);
  --color-card-foreground: var(--color-primary-50);
  --color-popover: var(--color-primary-900);
  --color-popover-foreground: var(--color-primary-50);
  --color-primary: var(--color-primary-500);
  --color-primary-foreground: #FFFFFF;
  --color-secondary: var(--color-primary-800);
  --color-secondary-foreground: var(--color-primary-50);
  --color-muted: var(--color-primary-800);
  --color-muted-foreground: var(--color-primary-400);
  --color-accent: var(--color-primary-800);
  --color-accent-foreground: var(--color-primary-50);
  --color-destructive: #EF4444;
  --color-destructive-foreground: #FFFFFF;
  --color-border: var(--color-primary-800);
  --color-input: var(--color-primary-800);
  --color-ring: var(--color-primary-500);
}

Copy assets/tailwind-colors.css as a starting template.


Component Usage Examples

// Primary button
<button className="bg-primary text-primary-foreground hover:bg-primary/90">Click me</button>

// Secondary button
<button className="bg-secondary text-secondary-foreground hover:bg-secondary/80">Cancel</button>

// Card
<div className="bg-card text-card-foreground border-border rounded-lg">
  <h2>Title</h2>
  <p className="text-muted-foreground">Description</p>
</div>

// Input
<input className="bg-background text-foreground border-input focus:ring-ring" />

Common Adjustments

  • Too vibrant at light shades: Reduce saturation by 10-20%
  • Poor contrast on primary: Use shade 700+ for text
  • Dark mode too dark: Use shade 900 instead of 950 for backgrounds
  • Brand colour too light/dark: Adjust to shade 500-600 range
  • Dark mode looks washed out: Use shade 500 for primary (brighter than light mode's 600)
  • Pure white text too harsh in dark mode: Use shade 50 (off-white) instead
  • Dark mode muted text fails contrast: Use more extreme shades (300 on 900 instead of 400 on 800)

Brand Identity Adjustments

  • Conservative brands (finance, law): Use primary-700 for buttons, reduce saturation in light shades
  • Vibrant brands (creative, tech): Use primary-500-600, keep full saturation
  • Minimal brands (design, architecture): Use primary sparingly, emphasise muted tones, subtle borders (primary-100)

Verification Checklist

  • Body text: >=4.5:1 (normal) or >=3:1 (large)
  • Primary button text: >=4.5:1
  • Secondary button text: >=4.5:1
  • Muted text: >=4.5:1
  • Links: >=4.5:1 (or underlined)
  • UI elements (borders): >=3:1
  • Focus indicators: >=3:1
  • Error text: >=4.5:1
  • Dark mode: All above checks pass
  • Every background has a foreground pair
  • Brand colour recognisable in both modes
  • Borders visible but not harsh
  • Cards/sections have clear boundaries

Test both modes before shipping.


Optional References

  • Online contrast checkers: WebAIM (webaim.org/resources/contrastchecker), Coolors (coolors.co/contrast-checker), Accessible Colors (accessible-colors.com)
  • CI/CD contrast tests: Use getContrastRatio() in test suites to assert minimum ratios for all token pairs
  • Transparent/gradient edge cases: For colours with opacity, calculate against final rendered colour. For gradients, check both endpoints.
  • OLED dark mode: Use @media (prefers-contrast: high) with #000000 background for battery savings on AMOLED screens
  • Multi-colour palettes: Generate separate shade scales for each brand colour, map to different semantic roles (primary, accent)
  • Palette visualisation tools: coolors.co, paletton.com, Figma swatches
  • assets/tailwind-colors.css — Complete CSS output template

Related skills

More from jezweb/claude-skills and the wider catalog.

d1-drizzle-schema logo

d1-drizzle-schema

jezweb/claude-skills

Generate Drizzle ORM schemas for Cloudflare D1 with correct D1-specific patterns and migrations.

1.3k installs
d1-migration logo

d1-migration

jezweb/claude-skills

Cloudflare D1 migration workflow: generate with Drizzle, inspect SQL for gotchas, apply to local and remote, fix stuck migrations, handle partial failures. Use when running migrations, fixing migration errors, or setting up D1 schemas.

876 installsAudited
db-seed logo

db-seed

jezweb/claude-skills

Generate database seed scripts with realistic sample data. Reads Drizzle schemas or SQL migrations, respects foreign key ordering, produces idempotent TypeScript or SQL seed files. Handles D1 batch limits, unique constraints, and domain-appropriate data. Use when populating dev/demo/test databases. Triggers: 'seed database', 'seed data', 'sample data', 'populate database', 'db seed', 'test data', 'demo data', 'generate fixtures'.

755 installsAudited
deep-research logo

deep-research

jezweb/claude-skills

Deep research and discovery before building something new. Explores local projects for reusable code, researches competitors, reads forums and reviews, analyses plugin ecosystems, investigates technical options, and produces a comprehensive research brief. Three depths: focused (30 min), wide (1-2 hours), deep (3-6 hours). Triggers: 'research this', 'discovery', 'explore the space', 'what should I build', 'competitive analysis', 'before I start building', 'research before coding'. Not for cited fact-checking research reports (a separate harness does those); this is pre-build product discovery.

859 installs
design-loop logo

design-loop

jezweb/claude-skills

Autonomous multi-page site builder using a baton-passing loop. Each iteration reads a task from .design/next-prompt.md, generates a page in HTML/Tailwind, integrates it into the site, verifies visually, then writes the next task to keep the loop alive. Use whenever the user asks to build an entire site autonomously, build all pages of a site, generate multiple pages in sequence, or run a 'design loop' / 'baton loop' / 'autonomous site build' — even if they say 'just keep going' or 'build the next page' or 'next page' mid-flow.

651 installs
design-review logo

design-review

jezweb/claude-skills

Review a web app or page for visual design quality — layout, typography, spacing, colour, hierarchy, consistency, interaction patterns, and responsive behaviour. Not a UX audit (that checks usability) — this checks whether it looks professional and polished. Produces a design findings report with screenshots. Triggers: 'design review', 'does this look good', 'review the design', 'check the layout', 'is this polished', 'visual review', 'design audit', 'make it look better', 'it looks off'.

970 installs