{"slug":"color-ops","title":"color-ops","summary":"Color for developers: color spaces, accessibility contrast, palette generation, CSS color functions, design tokens, dark mode. Triggers on: color, palette, contrast, WCAG, APCA, OKLCH, color-mix, dark mode colors, design tokens, CVD, color blind, P3, sRGB.","platform":"Claude","tags":[],"authorName":"LLM Mart","authorSlug":"llm-mart","score":0,"source":"github","price":null,"verified":false,"createdAt":"2026-09-30T19:36:42.464564Z","repo":{"url":"https://github.com/0xDarkMatter/claude-mods","stars":43,"forks":7,"license":"MIT","updatedAt":"2026-09-30T15:18:48Z"},"bodyHtml":"<hr>\n<h2>name: color-ops\ndescription: \"Color for developers: color spaces, accessibility contrast, palette generation, CSS color functions, design tokens, dark mode. Triggers on: color, palette, contrast, WCAG, APCA, OKLCH, color-mix, dark mode colors, design tokens, CVD, color blind, P3, sRGB.\"\nlicense: MIT\nallowed-tools: \"Read Write Bash\"\nmetadata:\nauthor: claude-mods\nrelated-skills: tailwind-ops, react-ops, frontend-design</h2>\n<h1>Color Operations</h1>\n<p>Practical color knowledge for developers and designers. Covers color spaces, accessibility, palette generation, CSS implementation, and design token architecture.</p>\n<blockquote>\n<p>Inspired by <a href=\"https://github.com/meodai/skill.color-expert\">meodai/skill.color-expert</a> - a comprehensive 286K-word color science knowledge base with 113 reference files. This is a lightweight operational skill for everyday frontend and design work. For deep color science (spectral mixing, historical color theory, CAM16, pigment physics), install the full skill.</p>\n</blockquote>\n<h2>Color Space Decision Table</h2>\n<p>Pick the right space for the task. This is the single most impactful color decision you'll make.</p>\n<table>\n<thead>\n<tr>\n<th>Task</th>\n<th>Use</th>\n<th>Why</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Perceptual color manipulation</td>\n<td><strong>OKLCH</strong></td>\n<td>Best uniformity for lightness, chroma, hue</td>\n</tr>\n<tr>\n<td>CSS gradients &amp; palettes</td>\n<td><strong>OKLCH</strong> or <code>color-mix(in oklab)</code></td>\n<td>No mid-gradient grey/brown deadzone</td>\n</tr>\n<tr>\n<td>Gamut-aware color picking</td>\n<td><strong>OKHSL / OKHSV</strong></td>\n<td>Cylindrical like HSL but perceptually grounded</td>\n</tr>\n<tr>\n<td>Normalized saturation (0-100%)</td>\n<td><strong>HSLuv</strong></td>\n<td>CIELUV chroma normalized per hue/lightness</td>\n</tr>\n<tr>\n<td>Print workflows</td>\n<td><strong>CIELAB D50</strong></td>\n<td>ICC standard illuminant</td>\n</tr>\n<tr>\n<td>Screen workflows</td>\n<td><strong>OKLAB</strong></td>\n<td>D65 standard, perceptually uniform</td>\n</tr>\n<tr>\n<td>Color difference (precision)</td>\n<td><strong>CIEDE2000</strong></td>\n<td>Gold standard perceptual distance metric</td>\n</tr>\n<tr>\n<td>Color difference (fast)</td>\n<td><strong>Euclidean in OKLAB</strong></td>\n<td>Good enough for most applications</td>\n</tr>\n<tr>\n<td>Quick prototyping</td>\n<td><strong>HSL</strong></td>\n<td>Simple, fast, every tool supports it</td>\n</tr>\n</tbody>\n</table>\n<h3>Why HSL Falls Short</h3>\n<p>HSL is fine for quick prototyping. It fails for anything perceptual:</p>\n<ul>\n<li><strong>Lightness is a lie</strong>: <code>hsl(60,100%,50%)</code> (yellow) and <code>hsl(240,100%,50%)</code> (blue) have the same L=50% but vastly different perceived brightness</li>\n<li><strong>Hue is non-uniform</strong>: 20 degrees near red is a dramatic shift; 20 degrees near green is barely visible</li>\n<li><strong>Saturation doesn't correlate</strong>: S=100% dark blue still looks muted</li>\n</ul>\n<p><strong>Rule of thumb</strong>: Use HSL for throwaway work. Use OKLCH for anything that ships.</p>\n<h3>Key Distinctions</h3>\n<ul>\n<li><strong>Chroma</strong> = colorfulness relative to a same-lightness neutral</li>\n<li><strong>Saturation</strong> = perceived colorfulness relative to the color's own brightness</li>\n<li><strong>Lightness</strong> = perceived reflectance relative to a similarly lit white</li>\n<li>Same chroma != same saturation. These are different dimensions.</li>\n</ul>\n<h2>Accessibility - Contrast Numbers That Matter</h2>\n<h3>The Odds Are Against You</h3>\n<p>Of ~281 trillion hex color pairs:</p>\n<table>\n<thead>\n<tr>\n<th>Threshold</th>\n<th>% passing</th>\n<th>Odds</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>WCAG 3:1 (large text)</td>\n<td>26.49%</td>\n<td>~1 in 4</td>\n</tr>\n<tr>\n<td>WCAG 4.5:1 (AA body)</td>\n<td>11.98%</td>\n<td>~1 in 8</td>\n</tr>\n<tr>\n<td>WCAG 7:1 (AAA)</td>\n<td>3.64%</td>\n<td>~1 in 27</td>\n</tr>\n<tr>\n<td>APCA 60</td>\n<td>7.33%</td>\n<td>~1 in 14</td>\n</tr>\n<tr>\n<td>APCA 75 (fluent reading)</td>\n<td>1.57%</td>\n<td>~1 in 64</td>\n</tr>\n<tr>\n<td>APCA 90 (preferred body)</td>\n<td>0.08%</td>\n<td>~1 in 1,250</td>\n</tr>\n</tbody>\n</table>\n<h3>WCAG vs APCA</h3>\n<table>\n<thead>\n<tr>\n<th></th>\n<th>WCAG 2.x</th>\n<th>APCA (WCAG 3 draft)</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Model</td>\n<td>Simple luminance ratio</td>\n<td>Perceptual contrast, polarity-aware</td>\n</tr>\n<tr>\n<td>Dark-on-light vs light-on-dark</td>\n<td>Same ratio</td>\n<td>Different - accounts for spatial frequency</td>\n</tr>\n<tr>\n<td>Text size/weight</td>\n<td>Only large vs normal</td>\n<td>Continuous scale with font lookup table</td>\n</tr>\n<tr>\n<td>Accuracy</td>\n<td>Known problems with blue, dark mode</td>\n<td>Much better perceptual accuracy</td>\n</tr>\n<tr>\n<td>Status</td>\n<td>Current standard, legally referenced</td>\n<td>Draft - not yet a requirement</td>\n</tr>\n</tbody>\n</table>\n<p><strong>Practical guidance</strong>: Test with WCAG 2.x for compliance. Use APCA for better perceptual results. When they disagree, APCA is usually more accurate.</p>\n<h3>Quick Contrast Checks</h3>\n<pre><code>/* Use relative color syntax to auto-generate readable text */\n--surface: oklch(0.95 0.02 250);\n--on-surface: oklch(from var(--surface) calc(l - 0.6) c h);\n\n/* Or simpler: light surface = dark text, dark surface = light text */\n--text: oklch(from var(--surface) calc(1 - l) 0 h);\n</code></pre>\n<pre><code>// Quick WCAG 2.x relative luminance contrast\nfunction contrastRatio(l1, l2) {\n  const lighter = Math.max(l1, l2);\n  const darker = Math.min(l1, l2);\n  return (lighter + 0.05) / (darker + 0.05);\n}\n\nfunction relativeLuminance(r, g, b) {\n  const [rs, gs, bs] = [r, g, b].map(c =&gt; {\n    c /= 255;\n    return c &lt;= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;\n  });\n  return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;\n}\n</code></pre>\n<h3>Color Vision Deficiency (CVD)</h3>\n<p>~8% of men and ~0.5% of women have some form of color vision deficiency. Design accordingly.</p>\n<table>\n<thead>\n<tr>\n<th>Type</th>\n<th>Affects</th>\n<th>Prevalence</th>\n<th>What breaks</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Protanopia</td>\n<td>Red perception</td>\n<td>~1% men</td>\n<td>Red/green distinction, red appears dark</td>\n</tr>\n<tr>\n<td>Deuteranopia</td>\n<td>Green perception</td>\n<td>~1% men</td>\n<td>Red/green distinction (most common)</td>\n</tr>\n<tr>\n<td>Tritanopia</td>\n<td>Blue perception</td>\n<td>~0.01%</td>\n<td>Blue/yellow distinction (rare)</td>\n</tr>\n</tbody>\n</table>\n<p><strong>Rules</strong>:</p>\n<ul>\n<li>Never use color alone to convey information (add icons, labels, patterns)</li>\n<li>Test with CVD simulation tools (see references)</li>\n<li>Red/green is the most dangerous pair - always add a secondary signal</li>\n</ul>\n<h2>CSS Color Functions - Modern Syntax</h2>\n<h3>Core Functions (Baseline 2024+)</h3>\n<pre><code>/* OKLCH - the recommended default */\ncolor: oklch(0.7 0.15 150);           /* lightness chroma hue */\ncolor: oklch(0.7 0.15 150 / 0.5);     /* with alpha */\n\n/* OKLAB - for interpolation and mixing */\ncolor: oklab(0.7 -0.1 0.1);           /* lightness a b */\n\n/* color-mix() - blend two colors in any space */\ncolor: color-mix(in oklch, #3b82f6 70%, white);\ncolor: color-mix(in oklab, var(--primary), black 20%);\n\n/* Relative color syntax - transform existing colors */\ncolor: oklch(from var(--brand) calc(l + 0.1) c h);          /* lighten */\ncolor: oklch(from var(--brand) calc(l - 0.1) c h);          /* darken */\ncolor: oklch(from var(--brand) l calc(c * 0.5) h);          /* desaturate */\ncolor: oklch(from var(--brand) l c calc(h + 180));           /* complement */\n\n/* P3 wide gamut */\ncolor: color(display-p3 1 0.5 0);     /* ~25% more colors than sRGB */\n\n/* Fallback pattern for wide gamut */\ncolor: #ff8800;                        /* sRGB fallback */\ncolor: oklch(0.79 0.17 70);           /* oklch version */\ncolor: color(display-p3 1 0.55 0);    /* P3 if supported */\n</code></pre>\n<h3>Gradients That Don't Muddy</h3>\n<pre><code>/* BAD - RGB interpolation goes through grey/brown */\nbackground: linear-gradient(to right, blue, yellow);\n\n/* GOOD - OKLCH interpolation stays vivid */\nbackground: linear-gradient(in oklch, blue, yellow);\n\n/* GOOD - OKLAB also works well */\nbackground: linear-gradient(in oklab, blue, yellow);\n\n/* Longer hue path for rainbow-style gradients */\nbackground: linear-gradient(in oklch longer hue, red, red);\n</code></pre>\n<h2>Design Token Architecture</h2>\n<h3>Three-Layer Pattern</h3>\n<pre><code>/* Layer 1: Reference tokens (the palette) */\n:root {\n  --ref-blue-50: oklch(0.97 0.01 250);\n  --ref-blue-100: oklch(0.93 0.03 250);\n  --ref-blue-500: oklch(0.62 0.18 250);\n  --ref-blue-900: oklch(0.25 0.09 250);\n  --ref-red-500: oklch(0.63 0.22 25);\n  --ref-neutral-50: oklch(0.97 0.005 250);\n  --ref-neutral-900: oklch(0.15 0.005 250);\n}\n\n/* Layer 2: Semantic tokens (meaning) */\n:root {\n  --color-surface: var(--ref-neutral-50);\n  --color-on-surface: var(--ref-neutral-900);\n  --color-primary: var(--ref-blue-500);\n  --color-error: var(--ref-red-500);\n  --color-border: oklch(from var(--color-surface) calc(l - 0.15) 0.01 h);\n}\n\n/* Layer 3: Dark mode swaps semantics, not components */\n[data-theme=\"dark\"] {\n  --color-surface: var(--ref-neutral-900);\n  --color-on-surface: var(--ref-neutral-50);\n  --color-primary: var(--ref-blue-100);\n  --color-border: oklch(from var(--color-surface) calc(l + 0.15) 0.01 h);\n}\n</code></pre>\n<h3>Generating Scales in OKLCH</h3>\n<pre><code>// Generate a perceptually uniform color scale\nfunction generateScale(hue, steps = 10) {\n  return Array.from({ length: steps }, (_, i) =&gt; {\n    const t = i / (steps - 1);\n    return {\n      step: (i + 1) * 100,  // 100..1000\n      l: 0.97 - t * 0.82,   // 0.97 (lightest) to 0.15 (darkest)\n      c: Math.sin(t * Math.PI) * 0.18,  // peak chroma in midtones\n      h: hue,\n    };\n  });\n}\n\n// Usage: generateScale(250) for a blue scale\n// Format: oklch(${l} ${c} ${h})\n</code></pre>\n<h2>Palette &amp; Harmony</h2>\n<h3>What Actually Works</h3>\n<p>Geometric hue harmony (complementary, triadic, etc.) is a weak predictor of good palettes on its own. Better approaches:</p>\n<ul>\n<li><strong>Character-first</strong>: Organize by mood (pale/muted/deep/vivid/dark). Chroma + lightness drive emotional response more than hue.</li>\n<li><strong>60-30-10 rule</strong>: 60% dominant, 30% secondary, 10% accent. One color dominates.</li>\n<li><strong>Lightness variation = legibility</strong>: Same character + varied lightness is readable. Same lightness across hues is illegible.</li>\n<li><strong>Grayscale sanity check</strong>: If your UI doesn't work in grayscale, the color system has a structural problem.</li>\n</ul>\n<h3>Practical Palette Workflow</h3>\n<ol>\n<li>Pick a brand hue in OKLCH</li>\n<li>Generate a 10-step scale (lightness 0.97 to 0.15, chroma peaks at midtones)</li>\n<li>Pick a neutral (same hue, near-zero chroma) for another 10-step scale</li>\n<li>Add 1-2 semantic accent hues (success green, error red, warning amber)</li>\n<li>Map to semantic tokens: surface, on-surface, primary, secondary, error</li>\n<li>Test contrast at every text/surface combination (WCAG 4.5:1 minimum)</li>\n<li>Swap semantic mappings for dark mode (don't just invert)</li>\n</ol>\n<h3>Quick Harmony Shortcuts</h3>\n<pre><code>/* Complementary (opposite hue) */\n--complement: oklch(from var(--primary) l c calc(h + 180));\n\n/* Analogous (adjacent hues) */\n--analogous-1: oklch(from var(--primary) l c calc(h - 30));\n--analogous-2: oklch(from var(--primary) l c calc(h + 30));\n\n/* Triadic */\n--triadic-1: oklch(from var(--primary) l c calc(h + 120));\n--triadic-2: oklch(from var(--primary) l c calc(h + 240));\n\n/* Tint (lighter, less chroma) */\n--tint: oklch(from var(--primary) calc(l + 0.2) calc(c * 0.5) h);\n\n/* Shade (darker, slightly less chroma) */\n--shade: oklch(from var(--primary) calc(l - 0.2) calc(c * 0.8) h);\n</code></pre>\n<h2>Gamut &amp; Wide Color</h2>\n<h3>sRGB vs P3 vs Rec2020</h3>\n<table>\n<thead>\n<tr>\n<th>Gamut</th>\n<th>Coverage</th>\n<th>Support</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>sRGB</td>\n<td>Baseline</td>\n<td>Universal - every screen</td>\n</tr>\n<tr>\n<td>Display P3</td>\n<td>~25% more than sRGB</td>\n<td>Modern Apple, high-end Android, new monitors</td>\n</tr>\n<tr>\n<td>Rec2020</td>\n<td>~37% more than P3</td>\n<td>HDR content, limited device support</td>\n</tr>\n</tbody>\n</table>\n<pre><code>/* Progressive enhancement for wide gamut */\n.brand-accent {\n  /* sRGB fallback - every browser */\n  background: #ff6b00;\n\n  /* P3 if supported - more vivid */\n  @supports (color: color(display-p3 1 0 0)) {\n    background: color(display-p3 1 0.42 0);\n  }\n}\n\n/* Or use @media for gamut detection */\n@media (color-gamut: p3) {\n  :root {\n    --accent: oklch(0.75 0.2 50);  /* Can push chroma higher in P3 */\n  }\n}\n</code></pre>\n<h3>Gamut Mapping</h3>\n<p>When a color is out of gamut (e.g., high-chroma OKLCH on an sRGB screen), browsers clamp it. Control this:</p>\n<pre><code>/* Browser auto-maps (default) */\ncolor: oklch(0.7 0.3 150);  /* if out of sRGB, browser reduces chroma */\n\n/* Explicit gamut check in JS */\n// CSS.supports('color', 'color(display-p3 1 0 0)')\n</code></pre>\n<h2>Scripts</h2>\n<p>Zero-dependency Node.js tools. Run directly or let Claude invoke them during color tasks.</p>\n<h3>Contrast Checker</h3>\n<pre><code>node scripts/contrast-check.js &lt;color1&gt; &lt;color2&gt;\nnode scripts/contrast-check.js \"#1a1a2e\" \"#e0e0e0\"\nnode scripts/contrast-check.js \"oklch(0.15 0.02 250)\" \"oklch(0.9 0.01 250)\"\n</code></pre>\n<p>Returns WCAG 2.x contrast ratio with AA/AAA pass/fail for normal and large text.</p>\n<h3>Palette Generator</h3>\n<pre><code>node scripts/palette-gen.js &lt;hue&gt; [name] [--neutral] [--json]\nnode scripts/palette-gen.js 250 blue              # 10-step blue scale\nnode scripts/palette-gen.js 250 blue --neutral     # + matching neutral scale\nnode scripts/palette-gen.js 30 orange --json       # JSON output\n</code></pre>\n<p>Generates a perceptually uniform 10-step OKLCH scale (100-1000) as CSS custom properties. Chroma peaks at midtones via sine curve. Flags out-of-gamut sRGB values.</p>\n<h3>Color Converter</h3>\n<pre><code>node scripts/color-convert.js &lt;color&gt;\nnode scripts/color-convert.js \"#3b82f6\"\nnode scripts/color-convert.js \"oklch(0.62 0.18 250)\"\nnode scripts/color-convert.js \"hsl(217, 91%, 60%)\"\n</code></pre>\n<p>Converts any color to all formats: hex, rgb, hsl, oklch, oklab. Shows relative luminance and sRGB gamut status.</p>\n<h3>Harmony Generator</h3>\n<pre><code>node scripts/harmony-gen.js &lt;color|hue&gt; [scheme] [--css] [--json] [--tokens] [--tints]\nnode scripts/harmony-gen.js \"#3b82f6\" triadic      # Triadic palette from hex\nnode scripts/harmony-gen.js 250 complementary --tokens  # Design tokens\nnode scripts/harmony-gen.js 30 earth               # Earth tone palette\nnode scripts/harmony-gen.js random                  # Curated random palette\n</code></pre>\n<p>12 harmony schemes: <code>complementary</code>, <code>analogous</code>, <code>triadic</code>, <code>split</code>, <code>tetradic</code>, <code>monochromatic</code>, <code>warm</code>, <code>cool</code>, <code>earth</code>, <code>pastel</code>, <code>vibrant</code>, <code>random</code>. All output gamut-clamped to sRGB. Use <code>--tokens</code> for semantic design tokens (primary, secondary, accent, surface), <code>--tints</code> for tint/shade/muted variants per color.</p>\n<h2>Agent Dispatch</h2>\n<p>For complex color work beyond this skill's scope, dispatch to specialized agents:</p>\n<ul>\n<li><strong>Palette generation algorithms</strong> (RampenSau, Poline, IQ cosine): Route to <code>frontend-design</code> skill or a dedicated subagent with <code>references/tools-and-libraries.md</code> preloaded</li>\n<li><strong>Accessibility audits</strong> (full APCA + CVD simulation): Route to a subagent that runs contrast checks across all component/token combinations</li>\n<li><strong>Design system color architecture</strong>: Route to <code>tailwind-ops</code> for Tailwind-specific implementation, or handle directly for CSS custom properties</li>\n</ul>\n<h2>Reference Files</h2>\n<table>\n<thead>\n<tr>\n<th>File</th>\n<th>Content</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>references/tools-and-libraries.md</code></td>\n<td>Palette generators, analysis tools, color libraries, online tools, browser extensions</td>\n</tr>\n<tr>\n<td><code>references/css-color-reference.md</code></td>\n<td>Complete CSS Color Level 4/5 function reference, browser support, conversion formulas</td>\n</tr>\n</tbody>\n</table>\n<h2>See Also</h2>\n<ul>\n<li><code>tailwind-ops</code> - Tailwind color configuration and dark mode patterns</li>\n<li><code>react-ops</code> - Theme context and color mode implementation in React</li>\n<li><a href=\"https://github.com/meodai/skill.color-expert\">meodai/skill.color-expert</a> - Full color science skill (113 references, spectral mixing, historical theory)</li>\n<li><a href=\"https://oklch.com/\">oklch.com</a> - Interactive OKLCH picker by Evil Martians</li>\n<li><a href=\"https://huetone.ardov.me/\">Huetone</a> - Accessible color system builder</li>\n</ul>\n","files":[{"path":"assets/.gitkeep","sizeBytes":0,"isText":false},{"path":"references/css-color-reference.md","sizeBytes":8698,"isText":true},{"path":"references/tools-and-libraries.md","sizeBytes":4368,"isText":true},{"path":"scripts/color-convert.js","sizeBytes":6387,"isText":true},{"path":"scripts/contrast-check.js","sizeBytes":4683,"isText":true},{"path":"scripts/harmony-gen.js","sizeBytes":14069,"isText":true},{"path":"scripts/palette-gen.js","sizeBytes":4465,"isText":true},{"path":"SKILL.md","sizeBytes":14501,"isText":true}],"reviewScore":null,"reviewSummary":null,"trust":{"provenance":"trusted-source-unreviewed","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow.","bodySource":null},"bodyLocked":false,"purchaseUrl":null,"sourceUrl":null,"report":{"provenance":"trusted-source-unreviewed","screen":{"ran":true,"outcome":"clean","suspicious":0,"notes":0,"hiddenCharacters":false},"virusScan":{"engine":"clamav","status":"clean","scannedAt":"2026-09-30T19:37:16.420103Z","sha256":"6608C4B9CAEB8804C78C82C384F59CFDEFEEEDCAE29A49CE160EDA2E17F790EB","sizeBytes":22768},"review":null,"source":{"repositoryUrl":"https://github.com/0xDarkMatter/claude-mods","path":"skills/color-ops","license":"MIT","commit":"3dfaf0ba5753026a99ee13f9d9ed56b9793bb6e8","subtreeSha":"0F97C80BFF667E08E5C0720927B39E40CA0A18AEB78485676605641D00B204D0","lastSyncedAt":"2026-09-30T19:37:28.226022Z"},"reviewedAt":"2026-09-30T19:38:17.570623Z","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow."},"install":[{"target":"skills-cli","command":"npx skills add https://github.com/0xDarkMatter/claude-mods/tree/main/skills/color-ops"},{"target":"claude-code","command":"claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install 0xdarkmatter-claude-mods@llmmart"},{"target":"git","command":"git clone https://github.com/0xDarkMatter/claude-mods.git"}]}