Генерация палитры в отдельный файл

main
lambda 2 months ago
parent d3ce9de83f
commit 4cf2780774

@ -88,11 +88,11 @@ export const hslToRgb: ColorProcessingFunc<RGB> = (h, s, l) => {
[c, 0, x], // 300..360 [c, 0, x], // 300..360
]; ];
const [rp, gp, bp] = table[sector]; const [rp, gp, bp] = table[sector] as [number, number, number];
const r = round(clamp(rp + m, 0, 1) * BYTE_MAX); const r = Math.round(clamp(rp + m, 0, 1) * BYTE_MAX);
const g = round(clamp(gp + m, 0, 1) * BYTE_MAX); const g = Math.round(clamp(gp + m, 0, 1) * BYTE_MAX);
const b = round(clamp(bp + m, 0, 1) * BYTE_MAX); const b = Math.round(clamp(bp + m, 0, 1) * BYTE_MAX);
return { r, g, b }; return { r, g, b };
}; };
@ -109,11 +109,12 @@ const hexToHsl = (hex: string) => {
// luminance & contrast // luminance & contrast
export const luminance = (hex: string) => { export const luminance = (hex: string) => {
const [r, g, b] = Array.from(Object.values(hexToRgb(hex))).map((v) => { const [r, g, b] = Object.values(hexToRgb(hex)).map((v) => {
v /= 255; v /= 255;
return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4); return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
}); });
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
return 0.2126 * (r ?? 0) + 0.7152 * (g ?? 0) + 0.0722 * (b ?? 0);
}; };
export const contrastRatio = (a: string, b: string) => { export const contrastRatio = (a: string, b: string) => {

@ -0,0 +1,83 @@
import colors from "./colors.json";
import { hslToHex, hexToHsl, contrastRatio } from "./colors";
import { clamp } from "./math";
type Pallette = {
bg: string;
fg: string;
red: string;
green: string;
shade1: string;
shade2: string;
shade3: string;
shade4: string;
};
const MIN_CONTRAST = 3.0;
const FALLBACK_WHITE = "#ffffff";
const bg = colors.bg ?? "#0f0f10";
const fg = colors.fg ?? "#e6e6e6";
const redHue = colors.accentRedHue ?? 0;
const greenHue = colors.accentGreenHue ?? 140;
const sat = colors.accentSaturation ?? 65;
const light = colors.accentLightness ?? 60;
const steps = colors.shadeSteps ?? 4;
// generate accents
// ensure reasonable contrast with bg; if too low, nudge lightness
const fixContrast = (
ref: string,
hue: number,
sat: number,
lightness: number,
) => {
let cur = hslToHex(hue, sat, lightness);
let ctr = contrastRatio(cur, ref);
let l = lightness;
let tries = 0;
while (ctr < MIN_CONTRAST && tries < 10) {
l = clamp(l + 6, 0, 100); // make lighter
cur = hslToHex(hue, sat, l);
ctr = contrastRatio(cur, ref);
tries++;
}
return cur;
};
const red = fixContrast(bg, redHue, sat, light);
const green = fixContrast(bg, greenHue, sat, light);
// generate 4 darker shades from fg towards bg by lightness interpolation
const { h: fgH, s: fgS, l: fgL } = hexToHsl(fg);
const { s: bgS, l: bgL } = hexToHsl(bg);
const shades: string[] = [];
for (let i = 1; i <= steps; i++) {
const t = i / (steps + 1); // fraction towards bg
const l = fgL + (bgL - fgL) * t;
const s = fgS + (bgS - fgS) * t;
const h = fgH; // keep fg hue
shades.push(hslToHex(h, s, l));
}
const pallette: Pallette = {
bg,
fg,
red,
green,
shade1: shades[0] ?? FALLBACK_WHITE,
shade2: shades[1] ?? FALLBACK_WHITE,
shade3: shades[2] ?? FALLBACK_WHITE,
shade4: shades[3] ?? FALLBACK_WHITE,
};
function* createPalletteGenerator() {
const keys = Object.keys(pallette) as (keyof Pallette)[];
for (let key of keys) {
yield [key, pallette[key]];
}
}
const palletteGenerator = createPalletteGenerator();
export { pallette, palletteGenerator };

@ -1,76 +1,28 @@
import colors from "./colors.json"; import { hexToRgb, contrastRatio } from "./colors";
import { hexToRgb, hslToHex, hexToHsl, clamp, contrastRatio } from "./colors"; import { pallette, palletteGenerator } from "./pallette";
const bg = colors.bg ?? "#0f0f10";
const fg = colors.fg ?? "#e6e6e6";
const redHue = colors.accentRedHue ?? 0;
const greenHue = colors.accentGreenHue ?? 140;
const sat = colors.accentSaturation ?? 65;
const light = colors.accentLightness ?? 60;
const steps = colors.shadeSteps ?? 4;
// generate accents
let red = hslToHex(redHue, sat, light);
let green = hslToHex(greenHue, sat, light);
// ensure reasonable contrast with bg; if too low, nudge lightness
const MIN_CONTRAST = 3.0;
const fixContrast = (
hex: string,
ref: string,
hue: number,
sat: number,
lightness: number,
) => {
let cur = hslToHex(hue, sat, lightness);
let ctr = contrastRatio(cur, ref);
let l = lightness;
let tries = 0;
while (ctr < MIN_CONTRAST && tries < 10) {
l = clamp(l + 6); // make lighter
cur = hslToHex(hue, sat, l);
ctr = contrastRatio(cur, ref);
tries++;
}
return cur;
};
red = fixContrast(red, bg, redHue, sat, light);
green = fixContrast(green, bg, greenHue, sat, light);
// generate 4 darker shades from fg towards bg by lightness interpolation
const { h: fgH, s: fgS, l: fgL } = hexToHsl(fg);
const { s: bgS, l: bgL } = hexToHsl(bg);
const shades: string[] = [];
for (let i = 1; i <= steps; i++) {
const t = i / (steps + 1); // fraction towards bg
const l = fgL + (bgL - fgL) * t;
const s = fgS + (bgS - fgS) * t;
const h = fgH; // keep fg hue
shades.push(hslToHex(h, s, l));
}
// final palette order: bg, fg, red, green, shade1..shade4
const palette = [bg, fg, red, green, ...shades];
const hexToRgbStr = (hex: string) => { const hexToRgbStr = (hex: string) => {
const [r, g, b] = hexToRgb(hex); const { r, g, b } = hexToRgb(hex);
return `${r};${g};${b}`; return `${r};${g};${b}`;
}; };
const block = (hex: string, label?: string) => { const block = (hex: string, label?: string) => {
const [r, g, b] = hexToRgb(hex); const { r, g, b } = hexToRgb(hex);
process.stdout.write(`\x1b[48;2;${r};${g};${b}m ${label ?? hex} \x1b[0m\n`); process.stdout.write(`\x1b[48;2;${r};${g};${b}m ${label ?? hex} \x1b[0m\n`);
}; };
console.log("\nGenerated 8-color palette:\n"); console.log("\nGenerated 8-color palette:\n");
["bg", "fg", "red", "green", "shade1", "shade2", "shade3", "shade4"].forEach(
(name, idx) => { for (let [name, color] of palletteGenerator) {
block(palette[idx], `${name} ${palette[idx]}`); block(color ?? "", `${name} ${color}`);
}, }
);
console.log(); console.log();
console.log( console.log(
`Contrast red/bg: ${contrastRatio(red, bg)} | green/bg: ${contrastRatio(green, bg)}\n`, `Contrast red/bg: ${contrastRatio(pallette.red, pallette.bg)} | green/bg: ${contrastRatio(pallette.green, pallette.bg)}\n`,
); );
console.log( console.log(
`\x1b[38;2;${hexToRgbStr(green)}m✔ Success\x1b[0m \x1b[38;2;${hexToRgbStr(red)}m✖ Error\x1b[0m\n`, `\x1b[38;2;${hexToRgbStr(pallette.green)}m✔ Success\x1b[0m \x1b[38;2;${hexToRgbStr(pallette.red)}m✖ Error\x1b[0m\n`,
); );

Loading…
Cancel
Save