skills/curated/tui-design/SKILL.md
This skill should be used when designing terminal user interfaces, creating TUI layouts, choosing TUI color schemes, implementing keyboard navigation, building terminal dashboards, or working with any TUI framework. Activates on mentions of TUI design, terminal UI, Ratatui layout, Ink components, Textual widgets, Bubbletea views, terminal color palette, keybinding design, panel layout, split panes, terminal dashboard, box-drawing characters, sparklines, progress bars, modal dialogs, focus management, or terminal accessibility.
npx skillsauth add pedronauck/skills tui-designInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
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.
development
Deep review of branch diffs, working trees, or GitHub PRs at any size. Use when the user asks for CodeRabbit-grade review, an incremental re-review after new pushes, publication of findings to a PR, a cross-LLM peer-review verdict round, or conformance review against spec artifacts. Don't use for applying fixes, reviewing specs or PRDs as documents, or quick single-file feedback.
tools
Orchestrate Claude and Codex worker TUIs from a controller agent through herdr panes and the herdr socket CLI. Use when delegating bounded tasks to herdr worker panes, running user-activated plan-first delegations (Claude Code plan mode, Codex Plan mode), waiting on native agent status (idle, working, blocked, done), or verifying worker reports. Workers launch as interactive TUIs via herdr agent start — never through headless runners (compozy exec, claude -p, codex exec). Not for cmux workspaces (see cmux-orchestration) and not for end-user herdr control.
tools
TanStack Query, Router, and Form patterns for React. Use when writing useQuery/queryOptions, mutations, caching, file-based routes, search params, loaders, or TanStack Form validation. Don't use for TanStack Start, TanStack DB/collections, Zustand client state, or non-TanStack routing.
development
Use when the user wants to design, redesign, shape, critique, audit, polish, clarify, distill, harden, optimize, adapt, animate, colorize, extract, or otherwise improve a frontend interface. Covers websites, landing pages, dashboards, product UI, app shells, components, forms, settings, onboarding, and empty states. Handles UX review, visual hierarchy, information architecture, cognitive load, accessibility, performance, responsive behavior, theming, anti-patterns, typography, fonts, spacing, layout, alignment, color, motion, micro-interactions, UX copy, error states, edge cases, i18n, and reusable design systems or tokens. Also use for bland designs that need to become bolder or more delightful, loud designs that should become quieter, live browser iteration on UI elements, or ambitious visual effects that should feel technically extraordinary. Not for backend-only or non-UI tasks.