Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

TUICommander — Visual Style Guide

Reference for all UI/CSS/layout work. Every visual change MUST follow this guide.

Design Philosophy

VS Code Dark theme adapted for a terminal-first, developer-focused interface. The UI is a frame for terminal content — chrome recedes, content dominates. No bright whites. Muted UI elements, vivid status colors. Everything monospace except UI labels.

Application Layout

┌─────────────────────────────────────────────────────────────────────┐
│ #toolbar (38px macOS / 32px Win+Linux, --bg-primary, drag region)  │
│ ┌──────────────┬────────────────────────────────────┬────────────┐ │
│ │ toolbar-left │ toolbar-center (tab bar)            │toolbar-right│ │
│ │ (sidebar w)  │ [Tab1] [Tab2] [Tab3] [+]           │ [IDE btns] │ │
│ └──────────────┴────────────────────────────────────┴────────────┘ │
├─────────────────────────────────────────────────────────────────────┤
│ #app-body (flex: 1, flex-direction: row)                           │
│ ┌──────────┬─────────────────────────────────┬───────────────────┐ │
│ │ #sidebar │ #main                            │ Side panels      │ │
│ │ 300px    │ (flex: 1)                        │ (400px, optional)│ │
│ │ --bg-    │                                  │                  │ │
│ │ secondary│ ┌──────────────────────────────┐ │ ┌──────────────┐ │ │
│ │          │ │ #terminal-container          │ │ │ Diff or      │ │ │
│ │ REPOS    │ │ (flex: 1, --bg-primary)      │ │ │ Markdown or  │ │ │
│ │  section │ │                              │ │ │ Notes/Ideas  │ │ │
│ │  title   │ │  terminal fills this          │ │ │ panel        │ │ │
│ │  repo    │ │  entire area                 │ │ │              │ │ │
│ │   header │ │                              │ │ │ panel-header │ │ │
│ │   branch │ │                              │ │ │ panel-content│ │ │
│ │   branch │ │                              │ │ │              │ │ │
│ │          │ │                              │ │ └──────────────┘ │ │
│ │ FOOTER   │ │                              │ │                  │ │
│ │ [+ Add]  │ └──────────────────────────────┘ │                  │ │
│ │ [icons]  │                                  │                  │ │
│ └──────────┴─────────────────────────────────┴───────────────────┘ │
├─────────────────────────────────────────────────────────────────────┤
│ #status-bar (28px, --bg-secondary, border-top)                     │
│ [zoom][sessions]  [branch ↑2][PR #42][CI ✓]  [toggles][💡][⚙][?] │
└─────────────────────────────────────────────────────────────────────┘

Key structural rules:

  • #app is flex-direction: column, fills 100vh × 100vw.
  • #app-body is flex-direction: row, flex: 1, min-height: 0.
  • Sidebar is fixed-width (resizable 200–500px), main area fills remaining space.
  • Side panels (Diff, Markdown, Notes) appear right of #main, width 400px, max 50vw.
  • All sections have overflow: hidden — scrolling is on inner content areas only.
  • Status bar is always at the bottom, never scrolls.

Color Palette

Values shown are the vscode-dark theme defaults (defined in :root of global.css). The app supports 11 themes — all core colors are CSS custom properties overridden at runtime by applyAppTheme() in themes.ts. When writing CSS, always use variables, never hardcode core palette values.

CSS Variables (:root in global.css)

VariableDefault (vscode-dark)Usage
--bg-primary#1e1e1eMain canvas — terminals, panel bodies
--bg-secondary#252526Sidebar, tab bar, status bar
--bg-tertiary#2d2d30Inputs, settings rows, button defaults
--bg-highlight#37373dHover states, active branch bg
--fg-primary#ccccccPrimary text (max brightness for text)
--fg-secondary#a0a0a0Labels, secondary text
--fg-muted#9aa1a9Section titles, tertiary text
--accent#59a8ddPrimary actions, active indicators, links (theme-dependent)
--accent-hover#7abde5Hover on accent elements (theme-dependent)
--activity#59a8ddBusy/activity pulse indicators (fixed in global.css, not overridden by themes)
--success#4ec9b0Positive states, open PRs (teal)
--warning#dcdcaaCaution, pending, main branch icon (yellow)
--attention#e8984cActionable alerts, confirmation prompts (orange)
--error#f48771Errors, failures, closed PRs (coral)
--merged#a371f7PR merged badge (purple)
--unseen#c084fcTerminal completed while user wasn’t viewing (purple, clears on view)
--border#3e3e42All borders and dividers
--text-on-accent#000000Black text on colored badge backgrounds
--text-on-error#000000Black text on error backgrounds
--text-on-success#000000Black text on success backgrounds

Extended Palette (hardcoded, contextual only)

ColorContext
#d29922Changes requested / review required (orange)
#e3b341CI pending (golden)
#ffd700Rate limit, question icon (gold)
rgba(122, 162, 247, *)Branch ahead/behind tint, pulse glow
rgba(158, 206, 106, *)Diff additions bg, CI success tint
rgba(247, 118, 142, *)Diff deletions bg, CI failure tint

Background Stacking Order (darkest → lightest)

#1e1e1e  --bg-primary    Terminal canvas, main area
#252526  --bg-secondary   Sidebar, tab bar, status bar, modals
#2d2d30  --bg-tertiary    Buttons, inputs, settings rows, panel headers
#37373d  --bg-highlight   Hover, active branch, selected items

Every surface uses exactly one of these four levels. Elevation = lighter.

Typography

VariableStackUsage
--font-monoJetBrains Mono, Fira Code, Hack, Cascadia Code, Source Code Pro, DejaVu Sans Mono, monospaceTerminals, branch names, stats badges, PR badges, code
--font-ui-apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Noto Sans, Liberation Sans, sans-serifUI labels, buttons, headings, descriptions, settings

Size Scale

VariableSizeWhere
--font-3xs8pxMicro labels, pixel-level detail
--font-2xs10pxSmallest visible labels
--font-xs11pxBadge text, hotkey hints, metadata
--font-sm12pxSection titles (REPOS), secondary labels
--font-md13pxBranch names, tab names, settings labels — default for UI
--font-base14pxBody text, document default
--font-lg15pxPanel headings, chevrons
--font-xl17pxDialog titles
--font-2xl20pxLarge headings
--font-3xl24pxHero text, splash screens

Font weight: 400 normal, 500 medium (branch names), 600 semibold (repo names, badges), 700 bold (headings only).

Spacing

Fixed Dimensions

VariableValue
--sidebar-width300px (resizable: min 200px, max 500px)
--toolbar-height38px macOS / 32px Win+Linux
--tab-bar-height32px
--status-height28px

Spacing Scale

SizeUsage
1–2pxBranch item vertical margin, micro separation
4pxSidebar content top padding, compact flex gaps, micro padding
6pxIcon-to-text gaps, sidebar footer gaps, repo header padding
8pxButton padding, form gaps, sidebar footer padding, standard gap
12pxBranch item horizontal padding, panel header padding, medium padding
16pxSidebar section margin, branch list left indent, modal padding
20pxDialog content padding, sidebar empty state padding

Use gap on flex containers, not margins between children.

Border Radius

VariableValueUsage
--radius-xs2pxMinimal — focus rings
--radius-sm3pxSmall interactive elements
--radius-md4pxStandard — buttons, badges, inputs, branch items
--radius-lg6pxLarger controls — dropdowns, add-repo button, form inputs
--radius-xl8pxModals, panels, dialogs
--radius-pill12pxPR badges, status pills
--radius-full50%Circles — toggle thumbs, repo initials avatar

Shadows

VariableValueUsage
--shadow-popup0 8px 32px rgba(0,0,0,0.4)Modals, dialogs
--shadow-dropdown0 4px 16px rgba(0,0,0,0.3)Menus, popovers, context menus
--shadow-bottom-anchor0 -4px 20px rgba(0,0,0,0.4)Bottom-anchored panels

Three levels only. Never invent new shadow values.

Transitions & Animation

Durations

DurationUsage
0.1sHover backgrounds, active states — instant feedback
0.15sStandard — opacity, color, transform, border changes
0.2sLayout — sidebar collapse, toggle switches, chevron rotation

Keyframe Animations

pulse-opacity: Opacity 0.4 → 1.0 → 0.4, infinite. Duration 1.5s or 2s. Defined in each CSS Module file that uses it (not in global.css — CSS Modules scope animation names). Used for: active branch icon, CI pending badge, rate limit indicator.

pulse-question: Box-shadow 0 → 0 0 12px 4px rgba(122,162,247,0.4) → 0. Variants exist with red (error) and orange (confirm) colors. Used for: terminal tab glow when agent awaits input.

pendulum: Translates text from 0 to -overflow-px and back. Duration computed dynamically from overflow width (~50px/s, minimum 4s cycle). Uses CSS custom properties --overflow-px and --ticker-duration. Used for: status bar notification text that overflows its container.

Tab status dot color scheme (single indicator left of tab name):

  • Grey (opacity 0.3): idle — no session or command never ran
  • Blue (--activity, pulse infinite): busy — producing output now
  • Green (--success): done — command completed
  • Purple (--unseen, static): completed while user wasn’t viewing (clears on view)
  • Orange (--attention, pulse infinite): agent needs user input (question)
  • Red (--error, pulse infinite): API error or agent stuck

Tab type color scheme (gradient background + colored border-bottom):

  • Red (#ef4444): diff tabs
  • Blue (--accent / #7aa2f7): editor tabs
  • Teal (#2dd4bf): markdown tabs
  • Purple (#a78bfa): panel tabs
  • Amber (#fbbf24): remote PTY sessions (created via HTTP/MCP)

Always use ease timing. Respect prefers-reduced-motion. Never transition: all.

Component Reference

#sidebar {
  width: var(--sidebar-width);    /* 300px */
  min-width: 200px;
  max-width: 500px;
  background: var(--bg-secondary);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
}

Section title (e.g. “REPOS”):

  • font-size: --font-sm, text-transform: uppercase, color: --fg-muted
  • letter-spacing: 0.05em, padding: 4px 16px

Repo header:

  • Flex row, gap: 6px, padding: 6px 12px 3px
  • Repo initials: 28×28px circle, --accent bg, --text-on-accent text, --font-xs, semibold
  • Repo name: --font-sm, semibold, uppercase, --fg-secondary, truncated with ellipsis
  • Chevron: --font-lg, --fg-muted, rotates 0→90° on expand (150ms ease)
  • Actions (⋯, +): hidden by default (opacity: 0), shown on repo-header hover

Branch item (the most complex sidebar element):

.branch-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 12px;
  border-radius: var(--radius-md);
  margin: 1px 0;
  transition: background 0.1s;
}
.branch-item:hover { background: var(--bg-highlight); }
.branch-item.active {
  background: var(--bg-highlight);
  border-left: 2px solid var(--accent);
  padding-left: 10px;  /* compensate for border */
}

Branch item anatomy (left to right):

[icon 18px] [name flex:1] [stats badge?] [PR badge?] [actions on hover]
  • Icon (18px wide, centered): yellow for main, Y muted for feature, Y accent+pulse when agent active, Y green when shell idle, ? warning (orange)+pulse when awaiting input
  • Name: --font-md, weight 500, --fg-primary, ellipsis on overflow
  • Stats badge (optional): --font-xs, monospace, --bg-tertiary bg, --border border, --radius-lg, shows +N -N in green/red
  • PR badge (optional): --font-xs, monospace, semibold, --radius-pill, colored by state (see Status Badges below)
  • Actions (on hover only): max-width: 0 → 44px, two 20×20px buttons (+, ×)

Tab Bar

Located inside #toolbar, center section. Background matches toolbar (--bg-primary).

.tab {
  height: var(--tab-bar-height);  /* 32px */
  padding: 0 12px;
  font-size: var(--font-md);
  font-family: var(--font-mono);
  color: var(--fg-secondary);
  background: transparent;
  border: none;
  border-top: 2px solid transparent;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 80px;
  max-width: 200px;
}
.tab.active {
  color: var(--fg-primary);
  border-top-color: var(--accent);
  background: var(--bg-secondary);
}
.tab:hover:not(.active) {
  color: var(--fg-primary);
  background: var(--bg-tertiary);
}

Tab anatomy: [agent badge?] [name, truncated] [close × on hover]

  • Agent badge: small colored prefix (e.g. C claude, G gemini)
  • Close button: invisible by default, opacity: 1 on tab hover
  • New tab button [+]: 28px circle, --accent color

Status Bar

.bar {
  height: var(--status-height);   /* 28px */
  min-height: var(--status-height);
  background: var(--bg-secondary);
  border-top: 1px solid var(--border);
  display: flex;
  align-items: center;
  padding: 0 12px;
  font-size: var(--font-sm);
  gap: 8px;
  overflow: hidden;
}

Three sections: left (zoom, status info, CWD, agent badge, ticker), center (PR + CI badges), right (toggle buttons).

Agent badge (.agentBadge): --font-mono, --font-sm, weight 500, 1px 6px padding, --radius-sm, --bg-tertiary bg. Usage-dependent color classes:

  • .agentUsage--fg-secondary text (normal usage)
  • .agentUsageWarning#dcdcaa text (usage >=70%)
  • .agentUsageCritical#f48771 text + pulse-opacity animation (usage >=90%)
  • .agentRateLimited#f44747 text + pulse-opacity animation

Ticker message (.tickerMessage): --font-mono, --font-sm, --fg-muted, max-width 300px, --radius-sm. Warning priority (>=80): #ffd700 text, gold bg at 0.1 alpha. .tickerClickable adds cursor pointer and hover effect.

Pendulum overflow (.infoTickerActive): When the status info text is wider than its container, a CSS pendulum keyframe animation scrolls the text left then back. Duration is computed dynamically from overflow width (~50px/s). Click dismisses.

Notes toggle badge (.toggleBadge): Small accent-colored pill positioned over the toggle button, showing the filtered note count.

PR badges (center section): PrBadge + CiBadge components in .githubStatus, separated by a left border. CLOSED PRs are hidden; MERGED PRs have a 5-minute activity-based grace period.

Toggle buttons (right section): --bg-tertiary bg, --border border, --font-xs, 2px 8px padding. Active: --accent bg, white text. Each has a hotkey hint overlay positioned below.

Side Panels (Diff, Markdown, Notes/Ideas)

All follow the same structure:

.panel {
  width: 400px;
  min-width: 300px;
  max-width: 50vw;
  border-left: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  background: var(--bg-primary);
}
.panel-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 12px;
  background: var(--bg-tertiary);
  border-bottom: 1px solid var(--border);
}
.panel-title { font-size: var(--font-lg); font-weight: bold; }
.file-count-badge {
  background: var(--accent);
  color: var(--text-on-accent);
  border-radius: var(--radius-pill);
  padding: 1px 6px;
  font-size: var(--font-xs);
}
.panel-content { flex: 1; overflow-y: auto; }

Dialog / Modal

.overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.65);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
}
.dialog {
  width: 480px;
  max-width: 90vw;
  max-height: 80vh;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-popup);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.dialog-header {
  padding: 16px;
  border-bottom: 1px solid var(--border);
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.dialog-header h2 { font-size: var(--font-xl); }
.dialog-content { padding: 16px; overflow-y: auto; flex: 1; }
.dialog-actions {
  padding: 12px 16px;
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  border-top: 1px solid var(--border);
}

Primary button: background: var(--accent); color: var(--text-on-accent); padding: 8px 16px; border-radius: var(--radius-lg); Secondary button: background: var(--bg-tertiary); color: var(--fg-secondary); same padding/radius. Danger button: background: var(--error); color: var(--text-on-error);

Form Controls

input, select, textarea {
  height: 36px;                        /* standard height */
  background: var(--bg-tertiary);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  color: var(--fg-primary);
  font-size: var(--font-md);
  padding: 0 8px;
}
input:focus, select:focus, textarea:focus {
  border-color: var(--accent);
  outline: none;
}

Toggle switch: 36×20px track, --radius-full (10px), off=--bg-tertiary, on=--accent. White thumb slides with 0.2s transition.

Range slider: 4px track height, 16px circular thumb in --accent.

Settings Panel

Full-screen overlay. Inner panel: --bg-secondary, 700px max-width, 80vh max-height.

  • Left sidebar with tabs (General, Notifications, Dictation, Terminal, Agents)
  • Right content area with sections
  • Section heading: <h3>, --font-lg, bold, margin-bottom: 12px
  • Settings row: flex space-between, label left, control right, padding: 8px 0

Status Badges Reference

PR State (sidebar .branch-pr-badge)

StateBackgroundBorderText ColorExtra
Open--successnone--text-on-success
Drafttransparent1px dashed --fg-muted--fg-muted
Merged#a371f7none--text-on-accent
Closed--errornone--text-on-error
Conflict--errornone--text-on-errorpulse-opacity 1.5s
CI Failed--errornone--text-on-errorbold
CI Pendingtransparent1px solid #e3b341#e3b341pulse-opacity 2s
Changes Req.#d29922none--text-on-accent
Review Req.transparent1px solid #d29922#d29922

All badges: font-size: --font-xs, font-family: --font-mono, font-weight: 600, border-radius: --radius-pill, padding: 1px 6px.

CI State (status bar)

StateBackgroundText
Successrgba(158,206,106,0.2)#9ece6a
Failurergba(247,118,142,0.2)#f7768e
Pendingrgba(224,175,104,0.2)#e0af68

Agent/Usage (tab + status bar)

StateCSS ClassStyle
Agent runningTab colored agent prefixTab has colored agent prefix badge
Usage normal.agentUsage--fg-secondary text
Usage ≥70%.agentUsageWarning#dcdcaa text (warning yellow)
Usage ≥90%.agentUsageCritical#f48771 text + pulse-opacity 2s
Rate limited.agentRateLimited#f44747 text + pulse-opacity 2s
Ticker warning (≥80 priority).tickerWarning#ffd700 text, gold bg at 0.1 alpha
Update available.updateBadge#4ec9b0 text, teal bg at 0.15 alpha

Icons

No icon library. Text symbols and Unicode only. Emoji sparingly, always with filter: grayscale(1) brightness(1.5) to match the monochrome UI.

SymbolMeaningWhere
Main/primary branchSidebar branch icon
YFeature branchSidebar branch icon
?Awaiting inputBranch icon (warning/orange, pulsing)
+Add/createButtons
×Close/removeTab close, panel close, dialog close
Context menuRepo header
Edit/renameBranch double-click
Send/executeNotes panel send button
>Chevron (expand/collapse)Repo sections
Tab status dotTab bar (grey=running, green=idle, purple=unseen, blue-pulse=activity, orange-pulse=awaiting, red-pulse=error)
Git branch symbolStatus bar
💡Ideas panelStatus bar, panel header

Icon dimensions: 18px wide container for branch icons. --font-md or --font-lg size. Always left of text with gap: 6–8px.

Scrollbars

::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--bg-highlight);
  border-radius: var(--radius-md);
}
::-webkit-scrollbar-thumb:hover { background: var(--fg-muted); }

