Designing TUIs

Other

Design, replicate, or iterate terminal user interfaces from screenshots, descriptions, layout sketches, or existing .tui files. Generate framework code (BubbleTea/Ink/Textual) directly or via .tui Schema intermediate representation.

Install

openclaw skills install designing-tuis

Designing TUIs

Use this skill to turn conversation, screenshots, or existing .tui files into practical terminal UI designs and runnable framework code. Two routes are available depending on the use case.

Trigger for welcome screens, dashboards, wizards, CLI launch screens, tool panels, lazygit/k9s/btop-style layouts, pane descriptions, or terminal UI visuals even when the user does not say “TUI”.

Architecture: Dual-Route Design

Default route:  Screenshot/Description → 3-Phase Decomposition → Framework Code → Preview/Compare/Iterate
Advanced route: Screenshot/Description → 3-Phase Decomposition → .tui Schema → Schema→Code Converter → Framework Code

Default Route (Screenshot → Code)

Preferred for most tasks. TUI's simplicity (no Z-axis overlap, ~20 component types, strict orthogonal grid layout) means the intermediate schema layer has low marginal benefit. Direct code generation is faster with no precision loss.

Advanced Route (Screenshot → Schema → Code)

Use when:

  • Multi-framework output: one .tui Schema generates BubbleTea (Go) + Ink (JS) + Textual (Python) simultaneously
  • Design asset persistence: team needs versioned, editable TUI design files
  • Cross-role collaboration: designers produce .tui files, developers consume code
  • Batch generation: CI/CD generates multi-platform code from .tui source

Operating Modes

Identify the mode before acting:

  • Screenshot replication: apply the 3-phase decomposition protocol (see below) before generating code or schema.
  • Text-to-layout: restate the intended structure, primary interaction, and target terminal size, then apply 3-phase protocol.
  • Existing .tui edit: inspect the current tree and patch only the requested nodes.
  • Code export (default route): generate framework code directly after 3-phase decomposition and user approval.
  • Schema export (advanced route): generate .tui file, then convert to framework code using schema-to-code mapping.

3-Phase Decomposition Protocol

Both routes share Phases 1-2. Phase 3 diverges by route.

Phase 1 — Grounding

Goal: Identify top-level structural regions and establish the global skeleton.

  1. Scan screenshot boundaries — determine if a global border wraps the entire terminal
  2. Identify top-level partitions:
    • Horizontal separators → top/bottom regions (header / main / footer / status-bar)
    • Vertical separators → left/right regions (sidebar / main-content / detail-panel)
  3. Record for each region:
    • Border style (single / double / rounded / none / ASCII art)
    • Size proportion (as character row/col counts) — e.g., sidebar 30%, main 70%
    • Background color differences and separator line positions

Output: Top-level region list (typically 2-5 regions) with direction and proportion annotations.

Phase 2 — Planning

Goal: Recursively analyze each top-level region, build a hierarchical layout tree, and lock proportions.

  1. For each top-level region, determine internal layout direction (row / column / grid)
  2. Quantify child element proportions (see Proportion Mechanism below) — use percentages, not absolute column counts
  3. Determine if each child is a container or atomic component (refer to references/layout-inference-rules.md)
  4. Record spacing: padding / gap
  5. Annotate responsive constraints: min sizes for each proportional region, degradation strategy for narrow terminals

Output:

  • Hierarchical layout tree (indented outline format)
  • Responsive proportion annotations (e.g., "sidebar 30% min 20col / main fill min 40col")

Phase 3 — Generation (Route Divergence)

Default route (→ Code):

  • Generate target framework code (BubbleTea / Ink / Textual) directly
  • Map proportions to framework-native layout mechanisms (flex ratio / percentage width)
  • Must implement responsive behavior: listen to terminal resize, use proportions not hardcoded sizes, set min size fallbacks

Advanced route (→ Schema → Code):

  • Generate .tui file with { version: "1", meta, tree } structure
  • Use percentages + min constraints for responsive intent
  • Convert to framework code using references/schema-to-code-mapping.md

Proportion Mechanism

Extraction (Phase 2)

