From Design System
Generates a full OKLCH-based color palette (light + dark, 9-step scale, semantic tokens) from a single accent color, with WCAG AA contrast verification.
How this skill is triggered — by the user, by Claude, or both
Slash command
/design-system:color-system-builderWhen to use
Создание палитры с нуля, или когда нужно расширить один цвет до полноценной системы.
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Принцип — **oklch + ramp**. Все цвета одного семейства имеют одинаковую chroma, варьируется lightness. Это даёт визуально согласованные шкалы, которых не получишь подбором HEX'ов.
Принцип — oklch + ramp. Все цвета одного семейства имеют одинаковую chroma, варьируется lightness. Это даёт визуально согласованные шкалы, которых не получишь подбором HEX'ов.
templates/build-palette.mjs:
node build-palette.mjs "#D97757"
# → palette.css + palette.json
Делает:
import fs from 'node:fs/promises';
import { converter, formatHex, wcagContrast } from 'culori';
const arg = process.argv[2];
if (!arg) { console.error('Usage: node build-palette.mjs <color>'); process.exit(1); }
const oklch = converter('oklch')(arg);
const C = oklch.c, H = oklch.h;
const steps = [98, 95, 90, 82, 72, 62, 52, 42, 32, 20];
const names = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900];
function ramp(hue, chroma) {
const out = {};
steps.forEach((L, i) => {
out[names[i]] = formatHex({ mode: 'oklch', l: L/100, c: chroma, h: hue });
});
return out;
}
const palette = {
primary: ramp(H, C),
neutral: ramp(H, 0.01), // тонированный серый, не «компьютерный»
success: ramp(145, C),
warning: ramp(80, C),
danger: ramp(25, C),
info: ramp(245, C),
};
// Светлая и тёмная тема — semantic mappings
const tokens = {
light: {
bg: palette.neutral[50],
fg: palette.neutral[900],
muted: palette.neutral[600],
rule: palette.neutral[200],
primary: palette.primary[500],
'primary-fg': palette.primary[50],
},
dark: {
bg: palette.neutral[900],
fg: palette.neutral[50],
muted: palette.neutral[400],
rule: palette.neutral[800],
primary: palette.primary[400],
'primary-fg': palette.primary[900],
},
};
// Контраст
function check(fg, bg) {
const c = wcagContrast(fg, bg);
return { ratio: c.toFixed(2), passAA: c >= 4.5, passLarge: c >= 3 };
}
const audit = {
'light fg/bg': check(tokens.light.fg, tokens.light.bg),
'light muted/bg': check(tokens.light.muted, tokens.light.bg),
'light primary-fg/primary': check(tokens.light['primary-fg'], tokens.light.primary),
'dark fg/bg': check(tokens.dark.fg, tokens.dark.bg),
'dark muted/bg': check(tokens.dark.muted, tokens.dark.bg),
};
await fs.writeFile('palette.json', JSON.stringify({ palette, tokens, audit }, null, 2));
let css = ':root {\n';
for (const [k, v] of Object.entries(tokens.light)) css += ` --${k}: ${v};\n`;
css += '}\n[data-theme="dark"] {\n';
for (const [k, v] of Object.entries(tokens.dark)) css += ` --${k}: ${v};\n`;
css += '}\n\n';
for (const [name, ramp] of Object.entries(palette)) {
for (const [step, hex] of Object.entries(ramp)) {
css += `:root { --${name}-${step}: ${hex}; }\n`;
}
}
await fs.writeFile('palette.css', css);
console.log('✓ palette.css + palette.json');
console.table(audit);
Зависимость: npm i culori.
palette.css подключай в проект первым.palette.json отдай разработчику или используй в dev-handoff.audit есть passAA: false для основных пар — палитра плохая, поправь L-значения.npx claudepluginhub jhamidun/claude-code-config-pack --plugin design-systemBuilds a throwaway prototype to answer a design question about UI appearance or state/logic behavior. Guides you through two branches: interactive terminal app for logic validation, or multiple UI variations for visual exploration.