Skip to content

feat(core): responsive startup logo with adaptive layout#11413

Open
stdevMac wants to merge 1 commit into
masterfrom
feat/responsive-startup-logo
Open

feat(core): responsive startup logo with adaptive layout#11413
stdevMac wants to merge 1 commit into
masterfrom
feat/responsive-startup-logo

Conversation

@stdevMac
Copy link
Copy Markdown
Member

Changes

Redesigns the Nethermind startup banner so it scales with terminal width and stays readable on both light and dark themes.

  • Picks one of three tiers based on Console.WindowWidth:
    • Full (≥ 75 cols): glyph + big figlet wordmark + URL
    • Glyph (50–74 cols): glyph + URL only
    • Compact (< 50 cols, or no TTY): one-line text fallback
  • Switches the wordmark from white-on-default (�[37m) to dimmed (�[2m) so it renders correctly on light terminals such as the default Docker tty, instead of being nearly invisible.
  • Centers each piece of the logo and the dividers within a single left-aligned block capped at the "Initialization Completed" separator width, so the whole screen reads as one cohesive column rather than floating in the middle of wide terminals.
  • Top and bottom dividers also adapt to terminal width (capped at 86 cols).

Types of changes

What types of changes does your code introduce?

  • Other: UX/cosmetic improvement to startup output

Testing

Requires testing

  • No

Notes on testing

Verified visually at terminal widths of 40, 60, 80, and 100 cols, plus the no-TTY (redirected stdout) path. Behavior is purely formatting of the startup banner; no functional surface is affected.

Documentation

Requires documentation update

  • No

Requires explanation in Release Notes

  • No

Redesigns the Nethermind startup banner so it scales with terminal width
and stays readable on light and dark themes:

- Picks one of three tiers based on Console.WindowWidth: full (glyph +
  figlet wordmark + URL), glyph + URL, or a one-line text fallback for
  very narrow terminals or no-TTY contexts.
- Switches the wordmark from white-on-default to dimmed (�[2m) so it
  renders correctly on light terminals (e.g. default Docker tty), instead
  of being nearly invisible.
- Centers each piece of the logo and the dividers within a single
  left-aligned block capped at the "Initialization Completed" separator
  width, so the whole screen reads as one column rather than floating in
  the middle of wide terminals.
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Apr 29, 2026

Claude finished @stdevMac's task in 4m 40s —— View job


PR Review — feat(core): responsive startup logo with adaptive layout

  • Gather context and read relevant rule files
  • Read the changed file and git diff
  • Analyze code for correctness, edge cases, security, performance
  • Post inline comments for specific issues
  • Post final review summary

Summary

The adaptive layout approach is clean and the fallback logic is sensible. Two issues need addressing before merge.


Findings

Medium — GlyphWidth = 47 does not match actual glyph content (line 26)

The widest glyph line (index 4: " ------ - " + "~~~ ") is 50 visible chars, not 47. All other lines are 46 chars. Because GlyphLogoMinWidth = 50 triggers glyph mode at exactly width == 50, the centering pad is:

LeadingPad(50, 47) → innerPad = (50 - 47) / 2 = 1
" " + <50-char line> = 51 chars → wraps on 50-col terminal

Width 51 also wraps (pad=2, total=52). The author tested 40 and 60 but not the 50–51 boundary. Fix: change GlyphWidth to 50. See inline comment on line 26.

Medium — Bare catch swallows all exceptions in GetTerminalWidth (lines 148–158)

Console.WindowWidth throws IOException on non-TTY — that is the only expected exception, and the comment correctly documents this. The bare catch {} also catches InvalidOperationException, NullReferenceException, etc., hiding unexpected bugs silently. Per robustness rules: "Never swallow exceptions in an empty catch block." Fix: catch (IOException). See inline comment on lines 148–150.


Low / Notes

  • Mixed newline styles: BuildLogo builds its content with \n (via Append('\n')), while BuildNodeInfoScreen wraps it with AppendLine (which appends \r\n on Windows). In practice this is benign on Linux/Docker but worth being consistent.
  • Wordmark centering at width = 75 (FullLogoMinWidth): WordmarkWidth = 69 drives LeadingPad(75, 69) → 3 spaces. The actual figlet lines vary in trailing whitespace — worth a quick sanity check at exactly 75 cols to ensure no line overflows.
  • The GlyphLogoMinWidth/FullLogoMinWidth comments are multi-line block comments explaining the why of the layout constants — acceptable and useful.

Verdict

2 Medium findings (incorrect centering constant, bare catch) that should be fixed before merge. Both are one-line fixes.

private const string SeparatorTitle = " Initialization Completed ";

// Visible widths used to compute centered padding at runtime.
private const int GlyphWidth = 47;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Medium — GlyphWidth constant is wrong; glyph line wraps at the boundary width

GlyphWidth = 47 does not match the actual widest glyph line. Counting the visible characters in _glyphLines:

  • All lines except index 4 are 46 visible chars.
  • Line index 4 (" ------ - " + "~~~ ") is 50 visible chars: 39 + 11.

Since GlyphLogoMinWidth = 50, the glyph mode activates exactly when width == 50. At that point:

LeadingPad(50, 47) → blockWidth=50, innerPad=(50-47)/2=1 → " "
" " + <50-char glyph> = 51 chars on a 50-col terminal → wraps

Same at width = 51 (pad=2, total=52 > 51 → wraps). The author tested 40 and 60 but not 50–51.

Fix: Change GlyphWidth to 50 so centering arithmetic uses the true max line width. At width=50 this yields pad=0 (left-aligned, no overflow); at width=52+ centering works correctly.

Suggested change
private const int GlyphWidth = 47;
private const int GlyphWidth = 50;

Fix this →

Comment on lines +148 to +150
private static int GetTerminalWidth()
{
try
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Medium — bare catch swallows all exceptions

Console.WindowWidth throws IOException when stdout is not a TTY (as the comment correctly describes). Catching every exception type — including OutOfMemoryException, InvalidOperationException, unexpected runtime faults — makes bugs invisible.

Per robustness rules: "Never swallow exceptions in an empty catch block — at minimum log the exception."

Fix: Narrow the catch to IOException (the documented throw source) so unexpected exceptions still surface:

Suggested change
private static int GetTerminalWidth()
{
try
private static int GetTerminalWidth()
{
try
{
int w = Console.WindowWidth;
return w > 0 ? w : SeparatorMaxWidth;
}
catch (IOException)
{
return SeparatorMaxWidth;
}
}

Fix this →

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant