User:Surjection/swatch

From Wiktionary, the free dictionary
Jump to navigation Jump to search

OUTDATED

See User:Surjection/swatch2 (WCAG) or User:Surjection/swatch3 (WCAG+APCA)

The base colors for each set are -5. The other colors are generated algorithmically.

Current algorithm:

  • -0 and -4 are linearly interpolated towards pure white at certain rates: -0 is 90% white, -1 is 80% white, -2 is 65% white, -3 is 50% white, -4 is 25% white.
  • -6 and -9 are more complicated. The color is converted to HSV, the saturation and value are altered, and then back to RGB. The new saturation is s' = 1 - (1 - s) * (1 - x) * s_scale and the new value is v' = v * (1 - x), where s_scale is s if s < 0.5 and 1 otherwise, and x is 0.15 for -6, 0.3 for -7, 0.45 for -8 and 0.6 for -9.

To convert colors from light mode to night mode, the color is converted to HSL and back, with the lightness value replaced by l' = min(1, 1.03 - l).

Swatches

[edit]

Light mode

[edit]
red-0
red-1
red-2
red-3
red-4
red-5
red-6
red-7
red-8
red-9
scarlet-0
scarlet-1
scarlet-2
scarlet-3
scarlet-4
scarlet-5
scarlet-6
scarlet-7
scarlet-8
scarlet-9
orange-0
orange-1
orange-2
orange-3
orange-4
orange-5
orange-6
orange-7
orange-8
orange-9
amber-0
amber-1
amber-2
amber-3
amber-4
amber-5
amber-6
amber-7
amber-8
amber-9
yellow-0
yellow-1
yellow-2
yellow-3
yellow-4
yellow-5
yellow-6
yellow-7
yellow-8
yellow-9
lime-0
lime-1
lime-2
lime-3
lime-4
lime-5
lime-6
lime-7
lime-8
lime-9
green-0
green-1
green-2
green-3
green-4
green-5
green-6
green-7
green-8
green-9
teal-0
teal-1
teal-2
teal-3
teal-4
teal-5
teal-6
teal-7
teal-8
teal-9
cyan-0
cyan-1
cyan-2
cyan-3
cyan-4
cyan-5
cyan-6
cyan-7
cyan-8
cyan-9
blue-0
blue-1
blue-2
blue-3
blue-4
blue-5
blue-6
blue-7
blue-8
blue-9
indigo-0
indigo-1
indigo-2
indigo-3
indigo-4
indigo-5
indigo-6
indigo-7
indigo-8
indigo-9
purple-0
purple-1
purple-2
purple-3
purple-4
purple-5
purple-6
purple-7
purple-8
purple-9
magenta-0
magenta-1
magenta-2
magenta-3
magenta-4
magenta-5
magenta-6
magenta-7
magenta-8
magenta-9
rose-0
rose-1
rose-2
rose-3
rose-4
rose-5
rose-6
rose-7
rose-8
rose-9
grey-0
grey-1
grey-2
grey-3
grey-4
grey-5
grey-6
grey-7
grey-8
grey-9
brown-0
brown-1
brown-2
brown-3
brown-4
brown-5
brown-6
brown-7
brown-8
brown-9
red-0
red-1
red-2
red-3
red-4
red-5
red-6
red-7
red-8
red-9
scarlet-0
scarlet-1
scarlet-2
scarlet-3
scarlet-4
scarlet-5
scarlet-6
scarlet-7
scarlet-8
scarlet-9
orange-0
orange-1
orange-2
orange-3
orange-4
orange-5
orange-6
orange-7
orange-8
orange-9
amber-0
amber-1
amber-2
amber-3
amber-4
amber-5
amber-6
amber-7
amber-8
amber-9
yellow-0
yellow-1
yellow-2
yellow-3
yellow-4
yellow-5
yellow-6
yellow-7
yellow-8
yellow-9
lime-0
lime-1
lime-2
lime-3
lime-4
lime-5
lime-6
lime-7
lime-8
lime-9
green-0
green-1
green-2
green-3
green-4
green-5
green-6
green-7
green-8
green-9
teal-0
teal-1
teal-2
teal-3
teal-4
teal-5
teal-6
teal-7
teal-8
teal-9
cyan-0
cyan-1
cyan-2
cyan-3
cyan-4
cyan-5
cyan-6
cyan-7
cyan-8
cyan-9
blue-0
blue-1
blue-2
blue-3
blue-4
blue-5
blue-6
blue-7
blue-8
blue-9
indigo-0
indigo-1
indigo-2
indigo-3
indigo-4
indigo-5
indigo-6
indigo-7
indigo-8
indigo-9
purple-0
purple-1
purple-2
purple-3
purple-4
purple-5
purple-6
purple-7
purple-8
purple-9
magenta-0
magenta-1
magenta-2
magenta-3
magenta-4
magenta-5
magenta-6
magenta-7
magenta-8
magenta-9
rose-0
rose-1
rose-2
rose-3
rose-4
rose-5
rose-6
rose-7
rose-8
rose-9
grey-0
grey-1
grey-2
grey-3
grey-4
grey-5
grey-6
grey-7
grey-8
grey-9
brown-0
brown-1
brown-2
brown-3
brown-4
brown-5
brown-6
brown-7
brown-8
brown-9

