feat: added a GNU Imp palette generator

This commit is contained in:
D. Moonfire 2024-05-07 01:02:23 -05:00
parent fb6d27f18a
commit 0a078698f7
7 changed files with 193 additions and 121 deletions

6
package-lock.json generated
View file

@ -10,6 +10,7 @@
"license": "MIT",
"dependencies": {
"@priduck-color-theme/cli": "^0.0.1",
"colorjs.io": "^0.5.0",
"yargs": "^17.7.2"
},
"devDependencies": {
@ -79,6 +80,11 @@
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"node_modules/colorjs.io": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/colorjs.io/-/colorjs.io-0.5.0.tgz",
"integrity": "sha512-qekjTiBLM3F/sXKks/ih5aWaHIGu+Ftel0yKEvmpbKvmxpNOhojKgha5uiWEUOqEpRjC1Tq3nJRT7WgdBOxIGg=="
},
"node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",

View file

@ -17,6 +17,7 @@
},
"dependencies": {
"@priduck-color-theme/cli": "^0.0.1",
"colorjs.io": "^0.5.0",
"yargs": "^17.7.2"
}
}

View file

@ -1,12 +1,14 @@
import yargs from "yargs";
import { hideBin } from "yargs/helpers";
import * as cssCmd from "./cmds/css.mjs";
import * as paletteCmd from "./cmds/palette.mjs";
// Set up the top-level command.
yargs(hideBin(process.argv))
.scriptName("priduck")
.usage("$0 <cmd> [args]")
.command(cssCmd)
.command(paletteCmd)
.demand(2)
.help()
.parse();

View file

