monobiome 1.4.0__py3-none-any.whl → 1.5.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- monobiome/__main__.py +1 -1
- monobiome/cli/__init__.py +6 -5
- monobiome/cli/fill.py +78 -0
- monobiome/cli/palette.py +5 -5
- monobiome/cli/scheme.py +12 -12
- monobiome/constants.py +18 -0
- monobiome/curve.py +3 -3
- monobiome/palette.py +3 -2
- monobiome/plotting.py +71 -39
- monobiome/scheme.py +14 -8
- monobiome-1.5.1.dist-info/METADATA +344 -0
- monobiome-1.5.1.dist-info/RECORD +18 -0
- monobiome-1.4.0.dist-info/METADATA +0 -232
- monobiome-1.4.0.dist-info/RECORD +0 -17
- {monobiome-1.4.0.dist-info → monobiome-1.5.1.dist-info}/WHEEL +0 -0
- {monobiome-1.4.0.dist-info → monobiome-1.5.1.dist-info}/entry_points.txt +0 -0
- {monobiome-1.4.0.dist-info → monobiome-1.5.1.dist-info}/top_level.txt +0 -0
monobiome/__main__.py
CHANGED
monobiome/cli/__init__.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
import
|
|
2
|
+
from argparse import ArgumentParser
|
|
3
3
|
|
|
4
|
-
from monobiome.cli import scheme, palette
|
|
4
|
+
from monobiome.cli import fill, scheme, palette
|
|
5
5
|
|
|
6
6
|
logger: logging.Logger = logging.getLogger(__name__)
|
|
7
7
|
|
|
@@ -12,8 +12,8 @@ def configure_logging(log_level: int) -> None:
|
|
|
12
12
|
|
|
13
13
|
logger.setLevel(log_level)
|
|
14
14
|
|
|
15
|
-
def create_parser() ->
|
|
16
|
-
parser =
|
|
15
|
+
def create_parser() -> ArgumentParser:
|
|
16
|
+
parser = ArgumentParser(
|
|
17
17
|
description="Accent modeling CLI",
|
|
18
18
|
)
|
|
19
19
|
parser.add_argument(
|
|
@@ -26,7 +26,8 @@ def create_parser() -> argparse.ArgumentParser:
|
|
|
26
26
|
|
|
27
27
|
subparsers = parser.add_subparsers(help="subcommand help")
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
fill.register_parser(subparsers)
|
|
30
30
|
scheme.register_parser(subparsers)
|
|
31
|
+
palette.register_parser(subparsers)
|
|
31
32
|
|
|
32
33
|
return parser
|
monobiome/cli/fill.py
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import tomllib
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from argparse import Namespace, ArgumentParser
|
|
5
|
+
|
|
6
|
+
from symconf.template import Template, TOMLTemplate
|
|
7
|
+
|
|
8
|
+
from monobiome.util import _SubparserType
|
|
9
|
+
from monobiome.palette import generate_palette
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def register_parser(subparsers: _SubparserType) -> None:
|
|
13
|
+
parser = subparsers.add_parser(
|
|
14
|
+
"fill",
|
|
15
|
+
help="fill scheme templates for applications"
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
parser.add_argument(
|
|
19
|
+
"scheme",
|
|
20
|
+
type=str,
|
|
21
|
+
help="scheme file path"
|
|
22
|
+
)
|
|
23
|
+
parser.add_argument(
|
|
24
|
+
"template",
|
|
25
|
+
nargs="?",
|
|
26
|
+
help="template file path (defaults to stdin)"
|
|
27
|
+
)
|
|
28
|
+
parser.add_argument(
|
|
29
|
+
"-p",
|
|
30
|
+
"--palette",
|
|
31
|
+
type=str,
|
|
32
|
+
help="palette file to use for color definitions",
|
|
33
|
+
)
|
|
34
|
+
parser.add_argument(
|
|
35
|
+
"-o",
|
|
36
|
+
"--output",
|
|
37
|
+
type=str,
|
|
38
|
+
help="output file to write filled template",
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
parser.set_defaults(func=handle_fill)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def handle_fill(args: Namespace, parser: ArgumentParser) -> None:
|
|
45
|
+
scheme = Path(args.scheme)
|
|
46
|
+
output = args.output
|
|
47
|
+
|
|
48
|
+
if args.template is None:
|
|
49
|
+
if sys.stdin.isatty():
|
|
50
|
+
parser.error("no template provided (file or stdin)")
|
|
51
|
+
return
|
|
52
|
+
template_content = sys.stdin.read()
|
|
53
|
+
elif args.template == "-":
|
|
54
|
+
template_content = sys.stdin.read()
|
|
55
|
+
else:
|
|
56
|
+
try:
|
|
57
|
+
template_content = Path(args.template).read_text()
|
|
58
|
+
except OSError as e:
|
|
59
|
+
parser.error(f"cannot read template file: {e}")
|
|
60
|
+
|
|
61
|
+
if args.palette:
|
|
62
|
+
try:
|
|
63
|
+
palette_toml = Path(args.palette).read_text()
|
|
64
|
+
except OSError as e:
|
|
65
|
+
parser.error(f"cannot read palette file: {e}")
|
|
66
|
+
return
|
|
67
|
+
else:
|
|
68
|
+
palette_toml = generate_palette("hex", "toml")
|
|
69
|
+
|
|
70
|
+
palette_dict = tomllib.loads(palette_toml)
|
|
71
|
+
concrete_scheme = TOMLTemplate(scheme).fill_dict(palette_dict)
|
|
72
|
+
filled_template = Template(template_content).fill(concrete_scheme)
|
|
73
|
+
|
|
74
|
+
if output is None:
|
|
75
|
+
print(filled_template)
|
|
76
|
+
else:
|
|
77
|
+
with Path(output).open("w") as f:
|
|
78
|
+
f.write(filled_template)
|
monobiome/cli/palette.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import argparse
|
|
2
1
|
from pathlib import Path
|
|
2
|
+
from argparse import Namespace, ArgumentParser
|
|
3
3
|
|
|
4
4
|
from monobiome.util import _SubparserType
|
|
5
5
|
from monobiome.palette import generate_palette
|
|
@@ -17,7 +17,7 @@ def register_parser(subparsers: _SubparserType) -> None:
|
|
|
17
17
|
type=str,
|
|
18
18
|
default="hex",
|
|
19
19
|
choices=["hex", "oklch"],
|
|
20
|
-
help="
|
|
20
|
+
help="color notation to export (either hex or oklch)",
|
|
21
21
|
)
|
|
22
22
|
parser.add_argument(
|
|
23
23
|
"-f",
|
|
@@ -25,19 +25,19 @@ def register_parser(subparsers: _SubparserType) -> None:
|
|
|
25
25
|
type=str,
|
|
26
26
|
default="toml",
|
|
27
27
|
choices=["json", "toml"],
|
|
28
|
-
help="
|
|
28
|
+
help="format of palette file (either JSON or TOML)",
|
|
29
29
|
)
|
|
30
30
|
parser.add_argument(
|
|
31
31
|
"-o",
|
|
32
32
|
"--output",
|
|
33
33
|
type=str,
|
|
34
|
-
help="
|
|
34
|
+
help="output file to write palette content",
|
|
35
35
|
)
|
|
36
36
|
|
|
37
37
|
parser.set_defaults(func=handle_palette)
|
|
38
38
|
|
|
39
39
|
|
|
40
|
-
def handle_palette(args:
|
|
40
|
+
def handle_palette(args: Namespace, parser: ArgumentParser) -> None:
|
|
41
41
|
notation = args.notation
|
|
42
42
|
file_format = args.format
|
|
43
43
|
output = args.output
|
monobiome/cli/scheme.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import argparse
|
|
2
1
|
from pathlib import Path
|
|
2
|
+
from argparse import Namespace, ArgumentParser
|
|
3
3
|
|
|
4
4
|
from monobiome.util import _SubparserType
|
|
5
5
|
from monobiome.scheme import generate_scheme
|
|
@@ -16,13 +16,13 @@ def register_parser(subparsers: _SubparserType) -> None:
|
|
|
16
16
|
"mode",
|
|
17
17
|
type=str,
|
|
18
18
|
choices=["dark", "light"],
|
|
19
|
-
help="
|
|
19
|
+
help="scheme mode (light or dark)"
|
|
20
20
|
)
|
|
21
21
|
parser.add_argument(
|
|
22
22
|
"biome",
|
|
23
23
|
type=str,
|
|
24
24
|
choices=list(monotone_h_map.keys()),
|
|
25
|
-
help="
|
|
25
|
+
help="biome setting for scheme"
|
|
26
26
|
)
|
|
27
27
|
parser.add_argument(
|
|
28
28
|
"-m",
|
|
@@ -30,7 +30,7 @@ def register_parser(subparsers: _SubparserType) -> None:
|
|
|
30
30
|
type=str,
|
|
31
31
|
default="oklch",
|
|
32
32
|
choices=["wcag", "oklch", "lightness"],
|
|
33
|
-
help="
|
|
33
|
+
help="metric to use for measuring swatch distances"
|
|
34
34
|
)
|
|
35
35
|
|
|
36
36
|
# e.g., wcag=4.5; oklch=0.40; lightness=40
|
|
@@ -39,13 +39,13 @@ def register_parser(subparsers: _SubparserType) -> None:
|
|
|
39
39
|
"--distance",
|
|
40
40
|
type=float,
|
|
41
41
|
default=0.40,
|
|
42
|
-
help="
|
|
42
|
+
help="distance threshold for specified metric",
|
|
43
43
|
)
|
|
44
44
|
parser.add_argument(
|
|
45
45
|
"-o",
|
|
46
46
|
"--output",
|
|
47
47
|
type=str,
|
|
48
|
-
help="
|
|
48
|
+
help="output file to write scheme content",
|
|
49
49
|
)
|
|
50
50
|
|
|
51
51
|
# these params remain rooted in lightness; no need to accommodate metric
|
|
@@ -58,13 +58,13 @@ def register_parser(subparsers: _SubparserType) -> None:
|
|
|
58
58
|
"--l-base",
|
|
59
59
|
type=int,
|
|
60
60
|
default=20,
|
|
61
|
-
help="
|
|
61
|
+
help="minimum lightness level (default: 20)",
|
|
62
62
|
)
|
|
63
63
|
parser.add_argument(
|
|
64
64
|
"--l-step",
|
|
65
65
|
type=int,
|
|
66
66
|
default=5,
|
|
67
|
-
help="
|
|
67
|
+
help="lightness step size (default: 5)",
|
|
68
68
|
)
|
|
69
69
|
|
|
70
70
|
# gaps
|
|
@@ -72,25 +72,25 @@ def register_parser(subparsers: _SubparserType) -> None:
|
|
|
72
72
|
"--fg-gap",
|
|
73
73
|
type=int,
|
|
74
74
|
default=50,
|
|
75
|
-
help="
|
|
75
|
+
help="foreground lightness gap (default: 50)",
|
|
76
76
|
)
|
|
77
77
|
parser.add_argument(
|
|
78
78
|
"--grey-gap",
|
|
79
79
|
type=int,
|
|
80
80
|
default=30,
|
|
81
|
-
help="
|
|
81
|
+
help="grey lightness gap (default: 30)",
|
|
82
82
|
)
|
|
83
83
|
parser.add_argument(
|
|
84
84
|
"--term-fg-gap",
|
|
85
85
|
type=int,
|
|
86
86
|
default=65,
|
|
87
|
-
help="
|
|
87
|
+
help="terminal foreground lightness gap (default: 60)",
|
|
88
88
|
)
|
|
89
89
|
|
|
90
90
|
parser.set_defaults(func=handle_scheme)
|
|
91
91
|
|
|
92
92
|
|
|
93
|
-
def handle_scheme(args:
|
|
93
|
+
def handle_scheme(args: Namespace, parser: ArgumentParser) -> None:
|
|
94
94
|
output = args.output
|
|
95
95
|
|
|
96
96
|
mode = args.mode
|
monobiome/constants.py
CHANGED
|
@@ -121,3 +121,21 @@ for h_str, L_points_C in Lpoints_Cqbr_Hmap.items():
|
|
|
121
121
|
max(0, min(_C, l_maxC_h(_L, _h)))
|
|
122
122
|
for _L, _C in zip(L_points, L_points_C, strict=True)
|
|
123
123
|
]
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
# strictly enforce curve bounds s.t. there are no intersections
|
|
127
|
+
# order is determined by the max attained chromap
|
|
128
|
+
max_Cstar_Horder = [
|
|
129
|
+
(h_str, max(Lpoints_Cstar))
|
|
130
|
+
for h_str, Lpoints_Cstar in Lpoints_Cstar_Hmap.items()
|
|
131
|
+
]
|
|
132
|
+
max_Cstar_Horder = sorted(max_Cstar_Horder, key=lambda t: t[1], reverse=True)
|
|
133
|
+
|
|
134
|
+
for i in range(len(max_Cstar_Horder)-1):
|
|
135
|
+
outer_h, _ = max_Cstar_Horder[i]
|
|
136
|
+
inner_h, _ = max_Cstar_Horder[i+1]
|
|
137
|
+
|
|
138
|
+
Lpoints_Cstar_Hmap[inner_h] = [
|
|
139
|
+
min(inner_c, Lpoints_Cstar_Hmap[outer_h][ci])
|
|
140
|
+
for ci, inner_c in enumerate(Lpoints_Cstar_Hmap[inner_h])
|
|
141
|
+
]
|
monobiome/curve.py
CHANGED
|
@@ -9,8 +9,8 @@ def quad_bezier_rational(
|
|
|
9
9
|
P1: float,
|
|
10
10
|
P2: float,
|
|
11
11
|
w: float,
|
|
12
|
-
t: np.
|
|
13
|
-
) -> np.
|
|
12
|
+
t: np.ndarray,
|
|
13
|
+
) -> np.ndarray:
|
|
14
14
|
"""
|
|
15
15
|
Compute the point values of a quadratic rational Bezier curve.
|
|
16
16
|
|
|
@@ -32,7 +32,7 @@ def bezier_y_at_x(
|
|
|
32
32
|
w: float,
|
|
33
33
|
x: float,
|
|
34
34
|
n: int = 400,
|
|
35
|
-
) -> np.
|
|
35
|
+
) -> np.ndarray:
|
|
36
36
|
"""
|
|
37
37
|
For the provided QBR parameters, provide the curve value at the given
|
|
38
38
|
input.
|
monobiome/palette.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import json
|
|
2
|
+
from typing import Any
|
|
2
3
|
from functools import cache
|
|
3
4
|
from importlib.metadata import version
|
|
4
5
|
|
|
@@ -12,7 +13,7 @@ from monobiome.constants import (
|
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
@cache
|
|
15
|
-
def compute_hlc_map(notation: str) -> dict[str,
|
|
16
|
+
def compute_hlc_map(notation: str) -> dict[str, Any]:
|
|
16
17
|
hlc_map = {}
|
|
17
18
|
|
|
18
19
|
for h_str, Lpoints_Cstar in Lpoints_Cstar_Hmap.items():
|
|
@@ -44,7 +45,7 @@ def generate_palette(
|
|
|
44
45
|
hlc_map["version"] = mb_version
|
|
45
46
|
return json.dumps(hlc_map, indent=4)
|
|
46
47
|
else:
|
|
47
|
-
toml_lines = [f"version = {mb_version}", ""]
|
|
48
|
+
toml_lines = [f"version = \"{mb_version}\"", ""]
|
|
48
49
|
for _h, _lc_map in hlc_map.items():
|
|
49
50
|
toml_lines.append(f"[{_h}]")
|
|
50
51
|
for _l, _c in _lc_map.items():
|
monobiome/plotting.py
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
from importlib.metadata import version
|
|
2
|
+
|
|
1
3
|
import numpy as np
|
|
2
4
|
import matplotlib.pyplot as plt
|
|
3
5
|
from coloraide import Color
|
|
6
|
+
from matplotlib.collections import LineCollection
|
|
4
7
|
|
|
5
8
|
from monobiome.palette import compute_hlc_map
|
|
6
9
|
from monobiome.constants import (
|
|
@@ -10,11 +13,13 @@ from monobiome.constants import (
|
|
|
10
13
|
accent_h_map,
|
|
11
14
|
monotone_h_map,
|
|
12
15
|
Lspace_Cmax_Hmap,
|
|
16
|
+
max_Cstar_Horder,
|
|
13
17
|
Lpoints_Cstar_Hmap,
|
|
14
18
|
)
|
|
15
19
|
|
|
20
|
+
VERSION = version("monobiome")
|
|
16
21
|
|
|
17
|
-
def plot_hue_chroma_bounds() ->
|
|
22
|
+
def plot_hue_chroma_bounds() -> tuple[plt.Figure, plt.Axes]:
|
|
18
23
|
name_h_map = {}
|
|
19
24
|
ax_h_map = {}
|
|
20
25
|
fig, axes = plt.subplots(
|
|
@@ -63,43 +68,54 @@ def plot_hue_chroma_bounds() -> None:
|
|
|
63
68
|
ncol=3
|
|
64
69
|
)
|
|
65
70
|
|
|
66
|
-
plt.suptitle("$C^*$ curves for hue groups")
|
|
67
|
-
plt.show()
|
|
71
|
+
plt.suptitle(f"$C^*$ curves for hue groups (v{VERSION})")
|
|
68
72
|
|
|
73
|
+
return fig, axes
|
|
69
74
|
|
|
70
|
-
def plot_hue_chroma_star() ->
|
|
75
|
+
def plot_hue_chroma_star() -> tuple[plt.Figure, plt.Axes]:
|
|
71
76
|
fig, ax = plt.subplots(1, 1, figsize=(8, 6))
|
|
72
77
|
|
|
73
|
-
# uncomment to preview 5 core term colors
|
|
74
78
|
colors = accent_h_map.keys()
|
|
75
|
-
#
|
|
79
|
+
# uncomment to preview just the 5 core term colors
|
|
80
|
+
# colors = set(["red", "orange", "yellow", "green", "blue"])
|
|
81
|
+
|
|
82
|
+
for h_str, _ in max_Cstar_Horder:
|
|
83
|
+
Lpoints_Cstar = Lpoints_Cstar_Hmap[h_str]
|
|
76
84
|
|
|
77
|
-
for h_str in Lpoints_Cstar_Hmap:
|
|
78
85
|
if h_str not in accent_h_map or h_str not in colors:
|
|
79
86
|
continue
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
87
|
+
|
|
88
|
+
_h = h_map[h_str]
|
|
89
|
+
h_colors = [
|
|
90
|
+
Color('oklch', [_l/100, _c, _h]).convert("srgb")
|
|
91
|
+
for _l, _c in zip(L_points, Lpoints_Cstar, strict=True)
|
|
92
|
+
]
|
|
93
|
+
|
|
94
|
+
x = np.asarray(L_points)
|
|
95
|
+
y = np.asarray(Lpoints_Cstar)
|
|
96
|
+
pts = np.column_stack([x, y]).reshape(-1, 1, 2)
|
|
97
|
+
segs = np.concatenate([pts[:-1], pts[1:]], axis=1)
|
|
98
|
+
rgb = np.asarray(h_colors)
|
|
99
|
+
seg_colors = (rgb[:-1] + rgb[1:]) / 2
|
|
100
|
+
lc = LineCollection(segs, colors=seg_colors, linewidth=3,
|
|
101
|
+
capstyle="round", joinstyle="round",
|
|
102
|
+
label=h_str)
|
|
103
|
+
|
|
104
|
+
ax.add_collection(lc)
|
|
105
|
+
ax.autoscale_view()
|
|
91
106
|
|
|
92
107
|
ax.set_xlabel("Lightness (%)")
|
|
93
108
|
ax.set_xticks([L_points[0], 45, 50, 55, 60, 65, 70, L_points[-1]])
|
|
94
|
-
plt.suptitle("$C^*$ curves (v1.4.0)")
|
|
95
|
-
fig.show()
|
|
96
109
|
|
|
110
|
+
plt.suptitle(f"$C^*$ curves (v{VERSION})")
|
|
111
|
+
|
|
112
|
+
return fig, ax
|
|
97
113
|
|
|
98
114
|
def palette_image(
|
|
99
115
|
palette: dict[str, dict[int, str]],
|
|
100
116
|
cell_size: int = 40,
|
|
101
117
|
keys: list[str] | None = None
|
|
102
|
-
) ->
|
|
118
|
+
) -> tuple[np.ndarray, list[str], list[list[int]]]:
|
|
103
119
|
names = list(palette.keys()) if keys is None else keys
|
|
104
120
|
|
|
105
121
|
row_count = len(names)
|
|
@@ -114,41 +130,57 @@ def palette_image(
|
|
|
114
130
|
|
|
115
131
|
for r, name in enumerate(names):
|
|
116
132
|
shades = palette[name]
|
|
117
|
-
|
|
118
|
-
lightness_keys_per_row.append(
|
|
119
|
-
for c, k in enumerate(
|
|
133
|
+
lkeys = sorted(shades.keys())
|
|
134
|
+
lightness_keys_per_row.append(lkeys)
|
|
135
|
+
for c, k in enumerate(lkeys):
|
|
120
136
|
col = Color(shades[k]).convert("srgb").fit(method="clip")
|
|
121
137
|
rgb = [col["r"], col["g"], col["b"]]
|
|
122
138
|
r0, r1 = r * cell_size, (r + 1) * cell_size
|
|
123
139
|
c0, c1 = c * cell_size, (c + 1) * cell_size
|
|
124
140
|
img[r0:r1, c0:c1, :] = rgb
|
|
125
141
|
|
|
126
|
-
return img, names, lightness_keys_per_row
|
|
127
|
-
|
|
142
|
+
return img, names, lightness_keys_per_row
|
|
128
143
|
|
|
129
144
|
def show_palette(
|
|
130
145
|
palette: dict[str, dict[int, str]],
|
|
131
146
|
cell_size: int = 40,
|
|
132
|
-
keys: list[str] | None = None
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
)
|
|
147
|
+
keys: list[str] | None = None,
|
|
148
|
+
show_labels: bool = True,
|
|
149
|
+
dpi: int = 100,
|
|
150
|
+
) -> tuple[plt.Figure, plt.Axes]:
|
|
151
|
+
img, names, _ = palette_image(palette, cell_size, keys=keys)
|
|
137
152
|
|
|
138
153
|
fig_w = img.shape[1] / 100
|
|
139
154
|
fig_h = img.shape[0] / 100
|
|
140
|
-
fig, ax = plt.subplots(figsize=(fig_w, fig_h))
|
|
141
155
|
|
|
142
|
-
|
|
143
|
-
|
|
156
|
+
if show_labels:
|
|
157
|
+
fig, ax = plt.subplots(figsize=(fig_w, fig_h), dpi=dpi)
|
|
144
158
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
ax.set_yticklabels(names)
|
|
148
|
-
ax.set_ylim(img.shape[0], 0) # ensures rows render w/o half-cells
|
|
159
|
+
ax.imshow(img, interpolation="none", origin="upper")
|
|
160
|
+
ax.set_xticks([])
|
|
149
161
|
|
|
150
|
-
|
|
162
|
+
ytick_pos = [(i + 0.5) * cell_size for i in range(len(names))]
|
|
163
|
+
ax.set_yticks(ytick_pos)
|
|
164
|
+
ax.set_yticklabels(names)
|
|
165
|
+
ax.set_ylim(img.shape[0], 0) # ensures rows render w/o half-cells
|
|
166
|
+
|
|
167
|
+
return fig, ax
|
|
168
|
+
|
|
169
|
+
fig = plt.figure(figsize=(fig_w, fig_h), dpi=dpi, frameon=False)
|
|
170
|
+
ax = fig.add_axes((0, 0, 1, 1), frame_on=False)
|
|
171
|
+
ax.imshow(
|
|
172
|
+
img,
|
|
173
|
+
interpolation="nearest",
|
|
174
|
+
origin="upper",
|
|
175
|
+
extent=(0, img.shape[1], img.shape[0], 0),
|
|
176
|
+
aspect="auto",
|
|
177
|
+
)
|
|
178
|
+
ax.set_xlim(0, img.shape[1])
|
|
179
|
+
ax.set_ylim(img.shape[0], 0)
|
|
180
|
+
ax.axis("off")
|
|
181
|
+
fig.subplots_adjust(0, 0, 1, 1, hspace=0, wspace=0)
|
|
151
182
|
|
|
183
|
+
return fig, ax
|
|
152
184
|
|
|
153
185
|
if __name__ == "__main__":
|
|
154
186
|
keys = [
|
monobiome/scheme.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from functools import cache
|
|
2
2
|
from collections.abc import Callable
|
|
3
|
+
from importlib.metadata import version
|
|
3
4
|
|
|
4
5
|
from coloraide import Color
|
|
5
6
|
|
|
@@ -88,7 +89,7 @@ def generate_scheme_groups(
|
|
|
88
89
|
grey_gap: int,
|
|
89
90
|
term_fg_gap: int,
|
|
90
91
|
accent_color_map: dict[str, str],
|
|
91
|
-
) -> tuple[
|
|
92
|
+
) -> tuple[list[tuple[str, str]], ...]:
|
|
92
93
|
"""
|
|
93
94
|
Parameters:
|
|
94
95
|
mode: one of ["dark", "light"]
|
|
@@ -125,15 +126,16 @@ def generate_scheme_groups(
|
|
|
125
126
|
accent_colors = Lma_map.get(biome, {})
|
|
126
127
|
|
|
127
128
|
meta_pairs = [
|
|
129
|
+
("version", version("monobiome")),
|
|
128
130
|
("mode", mode),
|
|
129
131
|
("biome", biome),
|
|
130
132
|
("metric", metric),
|
|
131
|
-
("distance", distance),
|
|
132
|
-
("l_base", l_base),
|
|
133
|
-
("l_step", l_step),
|
|
134
|
-
("fg_gap", fg_gap),
|
|
135
|
-
("grey_gap", grey_gap),
|
|
136
|
-
("term_fg_gap", term_fg_gap),
|
|
133
|
+
("distance", str(distance)),
|
|
134
|
+
("l_base", str(l_base)),
|
|
135
|
+
("l_step", str(l_step)),
|
|
136
|
+
("fg_gap", str(fg_gap)),
|
|
137
|
+
("grey_gap", str(grey_gap)),
|
|
138
|
+
("term_fg_gap", str(term_fg_gap)),
|
|
137
139
|
]
|
|
138
140
|
|
|
139
141
|
# note how selection_bg steps up by `l_step`, selection_fg steps down by
|
|
@@ -233,7 +235,11 @@ def generate_scheme(
|
|
|
233
235
|
for lhs, rhs in pair_list
|
|
234
236
|
]
|
|
235
237
|
|
|
236
|
-
|
|
238
|
+
mb_version = version("monobiome")
|
|
239
|
+
scheme_pairs = [
|
|
240
|
+
"# ++ monobiome scheme file ++",
|
|
241
|
+
f"# ++ generated CLI @ {mb_version} ++",
|
|
242
|
+
]
|
|
237
243
|
scheme_pairs += pair_strings(meta)
|
|
238
244
|
scheme_pairs += pair_strings(mt)
|
|
239
245
|
scheme_pairs += pair_strings(ac)
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: monobiome
|
|
3
|
+
Version: 1.5.1
|
|
4
|
+
Summary: Monobiome color palette
|
|
5
|
+
Author-email: Sam Griesemer <git@olog.io>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://doc.olog.io/monobiome
|
|
8
|
+
Project-URL: Documentation, https://doc.olog.io/monobiome
|
|
9
|
+
Project-URL: Repository, https://git.olog.io/olog/monobiome
|
|
10
|
+
Project-URL: Issues, https://git.olog.io/olog/monobiome/issues
|
|
11
|
+
Keywords: tempate-engine,color-palette
|
|
12
|
+
Classifier: Programming Language :: Python
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Development Status :: 3 - Alpha
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
17
|
+
Requires-Python: >=3.12
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
Requires-Dist: coloraide>=5.1
|
|
20
|
+
Requires-Dist: imageio[ffmpeg]>=2.37.2
|
|
21
|
+
Requires-Dist: kaleido>=1.1.0
|
|
22
|
+
Requires-Dist: matplotlib>=3.10.7
|
|
23
|
+
Requires-Dist: nbformat>=5.10.4
|
|
24
|
+
Requires-Dist: numpy>=2.3.4
|
|
25
|
+
Requires-Dist: pillow>=12.0.0
|
|
26
|
+
Requires-Dist: plotly>=6.3.1
|
|
27
|
+
Requires-Dist: pyqt5>=5.15.11
|
|
28
|
+
Requires-Dist: scipy>=1.16.2
|
|
29
|
+
Requires-Dist: symconf>=0.8.4
|
|
30
|
+
Provides-Extra: dev
|
|
31
|
+
Requires-Dist: ipykernel; extra == "dev"
|
|
32
|
+
Provides-Extra: doc
|
|
33
|
+
Requires-Dist: furo; extra == "doc"
|
|
34
|
+
Requires-Dist: myst-parser; extra == "doc"
|
|
35
|
+
Requires-Dist: sphinx; extra == "doc"
|
|
36
|
+
Requires-Dist: sphinx-togglebutton; extra == "doc"
|
|
37
|
+
Requires-Dist: sphinx-autodoc-typehints; extra == "doc"
|
|
38
|
+
Provides-Extra: test
|
|
39
|
+
Requires-Dist: pytest; extra == "test"
|
|
40
|
+
|
|
41
|
+
# Monobiome
|
|
42
|
+
`monobiome` is a minimal, balanced color palette for use in terminals and text
|
|
43
|
+
editors. It was designed in OKLCH space to achieve perceptual uniformity across
|
|
44
|
+
all hues at various levels of luminance, and does so for eight monotone bases
|
|
45
|
+
and eight accent colors (plus one zero chroma default base). Each of the
|
|
46
|
+
monotone base colors (named according to a natural biome whose colors they
|
|
47
|
+
loosely resemble) are designed to achieve identical contrast with the accents,
|
|
48
|
+
and thus any one of the options can be selected to change the feeling of
|
|
49
|
+
downstream themes without sacrificing readability.
|
|
50
|
+
|
|
51
|
+

|
|
52
|
+
_(Preview of light and dark alpine theme variants)_
|
|
53
|
+
|
|
54
|
+
The name "monobiome" connects the palette to its two key sources of
|
|
55
|
+
inspiration:
|
|
56
|
+
|
|
57
|
+
- `mono-`: `monobiome` is inspired by the [`monoindustrial` theme][1], and
|
|
58
|
+
attempts to extend and balance its accents while retaining similar color
|
|
59
|
+
identities.
|
|
60
|
+
- `-biome`: the desire for several distinct monotone options entailed finding a
|
|
61
|
+
way to ground the subtle color variations that were needed, and I liked the
|
|
62
|
+
idea of tying the choices to naturally occurring environmental variation like
|
|
63
|
+
Earth's biomes (even if it is a very loose affiliation, e.g., green-ish =
|
|
64
|
+
grass, basically).
|
|
65
|
+
|
|
66
|
+
## Palette
|
|
67
|
+
The `monobiome` palette is fundamentally a set of parameterized curves in OKLCH
|
|
68
|
+
color space. Each color identity has one monotone curve and one accent curve,
|
|
69
|
+
both of which have fixed hue values and vary from 10% to 98% lightness.
|
|
70
|
+
Monotone curves have fixed chroma, whereas the accent curves' chroma varies
|
|
71
|
+
smoothly as a function of lightness within sRGB gamut bounds.
|
|
72
|
+
|
|
73
|
+
| Chroma curves | Color trajectories |
|
|
74
|
+
|----------------------------------------------------------|------------------------------------------|
|
|
75
|
+
|  |  |
|
|
76
|
+
|
|
77
|
+
| Palette |
|
|
78
|
+
|----------------------------------------------|
|
|
79
|
+
|  |
|
|
80
|
+
|
|
81
|
+
Chroma curves are designed specifically to establish a distinct role for each
|
|
82
|
+
accent and are non-intersecting over the lightness domain (hence the distinct
|
|
83
|
+
"bands" in the above chroma curve figure). There are eight monotone-accent
|
|
84
|
+
pairs, plus a single grey trajectory:
|
|
85
|
+
|
|
86
|
+
| Monotone / biome | Accent color | Hue |
|
|
87
|
+
| --- | --- | --- |
|
|
88
|
+
| alpine | grey | n/a |
|
|
89
|
+
| badlands | red | 29 |
|
|
90
|
+
| chaparral | orange | 62.5 |
|
|
91
|
+
| savanna | yellow | 104 |
|
|
92
|
+
| grassland | green | 148 |
|
|
93
|
+
| reef | cyan | 205 |
|
|
94
|
+
| tundra | blue | 262 |
|
|
95
|
+
| heathland | violet | 306 |
|
|
96
|
+
| moorland | magenta | 350 |
|
|
97
|
+
|
|
98
|
+
The `alpine`/`grey` curve has zero chroma (and is thus invariant to hue),
|
|
99
|
+
varying only in lightness from dark to light grey.
|
|
100
|
+
|
|
101
|
+
## Themes
|
|
102
|
+
|
|
103
|
+
| Dark themes | Light themes |
|
|
104
|
+
|----------------------------------------|------------------------------------------|
|
|
105
|
+
|  |  |
|
|
106
|
+
|
|
107
|
+
Themes are derived from the `monobiome` palette by selecting a monotone base
|
|
108
|
+
(the "biome"), a base lightness, and a contrast level. Although one can use
|
|
109
|
+
arbitrary contrast metrics, OKLCH distance (Euclidean distance in OKLab)
|
|
110
|
+
is designed to capture perceptual distinction. As such, perceptually uniform
|
|
111
|
+
themes under arbitrary monotones can be generated by calculating the accent
|
|
112
|
+
colors equidistant from that base. This is equivalent to determining the points
|
|
113
|
+
at which a sphere centered at the monotone base intersects with the accent
|
|
114
|
+
curves; the radius of such a sphere effectively determines the theme contrast,
|
|
115
|
+
and the colors on the sphere surface are equally perceptually distinct relative
|
|
116
|
+
to the background.
|
|
117
|
+
|
|
118
|
+
The following plots show the intersection of the sphere centered at a fixed
|
|
119
|
+
background color (`alpine` biome with a lightness of 20) under variable radii:
|
|
120
|
+
|
|
121
|
+
| | `-l 20 -d 0.3` | `-l 20 -d 0.4` | `-l 20 -d 0.5` |
|
|
122
|
+
|---------------------|---------------------------------------------------|---------------------------------------------------|---------------------------------------------------|
|
|
123
|
+
| Color visualization |  |  |  |
|
|
124
|
+
| Editor preview |  |  |  |
|
|
125
|
+
|
|
126
|
+
In short, the base lightness (`-l`) dictates the brightness of the background,
|
|
127
|
+
and the contrast (`-d`) controls how perceptually distinct the accent colors
|
|
128
|
+
appear with respect to that background. These are free parameters of the
|
|
129
|
+
`monobiome` model: themes can be generated under arbitrary settings that meet
|
|
130
|
+
user preferences.
|
|
131
|
+
|
|
132
|
+
## Generation
|
|
133
|
+
When generating full application themes, fixed lightness steps are used in the
|
|
134
|
+
chosen monotone trajectory to establish consistent levels of distinction
|
|
135
|
+
between background layers. For example, the following demonstrates how
|
|
136
|
+
background and foreground elements are chosen for the `monobiome` vim/neovim
|
|
137
|
+
themes:
|
|
138
|
+
|
|
139
|
+

|
|
143
|
+
|
|
144
|
+
Note how theme elements are mapped onto the general identifiers `bg0-bg3` for
|
|
145
|
+
backgrounds, `fg0-fg3` for foregrounds, and `gray` for a central gray tone. The
|
|
146
|
+
relative properties (lightness differences, contrast ratios) between colors
|
|
147
|
+
assigned to these identifiers are preserved regardless of biome or harshness
|
|
148
|
+
(e.g., `bg3` and `gray` are _always_ separated by 20 lightness points in any
|
|
149
|
+
theme). As a result, applying `monobiome` themes to specific applications can
|
|
150
|
+
effectively boil down to defining a single "relative template" that uses these
|
|
151
|
+
identifiers, after which any user-provided parameters can be applied
|
|
152
|
+
automatically.
|
|
153
|
+
|
|
154
|
+
The full palette $\rightarrow$ scheme $\rightarrow$ template $\rightarrow$
|
|
155
|
+
theme pipeline can be seen in detail below:
|
|
156
|
+
|
|
157
|
+

|
|
158
|
+
|
|
159
|
+
This figure demonstrates how `kitty` themes are generated, but the process is
|
|
160
|
+
generic to any palette, scheme, and app. This is implemented in two stages
|
|
161
|
+
using the `monobiome` CLI:
|
|
162
|
+
|
|
163
|
+
- First generate the scheme file, the lightness choices that achieve perceptual
|
|
164
|
+
uniformity of accents with respect to the base monotone:
|
|
165
|
+
|
|
166
|
+
```sh
|
|
167
|
+
monobiome scheme dark grassland -d 0.42 -l 20 -o scheme.toml
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
This calculates the accents a distance of `0.42` units in Oklab space from the
|
|
171
|
+
`grassland` monotone base at a lightness of `20`, and writes the output to
|
|
172
|
+
`scheme.toml`.
|
|
173
|
+
- Then populate the scheme file with concrete palette colors and push it
|
|
174
|
+
through an app config template:
|
|
175
|
+
|
|
176
|
+
```sh
|
|
177
|
+
monobiome fill scheme.toml templates/kitty/active.theme -o kitty.theme
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
This writes a concrete `kitty` theme to `kitty.theme` that matches the user
|
|
181
|
+
preferences as captured in the previously generated scheme file, i.e., the
|
|
182
|
+
contrast (`-d`), background lightness (`-l`), mode (`dark`), and biome
|
|
183
|
+
(`grassland`). Every part of this process can be customized: the scheme
|
|
184
|
+
parameters, the scheme definitions/file, the app template.
|
|
185
|
+
|
|
186
|
+
Running these commands in sequence from the repo root should work
|
|
187
|
+
out-of-the-box after having installed the CLI tool.
|
|
188
|
+
|
|
189
|
+
## Applications
|
|
190
|
+
This repo provides palette-agnostic theme templates for `kitty`,
|
|
191
|
+
`vim`/`neovim`, and `fzf` in the `templates/` directory. Pre-generated
|
|
192
|
+
*concrete* themes can be found in `app-config/`, if you'd like to try an
|
|
193
|
+
example out-of-the-box without using the `monobiome` CLI. Raw
|
|
194
|
+
palette colors can be found in `colors/` if you want to use them to define
|
|
195
|
+
static themes for other applications.
|
|
196
|
+
|
|
197
|
+
Themes files in the `app-config/` directory are generated for light and dark
|
|
198
|
+
modes of each biome, and named according to the following pattern:
|
|
199
|
+
|
|
200
|
+
```sh
|
|
201
|
+
<biome>-monobiome-<mode>.<filename>
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
One can set these themes for the provided applications as follows:
|
|
205
|
+
|
|
206
|
+
- `kitty`
|
|
207
|
+
|
|
208
|
+
Find `kitty` themes in `app-config/kitty`. Themes can be activated in your
|
|
209
|
+
`kitty.conf` with
|
|
210
|
+
|
|
211
|
+
```sh
|
|
212
|
+
include <theme-file>
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Themes are generated using the [`kitty` theme
|
|
216
|
+
template](templates/kitty/active.theme).
|
|
217
|
+
|
|
218
|
+
- `vim`/`neovim`
|
|
219
|
+
|
|
220
|
+
Find `vim`/`neovim` themes in `app-config/nvim`. Themes can be activated by placing a
|
|
221
|
+
theme file on Vim's runtime path and setting it in your
|
|
222
|
+
`.vimrc`/`init.vim`/`init.lua`
|
|
223
|
+
|
|
224
|
+
with
|
|
225
|
+
|
|
226
|
+
```sh
|
|
227
|
+
colorscheme <theme-name>
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Themes are generated using the [`vim` theme
|
|
231
|
+
template](templates/nvim/theme.vim).
|
|
232
|
+
|
|
233
|
+
- `fzf`
|
|
234
|
+
|
|
235
|
+
In `app-config/fzf`, you can find scripts that can be ran to export FZF theme
|
|
236
|
+
variables. In your shell config (e.g., `.bashrc` or `.zshrc`), you can source
|
|
237
|
+
these files to apply them in your terminal:
|
|
238
|
+
|
|
239
|
+
```sh
|
|
240
|
+
source <theme-file>
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Themes are generated using the [`fzf` theme
|
|
244
|
+
template](templates/fzf/active.theme).
|
|
245
|
+
|
|
246
|
+
- Firefox
|
|
247
|
+
|
|
248
|
+
Firefox themes for all monotone backgrounds are publicly listed as [Mozilla
|
|
249
|
+
add-ons][2], and switch between light/dark schemes based on system settings.
|
|
250
|
+
You can also download raw XPI files for each theme in `app-config/firefox/`,
|
|
251
|
+
each of which is generated using the [Firefox `manifest.json`
|
|
252
|
+
template](templates/firefox/auto-manifest.json).
|
|
253
|
+
|
|
254
|
+
Static [light][4] and [dark][5] themes are additionally available (i.e., that
|
|
255
|
+
don't change with system settings).
|
|
256
|
+
|
|
257
|
+
## CLI installation
|
|
258
|
+
A brief theme generation guide was provided in the [Generation
|
|
259
|
+
section](#generation), making use of the `monobiome` CLI. This tool can be
|
|
260
|
+
installed from PyPI, using `uv`/`pipx`/similar:
|
|
261
|
+
|
|
262
|
+
```sh
|
|
263
|
+
uv tool install monobiome
|
|
264
|
+
# or
|
|
265
|
+
pipx install monobiome
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
`monobiome` provides three subcommands:
|
|
269
|
+
|
|
270
|
+
- `monobiome palette`: generate palette files from raw parameterized curves
|
|
271
|
+
|
|
272
|
+
```
|
|
273
|
+
usage: monobiome palette [-h] [-n {hex,oklch}] [-f {json,toml}] [-o OUTPUT]
|
|
274
|
+
|
|
275
|
+
options:
|
|
276
|
+
-n {hex,oklch}, --notation {hex,oklch}
|
|
277
|
+
color notation to export (either hex or oklch)
|
|
278
|
+
-f {json,toml}, --format {json,toml}
|
|
279
|
+
format of palette file (either JSON or TOML)
|
|
280
|
+
-o OUTPUT, --output OUTPUT
|
|
281
|
+
output file to write palette content
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
- `monobiome scheme`: generate scheme files that match perceptual parameters
|
|
285
|
+
|
|
286
|
+
```
|
|
287
|
+
usage: monobiome scheme [-h] [-m {wcag,oklch,lightness}] [-d DISTANCE] [-o OUTPUT] [-l L_BASE]
|
|
288
|
+
[--l-step L_STEP] [--fg-gap FG_GAP] [--grey-gap GREY_GAP]
|
|
289
|
+
[--term-fg-gap TERM_FG_GAP]
|
|
290
|
+
{dark,light}
|
|
291
|
+
{alpine,badlands,chaparral,savanna,grassland,reef,tundra,heathland,moorland}
|
|
292
|
+
|
|
293
|
+
positional arguments:
|
|
294
|
+
{dark,light} scheme mode (light or dark)
|
|
295
|
+
{alpine,badlands,chaparral,savanna,grassland,reef,tundra,heathland,moorland}
|
|
296
|
+
biome setting for scheme.
|
|
297
|
+
|
|
298
|
+
options:
|
|
299
|
+
-m {wcag,oklch,lightness}, --metric {wcag,oklch,lightness}
|
|
300
|
+
metric to use for measuring swatch distances.
|
|
301
|
+
-d DISTANCE, --distance DISTANCE
|
|
302
|
+
distance threshold for specified metric
|
|
303
|
+
-o OUTPUT, --output OUTPUT
|
|
304
|
+
output file to write scheme content
|
|
305
|
+
-l L_BASE, --l-base L_BASE
|
|
306
|
+
minimum lightness level (default: 20)
|
|
307
|
+
--l-step L_STEP lightness step size (default: 5)
|
|
308
|
+
--fg-gap FG_GAP foreground lightness gap (default: 50)
|
|
309
|
+
--grey-gap GREY_GAP grey lightness gap (default: 30)
|
|
310
|
+
--term-fg-gap TERM_FG_GAP
|
|
311
|
+
terminal foreground lightness gap (default: 60)
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
- `monobiome fill`: produce concrete application themes from a given scheme and
|
|
315
|
+
app template
|
|
316
|
+
|
|
317
|
+
```
|
|
318
|
+
usage: monobiome fill [-h] [-p PALETTE] [-o OUTPUT] scheme [template]
|
|
319
|
+
|
|
320
|
+
positional arguments:
|
|
321
|
+
scheme scheme file path
|
|
322
|
+
template template file path (defaults to stdin)
|
|
323
|
+
|
|
324
|
+
options:
|
|
325
|
+
-p PALETTE, --palette PALETTE
|
|
326
|
+
palette file to use for color definitions
|
|
327
|
+
-o OUTPUT, --output OUTPUT
|
|
328
|
+
output file to write filled template
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
## Config management
|
|
332
|
+
The `monobiome` CLI tool attempts to provide the minimal functionality needed
|
|
333
|
+
to produce customized themes for individual applications. If seeking a more
|
|
334
|
+
holistic, system-wide approach, you might consider using [`symconf`][3], a
|
|
335
|
+
general-purpose application config manager. `symconf` provides the templating
|
|
336
|
+
subsystem used for `monobiome` internals, and can be configured to apply live
|
|
337
|
+
theme updates to many apps with a single command line invocation.
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
[1]: https://github.com/isa/TextMate-Themes/blob/master/monoindustrial.tmTheme
|
|
341
|
+
[2]: https://addons.mozilla.org/en-US/firefox/collections/18495484/monobiome/
|
|
342
|
+
[3]: https://github.com/ologio/symconf
|
|
343
|
+
[4]: https://addons.mozilla.org/en-US/firefox/collections/18495484/monobiome-light/
|
|
344
|
+
[5]: https://addons.mozilla.org/en-US/firefox/collections/18495484/monobiome-dark/
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
monobiome/__init__.py,sha256=ChC5YFLK0kgvi0MJwD68LtZgUMJVCtNbtY32UQTvdA4,75
|
|
2
|
+
monobiome/__main__.py,sha256=4K-CQWWiSXQbXgNLPqdOts6R3wOJeDJ0ygSARPI-eiA,439
|
|
3
|
+
monobiome/constants.py,sha256=zkIDBtPS3unt9EulnTfpJV8r82Cc1Q-8c7u2Y2jcgBY,3694
|
|
4
|
+
monobiome/curve.py,sha256=4IMn-YksJrqMOR-oYjA9oIJChI_Hz11AmynhYjLXl48,1754
|
|
5
|
+
monobiome/palette.py,sha256=EhB90k1XINzbCxU8bBWc_fnEtbOXoJYfwAbtyx1nG-g,1505
|
|
6
|
+
monobiome/plotting.py,sha256=pRGIsdW8SfjUbfEy8IZhLwzX5au6xc6vwtnDZymScvU,6127
|
|
7
|
+
monobiome/scheme.py,sha256=5AwQW5Ibs-B7ZahGSXSmTE7CFZUpk3SKN42Qo-EW2AM,7793
|
|
8
|
+
monobiome/util.py,sha256=qHLC-azOgslJcW1tNNX5TVeG3RPGpleUO2s9Nu1rbjY,1068
|
|
9
|
+
monobiome/cli/__init__.py,sha256=bs2ZJZSWNg5tuxzAMzRzyB25Lbc4PDCVbrF2IKl2lK8,819
|
|
10
|
+
monobiome/cli/fill.py,sha256=FbDpUZJegCUatFxPRk8hp4z2V93WBwqHPCOpw3rzJR4,2116
|
|
11
|
+
monobiome/cli/palette.py,sha256=X1QET3UU1RxzT8D0JLWL1JKNlSQ6Dulwl1J-GLc_218,1265
|
|
12
|
+
monobiome/cli/scheme.py,sha256=DNwA6Af3bJZpjImisncOgQo_kFHGTot-Ydv6o4FR1-Y,3769
|
|
13
|
+
monobiome/data/parameters.toml,sha256=7ru0j_1G5rNFWc7AFKSHJUpyL_I2qdZYeDFt6q5wtQw,801
|
|
14
|
+
monobiome-1.5.1.dist-info/METADATA,sha256=RBoL2842uiSvxZFi4wHxyJCX2GWFWUZm8Byus44J_Q0,14796
|
|
15
|
+
monobiome-1.5.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
16
|
+
monobiome-1.5.1.dist-info/entry_points.txt,sha256=LpqkPxdTacTY_TaRn8eczICmPbVlXdRSoMqaxSfVxh4,54
|
|
17
|
+
monobiome-1.5.1.dist-info/top_level.txt,sha256=ZA2wgRkPoG4xG0rSjyHKkuG8cdSHRr1U_DcrplXoi3A,10
|
|
18
|
+
monobiome-1.5.1.dist-info/RECORD,,
|
|
@@ -1,232 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: monobiome
|
|
3
|
-
Version: 1.4.0
|
|
4
|
-
Summary: Monobiome color palette
|
|
5
|
-
Project-URL: Homepage, https://doc.olog.io/monobiome
|
|
6
|
-
Project-URL: Documentation, https://doc.olog.io/monobiome
|
|
7
|
-
Project-URL: Repository, https://git.olog.io/olog/monobiome
|
|
8
|
-
Project-URL: Issues, https://git.olog.io/olog/monobiome/issues
|
|
9
|
-
Requires-Python: >=3.12
|
|
10
|
-
Description-Content-Type: text/markdown
|
|
11
|
-
Requires-Dist: coloraide>=5.1
|
|
12
|
-
Requires-Dist: imageio[ffmpeg]>=2.37.2
|
|
13
|
-
Requires-Dist: ipython>=9.6.0
|
|
14
|
-
Requires-Dist: kaleido>=1.1.0
|
|
15
|
-
Requires-Dist: matplotlib>=3.10.7
|
|
16
|
-
Requires-Dist: nbformat>=5.10.4
|
|
17
|
-
Requires-Dist: numpy>=2.3.4
|
|
18
|
-
Requires-Dist: pillow>=12.0.0
|
|
19
|
-
Requires-Dist: plotly>=6.3.1
|
|
20
|
-
Requires-Dist: pyqt5>=5.15.11
|
|
21
|
-
Requires-Dist: scipy>=1.16.2
|
|
22
|
-
|
|
23
|
-
# Monobiome
|
|
24
|
-
`monobiome` is a minimal, balanced color palette for use in terminals and text
|
|
25
|
-
editors. It was designed in OKLCH space to achieve perceptual uniformity across
|
|
26
|
-
all hues at various levels of luminance, and does so for _five_ monotone bases
|
|
27
|
-
and _five_ accent colors (plus one gray "default"). Each of the monotone base
|
|
28
|
-
colors (named according to a natural biome whose colors they loosely resemble)
|
|
29
|
-
are designed to achieve identical contrast with the accents, and thus any one
|
|
30
|
-
of the options can be selected to change the feeling of the palette without
|
|
31
|
-
sacrificing readability.
|
|
32
|
-
|
|
33
|
-

|
|
34
|
-
_(Preview of default light and dark theme variants)_
|
|
35
|
-
|
|
36
|
-
See screenshots for the full set of theme variants in [THEMES](THEMES.md) (also
|
|
37
|
-
discussed below).
|
|
38
|
-
|
|
39
|
-
The name "monobiome" connects the palette to its two key sources of
|
|
40
|
-
inspiration:
|
|
41
|
-
|
|
42
|
-
- `mono-`: `monobiome` is inspired by the [`monoindustrial` theme][1], and
|
|
43
|
-
attempts to extend and balance its accents while retaining similar color
|
|
44
|
-
identities.
|
|
45
|
-
- `-biome`: the desire for several distinct monotone options entailed finding a
|
|
46
|
-
way to ground the subtle color variations that were needed, and I liked the
|
|
47
|
-
idea of tying the choices to naturally occurring environmental variation like
|
|
48
|
-
Earth's biomes (even if it is a very loose affiliation, e.g., green-ish =
|
|
49
|
-
grass, basically).
|
|
50
|
-
|
|
51
|
-
## Palette
|
|
52
|
-
The `monobiome` palette consists of four monotone bases and five accent colors,
|
|
53
|
-
each of which is anchored by hue and spread uniformly across lightness levels
|
|
54
|
-
15 to 95 (in OKLCH space).
|
|
55
|
-
|
|
56
|
-

|
|
57
|
-
|
|
58
|
-
The chroma curve for each accent is carefully designed to vary smoothly across
|
|
59
|
-
the lightness spectrum, with the goal of retaining strong color identity in all
|
|
60
|
-
settings. Additionally, as alluded to above, the (WCAG 2) contrast ratio
|
|
61
|
-
between any choice of monotone background at a given lightness level and the
|
|
62
|
-
accent colors is virtually identical ($\pm 0.1$). Put another way, the relative
|
|
63
|
-
contrast between accents depends only on the _lightness_ of the background
|
|
64
|
-
monotone, not its hue. *(Note that this is not generally the case; at a fixed
|
|
65
|
-
lightness level, the contrast between two colors depends on their hue.)*
|
|
66
|
-
|
|
67
|
-
## Concrete themes
|
|
68
|
-
|
|
69
|
-

|
|
70
|
-
|
|
71
|
-
*(Light and dark theme splits of Alpine and Tundra biomes)*
|
|
72
|
-
|
|
73
|
-
Themes are derived from the `monobiome` palette by varying both the monotone
|
|
74
|
-
hue (the "biome") and the extent of the background/foreground lightness (the
|
|
75
|
-
"harshness"). This is done for both light and dark schemes, and in each case
|
|
76
|
-
accent colors are selected at a lightness level that ensures each meet a
|
|
77
|
-
minimum contrast relative to the primary background. The following diagram
|
|
78
|
-
shows each of the 36 resulting combinations:
|
|
79
|
-
|
|
80
|
-

|
|
81
|
-
|
|
82
|
-
The "soft" harshness level uses monotone shades closer to the mid-shade
|
|
83
|
-
(lightness level 55), whereas "hard" harshness uses shades further from it.
|
|
84
|
-
Once the biome and harshness level are chosen, we're left with a bounded
|
|
85
|
-
monotone range over which common theme elements can be defined. For example,
|
|
86
|
-
the following demonstrates how background and foreground elements are chosen
|
|
87
|
-
for the `monobiome` Vim themes:
|
|
88
|
-
|
|
89
|
-

|
|
93
|
-
|
|
94
|
-
Note how theme elements are mapped onto the general identifiers `bg0-bg3` for
|
|
95
|
-
backgrounds, `fg0-fg3` for foregrounds, and `gray` for a central gray tone. The
|
|
96
|
-
relative properties (lightness differences, contrast ratios) between colors
|
|
97
|
-
assigned to these identifiers are preserved regardless of biome or harshness
|
|
98
|
-
(e.g., `bg3` and `gray` are _always_ separated by 20 lightness points in any
|
|
99
|
-
theme). As a result, applying `monobiome` themes to specific applications can
|
|
100
|
-
effectively boil down to defining a single "relative template" that uses these
|
|
101
|
-
identifiers, after which any of the 36 theme options can applied immediately.
|
|
102
|
-
|
|
103
|
-
Read more about how themes are created in [DESIGN](DESIGN.md).
|
|
104
|
-
|
|
105
|
-
# Usage
|
|
106
|
-
This repo provides the 36 theme files for `kitty`, `vim`/`neovim`, and `fzf` in
|
|
107
|
-
the `app-config/` directory. You can also find raw palette colors in
|
|
108
|
-
`colors/monobiome.toml` if you want to use them to define themes for other
|
|
109
|
-
applications.
|
|
110
|
-
|
|
111
|
-
Each of the files in the `app-config/` directory are named according to
|
|
112
|
-
|
|
113
|
-
```sh
|
|
114
|
-
<harshness>-<biome>-monobiome-<mode>.<ext>
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
For example, `monobiome-tundra-dark-soft.vim` is the Vim theme file for the
|
|
118
|
-
dark `tundra` variant with the soft harshness level.
|
|
119
|
-
|
|
120
|
-
## Applications
|
|
121
|
-
- `kitty`
|
|
122
|
-
|
|
123
|
-
Find `kitty` themes in `app-config/kitty`. Themes can be activated in your
|
|
124
|
-
`kitty.conf` with
|
|
125
|
-
|
|
126
|
-
```sh
|
|
127
|
-
include <theme-file>
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
Themes are generated using the [`kitty` theme
|
|
131
|
-
template](templates/apps/kitty/templates/active.theme).
|
|
132
|
-
|
|
133
|
-
- `vim`/`neovim`
|
|
134
|
-
|
|
135
|
-
Find `vim`/`neovim` themes in `app-config/nvim`. Themes can be activated by placing a
|
|
136
|
-
theme file on Vim's runtime path and setting it in your `.vimrc`/`init.vim`
|
|
137
|
-
with
|
|
138
|
-
|
|
139
|
-
```sh
|
|
140
|
-
colorscheme <theme-name>
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
Themes are generated using the [`vim` theme
|
|
144
|
-
template](templates/apps/nvim/templates/theme.vim).
|
|
145
|
-
|
|
146
|
-
- `fzf`
|
|
147
|
-
|
|
148
|
-
In `app-config/fzf`, you can find scripts that can be ran to export FZF theme
|
|
149
|
-
variables. In your shell config (e.g., `.bashrc` or `.zshrc`), you can source
|
|
150
|
-
these files to apply them in your terminal:
|
|
151
|
-
|
|
152
|
-
```sh
|
|
153
|
-
source <theme-file>
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
Themes are generated using the [`fzf` theme
|
|
157
|
-
template](templates/apps/fzf/templates/active.theme).
|
|
158
|
-
|
|
159
|
-
- Firefox
|
|
160
|
-
|
|
161
|
-
Firefox themes for all monotone backgrounds are publicly listed as [Mozilla
|
|
162
|
-
add-ons][2], and switch between light/dark schemes based on system settings.
|
|
163
|
-
You can also download raw XPI files for each theme in `app-config/firefox/`,
|
|
164
|
-
each of which is generated using the [Firefox `manifest.json`
|
|
165
|
-
template](templates/apps/firefox/templates/none-dark.manifest.json).
|
|
166
|
-
|
|
167
|
-
Static [light][4] and [dark][5] are additionally available.
|
|
168
|
-
|
|
169
|
-

|
|
170
|
-
|
|
171
|
-
# Switching themes
|
|
172
|
-
[`symconf`][3] is a general-purpose application config manager that can be used
|
|
173
|
-
to generate all `monobiome` variants from a single palette file, and set themes
|
|
174
|
-
for all apps at once. You can find example theme templates in
|
|
175
|
-
`templates/groups/theme`, which provide general theme variables you can use in
|
|
176
|
-
your own config templates.
|
|
177
|
-
|
|
178
|
-
For instance, in an app like `kitty`, you can define a template like
|
|
179
|
-
|
|
180
|
-
```conf
|
|
181
|
-
# base settings
|
|
182
|
-
background f{{theme.term.background}}
|
|
183
|
-
foreground f{{theme.term.foreground}}
|
|
184
|
-
|
|
185
|
-
selection_background f{{theme.term.selection_bg}}
|
|
186
|
-
selection_foreground f{{theme.term.selection_fg}}
|
|
187
|
-
|
|
188
|
-
cursor f{{theme.term.cursor}}
|
|
189
|
-
cursor_text_color f{{theme.term.cursor_text_color}}
|
|
190
|
-
|
|
191
|
-
# black
|
|
192
|
-
color0 f{{theme.term.normal.black}}
|
|
193
|
-
color8 f{{theme.term.bright.black}}
|
|
194
|
-
|
|
195
|
-
# red
|
|
196
|
-
color1 f{{theme.term.normal.red}}
|
|
197
|
-
color9 f{{theme.term.bright.red}}
|
|
198
|
-
|
|
199
|
-
# green
|
|
200
|
-
color2 f{{theme.term.normal.green}}
|
|
201
|
-
color10 f{{theme.term.bright.green}}
|
|
202
|
-
|
|
203
|
-
# yellow
|
|
204
|
-
color3 f{{theme.term.normal.yellow}}
|
|
205
|
-
color11 f{{theme.term.bright.yellow}}
|
|
206
|
-
|
|
207
|
-
# blue
|
|
208
|
-
color4 f{{theme.term.normal.blue}}
|
|
209
|
-
color12 f{{theme.term.bright.blue}}
|
|
210
|
-
|
|
211
|
-
# purple (red)
|
|
212
|
-
color5 f{{theme.term.normal.purple}}
|
|
213
|
-
color13 f{{theme.term.bright.purple}}
|
|
214
|
-
|
|
215
|
-
# cyan (blue)
|
|
216
|
-
color6 f{{theme.term.normal.cyan}}
|
|
217
|
-
color14 f{{theme.term.bright.cyan}}
|
|
218
|
-
|
|
219
|
-
## white
|
|
220
|
-
color7 f{{theme.term.normal.white}}
|
|
221
|
-
color15 f{{theme.term.bright.white}}
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
and use `symconf` to dynamically fill these variables based on a selected
|
|
225
|
-
biome/harshness/mode. This can be done for any app config file.
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
[1]: https://github.com/isa/TextMate-Themes/blob/master/monoindustrial.tmTheme
|
|
229
|
-
[2]: https://addons.mozilla.org/en-US/firefox/collections/18495484/monobiome/
|
|
230
|
-
[3]: https://github.com/ologio/symconf
|
|
231
|
-
[4]: https://addons.mozilla.org/en-US/firefox/collections/18495484/monobiome-light/
|
|
232
|
-
[5]: https://addons.mozilla.org/en-US/firefox/collections/18495484/monobiome-dark/
|
monobiome-1.4.0.dist-info/RECORD
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
monobiome/__init__.py,sha256=ChC5YFLK0kgvi0MJwD68LtZgUMJVCtNbtY32UQTvdA4,75
|
|
2
|
-
monobiome/__main__.py,sha256=k2Pu_FeAsW_wnE55Y-JJaRP_GgxAZEjW3z_Kmk3O8C8,431
|
|
3
|
-
monobiome/constants.py,sha256=w4H9V2Tp2ZK3ddcjtBdDtokZdj2Y1ssW3RSopxqP7rw,3105
|
|
4
|
-
monobiome/curve.py,sha256=tw44OoRGDSxTzljxJkgifWhCTEj05TBYnw4jOdrNgfA,1748
|
|
5
|
-
monobiome/palette.py,sha256=fReZD1Aa7xOKQQgnYB8qRxszZy1nq9XLqjUIblENsvI,1489
|
|
6
|
-
monobiome/plotting.py,sha256=QZ1nVAb6E-eb1pwaQAbwOhqhRhzQ0SgR_8mC63zNFIo,4909
|
|
7
|
-
monobiome/scheme.py,sha256=CFP_WqTk-CwbgpVt2E_TczC9cZymAh_lqbkWmN4AsOg,7541
|
|
8
|
-
monobiome/util.py,sha256=qHLC-azOgslJcW1tNNX5TVeG3RPGpleUO2s9Nu1rbjY,1068
|
|
9
|
-
monobiome/cli/__init__.py,sha256=wtBhzdyyRy0-WM4fUpDESJBiedYy8MbwousVCdangUE,774
|
|
10
|
-
monobiome/cli/palette.py,sha256=i3baWZs4Sverbd79YMBPYnH0P2rT0i7z3ZAtO_UBWNw,1219
|
|
11
|
-
monobiome/cli/scheme.py,sha256=CkwtGBCPUEPt2TnK_WDQBg8TKTw_hjGoQtbjjBlNmH0,3725
|
|
12
|
-
monobiome/data/parameters.toml,sha256=7ru0j_1G5rNFWc7AFKSHJUpyL_I2qdZYeDFt6q5wtQw,801
|
|
13
|
-
monobiome-1.4.0.dist-info/METADATA,sha256=JsUQbx8Zr_LkhOIw8DY3kSSgMrJtxprJCK1f686082s,8974
|
|
14
|
-
monobiome-1.4.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
15
|
-
monobiome-1.4.0.dist-info/entry_points.txt,sha256=LpqkPxdTacTY_TaRn8eczICmPbVlXdRSoMqaxSfVxh4,54
|
|
16
|
-
monobiome-1.4.0.dist-info/top_level.txt,sha256=ZA2wgRkPoG4xG0rSjyHKkuG8cdSHRr1U_DcrplXoi3A,10
|
|
17
|
-
monobiome-1.4.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|