Files
beefcarver ec2ca72efb fix(frame): start the corner fade at the brightest palette stop
A ladder is a hue walk, not a brightness walk, so painting the hot end
backwards put the dim colour at the corner.  Sort the ramp by stock
brightness and follow the pane height for the bottom-left glow.
2026-11-04 15:49:26 -05:00

120 lines
3.6 KiB
Python

"""The colour palettes everything in the UI draws from.
Every colour in Beefy Player is a stock ANSI palette *name*, never RGB, so the
TUI adopts whatever colours the terminal is configured with. A palette here is
therefore a short ladder of those names — the "gradient" is a quantised walk
from the quiet end to the hot end, not an interpolation.
The active palette drives the spectrum analyser, the album-art mosaic, the
provider wordmarks and the pane corners; `c` cycles through them and the
choice is remembered in the config file.
"""
from __future__ import annotations
#: Dark → hot ladders of ANSI names. Sixteen of them: seven hue gradients, a
#: few near-monochromes, and the original spectrum.
PALETTES: dict[str, tuple[str, ...]] = {
"spectrum": (
"cyan",
"blue",
"magenta",
"bright_magenta",
"yellow",
"bright_yellow",
"red",
),
"rainbow": (
"red",
"bright_yellow",
"bright_green",
"bright_cyan",
"bright_blue",
"bright_magenta",
),
"ocean": (
"bright_black",
"blue",
"bright_blue",
"cyan",
"bright_cyan",
"bright_white",
),
"ember": (
"bright_black",
"red",
"bright_red",
"yellow",
"bright_yellow",
"bright_white",
),
"mint": (
"bright_black",
"green",
"bright_green",
"cyan",
"bright_cyan",
"bright_white",
),
"sunset": ("magenta", "bright_magenta", "red", "bright_red", "yellow"),
"violet": ("blue", "bright_blue", "magenta", "bright_magenta", "bright_white"),
"acid": ("bright_black", "green", "bright_green", "yellow", "bright_yellow"),
"neon": (
"bright_magenta",
"bright_red",
"bright_yellow",
"bright_green",
"bright_cyan",
),
"sand": ("bright_black", "yellow", "bright_yellow", "white", "bright_white"),
"blood": ("bright_black", "red", "bright_red", "bright_magenta"),
"forest": ("bright_black", "green", "bright_green", "yellow", "bright_white"),
"ice": ("bright_white", "bright_cyan", "cyan", "bright_blue", "blue"),
"steel": ("bright_black", "white", "bright_white", "bright_cyan"),
"candy": ("magenta", "bright_magenta", "bright_cyan", "bright_yellow"),
"mono": ("bright_black", "white", "bright_white"),
}
#: The stock names from dark to bright. These are xterm's default values in
#: Rec. 601 luma order — the closest thing to a stock answer. A theme may
#: disagree about the exact numbers, but the ordering is what the frame fades
#: need: a ladder is a *hue* walk, so where it ends says nothing about which
#: end is brighter.
BRIGHTNESS: tuple[str, ...] = (
"black",
"blue",
"red",
"bright_red",
"magenta",
"bright_magenta",
"bright_blue",
"green",
"bright_black",
"cyan",
"bright_green",
"bright_cyan",
"yellow",
"white",
"bright_yellow",
"bright_white",
)
_RANK = {name: rank for rank, name in enumerate(BRIGHTNESS)}
#: Cycle order for the palette key.
PALETTE_ORDER: tuple[str, ...] = tuple(PALETTES)
#: What you get until you press `c`.
DEFAULT_PALETTE = "spectrum"
def palette_stops(name: str | None) -> tuple[str, ...]:
"""The ladder for ``name``, falling back to the default palette."""
key = (name or "").strip().lower()
return PALETTES.get(key, PALETTES[DEFAULT_PALETTE])
def brightness(colour: str) -> int:
"""How bright a stock name is: 0 (black) to 15 (bright white)."""
return _RANK.get(colour.strip().lower(), 0)