okami.mom/albedo

git clone https://git.nkp.pet/okami.mom/albedo

dawnadd charm tui skillf7fcae1

main
8.2 KiB117 linesraw

Design and interaction

For a concrete build, use the compact picker. For a bug fix, use the focus and modal walkthrough.

These are design recommendations synthesized from the studied applications, not a mandatory Charm visual style. For observations and exact evidence, see the case studies.

Design the smallest complete loop

Start with the user outcome, not the component catalogue. For a server picker the loop might be: identify candidates, narrow the set, inspect health, connect. Every persistent screen element should support one of those steps or explain the current state.

An inline prompt should leave the surrounding shell comprehensible. A full-screen browser can spend more space on context and inspection because the user intends to stay. Do not use a full-screen dashboard for a yes/no question or hide a complex monitoring workflow inside a one-line prompt.

Gum's filter supports an inline/fixed-height presentation and a full-screen branch. Its command wrapper also separates interactive rendering from result production. The transferable idea is a scoped interaction that remains useful in a larger shell workflow. S06 S07

A useful design note before implementation is:

Task: choose a server and connect.
Primary flow: type to filter -> move cursor -> inspect health -> accept.
Cancel: exit without emitting a server ID.
Output: one stable server ID, not the displayed label.
Preserve: existing search semantics, indicators, counters, animation, and keys.
Small layout: hide secondary columns; retain identity, health, and accept/cancel.

This is an example of the note's content, not a requirement to add a new file to every repository.

Give the screen a reading order

A practical hierarchy is context first, work second, feedback third, controls last. Title and controls should be discoverable but not compete with the data.

An illustrative picker, not a prescribed theme:

  Connect                                      2 of 18
  Filter: prod_

  > prod-api-01       ready          23 ms
    prod-api-02       connecting     --

  enter connect   esc cancel   ? help

The second number describes matching or total candidates only if that relationship is clear. Missing latency is not 0 ms. A highlighted row is not automatically an accepted selection. While probing, allow the user to move or cancel; show pending work without pretending it has completed.

At a smaller width, simplify structure rather than scale all labels into fragments:

 Connect  2/18
 > prod-api-01
   ready · 23 ms

 enter connect · esc cancel

Do not let an automatic switch discard the query, move the cursor to a different ID, or clear multi-selection.

Make state readable without a legend

StateUseful presentationCommon failure
Initial loadWhat is loading and how to cancelA spinner with no object or action
RefreshExisting data plus refreshing/stale indicatorBlanking useful content every refresh
Truly empty datasetWhat is absent and how to create/import/retry“No results” with no context
No filter matchesQuery context and a clear-filter actionAn empty list that still accepts Enter
Recoverable failureOperation, concise reason, retry/backFull-screen fatal error for a transient issue
Destructive actionExact target and consequenceA generic “Are you sure?”
Completed actionStable confirmation or returned valueDisappearing feedback before it can be read

Avoid boolean combinations that can accidentally render “loading,” “failed,” and “success” together. Model lifecycle states clearly, while retaining separate flags only for genuinely independent concerns.

Progress bars need a meaningful denominator. Otherwise use an activity indicator and useful counts or elapsed time. An animation should stop when its operation stops. Do not animate the entire screen to prove that it is alive.

Focus is a spatial and behavioral promise

The focused control should be visually recognizable. The same visual emphasis should not mean focus in one place and danger in another. Multi-selection needs a separate mark from the cursor; keep marker widths stable so text does not jump between rows.

Define navigation per mode. An example policy is:

Normal: arrows or j/k move; / enters search; Enter accepts current item.
Search: printable text edits; arrows may navigate results if documented.
        Escape leaves search; a subsequent Escape cancels the picker.
Modal: only modal controls react; closing restores previous focus.

This is not a universal keymap. A type-to-filter picker may start in search and never need a separate normal mode. Preserve an existing convention rather than force a Vim-like mode onto it.

Glow explicitly protects an active filter from its ordinary q quit action. Gum disables normal-mode navigation bindings while search is focused. Both are evidence that keyboard shortcuts must respect editing context. S05 S06

Do not consume the same key both globally and locally. Enter that dismisses an error should not also open the first item. Escape that closes a dialog should not also quit the application. If Ctrl+C first cancels work instead of quitting, make that policy observable and test repeated presses.

Teach controls at the point of use

Show the few likely actions near the active task; put the complete reference behind a help action. Derive both from actual enabled bindings where feasible. Hide or explicitly disable controls that cannot work in the current state.