Night mode

[edit]
red-0
red-1
red-2
red-3
red-4
red-5
red-6
red-7
red-8
red-9
scarlet-0
scarlet-1
scarlet-2
scarlet-3
scarlet-4
scarlet-5
scarlet-6
scarlet-7
scarlet-8
scarlet-9
orange-0
orange-1
orange-2
orange-3
orange-4
orange-5
orange-6
orange-7
orange-8
orange-9
amber-0
amber-1
amber-2
amber-3
amber-4
amber-5
amber-6
amber-7
amber-8
amber-9
yellow-0
yellow-1
yellow-2
yellow-3
yellow-4
yellow-5
yellow-6
yellow-7
yellow-8
yellow-9
lime-0
lime-1
lime-2
lime-3
lime-4
lime-5
lime-6
lime-7
lime-8
lime-9
green-0
green-1
green-2
green-3
green-4
green-5
green-6
green-7
green-8
green-9
teal-0
teal-1
teal-2
teal-3
teal-4
teal-5
teal-6
teal-7
teal-8
teal-9
cyan-0
cyan-1
cyan-2
cyan-3
cyan-4
cyan-5
cyan-6
cyan-7
cyan-8
cyan-9
blue-0
blue-1
blue-2
blue-3
blue-4
blue-5
blue-6
blue-7
blue-8
blue-9
indigo-0
indigo-1
indigo-2
indigo-3
indigo-4
indigo-5
indigo-6
indigo-7
indigo-8
indigo-9
purple-0
purple-1
purple-2
purple-3
purple-4
purple-5
purple-6
purple-7
purple-8
purple-9
magenta-0
magenta-1
magenta-2
magenta-3
magenta-4
magenta-5
magenta-6
magenta-7
magenta-8
magenta-9
rose-0
rose-1
rose-2
rose-3
rose-4
rose-5
rose-6
rose-7
rose-8
rose-9
grey-0
grey-1
grey-2
grey-3
grey-4
grey-5
grey-6
grey-7
grey-8
grey-9
brown-0
brown-1
brown-2
brown-3
brown-4
brown-5
brown-6
brown-7
brown-8
brown-9
red-0
red-1
red-2
red-3
red-4
red-5
red-6
red-7
red-8
red-9
scarlet-0
scarlet-1
scarlet-2
scarlet-3
scarlet-4
scarlet-5
scarlet-6
scarlet-7
scarlet-8
scarlet-9
orange-0
orange-1
orange-2
orange-3
orange-4
orange-5
orange-6
orange-7
orange-8
orange-9
amber-0
amber-1
amber-2
amber-3
amber-4
amber-5
amber-6
amber-7
amber-8
amber-9
yellow-0
yellow-1
yellow-2
yellow-3
yellow-4
yellow-5
yellow-6
yellow-7
yellow-8
yellow-9
lime-0
lime-1
lime-2
lime-3
lime-4
lime-5
lime-6
lime-7
lime-8
lime-9
green-0
green-1
green-2
green-3
green-4
green-5
green-6
green-7
green-8
green-9
teal-0
teal-1
teal-2
teal-3
teal-4
teal-5
teal-6
teal-7
teal-8
teal-9
cyan-0
cyan-1
cyan-2
cyan-3
cyan-4
cyan-5
cyan-6
cyan-7
cyan-8
cyan-9
blue-0
blue-1
blue-2
blue-3
blue-4
blue-5
blue-6
blue-7
blue-8
blue-9
indigo-0
indigo-1
indigo-2
indigo-3
indigo-4
indigo-5
indigo-6
indigo-7
indigo-8
indigo-9
purple-0
purple-1
purple-2
purple-3
purple-4
purple-5
purple-6
purple-7
purple-8
purple-9
magenta-0
magenta-1
magenta-2
magenta-3
magenta-4
magenta-5
magenta-6
magenta-7
magenta-8
magenta-9
rose-0
rose-1
rose-2
rose-3
rose-4
rose-5
rose-6
rose-7
rose-8
rose-9
grey-0
grey-1
grey-2
grey-3
grey-4
grey-5
grey-6
grey-7
grey-8
grey-9
brown-0
brown-1
brown-2
brown-3
brown-4
brown-5
brown-6
brown-7
brown-8
brown-9

