Skip to content

Instantly share code, notes, and snippets.

@postspectacular
Last active July 10, 2023 10:57
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save postspectacular/a822677ec4d1286cb6ef947ca12818c0 to your computer and use it in GitHub Desktop.
Save postspectacular/a822677ec4d1286cb6ef947ca12818c0 to your computer and use it in GitHub Desktop.
Marblemania color theme swatch generator (context: https://mastodon.thi.ng/@toxi/110689378884928332)
import { sortByCachedKey } from "@thi.ng/arrays";
import { analog, lch, srgb, swatchesH } from "@thi.ng/color";
import { asRGB, type LCHTheme, type RGBTheme } from "@thi.ng/color-palettes";
import { compareNumAsc } from "@thi.ng/compare";
import { serialize } from "@thi.ng/hiccup";
import { svg } from "@thi.ng/hiccup-svg";
import { SYSTEM } from "@thi.ng/random";
import { map, mean, pluck, range } from "@thi.ng/transducers";
import { comparator3 } from "@thi.ng/vectors";
import { writeFileSync } from "fs";
// prettier-ignore
const CUSTOM_THEMES = [
[0x144145, 0x367d90, 0xcca902, 0xcdc46a, 0xe3d1b1, 0xfaf0e1],
[0xd10b18, 0x532e17, 0xa86437, 0xfd531b, 0xebe6dd, 0x197871],
[0xda3807, 0xf17d0a, 0xedba24, 0xf7e358, 0xa5bfb3, 0x373933],
[0xf6b3af, 0xfc8880, 0xf8321d, 0x202a46, 0xafa8b1, 0xe2dfe1],
[0x42180c, 0x9f4e2b, 0xf1b384, 0x8eb0b7, 0x768f9f, 0x373041],
[0xa54521, 0xdf9612, 0xc19b5c, 0x354535, 0x7eb09b, 0x20afb4],
[0x700217, 0xfb3c03, 0xebdecb, 0x68c6bc, 0x144f54, 0x022932],
[0x242c20, 0x772d0b, 0xc15627, 0x4a525e, 0xaabfd4, 0xebcdb8],
[0x473629, 0x75583f, 0xf39110, 0x0b566e, 0x397b90, 0xbcc4cb],
];
// prettier-ignore
const THEMES = [
7, 9, 10, 11, 22, 31, 34, 38, 39, 40, 41, 45, 49, 53, 71, 81, 82, 86,
89, 98, 99, 100, 102, 105, 119, 122, 123, 124, 129, 135, 137, 139,
140, 142, 143, 146, 147, 148, 149, 151, 152, 154, 157, 160, 162, 163, 168,
173, 176, 177, 178, 189, 195, 202, 204, 206, 207, 208, 210, 215, 216,
218, -1, -2, -3, -4, -5, -6, -7, -8, -9,
];
const themeForID = (id: number) =>
id < 0
? CUSTOM_THEMES[-id - 1].map((x) => srgb(x | 0xff000000))
: asRGB(id);
const asLCHTheme = (theme: RGBTheme) => theme.map((x) => lch(x));
// themes sorted by mean luminance
const themes = sortByCachedKey(
THEMES,
(id) => mean(pluck("l", asLCHTheme(themeForID(id)))),
compareNumAsc
);
// original theme + 4 random variations
const themeSwatches = (theme: LCHTheme, themeId: number, i: number) => [
"g",
{ translate: [0, i * 60 + 10] },
[
"text",
{
fill: "#000",
baseline: "middle",
align: "right",
},
[30, 25],
themeId,
],
swatchesH(theme, 50, 50, 0, { translate: [40, 0] }),
...map(
(i) =>
swatchesH(
theme.map((c) => analog(lch(), c, 0.12, SYSTEM)),
50,
50,
0,
{ translate: [i * 310 + 50, 0] }
),
range(1, 5)
),
];
// SVG doc
const doc = svg(
{ width: 50 + 5 * 310, height: THEMES.length * 60 + 20, __convert: true },
...themes.map((id, i) =>
themeSwatches(
// sort theme colors in L -> H -> C order
asLCHTheme(themeForID(id)).sort(comparator3(0, 2, 1)),
id,
i
)
)
);
writeFileSync("theme-swatches.svg", serialize(doc));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment