parent
d3ce9de83f
commit
4cf2780774
@ -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…
Reference in new issue