Skip to content

Commit 2e957d0

Browse files
authored
Merge pull request #12 from itsflaid/codex/redesign-welcome-logo
Refine CLI welcome branding
2 parents b54e4ba + b95d81e commit 2e957d0

4 files changed

Lines changed: 60 additions & 51 deletions

File tree

docs/design.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,9 +146,15 @@ The wordmark should use the aqua brand color.
146146

147147
Everything below the wordmark should stay concise.
148148

149-
The welcome brand signal is framed in a single aqua panel. Wide terminals show
150-
the DevMap symbol above the large wordmark. Narrow terminals keep the symbol
151-
but use a compact `DEVMAP` title so the panel does not wrap or clip.
149+
The welcome brand signal uses a large outlined block DevMap wordmark
150+
without a surrounding panel or separate symbol. A small CLI label, concise
151+
capability line, and solid aqua separator make it feel like a professional
152+
developer tool without adding decorative terminal noise.
153+
154+
Narrow terminals use a compact `DEVMAP` title and shorter capability label so
155+
the welcome header does not wrap or clip. The wide wordmark relies on Unicode
156+
block and box-drawing glyphs; terminals without compatible fonts may use the
157+
compact fallback or require a font configuration adjustment.
152158

153159
Example:
154160

docs/for-me-personal/PROGRESS.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,13 @@ Terakhir diperbarui: 2026-06-14
2121

2222
### Welcome Brand Panel
2323

24-
- Welcome screen sekarang menampilkan simbol logo DevMap di atas ASCII
25-
wordmark.
26-
- Logo, wordmark, dan border memakai warna aqua brand yang sama.
27-
- Terminal lebar memakai wordmark penuh dalam panel maksimal 76 kolom.
24+
- Simbol logo terpisah dan border luar dihapus agar welcome screen lebih bersih.
25+
- Terminal lebar memakai wordmark blok berpinggiran seperti identitas awal.
26+
- Label `DEVMAP CLI`, capability line, dan separator aqua solid memperjelas
27+
identitas produk sebagai developer tool.
28+
- Perbedaan render glyph Unicode pada sebagian font terminal dicatat sebagai
29+
known issue untuk compatibility pass berikutnya.
30+
- Terminal lebar memakai wordmark penuh dalam area maksimal 76 kolom.
2831
- Terminal sempit memakai judul `DEVMAP` ringkas agar panel tidak wrap atau
2932
terpotong.
3033
- Renderer panel dipisahkan agar layout lebar dan sempit dapat diuji langsung.

packages/cli/src/utils/welcome.ts

Lines changed: 31 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,6 @@ import { existsSync } from "node:fs";
22
import { getSnapshotPath } from "../cache/snapshot.js";
33
import { theme } from "./output.js";
44

