From b315f4516043f678ccc180e053294caad31243a4 Mon Sep 17 00:00:00 2001 From: Sergii Demianchuk Date: Mon, 17 Aug 2026 15:35:09 -0400 Subject: [PATCH 1/2] feat(chat): a font-independent wordmark for the empty state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces the pixel-art mark from #82, which shattered into disconnected bars in the editor. WHY THIS ONE SURVIVES WHERE THAT ONE DID NOT. The old mark drew letterforms out of `█`, which only works where the font FILLS the character cell — a property of the font, not the character, and one Monaco does not have. This mark asks for neither: the frame is built from box-drawing rules, which are CONNECTOR glyphs designed to join across cells in every monospace family, and the letters are real text rather than pixels. The `▁▃▅█` ramp is the only block run left, and it is a decorative ascent — "level" made literal — so a font that renders it slightly short costs nothing. Verified before shipping this time, which is the part I skipped last time: rendered in Monaco, SF Mono, Menlo, Courier New, Andale Mono, Consolas and the generic fallback, plus the real empty state in Monaco in both themes. Legible in all seven. Monaco leaves hairline gaps at the frame's corners and nothing else. The mark is 32 columns where the old one was 41, so the container-query factor moves with it: clamp(5px, 3.6cqi, 13px) -> clamp(5px, 4.6cqi, 13px). Those two numbers are halves of one value — 41 x 3.6 and 32 x 4.6 both land the mark at ~88% of its container — and the test now pins the RELATIONSHIP rather than either number, because changing the art without the factor is the way this breaks: widen it and it overflows, narrow it and it becomes a stamp floating in white space. The failure message reports the computed fill percentage. The old guard, which required full blocks only, is gone. It encoded a false belief as a rule and would have blocked this fix while waving through the bug it was written for. Guards, each bypass-verified by reverting the fix: - the cqi left at the old 41-column value (69% fill — a stamp) - the cqi raised too far (115%) and the art widened without it (127%) - sizing no longer container-relative at all - role="img" dropped; the accessible name dropped 33 tests in webviewCss, 34 suites green. --- extensions/levelcode-ai/media/chat.html | 19 +++------ .../levelcode-ai/test/webviewCss.test.js | 41 +++++++++++++------ 2 files changed, 34 insertions(+), 26 deletions(-) diff --git a/extensions/levelcode-ai/media/chat.html b/extensions/levelcode-ai/media/chat.html index a6188eb..2fd78a2 100644 --- a/extensions/levelcode-ai/media/chat.html +++ b/extensions/levelcode-ai/media/chat.html @@ -767,7 +767,7 @@ /* font-size is sized off the CONTAINER width (cqi) — reliable in a webview where vw = the whole editor, not this panel — so the wordmark always fits and the last glyph is never clipped. line-height:1 makes the box-drawing rows connect into solid letters. */ - #empty .lc-ascii { font-family: var(--vscode-editor-font-family, ui-monospace, monospace); font-size: clamp(5px, 3.6cqi, 13px); line-height: 1; white-space: pre; color: var(--vscode-terminal-ansiGreen, #98c379); opacity: 1; width: max-content; max-width: 100%; margin: 2px auto 6px; overflow-x: auto; user-select: none; } + #empty .lc-ascii { font-family: var(--vscode-editor-font-family, ui-monospace, monospace); font-size: clamp(5px, 4.6cqi, 13px); line-height: 1; white-space: pre; color: var(--vscode-terminal-ansiGreen, #98c379); opacity: 1; width: max-content; max-width: 100%; margin: 2px auto 6px; overflow-x: auto; user-select: none; } #empty .lc-ascii-sub { font-family: var(--vscode-editor-font-family, monospace); font-size: 11px; letter-spacing: .22em; color: var(--muted); opacity: .9; margin-bottom: 14px; } #empty .starters { display: flex; flex-wrap: wrap; gap: 7px; justify-content: center; margin-top: 14px; } #empty .starter { cursor: pointer; border: 1px solid var(--border); border-radius: 14px; padding: 4px 11px; font-size: 11.5px; background: var(--field-bg); color: var(--vscode-foreground); opacity: .95; } @@ -1259,18 +1259,11 @@
-
+
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 91156d2..f99fbb1 100644 --- a/extensions/levelcode-ai/test/webviewCss.test.js +++ b/extensions/levelcode-ai/test/webviewCss.test.js @@ -578,25 +578,40 @@ 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 fits its container and has an accessible name', () => { - // NOT asserted here: which characters it is drawn from. A previous version of this test required - // full blocks only, on the theory that `█` tiles seamlessly while `▀`/`▄` can seam. Half of that is - // right — `▀` above `▄` does leave a gap — but the other half is not: whether `█` FILLS its cell is - // a property of the FONT, not of the character. In Monaco it does not, and a wordmark built on that +test('WORDMARK: the mark and its cqi scale factor stay in agreement', () => { + // NOT asserted here: which characters it is drawn from. A previous version required full blocks + // only, on the theory that `█` tiles seamlessly while `▀`/`▄` can seam. Half of that is right — + // `▀` above `▄` does leave a gap — but the other half is not: whether `█` FILLS its cell is a + // property of the FONT, not of the character. In Monaco it does not, and a wordmark built on that // assumption shattered into disconnected bars in the editor while looking perfect in a harness - // running SF Mono. The lesson is that this file cannot check the thing that actually matters, so it - // should stop pretending to; ASCII art has to be looked at in the target font. + // running SF Mono. + // + // The current mark sidesteps that entirely: box-drawing rules are CONNECTOR glyphs that join in + // every monospace family, and the letters are real text rather than pixel art. Verified by + // rendering it in Monaco, SF Mono, Menlo, Courier New, Andale Mono, Consolas and the generic + // fallback — legible in all seven. That check cannot live in this file; ASCII art has to be looked + // at in the target font. const m = /
]*>([\s\S]*?)<\/pre>/.exec(html);
 	assert.ok(m, 'the empty-state wordmark is gone');
 	const art = m[1].replace(/^\n/, '');
