color-value-tools 1.1.1: от конвертера форматов до полноценного инструментария для работы с цветом

В первой версии color-value-tools закрывал базовую задачу: распознать формат цвета, конвертировать между hex, RGB, HSL, HSV, Lab, LCH, CMYK, распарсить CSS-переменную, вычислить контрастность по WCAG. Этого хватает, пока нужно просто «перевести цвет из одного формата в другой». Но как только появляется реальный UI — осветлить кнопку при hover, подобрать читаемый цвет текста, сгенерировать палитру из акцентного цвета, проверить доступность на градиентном фоне или сделать плавный переход без «серой зоны» посередине — базовых конвертаций быстро перестаёт хватать.
В этом посте — что изменилось в 1.1.1: поддержка современного CSS (oklch(), color(), Display P3), расширенная интерполяция с перцептивно правильными переходами, манипуляции и цветовые гармонии, генерация палитр, WCAG-утилиты с готовыми ответами, симуляция дальтонизма, кеш для hot-path, генераторы для больших последовательностей и CLI прямо из терминала.
Парсинг современных CSS-форматов
Функция normalizeColor теперь понимает CSS Color Level 4: oklch(), color(display-p3 ...), а также 4-значный hex #RGBA. Все они нормализуются в единую структуру {type, hex, r, g, b, a, h, s, l, v}.
ts
import { normalizeColor, parseOklchString, parseCssVar } from 'color-value-tools';
normalizeColor('oklch(0.65 0.15 25)');
// { type: 'oklch', hex: '#e3553e', r: 227, g: 85, b: 62, ... }
normalizeColor('color(display-p3 1 0.5 0)');
// { type: 'color', hex: '#ff8000', r: 255, g: 128, b: 0, ... }
normalizeColor('#f0f0');
// { type: 'hex', hex: '#ff00ff', a: 0, ... } (#RGBA shorthand)
Для парсинга в отдельных сценариях — специализированные функции:
ts
parseOklchString('oklch(65% 0.15 25 / 0.8)');
// { L: 0.65, C: 0.15, H: 25, alpha: 0.8 }
parseCssVar('var(--primary, #3498db)');
// { variableName: '--primary', fallback: '#3498db' }
getColorType возвращает 'oklch' и 'color' для новых форматов. isOklchColor и isColorFunction — для явной проверки.
Display P3 и широкие гаммы
Для работы с широким цветовым охватом добавлена полная цепочка конвертации. Display P3 покрывает примерно на 25% больше видимого спектра, чем sRGB.
ts
import { rgbToDisplayP3, toDisplayP3Hex, toColorP3String } from 'color-value-tools';
// sRGB (0–255) → Display P3 (0–1 на канал)
rgbToDisplayP3({ r: 255, g: 0, b: 0 });
// { r: 0.9175, g: 0.2003, b: 0.1386 }
// Форматирование как CSS Color Level 4
toColorP3String('#3498db');
// 'color(display-p3 0.2862 0.5862 0.8431)'
toColorP3String('#3498db', 0.9);
// 'color(display-p3 0.2862 0.5862 0.8431 / 0.9)'
Манипуляции с цветом
Набор функций для изменения отдельных характеристик. Все принимают любой поддерживаемый формат, возвращают hex.
lighten / darken — светлота через HSL:
ts
lighten('#3498db', 15); // '#6ab4e8'
darken('#3498db', 15); // '#1a6da3'
saturate / desaturate — насыщенность:
ts
desaturate('#ff0000', 60); // ближе к серому
saturate('#888888', 40); // цвет приобретает оттенок
setAlpha / getAlpha — прозрачность:
ts
setAlpha('#3498db', 0.4); // 'rgba(52, 152, 219, 0.4)'
getAlpha('rgba(52, 152, 219, 0.4)'); // 0.4
invertColor и grayscale — инверсия и обесцвечивание. grayscale использует перцептивные веса ITU-R BT.709:
ts
invertColor('#ff0000'); // '#00ffff'
grayscale('#3498db'); // '#666666'
Интерполяция и цветовые шкалы
Главное улучшение в работе с переходами — поддержка перцептивных пространств. В sRGB и HSL при интерполяции между контрастными цветами посередине часто появляется «грязный» серый участок. В Oklab и Oklch этого нет.
mixColors расширен до шести пространств и управления интерполяцией оттенка:
ts
import { mixColors } from 'color-value-tools';
// Серый посередине — типичная проблема RGB
mixColors('#ff0000', '#0000ff', 0.5, { mode: 'rgb' }); // '#800080'
// Oklch: насыщенный переход без потери яркости
mixColors('#ff0000', '#0000ff', 0.5, { mode: 'oklch' });
// Управление дугой оттенка
mixColors('#ff0000', '#0000ff', 0.5, {
mode: 'oklch',
hueInterpolation: 'longer', // через длинную дугу
});
interpolateColors — массив шагов между двумя цветами:
ts
import { interpolateColors } from 'color-value-tools';
interpolateColors('#ff0000', '#0000ff', 5, { space: 'oklab' });
// ['#ff0000', '#cc00cc', '#9900ff', '#6600ff', '#0000ff']
createColorScale — шкала из нескольких якорных цветов с опциональными позициями (0–1):
ts
import { createColorScale } from 'color-value-tools';
// Три якоря, равномерно
createColorScale(['#ff0000', '#ffff00', '#00ff00'], 7);
// С позициями — белый занимает 80% шкалы
createColorScale([
{ color: '#ffffff', position: 0 },
{ color: '#3498db', position: 0.8 },
{ color: '#1a3a5c', position: 1 },
], 9);
midpointColor — перцептивная середина между двумя цветами (по умолчанию в Oklab):
ts
import { midpointColor } from 'color-value-tools';
midpointColor('#ff0000', '#0000ff');
midpointColor('#ff0000', '#0000ff', { space: 'oklch' });
Палитры
Три терминологически корректные функции на основе смешивания в Oklab:
ts
import { tints, shades, tones } from 'color-value-tools';
tints('#3498db', 5); // от исходного к белому
shades('#3498db', 5); // от исходного к чёрному
tones('#3498db', 5); // от исходного к серому (#808080)
tones('#3498db', 5, '#a0a0a0'); // кастомный серый
Для дизайн-систем доступны также colorShades (HSL-шкала от белого до чёрного, 9 шагов по умолчанию) и monochromatic (варьирует насыщенность при фиксированной яркости).
Цветовые гармонии
ts
import { complement, triadic, analogous, splitComplementary, tetradic } from 'color-value-tools';
complement('#3498db'); // '#db6034'
triadic('#3498db'); // ['#3498db', '#db3498', '#98db34']
analogous('#3498db', 40); // три соседних через ±40°
splitComplementary('#3498db'); // ['#3498db', '#db9834', '#db3498']
tetradic('#3498db'); // четыре цвета через 90°
Первый элемент массива — всегда исходный цвет.
WCAG-доступность
В первой версии были только relativeLuminance и contrastRatio — числа без интерпретации. Теперь есть утилиты с готовыми ответами.
wcagLevel — уровень WCAG одной строкой:
ts
wcagLevel('#ffffff', '#000000'); // 'AAA'
wcagLevel('#ffffff', '#3498db'); // 'AA'
wcagLevel('#ffffff', '#aaaaaa'); // 'fail'
bestTextColor / bestContrastColor — автоподбор:
ts
bestTextColor('#3498db'); // '#ffffff' или '#000000' — что контрастнее
bestContrastColor('#3498db', ['#ffffff', '#000000', '#ffe0b2']);
bestContrastPalette — из набора палитр выбирает ту, что даёт наилучший суммарный контраст. Можно взвешивать элементы:
ts
import { bestContrastPalette } from 'color-value-tools';
bestContrastPalette('#3498db', [
['#ffffff', '#f0f0f0', '#cccccc'],
['#000000', '#222222', '#444444'],
]);
// { paletteIndex: 1, palette: [...], minContrastRatio: 8.4, avgContrastRatio: 10.2 }
isReadableOnBackground — проверяет читаемость на сложном фоне: сплошном, полупрозрачном или градиентном:
ts
import { isReadableOnBackground } from 'color-value-tools';
// Полупрозрачный фон поверх белой подложки
isReadableOnBackground('#ffffff', {
type: 'semi-transparent',
color: 'rgba(52,152,219,0.6)',
underlay: '#ffffff',
});
// { readable: true, minContrastRatio: 3.8, wcagLevel: 'AA-large' }
// Градиент — проверяет минимальный контраст по всем стопам
isReadableOnBackground('#ffffff', {
type: 'gradient',
stops: ['#3498db', '#1a3a5c'],
});
Симуляция дальтонизма
Позволяет увидеть, как цвет воспринимается при трёх типах нарушения цветового зрения. Используются матрицы Vienot 1999, применяются к линеаризованному RGB.
ts
import { simulateProtanopia, simulateDeuteranopia, simulateTritanopia } from 'color-value-tools';
simulateProtanopia('#3498db'); // нет L-колбочек (красный)
simulateDeuteranopia('#3498db'); // нет M-колбочек (зелёный)
simulateTritanopia('#3498db'); // нет S-колбочек (синий)
// Обобщённая версия
simulateColorBlindness('#3498db', 'deuteranopia');
Практический сценарий — прогнать каждый цвет палитры через все три симуляции и убедиться, что элементы интерфейса различимы при любом типе восприятия.
Цветовые пространства: HWB, OKLAB, OKLCH
HWB (Hue / Whiteness / Blackness) — нативно в CSS Color Level 4. Интуитивная модель: оттенок + сколько белого + сколько чёрного.
ts
rgbToHwb({ r: 52, g: 152, b: 219 }); // [204, 20, 14]
toHwbString(204, 20, 14); // 'hwb(204 20% 14%)'
toHwbString(204, 20, 14, 0.8); // 'hwb(204 20% 14% / 0.8)'
OKLAB / OKLCH — перцептивно равномерные пространства. Для форматирования:
ts
toOklchString('#3498db'); // 'oklch(0.627 0.111 251.3)'
toOklchString('#3498db', 0.9); // 'oklch(0.627 0.111 251.3 / 0.9)'
Утилиты
colorDeltaE — перцептивное расстояние по CIEDE2000. < 1 — разница незаметна, > 10 — явное различие:
ts
colorDeltaE('#ff0000', '#fe0000'); // ~0.9
colorDeltaE('#ff0000', '#0000ff'); // ~52
toNearestNamedColor — ближайший CSS named color. База расширена до 148 имён (включая rebeccapurple):
ts
toNearestNamedColor('#4169e1'); // 'royalblue'
toNearestNamedColor('#663399'); // 'rebeccapurple'
randomColor — случайный цвет с контролем диапазонов оттенка, насыщенности и яркости:
ts
randomColor({ hRange: [200, 260], sRange: [60, 80], lRange: [40, 60] });
Кеш и производительность
При многократном разборе одних строк — normalizeColorCached не пересчитывает, берёт из Map:
ts
import { normalizeColorCached, getCacheStats, clearColorCache, disableCache } from 'color-value-tools';
normalizeColorCached('#3498db'); // первый вызов — вычисляет
normalizeColorCached('#3498db'); // повторный — из кеша
getCacheStats(); // { size: 1, hits: 1 }
clearColorCache(); // сброс
disableCache(); // отключить глобально
Генераторы
Для больших последовательностей — без выделения массива:
ts
import { generateGradientColors, generateTints, generateShades } from 'color-value-tools';
// Покадровая анимация в Oklab
for (const color of generateGradientColors('#ff0000', '#0000ff', 60, { mode: 'oklab' })) {
element.style.background = color;
await nextFrame();
}
// Тинты к белому
for (const tint of generateTints('#3498db', 9)) {
paletteEl.append(createSwatch(tint));
}
CLI
После глобальной установки или через npx:
bash
npm install -g color-value-tools
bash
cvt "#3498db" # полная информация
cvt "#3498db" convert # все форматы: hex, rgb, hsl, oklch, cmyk...
cvt "#3498db" contrast "#ffffff" # контрастность и WCAG
cvt "#3498db" shades 7 # 7 оттенков
cvt "#3498db" harmonies # все гармонии
cvt "cornflowerblue" nearest # ближайший named color
Изменения в сборке
В первой версии vue был в dependencies без использования в коде — тянулся в бандл. В 1.1.1 убран полностью. Сборка теперь генерирует CJS (dist/cjs/), ESM (dist/esm/) и CLI (dist/cli/). exports в package.json маршрутизирует автоматически.
Краткий итог
color-value-tools 1.1.1 — полноценный инструментарий для работы с цветом в TypeScript-проектах. Парсинг любого CSS-формата (в том числе oklch(), color(display-p3 ...), #RGBA), конвертации между 12 пространствами, перцептивная интерполяция в Oklab/Oklch, генерация палитр (tints/shades/tones, гармонии, многоякорные шкалы), полный набор WCAG-утилит, симуляция дальтонизма по трём типам, кеш, генераторы, CLI — без runtime-зависимостей.
Пакет на npm: color-value-tools
Репозиторий: macrulezru/color-value-tools
Про первую версию пакета и базовые конвертации — в предыдущем посте: color-value-tools: конвертация и манипуляция цветами в любых форматах