Script

[edit]
import colorsys
import re


IDENTIFICATION = "[[User:Surjection/swatch]]"
HEX_COLOR_RGB = re.compile(r"^#[0-9A-Fa-f]{6}$")


def _hex_to_rgb_comp(x):
    return int(x, 16) / 255.0


def hex_to_rgb(hex_color):
    if not HEX_COLOR_RGB.match(hex_color):
        raise ValueError("hex color format not supported")
    r, g, b = hex_color[1:3], hex_color[3:5], hex_color[5:7]
    return (_hex_to_rgb_comp(r), _hex_to_rgb_comp(g), _hex_to_rgb_comp(b))


def rgb_to_hex(c):
    r, g, b = c
    r = int(round(r * 255.0))
    g = int(round(g * 255.0))
    b = int(round(b * 255.0))
    return "#{:02x}{:02x}{:02x}".format(r, g, b)


def _lighten_comp(component, power):
    if not 0 <= power <= 1:
        raise ValueError("power must be within [0, 1]")
    return power + component * (1 - power)


def lighten(color, power):
    if not 0 <= power <= 1:
        raise ValueError("power must be within [0, 1]")
    r, g, b = color
    return (_lighten_comp(r, power), _lighten_comp(g, power), _lighten_comp(b, power))


def deepen(color, power):
    if not 0 <= power <= 1:
        raise ValueError("power must be within [0, 1]")
    r, g, b = color
    h, s, v = colorsys.rgb_to_hsv(r, g, b)
    s_new = (1 - (1 - s) * (1 - power)) * (s if s < 0.5 else 1)
    v_new = v * (1 - power)
    return colorsys.hsv_to_rgb(h, s_new, v_new)


def nighten(color):
    r, g, b = color
    h, l, s = colorsys.rgb_to_hls(r, g, b)
    return colorsys.hls_to_rgb(h, min(1, 1.03 - l), s)


def op_lighten(power):
    return lambda color: lighten(color, power)


def op_identity():
    return lambda color: color


def op_deepen(power):
    return lambda color: deepen(color, power)


BASE = {
    "red":         hex_to_rgb("#e63949"),
    "scarlet":     hex_to_rgb("#e0562d"),
    "orange":      hex_to_rgb("#d9760f"),
    "amber":       hex_to_rgb("#cf9211"),
    "yellow":      hex_to_rgb("#baa72f"),
    "lime":        hex_to_rgb("#97b53c"),
    "green":       hex_to_rgb("#60b334"),
    "teal":        hex_to_rgb("#32b378"),
    "cyan":        hex_to_rgb("#28a0b5"),
    "blue":        hex_to_rgb("#3271f0"),
    "indigo":      hex_to_rgb("#584ee6"),
    "purple":      hex_to_rgb("#7f38e8"),
    "magenta":     hex_to_rgb("#9d2cdb"),
    "rose":        hex_to_rgb("#a6448c"),
    "grey":        hex_to_rgb("#666666"),
    "brown":       hex_to_rgb("#856142"),
}
WHITE_BG = "#ffffff"
BLACK_FG = "#202122"
WHITE_FG = "#eaecf0"
BLACK_BG = "#101418"


