From surface
The color & light lens for a frontend build — where the palette gets its perceptual foundation, dark mode gets its re-tuned ramp, contrast gets verified, and data-viz gets a rigorous scale. Use when establishing a color system from scratch, auditing an existing palette for coherence or accessibility failures, designing a dark theme, or building a data visualization. The one shift: every color is a TOKEN in a perceptual system (oklch), dark is a re-tuned ramp (never invert()), and contrast is verified at DESIGN time — the agent emits plausible-but-incoherent hexes and feels no wrongness, so the palette must be a DECIDED system. Triggers on "color palette / oklch / perceptual color", "dark mode / dark theme / re-tuned ramp", "contrast / WCAG / APCA / accessibility", "semantic colors / tokens / color system", "data visualization color / colorblind / sequential / diverging / categorical", "neutral ramp / temperature / gray", "make the colors work / feel right / coherent palette".
How this skill is triggered — by the user, by Claude, or both
Slash command
/surface:color [the UI / design system / data visualization to give a coherent color language][the UI / design system / data visualization to give a coherent color language]This skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
<!--
!checklist init ${CLAUDE_SKILL_DIR} --force
An atelier (a craftsman's studio) is named for the discipline of the hand — careful, deliberate, derived. color is the color & light lens of the atelier suite: where the other skills decide what is true and what is composed, color decides what every hue, tone, and value actually is — and makes that a system, not a scatter of hand-picked hexes. Its product is a tokenized color system: a perceptual neutral ramp with a chosen temperature, semantic role tokens mapped to that ramp, a correctly engineered dark theme, contrast verified at design time, and a data-viz scale engineered for perceptual uniformity and colorblind safety — each committed before components consume it. It runs across gated stages and will not advance past a GATE until the checklist tool clears it — order enforced, substance yours.
The governing fact: color coherence is not a matter of taste applied per component — it is a matter of deriving every value from a small, decided system. The same blue typed as #2563eb in one component and #2f6ae0 in another, a neutral gray that is just #888888, a dark mode that runs filter: invert(), a data viz that uses a stock rainbow — each is a hand-picked value, and their sum is the perceptual incoherence the eye reads as "off" without being able to name it. The craft is the same subtraction the suite preaches everywhere: define a small system (one perceptual space, one neutral temperature, a handful of semantic roles, one contrast target), then derive every concrete value from it. Do that and two things happen — the palette becomes coherent (a thousand component colors agree because they came from ten tokens), and it becomes evolvable (dark mode, re-theme, or rebrand by remapping the alias layer, not finding-and-replacing scattered hex).
This is where the agent era bites:
oklch(0.62 0.18 250) as a primary blue and oklch(0.60 0.17 248) for success green — close enough to look intentional, wrong enough to read as undesigned. It has no nervous system to flinch at a secondary text color that fails WCAG. The values must come from a decided system, not per-call taste.filter: invert(), a rainbow palette for a data series, color: gray for disabled, border-color: #ccc per component. Each is the move that looks like the craft and isn't.--color-primary: oklch(0.62 0.18 250) in CSS and then hardcodes color: '#2563eb' in a React inline style — two palettes, one in each language, that will silently drift. The design system is itself state; it gets one source of truth (see atelier:systems).Speak the user's language. The decisions are the user's — which neutral temperature (warm / cool / brand-tinted), which accent hue, what the contrast targets are, whether the surface skews editorial or product. Read their fluency and gloss a term on first use (perceptual color / oklch, neutral ramp, semantic token, alias layer, contrast ratio / APCA Lc, colorblind-safe / CVD). A token system the user can't read is a palette imposed, not shared.
The depth lives in references/. Open each when a stage sends you there — not all upfront.
The arc is one perceptual color system. Four stages — ramp & roles · dark ramp · contrast · data-viz — turn a scatter of hexes into a coherent, accessible, evolvable palette: STAGE 0 commits the neutral ramp and semantic tokens before any component touches a color; STAGE 1 re-tunes that ramp for dark without inversion; STAGE 2 verifies every text/background pair at design time; STAGE 3 builds the data-viz scale with rigor.
colorgates all four; it runs before components are colored and its token system is whatatelier:systemslater governs as a living artifact.
Greenfield or retrofit? Decide the entry, not a new stage. Most real work is not a blank canvas — it is a codebase thick with
#3B82F6,border: 1px solid #e5e7eb,color: rgba(0,0,0,0.45), and a dark mode toggle that setsbackground: #1a1a1ainline. The four stages are the same; only the entrance differs. If starting clean, walk STAGE 0→3 in order. If a surface already exists, do one pass first: inventory the ad-hoc color values — every magic hex, every inline color, every duplicate — and cluster them into the systems the stages will own (neutrals · accent · semantics · contrast targets · viz palette). The inventory is the raw material each gate consumes, not a deliverable to perfect. Bring the inventory to STAGE 0 and the gates run unchanged.
Open references/color-spaces-and-neutrals.md and references/oklch-palette-recipes.md. Build the color system before coloring any component.
--color-text-primary, --color-surface, --color-border, --color-primary, --color-success-bg, …) onto the ramp steps. Components consume only the alias layer — never a raw ramp step, never a hex. Theme switch = edit the alias mapping; component code unchanged. The three-layer architecture: raw/ramp → semantic/alias → component.oklch(from var(--accent) calc(l - 0.04) c h) — same hue, L delta. Never a fresh color per state. disabled: drop C toward neutral + raise L. focus: base color for the dual ring (verify contrast).checklist check ramp-and-roles neutral-ramp-in-oklch-with-temperaturechecklist check ramp-and-roles accent-and-semantic-family-as-tokenschecklist verify ramp-and-rolesOpen references/dark-theme-engineering.md. Dark mode is a design decision, not a filter.
oklch(0.14 0.008 250) (deep gray, not #000); text ≈ oklch(0.88 0.006 250) (off-white, not #fff). Elevation = lighter surface per layer (not deeper shadow — shadows nearly vanish on dark). Accents: raise L to ~0.70–0.75, drop C ~20–30% (saturated mid-L colors vibrate on dark backgrounds).--color-surface, --color-text-primary, --color-primary, …) get different ramp steps assigned in the [data-theme="dark"] scope (or @media (prefers-color-scheme: dark)). Light mode uses accent-600 as a link; dark mode uses accent-300/400. This is alias remapping, not color inversion.@media redefines tokens) and a [data-theme] override. color-scheme: light dark — almost always forgotten; tells the browser to render native form controls and scrollbars per theme.<head> reads localStorage and sets [data-theme] before first paint. SSR: store theme preference in a cookie the server reads for a correct first paint.<meta name="theme-color">, native controls via color-scheme.checklist check dark-ramp dark-ramp-re-tuned-not-invertedchecklist check dark-ramp three-state-switching-and-foucchecklist verify dark-rampOpen references/contrast-and-bw.md. Contrast is a design decision, not an audit finding.
oklch(0.20 0.010 250) (L≈0.15–0.25, not #000); large bg: off-white (L≈0.97–0.99, not #fff). Both carry the neutral hue tint — even black and white are branded.checklist check contrast contrast-hierarchy-verified-at-design-timechecklist check contrast non-text-contrast-and-cvdchecklist verify contrastOpen references/data-viz-color.md. Data visualization has its own color rigor; UI palette rules do not transfer.
--viz-categorical-1 through --viz-categorical-8, --viz-sequential-{1..9}, --viz-diverging-{low|mid|high} — consistent product-wide, so the same series always wears the same color. Chart marks vs plot background: ≥3:1 (SC 1.4.11). On dark: recolor (raise L, drop C), do not invert.checklist check data-viz data-viz-palette-perceptually-uniform-cvd-safe-and-tokenizedchecklist verify data-vizchecklist show — confirm all four stages passed.checklist done — clear this run's state.The gates ask you to verify the system; the agent has no nervous system to feel where a real surface violates it. probes/color-coherence.mjs is the prosthetic for the encodable layer: point it at a rendered surface and it reads every visible element's computed color and rendered area, converts to OKLCH, and flags the off-system facts this lens forbids — pure black / pure white, color-temperature breaks, a large off-ramp surface, near-duplicate hand-picked accents, and text below the contrast floor.
node "${CLAUDE_SKILL_DIR}/probes/color-coherence.mjs" http://localhost:5173/ # or ./index.html
Run it as a pre-check at STAGE 0 (retrofit: inventory what's actually on screen) and again
before the contrast gate. It flags the fact; you judge intent — a large near-black panel
on a warm page may be a mistake, or a deliberate inversion that should be re-tuned into the
system as a warm dark-elevation token. The probe makes the choice explicit; the GATE is
still yours. For a rigorous a11y contrast audit, defer to axe-core/Lighthouse; the probe's
unique value is the system-level checks those tools lack. See
probes/README.md.
color is the suite's perceptual conscience — the place where the claim that the agent picks plausible-but-incoherent values finally gets a gate. It runs before any component is colored, and its token system is what atelier:systems later governs as a living artifact and what atelier:canon uses as a quantified commitment ("contrast target: Lc 75 on body text, Lc 60 on headings, dark base L≈0.14"). The through-line is the suite's own — push correctness into structure — applied to color: a value derived from a system can't drift the way a hand-picked one can, so palette coherence becomes structural rather than maintained by vigilance. The line that keeps color honest inside a suite that says "the correct isn't in a document": the document holds the encodable technique (how oklch works, how APCA Lc is bound to size and weight, how a CVD-safe categorical palette is constructed); the taste — which temperature, which accent hue, what the contrast hierarchy actually is — stays a gate the user clears. Blur that line and the skill becomes a recipe book; hold it and it stays a lens.
color: #2563eb in a button file and background: #2f6ae0 in a badge.filter: invert() — it's a re-tuned ramp (deep gray base, off-white text, de-saturated accents, elevation by lighter surface), not a filter.--color-primary in CSS and primaryColor: '#2563eb' in a JS config are two sources of truth that will drift; pick one and derive the other (see atelier:systems).npx claudepluginhub iamk77/skill --plugin atelierProvides UI/UX resources: 50+ styles, color palettes, font pairings, guidelines, charts for web/mobile across React, Next.js, Vue, Svelte, Tailwind, React Native, Flutter. Aids planning, building, reviewing interfaces.
Searches MemPalace before answering questions about past work, people, projects, or prior decisions. Returns verbatim stored content instead of guessing from model memory.