brainstorming
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or planning anything new, in software or out of it (a talk, a business, a renovation).
tui-engineeringBuild production-grade, phone-friendly terminal UIs (full-screen TUI dashboards) with zero terminal libraries — pure-core architecture, ANSI-safe layout math, line-diffed painting, SGR mouse + touch gestures, hit-testing, narrow-width responsive layouts, and a headless test harness. Distilled from the axfleet fleet-monitoring TUI. MUST trigger when the user…
Independent GitHub snapshot · Automated classification · Original documentation governs
Cross-platform Agent Skill — Claude Code · OpenAI Codex · OpenCode · OpenClaw 通用。
Build a full-screen terminal UI the way axfleet is built: no ncurses, no
blessed, no ink — the terminal layer is ~500 lines you own and can test.
Every rule in this skill states the failure it prevents; every mechanism has a
runnable reference implementation at
xingfanxia/axfleet-ui-public
(fixture-driven demo — bun install && bun run tui). The reference stack is
Bun + TypeScript; the architecture is stack-agnostic.
contracts/ typed data model — the single shape everything renders from
state.ts pure transitions: (state, event) → new state (never mutate)
render/ pure renderers: (state, cols, rows) → string[] (one per tab)
term.ts THE ONLY module touching stdin/stdout
api.ts data source behind fetch/stream fns returning {ok,data}|{ok,error}
index.ts impure event loop wiring term → state → render → paint
Everything except term.ts/index.ts is a pure function — that's what makes
layout, input decoding, and gestures unit-testable without a TTY. Transitions
return the same reference when nothing changed; the loop skips redraws on
identity. Detail: references/architecture.md.
contracts/ — the typed data model. Fixtures and renderers both
compile against it, so tsc proves demo data is shape-complete.ansi.ts + tests — visibleWidth / truncate / padEnd / wrapPlain.
All layout math flows through here. CJK/emoji = 2 cells. Never
String.length. → architecture.md §2term.ts — alt screen, raw mode, line-diffed paints, crash restore,
pure decodeEvents with split-chunk carry-over + escape timeout.
→ architecture.md §3, input.mdstate.ts + tests — tabs, selection, scroll, data application.render/frame.ts — chrome + first tab; add the layout-contract test
NOW (every tab × sizes: exactly rows lines, each ≤ cols). Future tabs
inherit the guarantee by joining the loop. → testing.mdrows lines, every line visibleWidth ≤ cols, at ALL
sizes (45×30 / 76×24 / 120×40 minimum) — soft-wrap corrupts diff paintsuncaughtException → term.exit())contracts/; day-spaced noise periods don't
divide a day evenly (aliasing)bun run verify)| Phone action | What the TUI receives (Moshi, measured 2026-07) |
|---|---|
| tap | SGR press + release |
| vertical pan | wheel-up/down burst |
| horizontal swipe | nothing by default — armed only by moshi-hook's live env read of $TMUX_PANE/$ZELLIJ/$HERDR_ENV (that precedence); on detection swipe sends the mux's prefix chord (Ctrl-B n/p). Two verified recipes: tmux conditional binding forwards the chord into a pane titled via OSC 2 (input.md §6.5 — the default-setup path), or bare-shell HERDR_ENV=1 impersonation + speak the chord (§6.6) |
| Mouse-Mode drag | press/drag/release forwarded (gesture recognizer applies) |
Consequences: tap-the-tab-label is primary phone navigation, never make swipe
the only path, map D-pad ←/→ to next/prev, keep single-key aliases
(n/p) for custom shortcut slots. Full table + gesture state machine:
references/input.md.
docs/tui-methodology.md)