From hyperskills
Provides design patterns for terminal user interfaces: layout paradigms, keyboard navigation, visual systems, and TUI anti-pattern validation. Works with Ratatui, Ink, Textual, Bubbletea, or any TUI framework.
How this skill is triggered — by the user, by Claude, or both
Slash command
/hyperskills:tui-designThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Universal design patterns for building exceptional terminal user interfaces. Framework-agnostic, works with Ratatui, Ink, Textual, Bubbletea, or any TUI toolkit.
Universal design patterns for building exceptional terminal user interfaces. Framework-agnostic, works with Ratatui, Ink, Textual, Bubbletea, or any TUI toolkit.
Core philosophy: TUIs earn their power through spatial consistency, keyboard fluency, and information density that respects human attention. Design for the expert's speed without abandoning the beginner's discoverability.
digraph tui_design {
rankdir=TB;
"What are you building?" [shape=diamond];
"Select layout paradigm" [shape=box];
"Design interaction model" [shape=box];
"Define visual system" [shape=box];
"Validate against anti-patterns" [shape=box];
"Ship it" [shape=doublecircle];
"What are you building?" -> "Select layout paradigm";
"Select layout paradigm" -> "Design interaction model";
"Design interaction model" -> "Define visual system";
"Define visual system" -> "Validate against anti-patterns";
"Validate against anti-patterns" -> "Ship it";
}
Choose your primary layout based on what you're building:
| App Type | Paradigm | Examples |
|---|---|---|
| File manager | Miller Columns | yazi, ranger |
| Git / DevOps tool | Persistent Multi-Panel | lazygit, lazydocker |
| System monitor | Widget Dashboard | btop, bottom, oxker |
| Data browser / K8s | Drill-Down Stack | k9s, diskonaut |
| SQL / HTTP client | IDE Three-Panel | harlequin, posting |
| Shell augmentation | Overlay / Popup | atuin, fzf |
| Log / event viewer | Header + Scrollable List | htop, tig |
All panels visible simultaneously. Focus shifts between them. Users build spatial memory, "branches are always top-left."
┌─ Status ──┬─────────── Detail ──────────┐
├─ Files ───┤ │
│ > file.rs │ diff content here... │
│ main.rs │ │
├─ Branches ┤ │
│ * main │ │
│ feat/x │ │
├─ Commits ─┤ │
│ abc1234 │ │
└───────────┴──────────────────────────────┘
[q]uit [c]ommit [p]ush [?]help
When to use: Multi-faceted tools where users need simultaneous context (git clients, container managers, monitoring). Key rule: Panels maintain fixed positions across sessions. Never rearrange without user action.
Three-pane past/present/future navigation. Parent directory (left), current (center), preview (right).
┌── Parent ──┬── Current ──┬── Preview ────────┐
│ .. │ > config/ │ port: 8080 │
│ src/ │ lib/ │ host: localhost │
│ > config/ │ main.rs │ log_level: debug │
│ tests/ │ mod.rs │ db_url: postgres://│
└────────────┴─────────────┴───────────────────┘
When to use: Hierarchical data navigation (file systems, tree structures, nested configs). Key rule: Preview pane content adapts to selection type, code gets highlighting, images render, directories show contents.
Enter descends, Esc ascends. Browser-like navigation through hierarchical data.
When to use: Deep hierarchies where showing all levels simultaneously is impractical (Kubernetes resources, database schemas).
Key rule: Always show the current navigation path as a breadcrumb. Provide :resource command-mode for direct jumps.
Self-contained widget panels with independent data. All information visible at once, no navigation required.
┌─── CPU ──────────────┬─── Memory ──────────┐
│ ▁▂▃▅▇█▇▅▃▂▁▂▃▅▇ │ ████████░░ 78% │
│ core0: 45% core1: 67%│ 12.4G / 16.0G │
├─── Network ──────────┼─── Disk ────────────┤
│ ▲ 1.2 MB/s ▼ 340KB/s│ /: 67% /home: 45% │
├─── Processes ────────┴─────────────────────┤
│ PID USER CPU% MEM% CMD │
│ 1234 root 23.4 4.5 postgres │
└─────────────────────────────────────────────┘
When to use: Monitoring, real-time status, system dashboards. Key rule: Each widget is self-contained with its own title. Use braille/block characters for high-density data.
Sidebar (left), editor/main (center), detail/output (bottom). Tab bar along top.
When to use: Editing-focused tools (SQL clients, HTTP tools, config editors). Key rule: Sidebar toggles with a single key. Center panel supports tabs. Bottom panel can expand to full height.
TUI appears on demand over the shell, disappears after use.
When to use: Shell augmentations (history search, file picker, command palette). Key rule: Configurable height. Return selection to the caller. Never disrupt scrollback.
Fixed header with meters/stats, scrollable data below, function bar at bottom.
When to use: Single-list tools with metadata (process viewers, log viewers, sorted listings). Key rule: The header creates a natural "overview then detail" reading flow. Sort by the most actionable dimension by default.
Terminals resize. Your TUI must handle it gracefully.
| Strategy | When |
|---|---|
| Proportional split | Panels maintain percentage ratios on resize |
| Priority collapse | Less important panels hide first below minimum width |
| Stacking | Panels collapse to title-only bars, active one expands (zellij pattern) |
| Breakpoint modes | Switch layout entirely below a threshold (e.g., multi-panel → single panel) |
| Minimum size gate | Display "terminal too small" if below usable minimum |
Rules:
SIGWINCH gracefully.| App Complexity | Recommended Model |
|---|---|
| Single-purpose, <20 actions | Direct keybinding (every key = action) |
| Multi-view, complex | Vim-style modes + contextual footer |
| IDE-like, many features | Command palette + tabs + vim motions |
| Data browser | Drill-down + fuzzy search + : command mode |
Design keybindings in four progressive layers:
| Layer | Keys | Audience | Always show? |
|---|---|---|---|
| L0: Universal | Arrow keys, Enter, Esc, q | Everyone | Yes (footer) |
| L1: Vim motions | hjkl, /, ?, :, gg, G | Intermediate | Yes (footer) |
| L2: Actions | Single mnemonics: d(elete), c(ommit), p(ush) | Regular users | On ? help |
| L3: Power | Composed commands, macros, custom bindings | Power users | Docs only |
Keybinding conventions (lingua franca):
j/k, move down/uph/l, move left/right (or collapse/expand)/, search?, help overlay:, command modeq, quit (or Esc to go back one level)Enter, select / confirm / drill inTab, switch focus between panelsSpace, toggle selectiong/G, jump to top/bottomNever bind: Ctrl+C (interrupt), Ctrl+Z (suspend), Ctrl+\ (quit signal). These belong to the terminal.
The universal pattern: press /, type query, results filter live.
n/N, next/previous matchEsc, dismiss search' prefix for exact match| Tier | Trigger | Content | Audience |
|---|---|---|---|
| Always visible | Footer bar | 3-5 essential shortcuts | Everyone |
| On demand | ? key | Full keybinding overlay for current context | Regular users |
| Documentation | --help, man page | Complete reference | Power users |
Footer format: [q]uit [/]search [?]help [Tab]focus [Enter]select
Context-sensitive footers update based on the active panel or mode. Show only what's actionable right now.
| Action Severity | Pattern |
|---|---|
| Reversible | Just do it, show brief confirmation in status bar |
| Moderate (delete file) | Inline "Press y to confirm" |
| Severe (drop database) | Modal dialog requiring resource name input |
| Irreversible batch | --dry-run flag + explicit confirmation |
Design for graceful degradation across all three tiers:
| Tier | Escape Sequence | Colors | Strategy |
|---|---|---|---|
| 16 ANSI | \033[31m | 16 (relative) | Foundation. Terminal theme controls appearance. |
| 256 Color | \033[38;5;{n}m | 256 (16 relative + 240 fixed) | Extended palette. Fixed colors may clash with themes. |
| True Color | \033[38;2;{r};{g};{b}m | 16.7M (absolute) | Full control. Requires COLORTERM=truecolor. |
Detection hierarchy:
$COLORTERM = truecolor or 24bit → true color$TERM contains 256color → 256 colors$NO_COLOR is set → disable all colorGolden rule: Your TUI must be usable in 16-color mode. True color enhances, it never creates the hierarchy.
Define colors by function, not appearance. Map semantics to actual colors through your theme:
| Slot | Purpose | Typical Dark Theme |
|---|---|---|
fg.default | Body text | Off-white (#c0caf5) |
fg.muted | Secondary text, metadata | Gray (#565f89) |
fg.emphasis | Headers, focused items | Bright white (#e0e0e0) |
bg.base | Primary background | Near-black (#1a1b26) |
bg.surface | Panel/widget backgrounds | Slightly lighter (#24283b) |
bg.overlay | Popup/dialog backgrounds | Lighter still (#414868) |
bg.selection | Selected item highlight | Distinct (#364a82) |
accent.primary | Interactive elements, focus | Brand color (#7aa2f7) |
accent.secondary | Supporting interactions | Complementary (#bb9af7) |
status.error | Errors, deletions | Red (#f7768e) |
status.warning | Warnings, caution | Yellow (#e0af68) |
status.success | Success, additions | Green (#9ece6a) |
status.info | Informational | Cyan (#7dcfff) |
Never hardcode hex values in widget code. Always reference semantic slots.
Color is one tool among several. Use them in combination:
| Technique | Effect | Use For |
|---|---|---|
| Bold (SGR 1) | Increases visual weight | Headers, labels, active items |
| Dim (SGR 2) | Decreases visual weight | Metadata, timestamps, secondary info |
| Italic (SGR 3) | Semantic distinction | Comments, types, annotations |
| Underline (SGR 4) | Links, actionable items | Clickable elements, URLs |
| Reverse (SGR 7) | Swaps fg/bg | Selection highlight (always works!) |
| Strikethrough (SGR 9) | Negation | Deleted items, deprecated features |
Hierarchy recipe: 80% of content in fg.default. Headers in bold + fg.emphasis. Metadata in dim + fg.muted. Status in their semantic colors. Accents for interactive elements only.
Create depth without borders by layering background lightness:
bg.base (darkest) → bg.surface → bg.overlay (lightest)
Each step ~5-8% lighter in dark themes. The eye perceives depth from the contrast gradient. This reduces the need for box-drawing borders while maintaining clear visual zones.
Follow the Base16 pattern: define 16 named color slots, map them semantically:
Ship a dark theme by default. Detect light/dark terminal via OSC escape query or terminal-light crate. Provide at least one light variant. Respect NO_COLOR.
| Element | Characters | Resolution | Use For |
|---|---|---|---|
| Full blocks | █▉▊▋▌▍▎▏ | 8 steps/cell | Progress bars, bar charts |
| Shade blocks | ░▒▓█ | 4 densities | Heatmaps, density plots |
| Braille | ⠁⠂⠃...⣿ (U+2800-U+28FF) | 2x4 dots/cell | High-res line graphs, scatter plots |
| Sparkline | ▁▂▃▄▅▆▇█ | 8 heights | Inline mini-charts |
| Widget | Pattern | Tips |
|---|---|---|
| Progress bar | [████████░░░░] 67% | Show percentage + ETA. Color gradient green→yellow→red by urgency. |
| Sparkline | ▁▂▃▅▇█▇▅▃▂ | Perfect for inline time-series in headers/status bars. |
| Gauge | CPU [██████████░░] 83% | Label + bar + value. Color by threshold. |
| Table | Sortable columns, zebra stripes | Align numbers right, text left. Truncate with …. |
| Tree | ├── , └── , │ guides | Indent 2-4 chars per level. Expand/collapse with Enter. |
| Diff | Green + lines, red - lines | Word-level highlighting within changed lines elevates quality. |
| Log | Colored level, timestamp, message | TRACE=dim, DEBUG=cyan, INFO=default, WARN=yellow, ERROR=red, FATAL=red+bold. |
| Context | Spinner | Interval |
|---|---|---|
| Default / modern | Braille dots ⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏ | 80ms |
| Minimal | Line -|/ | 130ms |
| Heavy processing | Blocks ▖▘▝▗ | 100ms |
| Fun / branded | Custom frames | 70-100ms |
Use spinners for indeterminate operations. Progress bars for determinate. Show spinners only after 200ms delay to avoid flash on fast operations.
Three layers, all required for smooth TUI rendering:
CSI ? 2026 h ... CSI ? 2026 l for atomic terminal renderwrite() syscall| Situation | Animation | Duration |
|---|---|---|
| View transition | Fade or slide | 100-200ms |
| Selection change | Instant highlight | 0ms (never animate) |
| Data loading | Spinner or skeleton | Until complete |
| Success feedback | Brief flash/checkmark | 1-2 seconds |
| Panel resize | Immediate reflow | 0ms |
| Chart data update | Smooth value transition | 200-500ms |
Rule: Animations must never delay user input. If the user presses a key during a transition, cancel it and respond immediately.
Keyboard-first, mouse-optional: Every feature accessible via keyboard. Mouse enhances but never replaces. Shift+click must bypass mouse capture for text selection.
Spatial consistency: Panels stay in fixed positions. Users build mental maps. Never rearrange without explicit user action. Tabs provide stable landmarks.
Progressive disclosure: Show 5 essential shortcuts in the footer. Full help behind ?. Complete reference in docs. The floor is accessible, the ceiling is unlimited.
Async everything: Never freeze the UI. File operations, network requests, scans all run in the background with progress indication. Cancel with Esc.
Semantic color: Color encodes meaning, not decoration. If you removed all color, the interface should still be usable through layout, typography, and symbols.
Contextual intelligence: Keybindings update per panel. Status bars reflect current state. Help shows what's actionable right now, not everything ever.
Design in layers: Start monochrome (usable?). Add 16 ANSI colors (readable?). Layer true color (beautiful?). Each tier must stand independently.
Validate your design against these ranked pitfalls (ordered by real-world complaint frequency):
| # | Anti-Pattern | Fix |
|---|---|---|
| 1 | Colors break on different terminals | Use 16 ANSI colors as foundation. Test 3+ emulators + light/dark themes. |
| 2 | Flickering / full redraws | Double buffer + synchronized output + batched writes. Overwrite, never clear. |
| 3 | Undiscoverable keybindings | Context-sensitive footer + ? help overlay + Which-Key-style hints. |
| 4 | Broken on Windows / WSL | Test on Windows Terminal. Avoid advanced Unicode beyond box-drawing. |
| 5 | Unicode rendering inconsistency | Stick to box-drawing + block elements. Restrict emoji to Unicode 9.0. |
| 6 | Terminal multiplexer incompatibility | Test inside tmux and zellij. Mouse capture must not break selection. |
| 7 | No accessibility support | Respect NO_COLOR, provide monochrome mode, never color-only meaning. |
| 8 | Blocking UI during operations | Show feedback within 100ms. Use async + spinners + progress bars. |
| 9 | Modal confusion | Always show current mode in status bar. Cursor shape changes per mode. |
| 10 | Over-decorated chrome | Borders and colors serve content, not ego. The content IS the interface. |
Before shipping, verify:
NO_COLOR environment variableShift+click)Ctrl+C / SIGINT (restores terminal state)For Unicode character reference tables and border style gallery, see visual-catalog.md. For real-world TUI app design analysis and inspiration, see app-patterns.md.
npx claudepluginhub hyperb1iss/hyperskills --plugin hyperskillsProvides CLI design patterns for arguments/flags/subcommands and TUI patterns for frameworks in Go/Python/JS/Rust, interactions, and colors in terminal apps.
Guides building terminal UIs with RatatuiRuby Ruby gem, including managed loops, widgets like paragraphs/tables/charts, event handling, full-screen/inline modes, and testing.
Builds Textual TUI apps: widgets, screen stacks, CSS layouts, events, actions, reactive attributes, Pilot testing, and background workers.