-
-	// This bound IS checkable and is not about glyphs: the logo is sized from 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');
+
+	// What IS checkable, and the thing most likely to be got wrong: the mark is sized from the
+	// container, so its WIDTH IN COLUMNS and the cqi factor are two halves of one number. Widen the art
+	// without lowering the factor and it overflows; narrow it without raising the factor and it shrinks
+	// to a stamp floating in white space. The 41-column mark used 3.6cqi; this 32-column one uses 4.6
+	// precisely to land in the same place.
+	const cqi = /\.lc-ascii[^{]*\{[^}]*font-size:\s*clamp\(\s*\d+px\s*,\s*([\d.]+)cqi/.exec(css);
+	assert.ok(cqi, 'the wordmark is no longer sized from its container');
+	// A monospace cell is ~0.6em wide, so the mark occupies cols * 0.6 * (cqi/100) of the container.
+	const fill = cols * 0.6 * Number(cqi[1]) / 100;
+	assert.ok(fill > 0.8 && fill < 0.95,
+		'the mark would fill ' + Math.round(fill * 100) + '% of its container — ' + cols + ' columns at '
+		+ cqi[1] + 'cqi. Below ~80% it reads as a stamp; above ~95% it touches the edges and can overflow.');
+
+	assert.ok(lines.length <= 14,
+		'the wordmark is ' + lines.length + ' lines; it has to leave room for the prompt and starters beneath it');
 
 	// The accessible name is the whole reason a picture made of text is not a wall of noise to a
 	// screen reader.

From cfdd4dc52ebfa893d675ff4193a53f14bf8645e8 Mon Sep 17 00:00:00 2001
From: Sergii Demianchuk 
Date: Mon, 17 Aug 2026 16:54:50 -0400
Subject: [PATCH 2/2] test(chat): read the right rule, and assert the invariant
 instead of a proxy
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Review on #85, two distinct points and both correct.

THE SELECTOR COULD DRIFT TO THE WRONG RULE. `.lc-ascii-wrap` is declared BEFORE `.lc-ascii`
and `.lc-ascii-sub` immediately after it, and the old pattern —
`\.lc-ascii[^{]*\{[^}]*font-size:…cqi` — matched the right one only because -wrap happens to
declare no font-size. Luck of content, not construction.

Demonstrated rather than asserted: giving .lc-ascii-wrap a `clamp(5px, 9.9cqi, 13px)`, the
old regex reads 9.9 and the new one still reads 4.6. The rule is now anchored with a
negative lookahead so a hyphenated sibling cannot match, and the cqi is read from the
captured body rather than from a span that could cross rules.

THE FILL PERCENTAGE WAS FAKE PRECISION. It multiplied in a hard-coded 0.6em cell width to
report a tidy "88% of its container", but that factor is a property of whatever font the
editor resolves — it differs between Monaco and SF Mono — so the number dressed the real
invariant in an accuracy it does not have.

The contract is `cols x cqi`: the art's width in columns and the font size as a percentage
of the container are two halves of one value, and their product is what stays constant.
41x3.6 and 32x4.6 both land on ~147. That is what the test asserts now, and what the
failure message reports.

Guards, each bypass-verified by reverting the fix:
  - the decoy cqi on .lc-ascii-wrap, which the old pattern read and this one ignores
  - the cqi left at the old 41-column value (115.2); raised too far (192.0)
  - the art widened without the cqi (193.2)
  - sizing no longer container-relative at all

33 tests in webviewCss, 34 suites green.
---
 .../levelcode-ai/test/webviewCss.test.js      | 24 ++++++++++++++-----
 1 file changed, 18 insertions(+), 6 deletions(-)

diff --git a/extensions/levelcode-ai/test/webviewCss.test.js b/extensions/levelcode-ai/test/webviewCss.test.js
index f99fbb1..bc490ce 100644
--- a/extensions/levelcode-ai/test/webviewCss.test.js
+++ b/extensions/levelcode-ai/test/webviewCss.test.js
@@ -602,13 +602,25 @@ test('WORDMARK: the mark and its cqi scale factor stay in agreement', () => {
 	// without lowering the factor and it overflows; narrow it without raising the factor and it shrinks
 	// to a stamp floating in white space. The 41-column mark used 3.6cqi; this 32-column one uses 4.6
 	// precisely to land in the same place.
-	const cqi = /\.lc-ascii[^{]*\{[^}]*font-size:\s*clamp\(\s*\d+px\s*,\s*([\d.]+)cqi/.exec(css);
+	// The selector is anchored with a negative lookahead because `.lc-ascii-wrap` is declared BEFORE
+	// `.lc-ascii` and `.lc-ascii-sub` right after it. A looser `\.lc-ascii[^{]*\{` reads the right rule
+	// today only because -wrap happens to declare no font-size — luck of content, not construction, and
+	// it would silently start measuring the wrong rule the day one of them gains a cqi clamp.
+	const rule = /\.lc-ascii(?![-\w])[^{]*\{([^}]*)\}/.exec(css);
+	assert.ok(rule, 'the .lc-ascii rule is gone');
+	const cqi = /font-size:\s*clamp\(\s*\d+px\s*,\s*([\d.]+)cqi/.exec(rule[1]);
 	assert.ok(cqi, 'the wordmark is no longer sized from its container');
-	// A monospace cell is ~0.6em wide, so the mark occupies cols * 0.6 * (cqi/100) of the container.
-	const fill = cols * 0.6 * Number(cqi[1]) / 100;
-	assert.ok(fill > 0.8 && fill < 0.95,
-		'the mark would fill ' + Math.round(fill * 100) + '% of its container — ' + cols + ' columns at '
-		+ cqi[1] + 'cqi. Below ~80% it reads as a stamp; above ~95% it touches the edges and can overflow.');
+
+	// Asserted on cols x cqi directly, which IS the contract: the art width in columns and the font
+	// size as a percentage of the container are two halves of one number, and their product is what
+	// stays constant. The previous version multiplied in a hard-coded 0.6em cell width to report a
+	// tidy "fill %", but that factor is a property of whatever font the editor resolves — it differs
+	// between Monaco and SF Mono — so it dressed the real invariant in a precision it does not have.
+	const product = cols * Number(cqi[1]);
+	assert.ok(product > 132 && product < 162,
+		'cols x cqi is ' + product.toFixed(1) + ' (' + cols + ' columns at ' + cqi[1] + 'cqi). '
+		+ 'It must stay near 147 — the value both shipped marks share (41x3.6, 32x4.6). Lower and the '
+		+ 'mark shrinks to a stamp in white space; higher and it touches the edges and can overflow.');
 
 	assert.ok(lines.length <= 14,
 		'the wordmark is ' + lines.length + ' lines; it has to leave room for the prompt and starters beneath it');