skillZs
★ LIVE SKILL TAGS ★
>>> LIVE SKILLS INDEX <<<
* OPEN SOURCE *
NO LOGIN, NO TRACKING
※ REAL INSTALL DATA ※
← back to all skills
arnavpuri/designskills99 installs

color-palette

Generate accessible color palettes: OKLCH shade scales (50-950), tinted neutrals, semantic colors, WCAG contrast checks, dark-mode color remaps, gradients, and CSS/Tailwind color output. Use when the task is ONLY about color. Trigger phrases: "color palette", "color scheme", "generate colors", "shade scale", "color tokens", "color system", "accessible colors", "contrast ratio", "semantic colors", "palette from hex". For logo + fonts + guidelines use brand-identity; for full token/component systems (spacing, radius, components) use design-system; for complete dark themes use dark-mode.

How do I install this agent skill?

npx skills add https://github.com/arnavpuri/designskills --skill color-palette
view source ↗

Is this agent skill safe to install?

  • Gen Agent Trust Hubpass

    This skill provides comprehensive instructions for generating accessible color palettes and design systems using the OKLCH color model. It includes templates for CSS variables, Tailwind CSS configurations, and guidance on accessibility (WCAG) compliance. No malicious code or security vulnerabilities were identified.

  • Socketpass

    No alerts

  • Snykpass

    Risk: LOW · No issues

What does this agent skill do?

Color Palette Generation

Generate harmonious, accessible, and production-ready color systems from any starting point.

Prerequisites

Before generating colors, check for existing design context:

  • Read .agents/design-context.md (see the design-context skill). If it has a Color System, treat those hex values as the source of truth and extend them rather than replacing them.
  • If a design system already exists in the codebase (CSS variables, Tailwind theme, tokens.json), extend it rather than replacing it.

Naming convention (shared with design-system, layout-composition, etc.): primitive scales are --brand-50 … --brand-950, --gray-50 … --gray-950, --success-*, --warning-*, --error-*, --info-*; semantic tokens are --bg-*, --text-*, --border-*, --interactive-*, plus the brand aliases --color-primary, --color-secondary, --color-accent.


Step 1: Understand Color Theory Fundamentals

Generate palettes in OKLCH. Its lightness channel is perceptually even, so a fixed L step looks like the same visual step at every hue (in HSL, hsl(60 100% 50%) yellow is far lighter than hsl(240 100% 50%) blue at the "same" lightness). Use HSL only when a legacy tool forces it. Note that high-chroma OKLCH values can fall outside sRGB; reduce chroma (keep L and H) when converting to hex.

Color Wheel Relationships

HarmonyAngle(s) from baseFeel
Complementary180°High contrast, energetic
Analogous±30°Harmonious, natural
Triadic120°, 240°Vibrant, balanced
Split-comp.150°, 210°Contrast with less tension
Tetradic90°, 180°, 270°Rich, needs careful balance

Generating Harmonies in OKLCH

:root {
  /* Base brand color in oklch */
  --brand-hue: 250;         /* hue angle */
  --brand-chroma: 0.15;     /* chroma (not HSL saturation) */
  --brand-l: 0.55;          /* lightness */

  --color-primary:       oklch(var(--brand-l) var(--brand-chroma) var(--brand-hue));
  --color-complement:    oklch(var(--brand-l) var(--brand-chroma) calc(var(--brand-hue) + 180));
  --color-analogous-1:   oklch(var(--brand-l) var(--brand-chroma) calc(var(--brand-hue) + 30));
  --color-analogous-2:   oklch(var(--brand-l) var(--brand-chroma) calc(var(--brand-hue) - 30));
  --color-triadic-1:     oklch(var(--brand-l) var(--brand-chroma) calc(var(--brand-hue) + 120));
  --color-triadic-2:     oklch(var(--brand-l) var(--brand-chroma) calc(var(--brand-hue) + 240));
  --color-split-comp-1:  oklch(var(--brand-l) var(--brand-chroma) calc(var(--brand-hue) + 150));
  --color-split-comp-2:  oklch(var(--brand-l) var(--brand-chroma) calc(var(--brand-hue) + 210));
}