TINTS = {
    0: op_lighten(0.9),
    1: op_lighten(0.8),
    2: op_lighten(0.65),
    3: op_lighten(0.5),
    4: op_lighten(0.25),
    5: op_identity(),
    6: op_deepen(0.15),
    7: op_deepen(0.3),
    8: op_deepen(0.45),
    9: op_deepen(0.6),
}


colors_light = {}
colors_night = {}


for base_color_name, base_color in BASE.items():
    tints_light = colors_light[base_color_name] = {}
    tints_night = colors_night[base_color_name] = {}
    for tint_number, tint_function in TINTS.items():
        color = tint_function(base_color)
        tints_light[tint_number] = color
        tints_night[tint_number] = nighten(color)


def make_swatch_bg(colors, fg_color):
    lines = []
    for base_color_name, tints in colors.items():
        if lines:
            lines.append('|-')
        else:
            lines.append('{|')
        for tint_number, color in tints.items():
            name = f"{base_color_name}-{tint_number}"
            lines.append(f'| style="background:{rgb_to_hex(color)}" | <div style="color:{fg_color};padding:15px 5px">{name}</div>')
    lines.append("|}")
    return "\n".join(lines)


def make_swatch_fg(colors, bg_color):
    lines = []
    for base_color_name, tints in colors.items():
        if lines:
            lines.append('|-')
        else:
            lines.append("{| " + f'style="background:{bg_color}"')
        for tint_number, color in tints.items():
            name = f"{base_color_name}-{tint_number}"
            lines.append(f'| <div style="color:{rgb_to_hex(color)};padding:5px">{name}</div>')
    lines.append("|}")
    return "\n".join(lines)


def make_palette(colors_light, colors_night):
    def wrap_frame(prefix, indent, suffix):
        def _wrap(lines):
            return prefix + "\n" + "\n".join(indent + line for line in lines) + "\n" + suffix
        return _wrap

    def gather_colors(colors):
        rules = ["/* Autogenerated with " + IDENTIFICATION + " */"]
        for base_color_name, tints in colors.items():
            for tint_number, color in tints.items():
                name = f"{base_color_name}-{tint_number}"
                rules.append(f"--wikt-palette-{name}: {rgb_to_hex(color)};")
        return rules

    light_block = wrap_frame(":root, .skin-invert, .notheme {", "\t", "}")
    night_block_1 = wrap_frame("@media screen {\n\thtml.skin-theme-clientpref-night {", "\t\t", "\t}\n}")
    night_block_2 = wrap_frame("@media screen and (prefers-color-scheme: dark) {\n\thtml.skin-theme-clientpref-os {".strip(), "\t\t", "\t}\n}")

    rules_light = gather_colors(colors_light)
    rules_night = gather_colors(colors_night)

    return light_block(rules_light) + "\n\n/* Styles need to be duplicated exactly between these two selectors. */\n" + night_block_1(rules_night) + "\n" + night_block_2(rules_night)


def print_swatches():
    print("==Swatches==")
    print("")

    print("===Light mode===")
    print("<!-- Autogenerated with " + IDENTIFICATION + " */ -->")
    print(make_swatch_bg(colors_light, BLACK_FG))
    print("")
    print(make_swatch_fg(colors_light, WHITE_BG))
    print("")

    print("===Night mode===")
    print("<!-- Autogenerated with " + IDENTIFICATION + " */ -->")
    print(make_swatch_bg(colors_night, WHITE_FG))
    print("")
    print(make_swatch_fg(colors_night, BLACK_BG))


def print_palette():
    print(make_palette(colors_light, colors_night))


print_swatches()