TUI proportions are precisely quantifiable via character counting (no sub-pixel ambiguity):

  • Horizontal: count columns per region
  • Vertical: count rows per region
  • Express as: fixed (N rows/cols), percentage (30%), or fill (remaining space)

Proportion Categories

TypeWhen to UseExample
FixedSemantically fixed areasstatus bar (1-2 rows), divider (1 col), title (1 row)
PercentageProportional areassidebar 30%, main 70%
FillTakes all remaining spacemain content area

Responsive Layout Rules

  • Prefer percentages and fill over hardcoded absolute column counts
  • Set minimum sizes for proportional areas (prevent content crushing)
  • Narrow terminal degradation: row layouts should degrade to column stacking when width < threshold

Framework Mapping

TypeBubbleTea (Go)Ink (React)Textual (Python)
Fixed Nlipgloss.Width(N)<Box width={N}>min-width: N
PercentageCompute from tea.WindowSizeMsg<Box width="30%">width: 30% / fr units
FilltotalWidth - fixedChildren<Box flexGrow={1}>width: 1fr
Min sizemax(calculated, minW)<Box minWidth={20}>min-width: 20

BubbleTea note: No native percentage/flex. Must store window dimensions in model, recalculate on tea.WindowSizeMsg.

Rendering Stability Requirements

TUI rendering is character-by-character overwrite. Improper handling causes ghosts (old frame characters lingering). Generated code must follow:

  • Full-screen redraw: each render outputs the complete frame (BubbleTea View() is naturally full-return; Ink React reconciler naturally full-diff; Textual compositor naturally full-compose)
  • Clear on resize: clear screen before redraw after resize to prevent border remnants from mismatched sizes
  • Alternate screen buffer: use alt screen (BubbleTea tea.WithAltScreen(), Ink default, Textual default) to avoid mixing with shell output
  • Hide cursor: hide cursor during render to prevent mid-position blinking
  • Character width consistency: avoid mixing half-width/full-width characters causing column misalignment; use runewidth (Go) / string-width (JS) / wcwidth (Python) for CJK text

Comparison and Iteration Protocol

When a rendered preview or original screenshot is available, perform structured comparison:

Comparison Dimensions (by fix priority)

PriorityDimensionCheckFix Cost
P0layout-errorLayout direction wrong, nesting level wrongHigh
P0proportion-errorComponent proportion deviates >10% from target, or layout breaks on resizeHigh
P0render-ghostRender ghosts, lingering characters, screen flickerHigh
P1component-mismatchComponent type misidentified (e.g., List should be Table)Medium
P2content-missingText content omitted, list items missingLow
P3style-driftColor, border style, bold attribute deviationLow
P4spacing-offPadding/gap inconsistencyLow

Iteration Rules

  • Fix P0 deviations first (layout + proportion) — they propagate downstream
  • Each iteration round fixes only one category of deviation — avoid cross-edits causing regressions
  • After fix, re-preview and re-compare until no P0-P1 deviations remain

Proportion Fix Protocol

  • Calculate actual rendered component proportions vs Phase 2 target proportions
  • Deviation > 10% → fix: adjust width/height values or flex ratios
  • Deviation ≤ 10% → acceptable (terminal character grid minimum unit constraint)

Responsive Validation

  • Validate layout at minimum two terminal sizes (e.g., 80×24 and 120×40)
  • Confirm proportions hold after resize, no content overflow/truncation
  • Confirm narrow terminal degradation strategy (e.g., sidebar collapse) works

Render Stability Validation

  • Rapid resize produces no ghosts (lingering characters/border fragments) or flicker
  • Scroll, tab switch, tree expand/collapse — screen is complete after interaction, no remnants
  • High-frequency updates (live logs, progress bars) produce no tearing

Accuracy Expectations

TUI's character grid nature makes it easier to reproduce precisely than Web UI — no element overlap, no component crossing, layout is naturally an orthogonal tree.

ComplexityTypical ExamplesExpected FidelityIterations
Simple2-3 panels, clear bordersHigh — usable on first generation0-1
MediumMulti-panel nesting, tab navigation, lists/tablesMedium-high — structure correct, proportions need tuning1-2
Complexlazygit/k9s/btop levelMedium — multiple iterations, layout and proportions first2-3