5-
const SYMBOL_LOGO = [
6-
" ╷ ╱╲",
7-
" ╭──────┼──────╱ ╲",
8-
" ╭─╯ ●─────╯ ╱",
9-
" ╱ ╱│ ╱",
10-
"│ ╱ │ ╭────╯",
11-
"│ ╱ │╱╱",
12-
" ╲__╱ ╱│",
13-
" ╲____╱ │",
14-
" ╵"
15-
];
16-
175
const WIDE_WORDMARK = [
186
"██████╗ ███████╗██╗ ██╗███╗ ███╗ █████╗ ██████╗",
197
"██╔══██╗██╔════╝██║ ██║████╗ ████║██╔══██╗██╔══██╗",
@@ -26,6 +14,8 @@ const WIDE_WORDMARK = [
2614
const WIDE_PANEL_WIDTH = 76;
2715
const COMPACT_PANEL_WIDTH = 48;
2816
const WIDE_TERMINAL_MINIMUM = 72;
17+
const PRODUCT_LABEL = "DEVMAP CLI";
18+
const PRODUCT_CAPABILITIES = "CODEBASE MAP / STATIC ANALYSIS / AI CONTEXT";
2919

3020
export function printWelcome(projectRoot: string): void {
3121
const hasSnapshot = existsSync(getSnapshotPath(projectRoot));
@@ -49,32 +39,39 @@ export function printWelcome(projectRoot: string): void {
4939

5040
export function renderWelcomeBrandPanel(terminalWidth: number): string {
5141
const isWide = terminalWidth >= WIDE_TERMINAL_MINIMUM;
52-
const panelWidth = Math.max(
53-
28,
54-
Math.min(
55-
terminalWidth,
56-
isWide ? WIDE_PANEL_WIDTH : COMPACT_PANEL_WIDTH
57-
)
42+
const contentWidth = Math.max(
43+
24,
44+
Math.min(terminalWidth, isWide ? WIDE_PANEL_WIDTH : COMPACT_PANEL_WIDTH)
5845
);
59-
const contentWidth = panelWidth - 4;
6046
const wordmark = isWide ? WIDE_WORDMARK : ["DEVMAP"];
61-
const content = [
62-
...SYMBOL_LOGO,
47+
const label = centerLine(`[ ${PRODUCT_LABEL} ]`, contentWidth);
48+
const wordmarkRows = centerBlock(wordmark, contentWidth);
49+
const capabilities = centerLine(
50+
isWide ? PRODUCT_CAPABILITIES : "CODEBASE INTELLIGENCE",
51+
contentWidth
52+
);
53+
const separator = "━".repeat(Math.min(contentWidth, 64));
54+
55+
return [
56+
`${theme.gray}${label}${theme.reset}`,
6357
"",
64-
...wordmark
65-
];
66-
const top = `╭${"─".repeat(panelWidth - 2)}╮`;
67-
const bottom = `╰${"─".repeat(panelWidth - 2)}╯`;
68-
const rows = content.map((line) => {
69-
const visibleLine = line.slice(0, contentWidth);
70-
const leftPadding = Math.floor((contentWidth - visibleLine.length) / 2);
71-
const rightPadding = contentWidth - visibleLine.length - leftPadding;
72-
return `│ ${" ".repeat(leftPadding)}${visibleLine}${" ".repeat(rightPadding)} │`;
73-
});
58+
...wordmarkRows.map((line) => `${theme.aqua}${line}${theme.reset}`),
59+
"",
60+
`${theme.gray}${capabilities}${theme.reset}`,
61+
`${theme.aqua}${separator}${theme.reset}`
62+
].join("\n");
63+
}
64+
65+
function centerLine(line: string, width: number): string {
66+
const visibleLine = line.slice(0, width);
67+
const leftPadding = Math.floor((width - visibleLine.length) / 2);
68+
return `${" ".repeat(leftPadding)}${visibleLine}`;
69+
}
7470

75-
return [top, ...rows, bottom]
76-
.map((line) => `${theme.aqua}${line}${theme.reset}`)
77-
.join("\n");
71+
function centerBlock(lines: string[], width: number): string[] {
72+
const blockWidth = Math.min(width, Math.max(...lines.map((line) => line.length)));
73+
const leftPadding = Math.floor((width - blockWidth) / 2);
74+
return lines.map((line) => `${" ".repeat(leftPadding)}${line.slice(0, width)}`);
7875
}
7976

8077
function printCommand(command: string, description?: string): void {

packages/cli/test/welcome.test.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,29 @@ import assert from "node:assert/strict";
22
import test from "node:test";
33
import { renderWelcomeBrandPanel } from "../src/utils/welcome.js";
44

5-
test("welcome brand panel frames the logo and wordmark on wide terminals", () => {
5+
test("welcome brand panel renders an outlined block wordmark and tool identity", () => {
66
const panel = stripAnsi(renderWelcomeBrandPanel(100));
77
const lines = panel.split("\n");
88

9+
assert.match(panel, /\[ DEVMAP CLI \]/);
910
assert.match(panel, / /);
10-
assert.match(panel, //);
11-
assert.ok(lines.every((line) => line.length === lines[0]?.length));
12-
assert.ok((lines[0]?.length ?? 0) <= 76);
13-
assert.match(lines[0] ?? "", /^+$/);
14-
assert.match(lines.at(-1) ?? "", /^+$/);
11+
assert.match(panel, //);
12+
assert.match(panel, /CODEBASE MAP \/ STATIC ANALYSIS \/ AI CONTEXT/);
13+
assert.ok(lines.every((line) => line.length <= 76));
14+
assert.match(lines.at(-1) ?? "", /^+$/);
15+
assert.equal(lines[2]?.indexOf("█"), lines[3]?.indexOf("█"));
1516
});
1617

17-
test("welcome brand panel uses a compact wordmark on narrow terminals", () => {
18+
test("welcome brand panel uses a compact tool identity on narrow terminals", () => {
1819
const panel = stripAnsi(renderWelcomeBrandPanel(48));
1920
const lines = panel.split("\n");
2021

22+
assert.match(panel, /\[ DEVMAP CLI \]/);
2123
assert.match(panel, /DEVMAP/);
22-
assert.ok(lines.every((line) => line.length === lines[0]?.length));
23-
assert.ok((lines[0]?.length ?? 0) <= 48);
24-
assert.doesNotMatch(panel, //);
24+
assert.match(panel, /CODEBASE INTELLIGENCE/);
25+
assert.ok(lines.every((line) => line.length <= 48));
26+
assert.doesNotMatch(panel, //);
27+
assert.match(lines.at(-1) ?? "", /^+$/);
2528
});
2629

2730
function stripAnsi(value: string): string {

0 commit comments

Comments
 (0)