Skip to main content

max / alloy

Make the lock ring say that it is waiting, and count what you type Two complaints, one cause. On Akari Dawn the indicator was a 1.37:1 smudge on a cream field: nothing said a password was wanted, because there was barely anything on screen. The ring is now border.strong, 3.27:1 on dawn and 8.15:1 on night, and ten pixels thick instead of six. swaylock cannot draw a prompt, so this is the only lever available: --show-keyboard-layout is documented "while typing" and there is no text at rest. Keystrokes were already being drawn, one ring segment per keypress, with separator-color dividing them. That was 00000000 in the hand-written original, so the dividers were invisible and consecutive keystrokes merged into one growing arc: the ring showed roughly how much you had typed and never how many. Ink dividers at 13.25:1 against the segments make each keypress a countable notch. The segments themselves had to move off amber. Amber against border.strong is 1.17:1, so raising the ring would have swallowed the feedback whole. Only tokens that invert with polarity can contrast with a border tone that itself inverts, which rules the accents out and leaves surface.page: 3.27:1 to 8.15:1 against the ring, worst case 2.80:1 against any state the ring can take. Caps lock keeps the same segment tone on purpose, since the ring already turns amber and the caps text already appears.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-07-30 03:44 UTC
Signed with PGP, not checked
Commit: c5ebf419864b09937e701e9ea0a1fbdafcf275bf
Parent: 9bc820e
1 file changed, +40 insertions, -7 deletions
@@ -27,7 +27,14 @@
27 27 inside-ver-color=@{hex_alpha(surface.raised, 1.0)}
28 28 inside-wrong-color=@{hex_alpha(surface.raised, 1.0)}
29 29
30 - ring-color=@{hex_alpha(line.border, 1.0)}
30 + # The ring is the whole affordance, so it is `border.strong` and not the raw
31 + # `line.border` this file used to take. That was 1.37:1 against the page on Akari
32 + # Dawn: a smudge on a cream field, with nothing to say a password was wanted.
33 + # `border.strong` is 3.27:1 on dawn and 8.15:1 on night. swaylock cannot draw a
34 + # prompt (`--show-keyboard-layout` is documented "while typing", so there is no
35 + # text at rest), which leaves making the ring obviously a control as the only
36 + # lever there is.
37 + ring-color=@{hex_alpha(border.strong, 1.0)}
31 38 ring-clear-color=@{hex_alpha(status.warning, 1.0)}
32 39 ring-caps-lock-color=@{hex_alpha(status.warning, 1.0)}
33 40 ring-ver-color=@{hex_alpha(status.info, 1.0)}
@@ -45,20 +52,46 @@
45 52 text-ver-color=@{hex_alpha(content.primary, 1.0)}
46 53 text-wrong-color=@{hex_alpha(content.primary, 1.0)}
47 54
48 - key-hl-color=@{hex_alpha(status.warning, 1.0)}
55 + # One keypress draws one segment on the ring, so these are the only feedback
56 + # that typing is registering at all.
57 + #
58 + # `surface.page`, not the amber this file used to take. Amber against
59 + # `border.strong` is 1.17:1 — the segments would have disappeared into the very
60 + # ring the line above just made visible. Only tokens that invert with polarity
61 + # can contrast with a border tone that itself inverts, which is what rules the
62 + # accents out here. Against the page tone the segments run 3.27:1 (dawn) to
63 + # 8.15:1 (night), and they stay legible against every state the ring can take:
64 + # worst case 2.80:1 on dawn with caps on.
65 + #
66 + # Caps lock keeps the same segment color deliberately. The *ring* turns amber and
67 + # the caps text appears, which is where that state belongs; recoloring the
68 + # segments too would trade legible feedback for a signal already being sent.
69 + key-hl-color=@{hex_alpha(surface.page, 1.0)}
70 + caps-lock-key-hl-color=@{hex_alpha(surface.page, 1.0)}
71 + # Backspace stays the error tone, and reads against the segments it eats at
72 + # 8.07:1 (dawn) and 3.72:1 (night).
49 73 bs-hl-color=@{hex_alpha(status.danger, 1.0)}
50 - caps-lock-key-hl-color=@{hex_alpha(status.warning, 1.0)}
51 74 caps-lock-bs-hl-color=@{hex_alpha(status.danger, 1.0)}
52 75
53 - # Invisible, so which color it is cannot matter. It takes the page's so that
54 - # nothing in this file is a literal.
55 - separator-color=@{hex_alpha(surface.page, 0.0)}
76 + # The lines dividing one keypress's segment from the next, and the reason this
77 + # file was worth revisiting: it was `00000000`, fully transparent, inherited from
78 + # the hand-written original. With no divider, consecutive keystrokes merge into a
79 + # single growing arc, so the ring showed roughly how much had been typed and
80 + # never how many. Ink against the page-toned segments is 13.25:1 (dawn) and
81 + # 11.77:1 (night), which makes each keypress a countable notch.
82 + separator-color=@{hex_alpha(content.primary, 1.0)}
56 83
57 84 # -------------------------------------------------------------------
58 85 # Layout
59 86 # -------------------------------------------------------------------
60 87 indicator-radius=90
61 - indicator-thickness=6
88 + # Thicker than the 6 it was. The ring now carries three things that have to be
89 + # told apart at a glance — its own base tone, a segment per keypress, and a
90 + # divider between segments — and six pixels is not much to divide three ways.
91 + indicator-thickness=10
92 + # The ring is drawn before anything is typed. Without this the lock is a blank
93 + # field until you touch a key, which is the state that reads as "asleep" rather
94 + # than "locked and waiting".
62 95 indicator-idle-visible
63 96 font=IosevkaTerm Nerd Font
64 97 font-size=16