A faded chip keeps its node's colours, with less chroma
The part of a route that the user does not compose (a mirrored return leg, the return home) drew every hop as the same dark slate chip. Each faded chip now has the colours of its own node at FADE_CHROMA of their chroma, at the same lightness, so it still says which node it is. The PicoCalc has no colour of less chroma: there a faded hop keeps its label colour and drops its fill. Arrows keep faint. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
796ff94dad
commit
bd6df0b9fa
5 files changed
+97
-45
No files matched your search
+6
-1
@@ -20,7 +20,12 @@ can change how things behave. It does not only add new things.
|
|||||||
chat. Before, your messages showed only the `★`.
|
chat. Before, your messages showed only the `★`.
|
||||||
- **Your node's star is white.** The `★` that marks your node on the map, in routes, in
|
- **Your node's star is white.** The `★` that marks your node on the map, in routes, in
|
||||||
lists, and in a chat is white, the same white as your name in the lists. Before, it was
|
lists, and in a chat is white, the same white as your name in the lists. Before, it was
|
||||||
yellow. A star in a faded part of a route stays grey.
|
yellow.
|
||||||
|
- **The faded part of a route keeps the colours of its nodes.** The part of a route that
|
||||||
|
you do not choose, for example the mirrored way back of a trace, shows each node in the
|
||||||
|
colour of its key, but less vivid. Thus you can still see which node each one is.
|
||||||
|
Before, each of these nodes was the same grey box. When a route is drawn with arrows,
|
||||||
|
the faded part stays grey.
|
||||||
- **In a chat, a name that MeshTerm cannot match to a node is black on grey.** The box
|
- **In a chat, a name that MeshTerm cannot match to a node is black on grey.** The box
|
||||||
around a sender or a mention with no known node has black text on a grey box. Thus it
|
around a sender or a mention with no known node has black text on a grey box. Thus it
|
||||||
does not stand out among the coloured names. Before, it was light blue on slate.
|
does not stand out among the coloured names. Before, it was light blue on slate.
|
||||||
|
|||||||
@@ -423,7 +423,8 @@ as a grouped list does. Filling a page in is editing its `.md`; no Python follow
|
|||||||
`marks.SELF_MARK` carries the theme name `you` — the white of our name — so the console
|
`marks.SELF_MARK` carries the theme name `you` — the white of our name — so the console
|
||||||
picks its own white, and a raster resolves it through `mark_rgb`. It was the map's
|
picks its own white, and a raster resolves it through `mark_rgb`. It was the map's
|
||||||
yellow, then briefly our key's hue (set from the self-info at run time), and both were
|
yellow, then briefly our key's hue (set from the self-info at run time), and both were
|
||||||
dropped. A star something *mutes* keeps its grey — a faded hop, a dimmed return leg.
|
dropped. In arrows, a star something *mutes* keeps its `faint` grey — a faded hop, a
|
||||||
|
dimmed return leg; a faded *chip* only loses chroma, and white has none to lose.
|
||||||
- Path cuts: a path line drawn as **chips** that gets cut — a lane that ran out, a row
|
- Path cuts: a path line drawn as **chips** that gets cut — a lane that ran out, a row
|
||||||
scrolled past its edge — breaks the chip off on a half block in that chip's own fill
|
scrolled past its edge — breaks the chip off on a half block in that chip's own fill
|
||||||
(`▐` ends a line, `▌` opens one; `pathline.cut_mark`/`cut_to`), so half the cell is
|
(`▐` ends a line, `▌` opens one; `pathline.cut_mark`/`cut_to`), so half the cell is
|
||||||
@@ -443,8 +444,12 @@ as a grouped list does. Filling a page in is editing its `.md`; no Python follow
|
|||||||
merged neighbouring greens). The PicoCalc is the same rule at its resolution: the fill
|
merged neighbouring greens). The PicoCalc is the same rule at its resolution: the fill
|
||||||
is the bright slot's dim twin (`theme.DIM_TWIN`). A hash label and an annotation are
|
is the bright slot's dim twin (`theme.DIM_TWIN`). A hash label and an annotation are
|
||||||
the label colour throughout, never a grey; on a truecolor terminal the lit bytes are
|
the label colour throughout, never a grey; on a truecolor terminal the lit bytes are
|
||||||
bold. A keyless chip is the same pair in grey; our `★` and a faded hop keep their dark
|
bold. A keyless chip is the same pair in grey; our `★` keeps its dark grey; a **faded
|
||||||
greys; the composer's slot keeps the white chip (on the PicoCalc, a white `+` in a
|
hop** (a mirrored return leg, the return home: what the user doesn't compose) is its own
|
||||||
|
chip at `pathline.FADE_CHROMA` of its chroma, same lightness, so it still says which node
|
||||||
|
it is (JP, 2026-10-14; it was one dark slate) — the PicoCalc, with no colour of less
|
||||||
|
chroma, keeps its label colour and drops its fill; arrows keep `faint`; the composer's
|
||||||
|
slot keeps the white chip (on the PicoCalc, a white `+` in a
|
||||||
break of the ribbon).
|
break of the ribbon).
|
||||||
- Chip seams are **one** interlocked chevron (previous fill on next). Two chips of the
|
- Chip seams are **one** interlocked chevron (previous fill on next). Two chips of the
|
||||||
same fill are the exception the interlock can't draw — and so are two fills the eye
|
same fill are the exception the interlock can't draw — and so are two fills the eye
|
||||||
|
|||||||
@@ -121,6 +121,16 @@ def distance(first: str, second: str) -> float:
|
|||||||
return math.dist(from_hex(first), from_hex(second))
|
return math.dist(from_hex(first), from_hex(second))
|
||||||
|
|
||||||
|
|
||||||
|
def desaturated(colour: str, keep: float) -> str:
|
||||||
|
"""``colour`` with its chroma multiplied by ``keep``. The lightness and the hue do not change.
|
||||||
|
|
||||||
|
``1`` returns the colour, and ``0`` returns the grey of the same lightness. Less chroma
|
||||||
|
at the same lightness always stays in the sRGB gamut, because the grey is in it.
|
||||||
|
"""
|
||||||
|
lightness, a, b = from_hex(colour)
|
||||||
|
return to_hex((lightness, a * keep, b * keep))
|
||||||
|
|
||||||
|
|
||||||
def shaded(colour: str, by: float, *, floor: float | None = None) -> str:
|
def shaded(colour: str, by: float, *, floor: float | None = None) -> str:
|
||||||
"""``colour`` moved ``by`` in lightness, away from the end of the scale that is nearer.
|
"""``colour`` moved ``by`` in lightness, away from the end of the scale that is nearer.
|
||||||
|
|
||||||
|
|||||||
+36
-29
@@ -17,9 +17,10 @@ surface that the survey found can in the end use it.
|
|||||||
look, and each seam uses one cell. The label of the chip of a node has the hue that
|
look, and each seam uses one cell. The label of the chip of a node has the hue that
|
||||||
comes from its hash (:func:`~meshterm.ui.theme.node_style`). This is the colour that its
|
comes from its hash (:func:`~meshterm.ui.theme.node_style`). This is the colour that its
|
||||||
name has on each surface. The fill is that hue, but darker (:data:`CHIP_LIGHTNESS`). Our
|
name has on each surface. The fill is that hue, but darker (:data:`CHIP_LIGHTNESS`). Our
|
||||||
node is the white ``★`` of the map on a neutral dark grey. A faded hop is dark slate. A
|
node is the white ``★`` of the map on a neutral dark grey. A faded hop has the colours
|
||||||
keyless hop is light grey on grey. (On the 16-colour console of the PicoCalc, the fill
|
of its own chip, with less chroma (:data:`FADE_CHROMA`). A keyless hop is light grey on
|
||||||
is the dim twin of the hue. Refer to :func:`_slot_colours`.)
|
grey. (On the 16-colour console of the PicoCalc, the fill is the dim twin of the hue.
|
||||||
|
Refer to :func:`_slot_colours`.)
|
||||||
|
|
||||||
Sometimes two chips have the *same* fill (a mirrored return leg, or a stretch of
|
Sometimes two chips have the *same* fill (a mirrored return leg, or a stretch of
|
||||||
keyless greys). Sometimes they have two fills that are too close to tell apart (less
|
keyless greys). Sometimes they have two fills that are too close to tell apart (less
|
||||||
@@ -87,7 +88,8 @@ surface that the survey found can in the end use it.
|
|||||||
``★`` of the app. The user already knows who both ends are, and the cells are for the
|
``★`` of the app. The user already knows who both ends are, and the cells are for the
|
||||||
hops that *are* news. These stars fade where the route is being *composed*, because our
|
hops that *are* news. These stars fade where the route is being *composed*, because our
|
||||||
two ends are fixtures and not choices. A surface that only *shows* a walk passes
|
two ends are fixtures and not choices. A surface that only *shows* a walk passes
|
||||||
``dim_self=False`` and keeps our stars in the ``you`` white.
|
``dim_self=False`` and keeps our stars in the ``you`` white. (Only arrows show the
|
||||||
|
difference. A faded chip loses chroma, and the white star has no chroma to lose.)
|
||||||
|
|
||||||
The existing call sites still render through ``path_text``. A separate pass for each
|
The existing call sites still render through ``path_text``. A separate pass for each
|
||||||
surface will move them here. The insertion cursor of the composer is a hop in its own
|
surface will move them here. The insertion cursor of the composer is a hop in its own
|
||||||
@@ -101,7 +103,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import re
|
import re
|
||||||
from collections.abc import Callable, Sequence
|
from collections.abc import Callable, Sequence
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass, replace
|
||||||
from typing import NamedTuple
|
from typing import NamedTuple
|
||||||
|
|
||||||
from rich.cells import cell_len
|
from rich.cells import cell_len
|
||||||
@@ -215,18 +217,19 @@ _WHITE = "#ffffff"
|
|||||||
#: route is a fixture that the user already knows. It stays back and lets the hops that
|
#: route is a fixture that the user already knows. It stays back and lets the hops that
|
||||||
#: differ carry the colour.
|
#: differ carry the colour.
|
||||||
_YOU_BG = "#3f3f46"
|
_YOU_BG = "#3f3f46"
|
||||||
#: The chip of a dimmed hop: a dark slate fill with muted ink. It recedes like ``faint``
|
#: The part of its chroma (OKLab ``a`` and ``b``) that the chip of a faded hop keeps. A
|
||||||
#: text.
|
#: faded hop is a hop that the user does not compose: a mirrored return leg, or the
|
||||||
_DIM_BG = "#334155"
|
#: automatic return home. Its chip has the colours that it has with no fade, with less
|
||||||
_DIM_FG = "#94a3b8"
|
#: chroma and the same lightness. Thus each faded hop still says which node it is, and the
|
||||||
|
#: automatic part of the route recedes (JP, 2026-10-14). Before, each faded hop was the same
|
||||||
|
#: dark slate chip.
|
||||||
|
FADE_CHROMA = 0.35
|
||||||
|
|
||||||
#: On the 16-colour console, the page: slot 0, black. It is the fill of a chip that the
|
#: On the 16-colour console, the page: slot 0, black. It is the fill of a chip that the
|
||||||
#: console cannot fill, because the VT has no dark grey background. That chip is our ``★``,
|
#: console cannot fill, because the VT has no dark grey background. That chip is our ``★``,
|
||||||
#: a faded hop, or the slot of the composer. Its text then sits on the page, and the chips
|
#: a faded hop, or the slot of the composer. Its text then sits on the page, and the chips
|
||||||
#: on each side close on a point and open on a notch.
|
#: on each side close on a point and open on a notch.
|
||||||
_SLOT_PAGE = slot_hex(0)
|
_SLOT_PAGE = slot_hex(0)
|
||||||
#: On the console, the text of a faded hop: slot 8, the dark grey.
|
|
||||||
_SLOT_FAINT = slot_hex(8)
|
|
||||||
#: On the console, white: slot 15. It is the text of a keyless chip and of the slot of the
|
#: On the console, white: slot 15. It is the text of a keyless chip and of the slot of the
|
||||||
#: composer.
|
#: composer.
|
||||||
_SLOT_WHITE = slot_hex(15)
|
_SLOT_WHITE = slot_hex(15)
|
||||||
@@ -305,7 +308,8 @@ class PathHop:
|
|||||||
lit_bytes: For a hash label: the leading *bytes* that are drawn in the hue (the two
|
lit_bytes: For a hash label: the leading *bytes* that are drawn in the hue (the two
|
||||||
tones of ``highlighted_hash``). The rest is muted or soft. ``0`` for names.
|
tones of ``highlighted_hash``). The rest is muted or soft. ``0`` for names.
|
||||||
dim: Fade the hop (and the arrow that leads into it). It is the resolved return leg
|
dim: Fade the hop (and the arrow that leads into it). It is the resolved return leg
|
||||||
of a planned route, which the user does not compose.
|
of a planned route, which the user does not compose. A chip keeps its colours,
|
||||||
|
with less chroma (:data:`FADE_CHROMA`). Arrows draw the hop ``faint``.
|
||||||
style: An explicit colour override. It is a hex style (``"#rrggbb"``, attributes are
|
style: An explicit colour override. It is a hex style (``"#rrggbb"``, attributes are
|
||||||
permitted) or a theme name. It is for colourings of a context that win over the
|
permitted) or a theme name. It is for colourings of a context that win over the
|
||||||
identity. Plain mode uses it as the label style, and powerline uses it as the
|
identity. Plain mode uses it as the label style, and powerline uses it as the
|
||||||
@@ -1216,18 +1220,19 @@ def _spectrum_colours(hop: PathHop) -> _ChipColours:
|
|||||||
The label of a node is its hue. This is the colour that its name has in each list and
|
The label of a node is its hue. This is the colour that its name has in each list and
|
||||||
in arrow mode. The fill is that hue, but darker (:data:`CHIP_LIGHTNESS`). The whole
|
in arrow mode. The fill is that hue, but darker (:data:`CHIP_LIGHTNESS`). The whole
|
||||||
label is in the hue, also a hash label and an annotation. The lit bytes of a hash are
|
label is in the hue, also a hash label and an annotation. The lit bytes of a hash are
|
||||||
bold. A keyless chip is the same pair in grey. Our ``★`` and a faded hop keep their dark
|
bold. A keyless chip is the same pair in grey. Our ``★`` keeps its dark grey, which
|
||||||
greys, which already carry a light label. The PicoCalc draws the same rules at the
|
already carries a light label. The PicoCalc draws the same rules at the resolution of
|
||||||
resolution of its console (:func:`_slot_colours`).
|
its console (:func:`_slot_colours`).
|
||||||
|
|
||||||
The insertion slot wins over all other rules. It is the one chip that is not a node, and
|
The insertion slot wins over all other rules. It is the one chip that is not a node, and
|
||||||
it has the ``cursor`` white. Thus it reads as chrome among identities, and not as a hop
|
it has the ``cursor`` white. Thus it reads as chrome among identities, and not as a hop
|
||||||
with a hue that is unlucky. (White is outside the node spectrum, and its dark text stays
|
with a hue that is unlucky. (White is outside the node spectrum, and its dark text stays
|
||||||
readable on it.) It is the only light chip on the ribbon. The fade is next, and it wins
|
readable on it.) It is the only light chip on the ribbon. The fade is next. A dimmed
|
||||||
over the identity, also our own. A dimmed hop is a hop that nobody composed (an
|
hop is a hop that nobody composed (an automatic return home, a mirrored return leg). It
|
||||||
automatic return home, a mirrored return leg). Our end must recede with the rest of
|
has the colours that it has with no fade, with less chroma (:data:`FADE_CHROMA`). Thus
|
||||||
that automatic half, and not keep its hue among the greys. Plain mode says the same
|
each faded hop still says which node it is, and that automatic half recedes (JP,
|
||||||
thing when it fades the name.
|
2026-10-14). Our white star has no chroma, so its chip does not change. Plain mode
|
||||||
|
draws the same hops ``faint``.
|
||||||
|
|
||||||
Our chip in a chat (``white_ink``) has the fill of the chip of its key, and a white
|
Our chip in a chat (``white_ink``) has the fill of the chip of its key, and a white
|
||||||
label. A quiet chip (a node with no key in a chat) is black on a grey fill.
|
label. A quiet chip (a node with no key in a chat) is black on a grey fill.
|
||||||
@@ -1238,7 +1243,8 @@ def _spectrum_colours(hop: PathHop) -> _ChipColours:
|
|||||||
if resolved:
|
if resolved:
|
||||||
return _ChipColours(_chip_fill(resolved), resolved, resolved)
|
return _ChipColours(_chip_fill(resolved), resolved, resolved)
|
||||||
if hop.dim:
|
if hop.dim:
|
||||||
return _ChipColours(_DIM_BG, _DIM_FG, _DIM_FG)
|
normal = _spectrum_colours(replace(hop, dim=False))
|
||||||
|
return _ChipColours(*(oklab.desaturated(c, FADE_CHROMA) for c in normal))
|
||||||
hue = _style_hex(node_style(hop.key)) if hop.key else None
|
hue = _style_hex(node_style(hop.key)) if hop.key else None
|
||||||
if hop.white_ink and hue:
|
if hop.white_ink and hue:
|
||||||
return _ChipColours(_chip_fill(hue), _WHITE, _WHITE)
|
return _ChipColours(_chip_fill(hue), _WHITE, _WHITE)
|
||||||
@@ -1263,10 +1269,10 @@ def _slot_colours(hop: PathHop) -> _ChipColours:
|
|||||||
|
|
||||||
A keyless chip is white on light grey, the same pair one bank down. Our ``★``, a faded
|
A keyless chip is white on light grey, the same pair one bank down. Our ``★``, a faded
|
||||||
hop, and the slot of the composer have no fill of their own, because the console has no
|
hop, and the slot of the composer have no fill of their own, because the console has no
|
||||||
dark grey background. They stand on the page (:data:`_SLOT_PAGE`): the star in our
|
dark grey background. They stand on the page (:data:`_SLOT_PAGE`): the white star, and
|
||||||
hue, a faded hop in the dark grey, and the slot as a white ``+`` in a break of the
|
the slot as a white ``+`` in a break of the ribbon. The console also has no colour with
|
||||||
ribbon. The order of the rules is the same as on a truecolor terminal
|
less chroma. Thus a faded hop keeps the colour of its label and loses its fill. The
|
||||||
(:func:`_spectrum_colours`).
|
order of the rules is the same as on a truecolor terminal (:func:`_spectrum_colours`).
|
||||||
|
|
||||||
Our chip in a chat (``white_ink``) is white on the dim twin of its hue, the same rule as
|
Our chip in a chat (``white_ink``) is white on the dim twin of its hue, the same rule as
|
||||||
on a truecolor terminal. A quiet chip is black on the light grey of the keyless chip.
|
on a truecolor terminal. A quiet chip is black on the light grey of the keyless chip.
|
||||||
@@ -1280,7 +1286,7 @@ def _slot_colours(hop: PathHop) -> _ChipColours:
|
|||||||
ink = resolved if resolved in DIM_TWIN else _SLOT_WHITE
|
ink = resolved if resolved in DIM_TWIN else _SLOT_WHITE
|
||||||
return _ChipColours(fill, ink, ink)
|
return _ChipColours(fill, ink, ink)
|
||||||
if hop.dim:
|
if hop.dim:
|
||||||
return _ChipColours(_SLOT_PAGE, _SLOT_FAINT, _SLOT_FAINT)
|
return _slot_colours(replace(hop, dim=False))._replace(fill=_SLOT_PAGE)
|
||||||
if hop.you:
|
if hop.you:
|
||||||
return _ChipColours(_SLOT_PAGE, _SLOT_WHITE, _SLOT_WHITE)
|
return _ChipColours(_SLOT_PAGE, _SLOT_WHITE, _SLOT_WHITE)
|
||||||
hue = _style_hex(node_style(hop.key)) if hop.key else None
|
hue = _style_hex(node_style(hop.key)) if hop.key else None
|
||||||
@@ -1379,9 +1385,10 @@ def path_line(
|
|||||||
between them need.
|
between them need.
|
||||||
dim_self: Fade the bare stars (the default). On a surface where the user *composes*
|
dim_self: Fade the bare stars (the default). On a surface where the user *composes*
|
||||||
the route, to set out from us and to come home to us are fixtures. The user does
|
the route, to set out from us and to come home to us are fixtures. The user does
|
||||||
not choose or remove them, the same as for a mirrored return leg. Thus they have
|
not choose or remove them, the same as for a mirrored return leg. Thus they fade
|
||||||
the same automatic grey, and the colour on the line is for the nodes that the
|
as that leg does. (Arrows draw them ``faint``. A faded chip loses chroma, and our
|
||||||
user really picks. Pass ``False`` where nobody composes anything (a record of a
|
white star has no chroma to lose, so its chip does not change.) Pass ``False``
|
||||||
|
where nobody composes anything (a record of a
|
||||||
walk that is already made). Then there is no "not yours" to say, and our node
|
walk that is already made). Then there is no "not yours" to say, and our node
|
||||||
reads in the ``you`` white of the app, as in other places. A ``dim_from`` that
|
reads in the ``you`` white of the app, as in other places. A ``dim_from`` that
|
||||||
reaches a star still fades it in both cases.
|
reaches a star still fades it in both cases.
|
||||||
|
|||||||
+37
-12
@@ -9,6 +9,7 @@ cells. Thus these tests assert rendered strings and span styles, and not impress
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import math
|
||||||
import random
|
import random
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
@@ -21,8 +22,6 @@ from meshterm.platforms import CARDPUTER_ZERO, PICOCALC_LYRA, set_platform
|
|||||||
from meshterm.ui import oklab
|
from meshterm.ui import oklab
|
||||||
from meshterm.ui.fontset import FONT_CODEPOINTS
|
from meshterm.ui.fontset import FONT_CODEPOINTS
|
||||||
from meshterm.ui.pathline import (
|
from meshterm.ui.pathline import (
|
||||||
_DIM_BG,
|
|
||||||
_DIM_FG,
|
|
||||||
_YOU_BG,
|
_YOU_BG,
|
||||||
CHIP_LIGHTNESS,
|
CHIP_LIGHTNESS,
|
||||||
CRACK_HEAD,
|
CRACK_HEAD,
|
||||||
@@ -30,6 +29,7 @@ from meshterm.ui.pathline import (
|
|||||||
CURSOR_GLYPH,
|
CURSOR_GLYPH,
|
||||||
ELIDE_HEAD,
|
ELIDE_HEAD,
|
||||||
ELIDE_TAIL,
|
ELIDE_TAIL,
|
||||||
|
FADE_CHROMA,
|
||||||
PATH_INK,
|
PATH_INK,
|
||||||
POWERLINE_ROUND_CLOSE,
|
POWERLINE_ROUND_CLOSE,
|
||||||
POWERLINE_ROUND_OPEN,
|
POWERLINE_ROUND_OPEN,
|
||||||
@@ -279,7 +279,7 @@ def test_the_picocalc_draws_chips_from_its_eight_backgrounds(picocalc: None) ->
|
|||||||
assert at("(0a)").fg == _rgb(red) # the annotation also has the colour of the label
|
assert at("(0a)").fg == _rgb(red) # the annotation also has the colour of the label
|
||||||
assert (at("3d").fg, at("3d").bg) == (_rgb(slot_hex(15)), _rgb(slot_hex(7)))
|
assert (at("3d").fg, at("3d").bg) == (_rgb(slot_hex(15)), _rgb(slot_hex(7)))
|
||||||
assert at("Ridge").bg in (None, _rgb(slot_hex(0))) # faded: on the page
|
assert at("Ridge").bg in (None, _rgb(slot_hex(0))) # faded: on the page
|
||||||
assert at("Ridge").fg == _rgb(slot_hex(8))
|
assert at("Ridge").fg == _rgb(yellow) # in the colour of its label, with no fill
|
||||||
assert at(SELF_GLYPH).bg in (None, _rgb(slot_hex(0)))
|
assert at(SELF_GLYPH).bg in (None, _rgb(slot_hex(0)))
|
||||||
|
|
||||||
|
|
||||||
@@ -856,8 +856,33 @@ def test_a_seam_between_two_of_one_colour_is_the_thin_chevron_in_its_label() ->
|
|||||||
f"{_fill('aa')} on {_fill('77')}",
|
f"{_fill('aa')} on {_fill('77')}",
|
||||||
) # a blend, one cell
|
) # a blend, one cell
|
||||||
|
|
||||||
|
faded = pathline._spectrum_colours(PathHop("B", dim=True))
|
||||||
glyph, style = _seams(PathHop("A", dim=True), PathHop("B", dim=True))[0]
|
glyph, style = _seams(PathHop("A", dim=True), PathHop("B", dim=True))[0]
|
||||||
assert (glyph, style) == (POWERLINE_THIN, f"{_DIM_FG} on {_DIM_BG}")
|
assert (glyph, style) == (POWERLINE_THIN, f"{faded.ink} on {faded.fill}")
|
||||||
|
|
||||||
|
|
||||||
|
def test_a_faded_chip_is_its_own_chip_with_less_chroma() -> None:
|
||||||
|
"""A faded hop keeps the colours of its node, with less chroma and the same lightness.
|
||||||
|
|
||||||
|
The faded part of a route is the part that the user does not compose. Each node there
|
||||||
|
still has its hue, so the user can see which node it is (JP, 2026-10-14). Before, each
|
||||||
|
faded hop was the same dark slate chip.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def chroma(colour: str) -> float:
|
||||||
|
_lightness, a, b = oklab.from_hex(colour)
|
||||||
|
return math.hypot(a, b)
|
||||||
|
|
||||||
|
for key in ("00", "4c", "aa", None):
|
||||||
|
normal = pathline._spectrum_colours(PathHop("N", key=key))
|
||||||
|
faded = pathline._spectrum_colours(PathHop("N", key=key, dim=True))
|
||||||
|
for before, after in zip(normal, faded, strict=True):
|
||||||
|
assert after == oklab.desaturated(before, FADE_CHROMA)
|
||||||
|
assert abs(oklab.from_hex(after)[0] - oklab.from_hex(before)[0]) < 0.01
|
||||||
|
if key:
|
||||||
|
assert chroma(after) < chroma(before) * 0.5
|
||||||
|
star = pathline._spectrum_colours(PathHop(SELF_GLYPH, you=True, dim=True))
|
||||||
|
assert star.ink == "#ffffff" # white has no chroma to lose
|
||||||
|
|
||||||
|
|
||||||
def test_a_seam_blurs_by_perceived_distance_not_by_hue_gap() -> None:
|
def test_a_seam_blurs_by_perceived_distance_not_by_hue_gap() -> None:
|
||||||
@@ -866,9 +891,9 @@ def test_a_seam_blurs_by_perceived_distance_not_by_hue_gap() -> None:
|
|||||||
The eye decides, and not the wheel. Sixteen steps of the first byte across the greens
|
The eye decides, and not the wheel. Sixteen steps of the first byte across the greens
|
||||||
are one colour to a user. Sixteen steps across the reds are two colours. Thus the same
|
are one colour to a user. Sixteen steps across the reds are two colours. Thus the same
|
||||||
gap of hue blurs on one side of the wheel and interlocks on the other. The test measures
|
gap of hue blurs on one side of the wheel and interlocks on the other. The test measures
|
||||||
the fills, because the solid point is a fill on a fill. The greys follow the same metric
|
the fills, because the solid point is a fill on a fill. A faded chip follows the same
|
||||||
with no exception. The keyless grey and the faded slate are far apart, and they keep
|
metric with no exception. A hue and its faded chip are far apart, and they keep their
|
||||||
their seam.
|
seam.
|
||||||
"""
|
"""
|
||||||
green = _seams(PathHop("A", key="4c"), PathHop("B", key="5c"))[0]
|
green = _seams(PathHop("A", key="4c"), PathHop("B", key="5c"))[0]
|
||||||
red = _seams(PathHop("A", key="00"), PathHop("B", key="10"))[0]
|
red = _seams(PathHop("A", key="00"), PathHop("B", key="10"))[0]
|
||||||
@@ -880,16 +905,16 @@ def test_a_seam_blurs_by_perceived_distance_not_by_hue_gap() -> None:
|
|||||||
wrapped = _seams(PathHop("A", key="fc"), PathHop("B", key="02"))[0]
|
wrapped = _seams(PathHop("A", key="fc"), PathHop("B", key="02"))[0]
|
||||||
assert wrapped[0] == POWERLINE_THIN # neighbours across the seam of the wheel, also
|
assert wrapped[0] == POWERLINE_THIN # neighbours across the seam of the wheel, also
|
||||||
|
|
||||||
glyph, style = _seams(PathHop("A"), PathHop("B", dim=True))[0]
|
glyph, style = _seams(PathHop("A", key="00"), PathHop("B", key="00", dim=True))[0]
|
||||||
assert glyph == POWERLINE_SEP and " on " in style # two greys, which still interlock
|
assert glyph == POWERLINE_SEP and " on " in style # a hue and its fade still interlock
|
||||||
|
|
||||||
|
|
||||||
def test_bare_self_stands_us_on_a_star_and_fades_both_ends() -> None:
|
def test_bare_self_stands_us_on_a_star_and_fades_both_ends() -> None:
|
||||||
"""``bare_self`` puts a ★ for us at both ends, and fades both.
|
"""``bare_self`` puts a ★ for us at both ends, and fades both.
|
||||||
|
|
||||||
To set out from us and to land back on us are fixtures of the route and not choices.
|
To set out from us and to land back on us are fixtures of the route and not choices.
|
||||||
Thus they have the same automatic grey as a mirrored return leg. In chips, they have the
|
Thus they fade as a mirrored return leg does: ``faint`` in arrows. A faded chip only
|
||||||
same dark slate, and not the loud white of you.
|
loses chroma, and the white star has no chroma to lose, so its chip stays white.
|
||||||
"""
|
"""
|
||||||
hops = [None, *(f"{i:02x}aa" for i in range(6)), None]
|
hops = [None, *(f"{i:02x}aa" for i in range(6)), None]
|
||||||
line = path_line(
|
line = path_line(
|
||||||
@@ -909,7 +934,7 @@ def test_bare_self_stands_us_on_a_star_and_fades_both_ends() -> None:
|
|||||||
assert [str(s.style) for s in stars] == ["faint", "faint"]
|
assert [str(s.style) for s in stars] == ["faint", "faint"]
|
||||||
chips = PathLine(line.hops, mode="powerline").text()
|
chips = PathLine(line.hops, mode="powerline").text()
|
||||||
star_fills = [str(s.style) for s in chips.spans if chips.plain[s.start : s.end] == SELF_GLYPH]
|
star_fills = [str(s.style) for s in chips.spans if chips.plain[s.start : s.end] == SELF_GLYPH]
|
||||||
assert all("#ffffff" not in fill for fill in star_fills) # never the white of you
|
assert star_fills and all(fill.startswith("#ffffff on ") for fill in star_fills)
|
||||||
|
|
||||||
wrapped = path_line(
|
wrapped = path_line(
|
||||||
hops, prefix_bytes=2, self_name="Me", bare_self=True, mode="powerline"
|
hops, prefix_bytes=2, self_name="Me", bare_self=True, mode="powerline"
|
||||||
|
|||||||
Reference in new issue
Block a user