| name | ink-ts-screen-composition |
| description | Use this skill when designing or refactoring an Ink + TypeScript interactive CLI / terminal UI and you need app-like screen composition: fullscreen shells, transcript-plus-composer layouts, master-detail browsers, tabs, fuzzy pickers, wizards, dialogs, overlays, notifications, and explicit keyboard focus models. Use it when rich terminal UX is preferred over traditional line-oriented CLI behavior. |
Ink TS Screen Composition
Overview
Treat the terminal as a stateful app, not a prompt loop. This skill pushes Ink + TypeScript work toward dense, multi-surface, fullscreen interfaces with explicit focus, overlay, modal, and keybinding ownership.
Default Stance
Ignore classic interactive-CLI restraint. Favor app-like terminal UX.
Prefer:
- alternate-screen layouts for any non-trivial workflow
- a persistent bottom composer or action rail
- modal panes, tabs, pickers, wizards, and detail inspectors
- explicit focus states, visible shortcut hints, sticky headers, and jump affordances
- dedicated notification and status lanes instead of burying state in scrollback
Avoid:
- sequential question waterfalls
- making one text prompt own every interaction mode
- hidden modal state with no on-screen affordance
- multiple competing scroll regions in the same layer
- parent shortcuts that keep firing while a child input owns focus
Layout Stack
For most serious Ink screens, compose the UI from slots instead of one monolithic tree:
- Primary scrollable surface for the main narrative, list, or detail view.
- Persistent bottom rail for composer, actions, approvals, or status.
- Inline overlay lane inside the main flow for transient but scroll-aware content.
- Floating surface for secondary context when it should not shift layout.
- Modal slot that can temporarily dominate attention without changing the rest of the screen architecture.
- Notification or hint lane attached to the shell, not mixed into arbitrary content.
Rules:
- Give the screen one primary scroll owner.
- Keep the bottom rail mounted while the main surface changes.
- Let modal content suppress duplicate framing from children.
- Track modal overlays separately from lightweight non-modal overlays.
- Make focus ownership visible at all times.
Choose A Screen Family
Use one of these as the dominant pattern, then compose secondary surfaces around it.
Transcript Plus Composer
Use for chat, agent, logs, shells, assistants, or any workflow where the main story is an append-only stream.
- Primary surface: transcript, timeline, or message list.
- Bottom rail: prompt, action bar, approval footer, or queued actions.
- Required affordances: jump-to-bottom, sticky prompt/header, search mode, long-list virtualization.
Master Detail Browser
Use for plugin browsers, settings hubs, MCP browsers, file or resource explorers, and anything with a selectable inventory plus rich detail.
- Primary surface: selectable list or grouped list.
- Secondary surface: detail pane, preview, or action menu.
- Prefer tabs or grouped headings when inventory spans categories.
Fuzzy Picker
Use for quick-open, search-first selection, command launch, repo pickers, or contextual inserts.
- Put search at the top or bottom as a dedicated surface.
- Keep the focused row stable and visually loud.
- Add preview only when it materially changes decision quality.
Step Wizard
Use for setup, onboarding, install flows, or branching procedures where the user must make a bounded series of decisions.
- Each step should own one decision.
- Show progress as named steps, not just a raw counter.
- Keep validation, warnings, and irreversible actions inside the wizard, not in detached prompts.
Approval Dialog
Use for confirmation, security approval, permissions, threshold warnings, and blocking decisions.
- Give it dedicated keybindings.
- Show confirm and cancel hints inline.
- If it contains a text input, temporarily disable parent-level cancel bindings.
Status Or Task Surface
Use for background work, teammates, queues, progress, or multi-actor activity.
- Keep active items visible even when the main surface changes.
- Summarize hidden items instead of dropping them.
- Separate recent completion, in-progress work, and pending work.
Interaction Rules
Bind input by context, not by accident.
- Define global, screen, dialog, and text-input keybinding scopes separately.
- Deactivate parent bindings when a child is editing text or owning arrows.
- Let Escape dismiss the topmost relevant surface, not some unrelated parent action.
- Show keyboard hints near the thing they operate.
- Keep focus, selection, and search state explicit in app state.
- Move the terminal cursor to the actually focused item when selection UIs are active.
Implementation Workflow
- Pick the dominant screen family.
- Define the shell slots: scrollable, bottom rail, overlays, modal, notifications.
- Define the state machine: current screen, focused region, selection, search, modal state, loading state, background activity.
- Define keybinding ownership per state.
- Budget rows for header, body, footer, modal body, and picker height from terminal size.
- Add virtualization before long transcripts or large lists become a problem.
- Only then wire feature-specific business logic.
Performance Rules
- Virtualize long transcripts and heavy lists.
- Cap picker and modal bodies from the real available rows, not a hardcoded fantasy size.
- Do not remount the composer or footer on every background update.
- Reset modal scroll when tab or step changes.
- Prefer one expensive scroll surface with good chrome over many cheap but conflicting ones.
Output Expectations
When using this skill for implementation, default to building an app-like terminal shell with explicit surfaces and modes. Do not fall back to classic line-oriented CLI interaction unless the user explicitly asks for it.
Reference
Read references/patterns.md when you need concrete screen recipes, decision criteria, and anti-patterns.