Terminal scrollbar overridden to 8px with !important.

Interactive States

Hover

  • Background: one level up (--bg-secondary--bg-tertiary, or --bg-tertiary--bg-highlight)
  • Text: --fg-secondary--fg-primary
  • Border: transparent → --accent (for add-repo button)
  • Duration: 0.1s

Active / Selected

  • Active branch: --bg-highlight bg + 2px solid var(--accent) left border
  • Active tab: --bg-secondary bg + 2px solid var(--accent) top border + --fg-primary text
  • Active toggle: --accent bg + white text
  • No hover animation on already-active items

Focus

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

Excluded on toggle buttons and mic button.

Disabled

  • opacity: 0.3 (strong) or 0.5 (mild)
  • cursor: not-allowed
  • No hover, no transitions

Hidden-until-hover

Pattern used for actions that clutter the UI when always visible:

  • Repo actions: opacity: 0; pointer-events: none;opacity: 1; pointer-events: auto; on .repo-header:hover
  • Branch actions: max-width: 0; overflow: hidden;max-width: 44px; on .branch-item:hover
  • Tab close button: opacity: 0opacity: 1 on .tab:hover

Platform Differences

PropertymacOSWindows/Linux
Toolbar height38px32px
Traffic light offset.platform-macos .toolbar-left { padding-left: 78px; }None
System font-apple-system firstSegoe UI (Win) / Roboto (Linux) first
Quit menuApp menuFile menu
Check for UpdatesApp menuHelp menu