Step 2: Generate a Full Shade Scale (50-950)

From a single brand color, generate an 11-step lightness scale (50, 100-900, 950). In OKLCH, vary lightness while keeping hue stable and slightly reducing chroma at extremes.

Lightness Map

TokenOKLCH LightnessUsage
500.97Tinted background
1000.93Hover background
2000.87Active background
3000.78Borders
4000.68Placeholder text
5000.55Base / primary actions
6000.48Hover on primary
7000.40Active on primary
8000.32Headings on light bg
9000.24Body text on light bg
9500.16High-contrast text

CSS Implementation

:root {
  --brand-hue: 250;
  --brand-chroma: 0.15;

  --brand-50:  oklch(0.97 calc(var(--brand-chroma) * 0.3) var(--brand-hue));
  --brand-100: oklch(0.93 calc(var(--brand-chroma) * 0.4) var(--brand-hue));
  --brand-200: oklch(0.87 calc(var(--brand-chroma) * 0.5) var(--brand-hue));
  --brand-300: oklch(0.78 calc(var(--brand-chroma) * 0.7) var(--brand-hue));
  --brand-400: oklch(0.68 calc(var(--brand-chroma) * 0.85) var(--brand-hue));
  --brand-500: oklch(0.55 var(--brand-chroma) var(--brand-hue));
  --brand-600: oklch(0.48 var(--brand-chroma) var(--brand-hue));
  --brand-700: oklch(0.40 var(--brand-chroma) var(--brand-hue));
  --brand-800: oklch(0.32 calc(var(--brand-chroma) * 0.9) var(--brand-hue));
  --brand-900: oklch(0.24 calc(var(--brand-chroma) * 0.8) var(--brand-hue));
  --brand-950: oklch(0.16 calc(var(--brand-chroma) * 0.7) var(--brand-hue));
}

Step 3: Define Semantic Colors

Map purpose-driven tokens to your palette or define independent hues.

Recommended Semantic Hues

RoleHue (OKLCH)Rationale
Success145Green, universal "go"
Warning85Amber/yellow, caution
Error25Red, urgency
Info230Blue, neutral info
:root {
  /* Semantic: success */
  --success-50:  oklch(0.97 0.04 145);
  --success-400: oklch(0.68 0.15 145);  /* dark-mode foreground */
  --success-500: oklch(0.55 0.16 145);
  --success-700: oklch(0.40 0.14 145);

  /* Semantic: warning */
  --warning-50:  oklch(0.97 0.04 85);
  --warning-400: oklch(0.72 0.15 85);
  --warning-500: oklch(0.60 0.16 85);   /* ~4:1 on white: use dark text ON it, 700 for warning TEXT */
  --warning-700: oklch(0.45 0.14 85);

  /* Semantic: error */
  --error-50:  oklch(0.97 0.04 25);
  --error-400: oklch(0.68 0.16 25);
  --error-500: oklch(0.55 0.18 25);
  --error-700: oklch(0.40 0.16 25);

  /* Semantic: info */
  --info-50:  oklch(0.97 0.04 230);
  --info-400: oklch(0.68 0.12 230);
  --info-500: oklch(0.55 0.14 230);
  --info-700: oklch(0.40 0.12 230);
}

Generate the full 50-950 scale for a semantic hue only if the product needs it (alerts, badges, charts); 50/400/500/700 covers most UI.


Step 4: Generate a Neutral Scale

Neutrals are the backbone. Add a slight hue tint from the brand for warmth.

