From b0717ae4e790f34c305e3636c53d3ac56e07336e Mon Sep 17 00:00:00 2001 From: Sergii Demianchuk Date: Sun, 16 Aug 2026 18:20:51 -0400 Subject: [PATCH] feat(chat): a proper wordmark for the empty state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces the figlet "ANSI Shadow" dump with a wordmark drawn for this space. The old one was the most-used figlet font there is, carried a double-outline shadow that read as noise at the size it actually renders, and did not line up: LEVEL ran to 41 columns while CODE ran to 38 and sat at a 5-space indent, so the two words never shared an edge. The new one is 11x39 (was 12x41), both words centred on the same axis, no shadow. DRAWN, NOT GENERATED. A 10-row pixel grid with every stroke 2px thick, packed two pixel rows per text row. That last constraint is the whole trick, and it was learned the hard way: `▀` sits at the TOP of its cell and `▄` at the BOTTOM, so `▀` directly above `▄` leaves a full empty cell between them — a seam straight through the letterform. A 1px-stroke font produces that on nearly every row, and the first three attempts shattered into fragments because of it. With 2px strokes every pixel pair collapses to a FULL block, so the shipped art contains `█` and spaces and nothing else — it cannot develop seams in any monospace font, whatever the user has configured. That property is now pinned. Two things measured rather than assumed: - Verified the seam directly: `█` over `█`, `▄` over `▀`, and `█` over `▀` all tile solidly; only `▀` over `▄` gaps. That test is what redirected the design. - Width is capped at ~44 columns. #empty is max 560px and the font is sized from the container (clamp(5px, 3.6cqi, 13px)), so a wider mark does not scale down — it overflows and grows a horizontal scrollbar under the logo. An earlier 71-column one-line version did exactly that, which is why this stayed stacked. Guards, each bypass-verified by reverting the fix: - half-blocks reintroduced, i.e. the seam bug - role="img" dropped, so a screen reader reads the picture out block by block - the accessible name dropped - the mark widened past the container 33 tests in webviewCss, 34 suites green. --- extensions/levelcode-ai/media/chat.html | 23 +++++++------- .../levelcode-ai/test/webviewCss.test.js | 30 +++++++++++++++++++ 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/extensions/levelcode-ai/media/chat.html b/extensions/levelcode-ai/media/chat.html index a6188eb..280e220 100644 --- a/extensions/levelcode-ai/media/chat.html +++ b/extensions/levelcode-ai/media/chat.html @@ -1259,18 +1259,17 @@
-
+
levelcode.ai
Ask about your code, or describe what to build. The open file is sent as context; add a selection with + or ⌥⌘A.
diff --git a/extensions/levelcode-ai/test/webviewCss.test.js b/extensions/levelcode-ai/test/webviewCss.test.js index ab1afc4..f2f16d1 100644 --- a/extensions/levelcode-ai/test/webviewCss.test.js +++ b/extensions/levelcode-ai/test/webviewCss.test.js @@ -578,6 +578,36 @@ test('TRANSCRIPT: the user bubble hugs its content, and is capped short of the c 'tint is the secondary cue and still earns its place — side alone would drop on a wrapped log'); }); +test('WORDMARK: the empty-state logo is full blocks only, and fits its container', () => { + // Drawn on a 10-row pixel grid with 2px strokes, then packed two pixel rows per text row. Because + // every stroke is an even number of pixels, each pair collapses to a FULL block — no ▀ or ▄ survives. + // + // That is the property worth pinning, and it was learned the hard way. `▀` sits at the top of its + // cell and `▄` at the bottom, so `▀` directly above `▄` leaves a full cell of empty space between + // them: a seam straight through the letterform. A 1px-stroke font produces that constantly and + // shatters. Full blocks tile seamlessly in any monospace font, so this art cannot develop seams no + // matter what the user's editor font is. + const m = /
]*>([\s\S]*?)<\/pre>/.exec(html);
+	assert.ok(m, 'the empty-state wordmark is gone');
+	const art = m[1].replace(/^\n/, '');
+	const glyphs = new Set(art.replace(/[\n ]/g, ''));
+	assert.deepStrictEqual([...glyphs], ['█'],
+		'the wordmark uses partial blocks: ▀ above ▄ leaves a seam through the stroke in most fonts. '
+		+ 'Found: ' + [...glyphs].join(''));
+
+	// It is sized by the container (clamp(5px, 3.6cqi, 13px)) inside #empty, which is capped at 560px.
+	// Past ~44 columns it stops fitting and the pre grows a horizontal scrollbar under the logo.
+	const lines = art.split('\n');
+	const cols = Math.max(...lines.map((l) => l.length));
+	assert.ok(cols <= 44, 'the wordmark is ' + cols + ' columns; wider than ~44 overflows #empty (max 560px)');
+	assert.ok(lines.length <= 14, 'the wordmark is ' + lines.length + ' lines; it has to leave room for the prompt beneath it');
+
+	// The accessible name is the whole reason a picture made of text is not a wall of noise to a
+	// screen reader.
+	assert.match(m[0], /role="img"/, 'the wordmark must be exposed as an image, not read out block by block');
+	assert.match(m[0], /aria-label="[^"]+"/, 'the wordmark has no accessible name');
+});
+
 test('CODE: prose blocks get room, and nothing else that uses 
 moves', () => {
 	// docs/CHAT-TYPOGRAPHY.md D5/T3. `pre` is a GLOBAL selector in this file, and it draws four different
 	// things: the empty state's ASCII logo, the MCP approval card's command block, the terminal output