Soft Serve's help depends on the active page and whether filtering is occurring; it also measures its rendered footer for layout. Help is an active part of the interaction and geometry, not a fixed decorative string. S10

Use action verbs: “open,” “connect,” “retry,” “clear filter,” “cancel.” “Submit” may be appropriate for a form, but it often says less than the actual operation. Show the target or scope for a destructive action. Reserve a persistent status area when frequent updates would otherwise make content move.

Develop a theme from semantic roles

A small theme may define foreground, muted foreground, accent, border, focused row, selected mark, success, warning, and error. Derive component styles from these roles. Let a product's existing identity guide the actual colors.

Prefer the terminal's own background unless full-surface coloring serves a clear purpose. Check muted text on both light and dark backgrounds; “muted” must still be legible. Test a monochrome rendering: cursor marks, labels, and layout should preserve meaning after color disappears.

Borders consume cells and add noise. Use one around a coherent interaction, or a separator between independent regions, before boxing every field. Prefer padding inside a frame to margins that accidentally push content past it. Use bold or contrast for a few hierarchy levels, not every heading, badge, and value.

A mascot or accent animation can make a tool memorable. Keep it small, optional when appropriate, and separate from the user's input cursor. Do not remove an existing distinctive feature under the guise of code simplification; reduce implementation duplication rather than behavior.

Accessibility and terminal-native operation

Keep the whole workflow usable with a keyboard and without special fonts. Use text alternatives for icons, color, and changing animation. Avoid stealing conventional copy/paste combinations without a strong reason. Mouse support should add convenience, not become the only way to reach an action.

A no-color TUI can still be difficult for assistive software because it repeatedly redraws and repositions text. Huh provides WithAccessible(true), which changes interaction into ordinary prompts; that is a distinct capability from changing a palette. Offer a comparable plain or noninteractive path where the application needs one. S11

Treat confirmation, cancellation, and recovery as part of polish. A pretty interface that cannot be safely cancelled, piped, or read at a small size is not finished.

