DBax127 Claude Opus 5 commited on
Commit
292016c
Β·
1 Parent(s): 37102eb

banner: the framed NX wordmark, in the colours it already had

Browse files

New letterforms, from the art you sent: a compact NX built from half-blocks,
inside a box rule. Seven rows -- frame, five rows of wordmark, frame.

THE PALETTE IS THE ONE IT HAD

Cyan, ice, white, pink, magenta, and the neutral. Nothing new was mixed. What
changed is where the neutral goes: it is the frame now, not the last row of the
letterforms, so the wordmark ends on magenta instead of fading to grey at the
baseline. The five hues land one per wordmark row.

banner() bands by row index, so the frame is painted by position rather than by
being a special case, and the wordmark is banded by its position WITHIN the
wordmark -- adding or removing a frame row cannot shift the hues by one.

THE RAMP IS NUMBERS NOW

`BANNER_RAMP` and `BANNER_FRAME` hold the 256-colour indices, and the escape
codes are built from them. That is not tidiness. Under NO_COLOR every code in
this file is the empty string, so a test asserting the wordmark is cyan-to-
magenta passes against any ramp at all -- "" == "" for every row. Asserting the
numbers is an assertion that can fail.

Four tests: both spellings are the same height, the ASCII fallback is actually
ASCII, the ramp is the five hues with the neutral held back for the frame and no
two rows sharing a step, and the rendered codes come from the ramp rather than
from a second hand-kept list beside it.

The ASCII fallback is seven rows too, for the same reason it has always had to
match: a fallback of a different height would paint a frame row as a letterform.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Files changed (2) hide show
  1. nexa.py +45 -15
  2. tests/test_cli.py +45 -0
nexa.py CHANGED
@@ -88,25 +88,44 @@ CYAN, ICE, MAG, PINK = c(51), c(87), c(201), c(213)
88
  AMBER, GOLD, GREEN, RED = c(214), c(220), c(48), c(203)
89
  DIM, GREY, WHITE = c(240), c(245), c(255)
90
 
 
 
 
 
 
 
 
 
 
 
 
91
  BANNER_UNICODE = """
92
- β–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•—β–ˆβ–ˆβ•— β–ˆβ–ˆβ•—
93
- β–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•‘β•šβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•
94
- β–ˆβ–ˆβ•”β–ˆβ–ˆβ•— β–ˆβ–ˆβ•‘ β•šβ–ˆβ–ˆβ–ˆβ•”β•
95
- β–ˆβ–ˆβ•‘β•šβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•”β–ˆβ–ˆβ•—
96
- β–ˆβ–ˆβ•‘ β•šβ–ˆβ–ˆβ–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β• β–ˆβ–ˆβ•—
97
- β•šβ•β• β•šβ•β•β•β•β•šβ•β• β•šβ•β•
 
98
  """
99
 
100
- # The same shape in plain ASCII, for a console stuck on a legacy code page.
 
 
101
  BANNER_ASCII = """
102
- ## ## ## ##
103
- ### ## ## ##
104
- ## ## ## ###
105
- ## ### ## ##
106
- ## ## ## ##
107
- == == == ==
 
108
  """
109
 
 
 
 
 
110
  BANNER = BANNER_UNICODE if UNICODE else BANNER_ASCII
111
 
112
  # Glyphs used throughout, degraded together with the banner.
@@ -116,8 +135,12 @@ ARROW = "β–Έ" if UNICODE else ">"
116
  FILLED, HOLLOW = ("β—†", "β—‡") if UNICODE else ("*", "o")
117
  MIDDOT = "Β·" if UNICODE else "-"
118
 
119
- # Per-line gradient, top to bottom.
 
 
120
  GRADIENT = [CYAN, ICE, WHITE, PINK, MAG, DIM]
 
 
121
 
122
 
123
  _BANNER_SHOWN = False
@@ -137,7 +160,14 @@ def banner(subtitle=True, once=False):
137
  lines = BANNER.strip("\n").split("\n")
138
  out = [""]
139
  for i, line in enumerate(lines):
140
- out.append(GRADIENT[i % len(GRADIENT)] + line + RESET)
 
 
 
 
 
 
 
141
  out.append("")
142
  out.append(" {0}{1}NEXA{2}{3} validation intelligence {4}v{5}{6}".format(
143
  BOLD, AMBER, RESET, GREY, DIM, VERSION, RESET))
 
88
  AMBER, GOLD, GREEN, RED = c(214), c(220), c(48), c(203)
89
  DIM, GREY, WHITE = c(240), c(245), c(255)
90
 
91
+ # The wordmark's ramp as COLOUR NUMBERS, top to bottom, with the frame's neutral
92
+ # last. The escape codes above are "" whenever colour is off, so a palette
93
+ # written only as codes cannot be asserted about under NO_COLOR -- every claim
94
+ # becomes "" == "" and passes whatever the ramp says. The numbers are the design;
95
+ # the codes are how it reaches a terminal.
96
+ BANNER_RAMP = (51, 87, 255, 213, 201)
97
+ BANNER_FRAME = 240
98
+
99
+ # Five rows of wordmark inside a frame. The frame is the first and last line, so
100
+ # banner() -- which bands by row index -- paints it from the ends of GRADIENT and
101
+ # the letterforms from the middle. See BANNER_ROWS.
102
  BANNER_UNICODE = """
103
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
104
+ β”‚ ▐ β–„ ▐▄‒ β–„ β”‚
105
+ β”‚ β€’β–ˆβ–Œβ–β–ˆ β–ˆβ–Œβ–ˆβ–Œβ–ͺ β”‚
106
+ β”‚ β–β–ˆβ–β–β–Œ Β·β–ˆβ–ˆΒ· β”‚
107
+ β”‚ β–ˆβ–ˆβ–β–ˆβ–Œβ–ͺβ–β–ˆΒ·β–ˆβ–Œ β”‚
108
+ β”‚ β–€β–€ β–ˆβ–ͺβ€’β–€β–€ β–€β–€ β”‚
109
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
110
  """