CSS classes on <html>: .platform-macos, .platform-windows, .platform-linux.

Accessibility

  • Primary text (#cccccc on #1e1e1e): 10:1+ contrast ratio (exceeds WCAG AAA).
  • Secondary text (#a0a0a0 on #252526): 6:1+ (exceeds WCAG AA).
  • Status communicated by color + shape + icon — never color alone.
  • :focus-visible outlines for keyboard navigation.
  • prefers-reduced-motion query disables all animations.
  • Custom scrollbars maintain 8px touch target.

PWA / Mobile (src/mobile/mobile.css)

The mobile PWA has its own standalone stylesheet at src/mobile/mobile.css, completely independent from the desktop global.css. This allows the mobile UI to evolve separately while sharing the same design language.

What’s shared

  • Core color palette (same --bg-*, --fg-*, --accent, --success, --warning, --attention, --error variables with identical default values)
  • Border radius scale (--radius-sm through --radius-full, excluding --radius-xs)
  • Shadow tokens (--shadow-popup, --shadow-dropdown)
  • ANSI terminal palette

What differs

PropertyDesktop (global.css)Mobile (mobile.css)
Font mono stackJetBrains Mono, Fira Code, Hack, Cascadia, …SF Mono, Menlo, Consolas, DejaVu, …
Font size scale--font-3xs through --font-3xl (8–24px)Not defined — components use explicit px values
Layout variables--sidebar-width, --toolbar-height, --tab-bar-height, --status-heightNot used — mobile uses flex-based layout
User selectDisabled (none)Enabled (text)
Theme variables--activity, --merged, --unseenNot present (mobile has no terminal activity tracking yet)
Safe areasNot usedenv(safe-area-inset-top/bottom) on #mobile-app
Input font-sizeFrom scaleFixed 16px minimum to prevent iOS auto-zoom

Keeping in sync

When updating core palette colors in global.css, also update mobile.css — the :root blocks must stay aligned for the shared variables. Theme-specific variables (--activity, --merged, --unseen) are desktop-only and do not need mobile equivalents until that functionality ships in PWA.

Anti-Patterns (DO NOT)

  • No bright whites — max text brightness is --fg-primary (#cccccc).
  • No new shadows — only the three defined levels exist.
  • No transition: all — always list specific properties.
  • No hardcoded core colors — use CSS variables for the four bg levels, three fg levels, and status colors.
  • No icon libraries — text/unicode/emoji only.
  • No off-scale radius — only --radius-xs through --radius-full.
  • No !important — except terminal scrollbar overrides.
  • No pixel values outside the spacing scale unless component-specific dimension (like 28px repo initials).
  • No inline styles for theming — all colors and spacing via CSS variables (desktop: global.css, mobile: mobile.css).