1# Design and interaction
2
3For a concrete build, use [the compact picker](../examples/WORKED-EXAMPLES.md#1-build-a-compact-picker). For a bug fix, use [the focus and modal walkthrough](../examples/WORKED-EXAMPLES.md#2-fix-search-keys-and-modal-fall-through).
4
5These are design recommendations synthesized from the studied applications, not a mandatory Charm visual style. For observations and exact evidence, see the [case studies](case-studies.md).
6
7## Design the smallest complete loop
8
9Start with the user outcome, not the component catalogue. For a server picker the loop might be: identify candidates, narrow the set, inspect health, connect. Every persistent screen element should support one of those steps or explain the current state.
10
11An inline prompt should leave the surrounding shell comprehensible. A full-screen browser can spend more space on context and inspection because the user intends to stay. Do not use a full-screen dashboard for a yes/no question or hide a complex monitoring workflow inside a one-line prompt.
12
13Gum's filter supports an inline/fixed-height presentation and a full-screen branch. Its command wrapper also separates interactive rendering from result production. The transferable idea is a scoped interaction that remains useful in a larger shell workflow. [S06](sources.md#s06) [S07](sources.md#s07)
14
15A useful design note before implementation is:
16
17```text
18Task: choose a server and connect.
19Primary flow: type to filter -> move cursor -> inspect health -> accept.
20Cancel: exit without emitting a server ID.
21Output: one stable server ID, not the displayed label.
22Preserve: existing search semantics, indicators, counters, animation, and keys.
23Small layout: hide secondary columns; retain identity, health, and accept/cancel.
24```
25
26This is an example of the note's content, not a requirement to add a new file to every repository.
27
28## Give the screen a reading order
29
30A practical hierarchy is context first, work second, feedback third, controls last. Title and controls should be discoverable but not compete with the data.
31
32An illustrative picker, not a prescribed theme:
33
34```text
35  Connect                                      2 of 18
36  Filter: prod_
37
38  > prod-api-01       ready          23 ms
39    prod-api-02       connecting     --
40
41  enter connect   esc cancel   ? help
42```
43
44The second number describes matching or total candidates only if that relationship is clear. Missing latency is not `0 ms`. A highlighted row is not automatically an accepted selection. While probing, allow the user to move or cancel; show pending work without pretending it has completed.
45
46At a smaller width, simplify structure rather than scale all labels into fragments:
47
48```text
49 Connect  2/18
50 > prod-api-01
51   ready · 23 ms
52
53 enter connect · esc cancel
54```
55
56Do not let an automatic switch discard the query, move the cursor to a different ID, or clear multi-selection.
57
58## Make state readable without a legend
59
60| State | Useful presentation | Common failure |
61| --- | --- | --- |
62| Initial load | What is loading and how to cancel | A spinner with no object or action |
63| Refresh | Existing data plus refreshing/stale indicator | Blanking useful content every refresh |
64| Truly empty dataset | What is absent and how to create/import/retry | “No results” with no context |
65| No filter matches | Query context and a clear-filter action | An empty list that still accepts Enter |
66| Recoverable failure | Operation, concise reason, retry/back | Full-screen fatal error for a transient issue |
67| Destructive action | Exact target and consequence | A generic “Are you sure?” |
68| Completed action | Stable confirmation or returned value | Disappearing feedback before it can be read |
69
70Avoid boolean combinations that can accidentally render “loading,” “failed,” and “success” together. Model lifecycle states clearly, while retaining separate flags only for genuinely independent concerns.
71
72Progress bars need a meaningful denominator. Otherwise use an activity indicator and useful counts or elapsed time. An animation should stop when its operation stops. Do not animate the entire screen to prove that it is alive.
73
74## Focus is a spatial and behavioral promise
75
76The focused control should be visually recognizable. The same visual emphasis should not mean focus in one place and danger in another. Multi-selection needs a separate mark from the cursor; keep marker widths stable so text does not jump between rows.
77
78Define navigation per mode. An example policy is:
79
80```text
81Normal: arrows or j/k move; / enters search; Enter accepts current item.
82Search: printable text edits; arrows may navigate results if documented.
83        Escape leaves search; a subsequent Escape cancels the picker.
84Modal: only modal controls react; closing restores previous focus.
85```
86
87This is not a universal keymap. A type-to-filter picker may start in search and never need a separate normal mode. Preserve an existing convention rather than force a Vim-like mode onto it.
88
89Glow explicitly protects an active filter from its ordinary `q` quit action. Gum disables normal-mode navigation bindings while search is focused. Both are evidence that keyboard shortcuts must respect editing context. [S05](sources.md#s05) [S06](sources.md#s06)
90
91Do not consume the same key both globally and locally. Enter that dismisses an error should not also open the first item. Escape that closes a dialog should not also quit the application. If Ctrl+C first cancels work instead of quitting, make that policy observable and test repeated presses.
92
93## Teach controls at the point of use
94
95Show the few likely actions near the active task; put the complete reference behind a help action. Derive both from actual enabled bindings where feasible. Hide or explicitly disable controls that cannot work in the current state.
96
97Soft Serve's help depends on the active page and whether filtering is occurring; it also measures its rendered footer for layout. Help is an active part of the interaction and geometry, not a fixed decorative string. [S10](sources.md#s10)
98
99Use action verbs: “open,” “connect,” “retry,” “clear filter,” “cancel.” “Submit” may be appropriate for a form, but it often says less than the actual operation. Show the target or scope for a destructive action. Reserve a persistent status area when frequent updates would otherwise make content move.
100
101## Develop a theme from semantic roles
102
103A small theme may define foreground, muted foreground, accent, border, focused row, selected mark, success, warning, and error. Derive component styles from these roles. Let a product's existing identity guide the actual colors.
104
105Prefer the terminal's own background unless full-surface coloring serves a clear purpose. Check muted text on both light and dark backgrounds; “muted” must still be legible. Test a monochrome rendering: cursor marks, labels, and layout should preserve meaning after color disappears.
106
107Borders consume cells and add noise. Use one around a coherent interaction, or a separator between independent regions, before boxing every field. Prefer padding inside a frame to margins that accidentally push content past it. Use bold or contrast for a few hierarchy levels, not every heading, badge, and value.
108
109A mascot or accent animation can make a tool memorable. Keep it small, optional when appropriate, and separate from the user's input cursor. Do not remove an existing distinctive feature under the guise of code simplification; reduce implementation duplication rather than behavior.
110
111## Accessibility and terminal-native operation
112
113Keep the whole workflow usable with a keyboard and without special fonts. Use text alternatives for icons, color, and changing animation. Avoid stealing conventional copy/paste combinations without a strong reason. Mouse support should add convenience, not become the only way to reach an action.
114
115A no-color TUI can still be difficult for assistive software because it repeatedly redraws and repositions text. Huh provides `WithAccessible(true)`, which changes interaction into ordinary prompts; that is a distinct capability from changing a palette. Offer a comparable plain or noninteractive path where the application needs one. [S11](sources.md#s11)
116
117Treat confirmation, cancellation, and recovery as part of polish. A pretty interface that cannot be safely cancelled, piped, or read at a small size is not finished.