@ -1,25 +1,18 @@
import { mkdirp } from "mkdirp";
import { fileURLToPath } from "url";
import path from "path";
import fs from "node:fs/promises";
import * as colors from "../../colors.mjs";
export const command = "variables [path.css]";
export const desc = "Generate a CSS file that uses variables to generate";
export function builder(argv) {
argv
.option("c", {
alias: "hue",
default: 220,
describe: "The hue (0-360) for the base color",
type: "number",
})
.option("o", {
alias: "output",
demandOption: true,
describe: "The output path for colors.css",
type: "string",
});
argv.option("o", {
alias: "output",
demandOption: true,
describe: "The output path for colors.css",
type: "string",
});
}
export async function handler(argv) {
@ -36,19 +29,19 @@ export async function handler(argv) {
// We have ten colors, with 0 being the base hue and the others being evenly
// rotated around the color wheel.
for (let color = 0; color < 10; color++) {
for (const color of colors.colorList) {
// Figure out the rotation.
const rotation = color * 36; // 1/10th of a circle
const rotation = colors.getHue(color);
// For each hue, we have ten levels of brightness ranging from very dark
// to very light.
for (let brightness = 0; brightness < 10; brightness++) {
for (const brightness of colors.brightnessList) {
// We use a standard code (--color-cXbY) for our codes.
const code = `--color-priduck-c${color}b${brightness}`;
// Figure out the ramps we are using for brighteness.
const l = brightness * 11;
const s = 50 - brightness * 5;
const l = colors.getLightness(brightness);
const s = colors.getChroma(brightness);
// Write out the CSS.
lines.push(

79
src/cmds/palette.mjs Normal file
View file

@ -0,0 +1,79 @@
import { mkdirp } from "mkdirp";
import path from "path";
import fs from "node:fs/promises";
import * as colors from "../colors.mjs";
export const command = "palette [path.gpl]";
export const desc = "Generate a GNU Imp/Inkscape palette";
export function builder(argv) {
argv
.option("c", {
alias: "hue",
default: 220,
describe: "The hue (0-360) for the base color",
type: "number",
})
.option("s", {
alias: "secondary",
default: 5,
choices: colors.colorList,
describe: "The color code (0-9) based on the hue",
type: "number",
})
.option("t", {
alias: "tertiary",
default: 8,
choices: colors.colorList,
describe: "The color code (0-9) based on the hue",
type: "number",
})
.option("n", {
alias: "name",
default: "Priduck",
describe: "The name of the palette",
type: "string",
})
.option("o", {
alias: "output",
demandOption: true,
describe: "The output path for colors.css",
type: "string",
});
}
export async function handler(argv) {
// Figure out where we need to write the files.
const file = argv.output;
const dir = path.dirname(file);
console.log("base hue", argv.hue);
console.log("writing", file);
await mkdirp(dir);
// Start with the header.
let lines = ["GIMP Palette", `Name: ${argv.name}`, "Columns: 30", ""];
// Loop through the three primary colors, then the brightness for each one.
const colorList = [0, argv.secondary, argv.tertiary];
for (const colorIndex in colorList) {
const color = colorList[colorIndex];
const colorName =
colorIndex == 0 ? "primary" : colorIndex == 1 ? "secondary" : "tertiary";
for (const brightness of colors.brightnessList) {
const lch = colors.getLchCss(argv.hue, color, brightness);
const rgb = colors.getRgbArray(argv.hue, color, brightness);
const line = `${rgb[0]} ${rgb[1]} ${rgb[2]} ${colorName}-${brightness} # ${lch}`;
lines.push(line);
}
}
// Write out the files.
await fs.writeFile(file, Buffer.from(lines.join("\n")));
console.log("wrote", file);
}

View file

@ -1,102 +0,0 @@
:root {
--color-c0b0: lch(0 50 calc(var(--color-hue) + 0));
--color-c0b1: lch(11 45 calc(var(--color-hue) + 0));
--color-c0b2: lch(22 40 calc(var(--color-hue) + 0));
--color-c0b3: lch(33 35 calc(var(--color-hue) + 0));
--color-c0b4: lch(44 30 calc(var(--color-hue) + 0));
--color-c0b5: lch(55 25 calc(var(--color-hue) + 0));
--color-c0b6: lch(66 20 calc(var(--color-hue) + 0));
--color-c0b7: lch(77 15 calc(var(--color-hue) + 0));
--color-c0b8: lch(88 10 calc(var(--color-hue) + 0));
--color-c0b9: lch(99 5 calc(var(--color-hue) + 0));
--color-c1b0: lch(0 50 calc(var(--color-hue) + 36));
--color-c1b1: lch(11 45 calc(var(--color-hue) + 36));
--color-c1b2: lch(22 40 calc(var(--color-hue) + 36));
--color-c1b3: lch(33 35 calc(var(--color-hue) + 36));
--color-c1b4: lch(44 30 calc(var(--color-hue) + 36));
--color-c1b5: lch(55 25 calc(var(--color-hue) + 36));
--color-c1b6: lch(66 20 calc(var(--color-hue) + 36));
--color-c1b7: lch(77 15 calc(var(--color-hue) + 36));
--color-c1b8: lch(88 10 calc(var(--color-hue) + 36));
--color-c1b9: lch(99 5 calc(var(--color-hue) + 36));
--color-c2b0: lch(0 50 calc(var(--color-hue) + 72));
--color-c2b1: lch(11 45 calc(var(--color-hue) + 72));
--color-c2b2: lch(22 40 calc(var(--color-hue) + 72));
--color-c2b3: lch(33 35 calc(var(--color-hue) + 72));
--color-c2b4: lch(44 30 calc(var(--color-hue) + 72));
--color-c2b5: lch(55 25 calc(var(--color-hue) + 72));
--color-c2b6: lch(66 20 calc(var(--color-hue) + 72));
--color-c2b7: lch(77 15 calc(var(--color-hue) + 72));
--color-c2b8: lch(88 10 calc(var(--color-hue) + 72));
--color-c2b9: lch(99 5 calc(var(--color-hue) + 72));
--color-c3b0: lch(0 50 calc(var(--color-hue) + 108));
--color-c3b1: lch(11 45 calc(var(--color-hue) + 108));
--color-c3b2: lch(22 40 calc(var(--color-hue) + 108));
--color-c3b3: lch(33 35 calc(var(--color-hue) + 108));
--color-c3b4: lch(44 30 calc(var(--color-hue) + 108));
--color-c3b5: lch(55 25 calc(var(--color-hue) + 108));
--color-c3b6: lch(66 20 calc(var(--color-hue) + 108));
--color-c3b7: lch(77 15 calc(var(--color-hue) + 108));
--color-c3b8: lch(88 10 calc(var(--color-hue) + 108));
--color-c3b9: lch(99 5 calc(var(--color-hue) + 108));
--color-c4b0: lch(0 50 calc(var(--color-hue) + 144));
--color-c4b1: lch(11 45 calc(var(--color-hue) + 144));
--color-c4b2: lch(22 40 calc(var(--color-hue) + 144));
--color-c4b3: lch(33 35 calc(var(--color-hue) + 144));
--color-c4b4: lch(44 30 calc(var(--color-hue) + 144));
--color-c4b5: lch(55 25 calc(var(--color-hue) + 144));
--color-c4b6: lch(66 20 calc(var(--color-hue) + 144));
--color-c4b7: lch(77 15 calc(var(--color-hue) + 144));
--color-c4b8: lch(88 10 calc(var(--color-hue) + 144));
--color-c4b9: lch(99 5 calc(var(--color-hue) + 144));
--color-c5b0: lch(0 50 calc(var(--color-hue) + 180));
--color-c5b1: lch(11 45 calc(var(--color-hue) + 180));
--color-c5b2: lch(22 40 calc(var(--color-hue) + 180));
--color-c5b3: lch(33 35 calc(var(--color-hue) + 180));
--color-c5b4: lch(44 30 calc(var(--color-hue) + 180));
--color-c5b5: lch(55 25 calc(var(--color-hue) + 180));
--color-c5b6: lch(66 20 calc(var(--color-hue) + 180));
--color-c5b7: lch(77 15 calc(var(--color-hue) + 180));
--color-c5b8: lch(88 10 calc(var(--color-hue) + 180));
--color-c5b9: lch(99 5 calc(var(--color-hue) + 180));
--color-c6b0: lch(0 50 calc(var(--color-hue) + 216));
--color-c6b1: lch(11 45 calc(var(--color-hue) + 216));
--color-c6b2: lch(22 40 calc(var(--color-hue) + 216));
--color-c6b3: lch(33 35 calc(var(--color-hue) + 216));
--color-c6b4: lch(44 30 calc(var(--color-hue) + 216));
--color-c6b5: lch(55 25 calc(var(--color-hue) + 216));
--color-c6b6: lch(66 20 calc(var(--color-hue) + 216));
--color-c6b7: lch(77 15 calc(var(--color-hue) + 216));
--color-c6b8: lch(88 10 calc(var(--color-hue) + 216));
--color-c6b9: lch(99 5 calc(var(--color-hue) + 216));
--color-c7b0: lch(0 50 calc(var(--color-hue) + 252));
--color-c7b1: lch(11 45 calc(var(--color-hue) + 252));
--color-c7b2: lch(22 40 calc(var(--color-hue) + 252));
--color-c7b3: lch(33 35 calc(var(--color-hue) + 252));
--color-c7b4: lch(44 30 calc(var(--color-hue) + 252));
--color-c7b5: lch(55 25 calc(var(--color-hue) + 252));
--color-c7b6: lch(66 20 calc(var(--color-hue) + 252));
--color-c7b7: lch(77 15 calc(var(--color-hue) + 252));
--color-c7b8: lch(88 10 calc(var(--color-hue) + 252));
--color-c7b9: lch(99 5 calc(var(--color-hue) + 252));
--color-c8b0: lch(0 50 calc(var(--color-hue) + 288));
--color-c8b1: lch(11 45 calc(var(--color-hue) + 288));
--color-c8b2: lch(22 40 calc(var(--color-hue) + 288));
--color-c8b3: lch(33 35 calc(var(--color-hue) + 288));
--color-c8b4: lch(44 30 calc(var(--color-hue) + 288));
--color-c8b5: lch(55 25 calc(var(--color-hue) + 288));
--color-c8b6: lch(66 20 calc(var(--color-hue) + 288));
--color-c8b7: lch(77 15 calc(var(--color-hue) + 288));
--color-c8b8: lch(88 10 calc(var(--color-hue) + 288));
--color-c8b9: lch(99 5 calc(var(--color-hue) + 288));
--color-c9b0: lch(0 50 calc(var(--color-hue) + 324));
--color-c9b1: lch(11 45 calc(var(--color-hue) + 324));
--color-c9b2: lch(22 40 calc(var(--color-hue) + 324));
--color-c9b3: lch(33 35 calc(var(--color-hue) + 324));
--color-c9b4: lch(44 30 calc(var(--color-hue) + 324));
--color-c9b5: lch(55 25 calc(var(--color-hue) + 324));
--color-c9b6: lch(66 20 calc(var(--color-hue) + 324));
--color-c9b7: lch(77 15 calc(var(--color-hue) + 324));
--color-c9b8: lch(88 10 calc(var(--color-hue) + 324));
--color-c9b9: lch(99 5 calc(var(--color-hue) + 324));
}

93
src/colors.mjs Normal file
View file

@ -0,0 +1,93 @@
import Color from "colorjs.io";
/**
* Contains the color codes with zero (0) being the base hue.
*
* @type {number[]}
*/
export const colorList = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
/**
* Contains the standard brightness codes with zero (0) being the darkest and
* nine (9) being the lightest.
*
* @type {number[]}
*/
export const brightnessList = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
/**
* Gets the degree rotation for the given color code.
*
* @param {number} base The base hue, in the range [0-360)
* @param {number} color The color code, in the range of [0-9]
*/
export function getHue(base, color) {
return (base + color * 36) % 360;
}
/**
* Gets the lighteness for a given brightness.
*
* @param {number} brightness The brightenss, in the range of [0-9]
*/
export function getLightness(brightness) {
return 5 + brightness * 10;
}
/**
* Gets the saturation for a given brightness.
*
* @param {number} brightness The brightenss, in the range of [0-9]
*/
export function getChroma(brightness) {
return 50 - brightness * 5;
}
/**
* Get the LCH string
*
* @param {number} base The base hue, in the range [0-360)
* @param {number} color The color code, in the range of [0-9]
* @param {number} brightness The brightenss, in the range of [0-9]
*/
export function getLchCss(base, color, brightness) {
const l = getLightness(brightness);
const c = getChroma(brightness);
const h = getHue(base, color);
return `lch(${l}% ${c} ${h})`;
}
/**
* Gets the RGB values as a string hex of a hash plus 6 numbers.
*
* @param {number} base The base hue, in the range [0-360)
* @param {number} color The color code, in the range of [0-9]
* @param {number} brightness The brightenss, in the range of [0-9]
*/
export function getRgbHex(base, color, brightness) {
const lch = getLchCss(base, color, brightness);
const lchColor = new Color(lch);
const hex = lchColor
.to("srgb")
.toString({ format: "hex", inGamut: true })
.replace(/^#(\d)(\d)(\d)$/, "#$1$1$2$2$3$3");
return hex;
}
/**
* Gets the RGB values as an array of three numbers.
*
* @param {number} base The base hue, in the range [0-360)
* @param {number} color The color code, in the range of [0-9]
* @param {number} brightness The brightenss, in the range of [0-9]
*/
export function getRgbArray(base, color, brightness) {
const hex = getRgbHex(base, color, brightness);
const r = parseInt(hex.substring(1, 3), "16");
const g = parseInt(hex.substring(3, 5), "16");
const b = parseInt(hex.substring(5, 7), "16");
return [r, g, b];
}