:root {
  --neutral-hue: var(--brand-hue);
  --neutral-chroma: 0.01; /* barely tinted */

  --gray-50:  oklch(0.98 var(--neutral-chroma) var(--neutral-hue));
  --gray-100: oklch(0.96 var(--neutral-chroma) var(--neutral-hue));
  --gray-200: oklch(0.90 var(--neutral-chroma) var(--neutral-hue));
  --gray-300: oklch(0.83 var(--neutral-chroma) var(--neutral-hue));
  --gray-400: oklch(0.71 var(--neutral-chroma) var(--neutral-hue));
  --gray-500: oklch(0.55 var(--neutral-chroma) var(--neutral-hue));
  --gray-600: oklch(0.45 var(--neutral-chroma) var(--neutral-hue));
  --gray-700: oklch(0.37 var(--neutral-chroma) var(--neutral-hue));
  --gray-800: oklch(0.27 var(--neutral-chroma) var(--neutral-hue));
  --gray-900: oklch(0.20 var(--neutral-chroma) var(--neutral-hue));
  --gray-950: oklch(0.13 var(--neutral-chroma) var(--neutral-hue));
}

Step 5: Ensure WCAG Accessibility

Contrast Requirements (WCAG 2.2 -- the current legal/industry standard)

LevelNormal textLarge text (≥24px, or ≥18.66px / 14pt bold)Non-text UI (icons, borders, focus rings, chart marks)
WCAG AA4.5:13:13:1 against adjacent colors (SC 1.4.11)
WCAG AAA7:14.5:1--

Contrast ratio = (L1 + 0.05) / (L2 + 0.05), where L1/L2 are the lighter/darker relative luminance (0.2126 R + 0.7152 G + 0.0722 B on linearized sRGB). Ratios are not rounded up: 4.49:1 fails. APCA (Lc values) is a draft candidate for WCAG 3 -- useful as a second opinion, especially for dark mode, but never report it as the compliance standard.

Practical Rules

  • Body text on light bg: use 900 or 950 shade (passes AA comfortably with the lightness map above).
  • Body text on dark bg: use 50 or 100 shade.
  • Primary buttons: white text on 500+ shade usually passes (L 0.55 blue ≈ 4.9:1), but yellows/ambers/cyans at L 0.55-0.65 often fail -- use dark text on those. Always measure.
  • Disabled states: use 400 shade on light bg. Disabled elements are exempt from WCAG but should still be distinguishable.
  • Links: must be distinguishable from surrounding text by more than color alone -- underline them, or give them 3:1 contrast against the surrounding text plus a non-color cue on hover/focus.

Quick Contrast Check via OKLCH Lightness

For near-neutral colors, relative luminance ≈ L³, so a lightness gap of about 0.42-0.45+ is needed for 4.5:1 at the extremes (and more in the mid-range). Use it only to pick candidates, then measure.

text L 0.20 | bg L 0.97 | diff 0.77 -> ~16.6:1, passes AAA
text L 0.55 | bg L 0.97 | diff 0.42 -> ~4.5:1, borderline AA -- measure; safe for large text
text L 0.57 | bg L 0.97 | diff 0.40 -> ~4.1:1, FAILS AA for normal text

Measure, Don't Guess