111
 
112
+ # The same seven rows in plain ASCII, for a console stuck on a legacy code page.
113
+ # Same height on purpose: banner() bands by row index, so a fallback of a
114
+ # different height would colour the frame as a letterform.
115
  BANNER_ASCII = """
116
+ +---------------+
117
+ | N N X X |
118
+ | NN N XX |
119
+ | N NN XX |
120
+ | N N X X |
121
+ | = == == = |
122
+ +---------------+
123
  """
124
 
125
+ # The wordmark rows, frame excluded. banner() paints these from the middle of
126
+ # GRADIENT so the frame gets the ends of it.
127
+ BANNER_ROWS = 5
128
+
129
  BANNER = BANNER_UNICODE if UNICODE else BANNER_ASCII
130
 
131
  # Glyphs used throughout, degraded together with the banner.
 
135
  FILLED, HOLLOW = ("β—†", "β—‡") if UNICODE else ("*", "o")
136
  MIDDOT = "Β·" if UNICODE else "-"
137
 
138
+ # Per-line gradient, top to bottom. The same six colours the wordmark has
139
+ # always used; the frame takes the neutral one and the five letterform rows
140
+ # take the hues, so nothing fades to grey at the baseline.
141
  GRADIENT = [CYAN, ICE, WHITE, PINK, MAG, DIM]
142
+ FRAME_COLOUR = c(BANNER_FRAME)
143
+ WORDMARK_GRADIENT = [c(code) for code in BANNER_RAMP]
144
 
145
 
146
  _BANNER_SHOWN = False
 
160
  lines = BANNER.strip("\n").split("\n")
161
  out = [""]
162
  for i, line in enumerate(lines):
163
+ # First and last row are the frame. Everything between is wordmark,
164
+ # banded by its position WITHIN the wordmark rather than within the
165
+ # block, so adding or removing a frame cannot shift the hues.
166
+ if i == 0 or i == len(lines) - 1:
167
+ out.append(FRAME_COLOUR + line + RESET)
168
+ else:
169
+ out.append(WORDMARK_GRADIENT[(i - 1) % len(WORDMARK_GRADIENT)]
170
+ + line + RESET)
171
  out.append("")
172
  out.append(" {0}{1}NEXA{2}{3} validation intelligence {4}v{5}{6}".format(
173
  BOLD, AMBER, RESET, GREY, DIM, VERSION, RESET))
tests/test_cli.py CHANGED
@@ -167,3 +167,48 @@ def test_subprocess_output_is_clean_when_not_a_terminal():
167
  code, out = shell("rules", "onchange")
168
  assert code == OK
169
  assert "\033" not in out
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167
  code, out = shell("rules", "onchange")
168
  assert code == OK
169
  assert "\033" not in out
170
+
171
+
172
+ # ------------------------------------------------- the wordmark and its frame
173
+
174
+ def test_both_spellings_are_the_same_height():
175
+ """banner() bands by row index, so a fallback of a different height would
176
+ paint a frame row as a letterform and vice versa."""
177
+ unicode_rows = nexa.BANNER_UNICODE.strip("\n").split("\n")
178
+ ascii_rows = nexa.BANNER_ASCII.strip("\n").split("\n")
179
+ assert len(unicode_rows) == len(ascii_rows)
180
+ # Frame top and bottom, wordmark between.
181
+ assert len(unicode_rows) == nexa.BANNER_ROWS + 2
182
+
183
+
184
+ def test_the_ascii_fallback_is_actually_ascii():
185
+ """It exists for a console on a legacy code page. A block-drawing character
186
+ surviving into it defeats the entire point."""
187
+ assert nexa.BANNER_ASCII.isascii()
188
+
189
+
190
+ def test_the_wordmark_takes_the_hues_and_the_frame_takes_the_neutral():
191
+ """The ramp is the palette the banner already had -- cyan, ice, white, pink,
192
+ magenta -- with the neutral reserved for the frame.
193
+
194
+ Asserted against the NUMBERS, not the escape codes. Under NO_COLOR every code
195
+ is the empty string, so a test written against codes would pass for any ramp
196
+ at all, which is worse than not testing it.
197
+ """
198
+ assert nexa.BANNER_RAMP == (51, 87, 255, 213, 201)
199
+ assert nexa.BANNER_FRAME == 240
200
+ assert nexa.BANNER_FRAME not in nexa.BANNER_RAMP, "the frame's neutral is not one of the wordmark's hues"
201
+ assert len(set(nexa.BANNER_RAMP)) == len(nexa.BANNER_RAMP), "two rows sharing a colour is a ramp with a step missing"
202
+
203
+
204
+ def test_the_rendered_palette_is_built_from_the_ramp():
205
+ """And the codes that reach the terminal come from those numbers rather than
206
+ from a second, hand-kept list that can drift from them."""
207
+ assert nexa.WORDMARK_GRADIENT == [nexa.c(n) for n in nexa.BANNER_RAMP]
208
+ assert nexa.FRAME_COLOUR == nexa.c(nexa.BANNER_FRAME)
209
+
210
+
211
+ def test_the_wordmark_row_count_matches_the_hue_count():
212
+ """One hue per letterform row. If they drift, the banding wraps and two rows
213
+ share a colour."""
214
+ assert len(nexa.WORDMARK_GRADIENT) == nexa.BANNER_ROWS