Known Difficulties

  • Dynamic/stateful content (blinking cursor, animations, live data)
  • Low-resolution screenshots causing border character blur
  • Highly customized Unicode box-drawing variants
  • Responsive degradation at extreme terminal sizes (screenshot reflects only one size)
  • Render ghosts: old frame characters lingering after resize/interaction (requires full-screen redraw + clear)

Reproduction Priority Order

  1. Layout structure (pane partitioning and nesting relationships)
  2. Component proportions (width/height ratios of each region)
  3. Component types (correct identification of List/Table/Tree etc.)
  4. Text content (labels, titles, data items)
  5. Colors and styles
  6. Precise spacing

Reference Loading

Load only what is needed:

  • Read references/components-cheatsheet.md before creating or editing components. It is the field/default/visual-signature source of truth.
  • Read references/layout-inference-rules.md during Phase 1-2 decomposition for layout direction, component identification, spacing, and proportion rules.
  • Read references/color-accessibility.md when choosing colors, designing status indicators, or any time color conveys meaning. Ensures WCAG compliance and color-blind safety.
  • Read references/schema-to-code-mapping.md when using the advanced route (Schema → Code conversion) or when generating multi-framework output.
  • Read references/known-quirks.md before debugging rendering problems or using edge-case layout behavior.
  • Read references/workflow-examples.md when the task resembles screenshot replication, multi-framework output, or iterative refinement.

This repository is documentation-only. Do not assume render or export tools ship with it.

Workflow

Default Route (→ Code)

  1. Align on intent
    • For screenshots: apply Phase 1 (Grounding), describe the layout, and wait for confirmation
    • For text prompts: confirm the panes, emphasis, interaction model, and target framework
  2. Decompose (Phase 2 — Planning)
    • Build hierarchical layout tree with proportions
    • Annotate responsive constraints
    • Confirm with user if ambiguous
  3. Generate code (Phase 3)
    • Produce framework code (BubbleTea / Ink / Textual) with responsive layout
    • Include rendering stability measures (alt screen, full redraw, cursor hide)
  4. Preview and compare
    • Render at target terminal size
    • Apply comparison protocol (P0 → P4 priority)
  5. Iterate surgically
    • Fix one deviation category per round
    • Preserve unrelated structure
    • Re-preview after each fix

Advanced Route (→ Schema → Code)

  1. Align on intent (same as default)
  2. Decompose (same as default)
  3. Draft the .tui
    • Save to designs/<name>.tui unless user specifies another path
    • Use { version: "1", meta, tree }
    • Prefer theme color names over hardcoded hex colors
    • Use percentage + min constraints for responsive intent
  4. Convert Schema → Code
    • Follow references/schema-to-code-mapping.md for target framework
    • Generate one or more framework outputs
  5. Preview and compare (same as default)
  6. Iterate (same as default)

Output Contract

When delivering a design update, include:

  • The file path(s) created or changed (code file and/or .tui file)
  • A brief layout summary with proportion annotations
  • Route used (default or advanced) and target framework(s)
  • Preview status, including any missing renderer/exporter blocker
  • Responsive behavior summary (how the layout adapts to different sizes)
  • Specific follow-up questions only when needed to continue

Guardrails

Stop and re-check before any of these:

  • Using "fill" on a non-main flex axis
  • Guessing whether a field belongs in props or layout
  • Using unavailable components: Popover, Tooltip, or TextArea
  • Generating code or .tui directly from a screenshot without confirming intent
  • Rewriting an entire existing design for a small requested edit
  • Hardcoding absolute column/row counts instead of percentages (except for semantically fixed areas)
  • Omitting tea.WithAltScreen() (BubbleTea) or equivalent alternate screen usage
  • Generating BubbleTea code without tea.WindowSizeMsg handling for responsive layout
  • Mixing half-width and full-width characters without width calculation library
  • Using color as the sole indicator of state (success/error/warning/selected) without symbol or text label (WCAG 1.4.1)
  • Using red-green color pairs as sole differentiator between states (color-blind unsafe)
  • Using dim text on dark backgrounds without verifying contrast ≥ 4.5:1 (WCAG 1.4.3)