Browsers render OKLCH directly, but design-context stores hex and contrast must be computed on sRGB. Use the bundled scripts (<color-palette> and <design-context> are those skills' directories):

python <color-palette>/scripts/palette.py --from "#2563eb"                 # scale around a brand color
python <color-palette>/scripts/palette.py 250 0.15 --name brand --css      # hue + chroma -> CSS vars
python <color-palette>/scripts/palette.py 250 0.02 --name gray --json      # neutrals as JSON
python <design-context>/scripts/contrast.py "#ffffff" "#2563eb"             # any real pairing

palette.py prints each step's hex and contrast on white/black, marked AA (4.5:1), large/UI (3:1) or -. Out-of-gamut steps lose chroma, never lightness or hue. contrast.py exits 1 on a failure and suggests the nearest passing shade.

Also check every real text/background pairing you ship (text on --bg-*, button label on --interactive-*, dark-mode pairs), not just against pure white/black.


Step 6: Dark Mode Adaptation

Do NOT simply invert the scale. Instead, remap semantic usage.

Dark Mode Strategy

[data-theme="dark"] {
  /* Backgrounds: use 900/950 instead of 50/white */
  --bg-primary:   var(--gray-950);
  --bg-secondary: var(--gray-900);
  --bg-tertiary:  var(--gray-800);

  /* Text: use 50/100 instead of 900/950 */
  --text-primary:   var(--gray-50);
  --text-secondary: var(--gray-300);
  --text-tertiary:  var(--gray-400);

  /* Surfaces: slightly lighter than bg */
  --surface:       var(--gray-900);
  --surface-hover: var(--gray-800);

  /* Borders: use 700 instead of 200 */
  --border-default: var(--gray-700);

  /* Brand colors: increase lightness for dark bg */
  --interactive-primary: var(--brand-400); /* lighter than 500 */

  /* Semantic: bump to lighter shades */
  --color-success: var(--success-400);
  --color-warning: var(--warning-400);
  --color-error:   var(--error-400);
}

These names must match the light-mode Layer 2 tokens in Step 10 -- dark mode only remaps them. For a full dark theme (elevation surfaces, images, toggles) hand off to the dark-mode skill.

Key Principles

  1. Reduce contrast slightly -- pure white on pure black is harsh. Use gray-50 on gray-950.
  2. Reduce chroma slightly in dark mode -- saturated colors glow on dark backgrounds.
  3. Elevations in dark mode use lighter surfaces (opposite of light mode shadows).

Step 7: Color Psychology by Industry

IndustryPrimary colorsWhy
FinanceNavy, dark blue, greenTrust, stability, growth
HealthBlue, teal, whiteCalm, cleanliness, trust
FoodRed, orange, yellowAppetite, energy, warmth
Tech/SaaSBlue, violet, cyanInnovation, reliability
LuxuryBlack, gold, deep purpleElegance, exclusivity
Eco/GreenGreen, earth tonesNature, sustainability
EducationBlue, orange, greenTrust, enthusiasm, growth
CreativeBold primaries, neonsEnergy, expression, fun

Step 8: Gradient Combinations

Rules for Effective Gradients

  1. Stay within 60 degrees of hue rotation for subtle gradients.
  2. Use 90-180 degrees for vibrant, energetic gradients.
  3. Writing stops in oklch() does NOT make the gradient interpolate in OKLCH. Without an interpolation hint, browsers use Oklab for modern colors and sRGB for hex/rgb/hsl stops -- both go straight through the color space and can pass through gray between distant hues. Add in oklch to interpolate around the hue wheel (add longer hue for rainbow sweeps).
  4. Or add a mid stop with a slight chroma boost to avoid the "gray dead zone."
/* Subtle brand gradient */
.gradient-subtle {
  background: linear-gradient(
    135deg in oklch,
    oklch(0.55 0.15 250),
    oklch(0.55 0.15 280)
  );
}

/* Vibrant hero gradient */
.gradient-vibrant {
  background: linear-gradient(
    135deg in oklch,
    oklch(0.65 0.20 280),
    oklch(0.60 0.22 330),
    oklch(0.65 0.20 20)
  );
}

/* Mesh gradient (modern trend) */
.gradient-mesh {
  background:
    radial-gradient(at 0% 0%, oklch(0.70 0.15 280) 0%, transparent 50%),
    radial-gradient(at 100% 0%, oklch(0.70 0.15 200) 0%, transparent 50%),
    radial-gradient(at 100% 100%, oklch(0.70 0.15 330) 0%, transparent 50%),
    oklch(0.97 0.01 250);
}

Step 9: Tailwind Config Generation

Tailwind v4 (CSS-first) -- put the scale in @theme, which generates bg-brand-500, text-brand-900, etc.:

@import "tailwindcss";
@theme {
  --color-brand-50:  oklch(0.97 0.045 250);
  --color-brand-500: oklch(0.55 0.15 250);
  --color-brand-900: oklch(0.24 0.12 250);
  /* ...every step 50-950, plus success/warning/error/info */
}

Tailwind v3 (tailwind.config.js):

// tailwind.config.js
const brand = {
  50:  'oklch(0.97 0.045 250)',
  100: 'oklch(0.93 0.06 250)',
  200: 'oklch(0.87 0.075 250)',
  300: 'oklch(0.78 0.105 250)',
  400: 'oklch(0.68 0.1275 250)',
  500: 'oklch(0.55 0.15 250)',
  600: 'oklch(0.48 0.15 250)',
  700: 'oklch(0.40 0.15 250)',
  800: 'oklch(0.32 0.135 250)',
  900: 'oklch(0.24 0.12 250)',
  950: 'oklch(0.16 0.105 250)',
};

module.exports = {
  theme: {
    extend: {
      colors: {
        brand,
        success: { /* ... same pattern, hue 145 */ },
        warning: { /* ... same pattern, hue 85 */ },
        error:   { /* ... same pattern, hue 25 */ },
        info:    { /* ... same pattern, hue 230 */ },
      },
    },
  },
};

Step 10: CSS Custom Properties Architecture

Structure tokens in three layers:

/* Layer 1: Primitive (raw values) */
:root {
  --brand-500: oklch(0.55 0.15 250);
  --error-500: oklch(0.55 0.18 25);
  /* ...full --brand-*, --gray-*, semantic scales from Steps 2-4 */
}

/* Layer 2: Semantic (purpose) -- same names design-system uses */
:root {
  --color-primary:       var(--brand-500);
  --interactive-primary: var(--brand-500);
  --color-error:         var(--error-500);
  --bg-primary:          var(--gray-50);
  --text-primary:        var(--gray-900);
  --border-default:      var(--gray-200);
}

/* Layer 3: Component (scoped) */
.btn-primary {
  background: var(--interactive-primary);
  color: white; /* verified >= 4.5:1 against brand-500 */
}

This three-layer approach makes theming and dark mode trivial -- you only remap Layer 2.


Step 11: Verify Visually and Save to Design Context

  1. Render a swatch sheet: write a small HTML file (scratchpad) showing each scale as a row of swatches labeled with token, hex, and contrast vs white/black, plus sample text/button pairings in light AND dark mode. Screenshot it (e.g. npx playwright screenshot --full-page "file://$PWD/swatches.html" swatches.png; add --color-scheme=dark for the dark pass) and look at the image with Read. Check that steps look evenly spaced, no step is muddy or neon, and neutrals read as neutral.
  2. Offer to write back to .agents/design-context.md (the design-context skill's file). Update only the Color System rows that changed; never rewrite the whole file. Map the scale to the design-context roles as hex:
design-context roleTake from
Primary--brand-500 (or 600 if 500 fails 4.5:1 with white text)
Primary Light / Primary Dark--brand-400 / --brand-700
Secondary / Accent500 step of the secondary / accent hue
Neutral 50 / 100 / 200 / 500 / 800 / 900matching --gray-* steps
Success / Warning / Error--success-500 / --warning-500 / --error-500

Show the user a before/after diff of the changed rows and ask before saving.


Quick Reference: Palette from a Single Hex

  1. Read .agents/design-context.md; convert the brand hex to OKLCH.
  2. Extract hue. This is your brand hue.
  3. Generate 50-950 scale using the lightness map in Step 2.
  4. Generate neutrals tinted with brand hue (Step 4).
  5. Pick semantic hues (Step 3).
  6. Measure contrast with palette.py / contrast.py (Step 5) -- fix failures before continuing.
  7. Build dark mode remap (Step 6).
  8. Export as CSS custom properties or Tailwind config.
  9. Render and inspect a swatch sheet; offer to save hex values to design-context (Step 11).

Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.

<a href="https://skillzs.dev/skills/arnavpuri/designskills/color-palette">View color-palette on skillZs</a>