| 1 | --- |
| 2 | name: ux-flows |
| 3 | description: Design how an app flows before drawing it. Covers onboarding and first run, empty states, settings, menus and context menus, command palettes, dialogs and confirmations, status and error surfaces, account and connect flows, navigation, and list and detail pages. Use this whenever you add or change a screen, page, menu item, setting, status indicator or any path a person takes through an app, even a single context-menu action or toggle. Also use it when deciding how a remake should behave, when a page feels clunky or a flow breaks down once you think it through, and before redesigning one. Pairs with ui-copy for the words. |
| 4 | --- |
| 5 | |
| 6 | # UX flows |
| 7 | |
| 8 | The examples come from Clover's apps: Snowbound (a OneNote 2010 remake), Clover |
| 9 | Chat (a chat multiplexer) and the snow globe dashboard (a home-server console). |
| 10 | The quotes are hers. Most flow corrections there came from two habits: |
| 11 | inventing something a known product had already solved, and showing people how |
| 12 | the system works instead of what they can do. |
| 13 | |
| 14 | Work in this order: |
| 15 | |
| 16 | 1. **Name the job.** Write down what the person is trying to do on this surface. |
| 17 | For a page, list its jobs. A page has to earn its place: "i dont fully |
| 18 | understand the use of the overview page. idk if theres more info that can go |
| 19 | here, or just delete it". |
| 20 | 2. **Find who already solved it.** Name the product and look at it (section 1). |
| 21 | 3. **Sketch two or three options** as ASCII, pick one, and list the others as a |
| 22 | taste call for the owner. |
| 23 | 4. **Apply the rules** in section 2. |
| 24 | 5. **Write the strings with `ui-copy`.** |
| 25 | |
| 26 | ## 1. Find who already solved it |
| 27 | |
| 28 | If the app is a remake, the original is the spec. Snowbound's standing rule for |
| 29 | product calls: "compare to what the actual onenote application is observed to |
| 30 | do. and then if that feels like a reasonable ux, it's matched for |
| 31 | compatibility." Answer these questions yourself before asking the owner: "you |
| 32 | can likely answer these questions with "what would onenote do" and "is this |
| 33 | documented behavior we can clone", and "what is the better long term, durable |
| 34 | solution"". |
| 35 | |
| 36 | Observe the behaviour; don't recall it. The owner's description points at the |
| 37 | behaviour, but the reference is the spec: "my descriptions of the keyboard |
| 38 | actions and box behaviors are tricky to describe in writing." `ui-craft` covers |
| 39 | how to observe and measure a reference app. |
| 40 | |
| 41 | For a new app, name the pattern other products converged on and copy it |
| 42 | literally. Clover named each of these, and they landed once copied: |
| 43 | |
| 44 | | Job | Copy | |
| 45 | | --- | --- | |
| 46 | | Mute a noisy chat | Discord: "Mute <Name> ›" with durations ("they solved this") | |
| 47 | | Pick an emoji or reaction | Discord and Signal: tabs, search, a category rail, one vertical grid | |
| 48 | | Pinned chats and unread state | iMessage: compact pins, an unread dot before the name, a peek bubble with a tail | |
| 49 | | Jump anywhere, run commands | VS Code: ⌘P for places, a `>` prefix for commands; Raycast-style actions on a result | |
| 50 | | See who else is here | Google Docs: avatars and caret flags | |
| 51 | | Choose where a file lives on iPhone | Files and Notes: "On My iPhone" as a folder, Open for elsewhere | |
| 52 | | A tool button with options | Office split buttons: remember the last value, one hover border around both halves | |
| 53 | | File manager keys | Finder: Enter renames, ⌘O opens | |
| 54 | |
| 55 | Parity is a floor, not a ceiling. Where the reference is worse, deviate, and |
| 56 | say you did. Snowbound continues a to-do list on Enter and zooms with ⌘+/−/0, |
| 57 | though OneNote 2010 does neither. |
| 58 | |
| 59 | The owner's other apps count as prior art. The snow globe dashboard took its |
| 60 | look from Clover's own Keycloak theme and her hexiflare components: "i |
| 61 | specifically tried to optimize for feeling "cozy", which is a real visual theme |
| 62 | i want to maintain". |
| 63 | |
| 64 | ## 2. Rules |
| 65 | |
| 66 | ### First run and empty states |
| 67 | |
| 68 | - **Derive first run from state**, such as zero accounts or no documents. After |
| 69 | eight research agents, Clover's verdict was "if no accounts connected the |
| 70 | onboarding is literally just to connect an account or server. genious". For |
| 71 | account, connect and permission flows, follow |
| 72 | `references/onboarding-checklist.md`. |
| 73 | - **Strip chrome that has nothing to act on.** With no notebook open, Snowbound |
| 74 | dropped its toolbar, sidebar, frame and explanatory line, and kept two centred |
| 75 | buttons. |
| 76 | - **Two actions must not look equal.** The default is filled and takes Return; |
| 77 | the other is bordered. |
| 78 | - **A search with no results offers what it implies:** `Create Page "query"`. |
| 79 | - **Every new entry point also goes on the empty state** ("its worth putting |
| 80 | that connect to server option as a button in the no notebooks menu"). |
| 81 | - **Never seed test fixtures into a real install.** |
| 82 | |
| 83 | ### Hide the machinery |
| 84 | |
| 85 | - **People see people, documents and outcomes**, not backends, hosts, paths, |
| 86 | hashes, job names or codenames. "i want to hide the underlying platforms in |
| 87 | most cases"; "scrub the "studio" name from all the ui copy". |
| 88 | - **Show machinery only where it tells two things apart, or on the error |
| 89 | path.** A network mark appears only for a contact you can reach on two or |
| 90 | more networks. Otherwise "show a warning icon, to case the error path instead |
| 91 | of extra info on the happy path". |
| 92 | - **Turn raw values into meaning.** "stuff like data should be a pill that |
| 93 | reports storage usage instead of a path. `app` showing a hash should be a |
| 94 | pill." |
| 95 | - **What is one thing to the user is one entry.** Three metrics services become |
| 96 | one list item with one icon. |
| 97 | - **Design for each role.** Hide internal tools from people who can't use them, |
| 98 | and give admins a "view as" so they can check. |
| 99 | |
| 100 | ### One way per job |
| 101 | |
| 102 | - **One flow per job, reachable from everywhere.** Clover Chat's linking |
| 103 | became "Link Contact -> search name -> create new if the result is not found |
| 104 | -> name prefilled from search". A second route to the same job is what Clover |
| 105 | calls slop: "link another account is slop". |
| 106 | - **One command table drives the toolbar, menus, menu bar, palette and |
| 107 | shortcuts.** Every context-menu action is also a palette command, and a test |
| 108 | enforces it. |
| 109 | - **A command has one title and one icon everywhere.** A dialog's title is the |
| 110 | name of the command that opened it. |
| 111 | - **One component per concept.** One file browser, one tab strip, one confirm |
| 112 | dialog: "the files viewer should probably be the exact same system as the |
| 113 | jellyfin viewer". |
| 114 | |
| 115 | ### Menus and actions |
| 116 | |
| 117 | - **Context menus hold only what applies to the thing clicked.** Creation comes |
| 118 | first. Destruction comes last, with its own icon. |
| 119 | - **Offer only actions that can be carried out.** No "Open in [platform]" on |
| 120 | every message, because it "isnt always satisfiable and it requires you have |
| 121 | the original app installed". |
| 122 | - **Disable an item that would do nothing**, rather than ending in an alert. |
| 123 | - **Menus use the full window height**, flipping or shifting before they |
| 124 | scroll. Submenus open on hover, after about 200 ms. |
| 125 | - **A submit that changes nothing closes silently.** Renaming to the same name |
| 126 | just closes the field. |
| 127 | - **Success feedback is transient, never a persistent bar** ("rename success |
| 128 | should show a toast not a persistent thing at bottom"). Whether a routine |
| 129 | action gets feedback at all is `ui-copy`'s call. |
| 130 | - **A destructive confirmation names the person's object, not its file**: |
| 131 | "Garden", not `Garden.one`. Its default button follows the platform, or the |
| 132 | owner's component library where there is one; Clover's web dashboard confirms |
| 133 | on Enter, as her hexiflare dialogs do. |
| 134 | - **Anything people act on gets its own page**: deploys, users, VMs. Avoid the |
| 135 | side drawer plus a wall of filter boxes ("user management feels clunky with |
| 136 | the right sidebar that shows up"). |
| 137 | - **Temporary or abnormal state goes on the landing page, with a direct |
| 138 | action.** Staging previews show on the dashboard overview, and right-click |
| 139 | destroys one. |
| 140 | |
| 141 | ### Settings |
| 142 | |
| 143 | - **Every setting has a visible effect.** "what does notebook color mean?" came |
| 144 | from a colour that was stored but shown nowhere. |
| 145 | - **One scrolling list with a section index and search** beats many near-empty |
| 146 | pages. A section appears only once it has rows. |
| 147 | - **Pick the control by the choice.** A checkbox is only for true on/off. |
| 148 | Exclusive choices get a segmented control ("not this checkbox flow"). Long |
| 149 | lists get a menu. |
| 150 | - **Leave out rows that can't apply** on this platform. |
| 151 | - **Ask scope at save time**, defaulting to the safest option ("This page"). |
| 152 | |
| 153 | ### Status, errors and liveness |
| 154 | |
| 155 | - **Never show a success glyph over a degraded state.** A checkmark cloud over a |
| 156 | fallback read to Clover as an error. |
| 157 | - **Errors live on the object** ("this belongs as an error state on the |
| 158 | message"). |
| 159 | - **Name the actual failure, in the person's terms**: server not found, sign-in |
| 160 | rejected, untrusted certificate. Never pass through raw OS strings, and never |
| 161 | write "Check your internet" ("\"Check your internet\" is not a great error |
| 162 | lol"). |
| 163 | - **Missing data shows as "not connected".** Never delete display code because |
| 164 | the data isn't wired yet: "restore things as not connected so that we dont |
| 165 | lose the code to display them". |
| 166 | - **Show a tab only when its data source is real**, and label partial data |
| 167 | honestly ("edge requests", not "traces"). |
| 168 | - **Live views say they're live.** A dead stream must never look live. |
| 169 | - **Never show the previous item's data under the next item's name.** |
| 170 | |
| 171 | ### Platform conventions in flows |
| 172 | |
| 173 | - **Use the platform's pickers, alerts and file dialogs**, falling back to the |
| 174 | app's own, never to third-party helper programs. |
| 175 | - **Sign-in and consent are full-screen routes** with explicit Allow, Decline |
| 176 | and Cancel, never a panel you can navigate away from. |
| 177 | - **iOS lists follow current iOS.** Search goes at the bottom, there is one add |
| 178 | button, and a bottom "+" appears only where creation has an obvious |
| 179 | destination ("new notebook at the bottom is slop"). |
| 180 | |
| 181 | ### Decisions that belong to the owner |
| 182 | |
| 183 | These belong to the owner: |
| 184 | |
| 185 | - names; |
| 186 | - public prose such as READMEs and landing pages. Clover: "when it's publicly |
| 187 | facing i want to ensure i put my best explaination forward so i will continue |
| 188 | to write that"; |
| 189 | - guides and onboarding voice ("i value the human<->human communication"); |
| 190 | - any flow they say they'll design themselves ("dont do that yet i want to |
| 191 | design that a bit more nicely"). |
| 192 | |
| 193 | Propose these; never ship them. Research recommendations lose to identity: |
| 194 | Clover kept the name "archive server" and kept Discord, both against the |
| 195 | research. |
| 196 | |
| 197 | ## 3. Research a novel flow |
| 198 | |
| 199 | When a flow is new or contested (onboarding, server-optional setup, naming), |
| 200 | research it before designing. Use `deep-research` if it's available. |
| 201 | |
| 202 | - **One agent per question.** Clover Chat's onboarding used eight: principles |
| 203 | evidence, teardowns of comparable products, server-optional patterns, naming, |
| 204 | connect flows and permissions, activation and upgrade prompts, platform |
| 205 | limits, and the repo's own constraints. |
| 206 | - **Each brief carries:** |
| 207 | - the objective and the shape of the deliverable; |
| 208 | - the owner's gripes, verbatim; |
| 209 | - the current screens; |
| 210 | - key questions that name real products; |
| 211 | - primary sources first (shipped string files, help centres); |
| 212 | - a version date for every teardown; |
| 213 | - findings kept separate from implications, with an evidence-strength tag on |
| 214 | every claim; |
| 215 | - one notes file; |
| 216 | - an instruction not to touch the prototype. |
| 217 | - **One synthesizer writes the report:** |
| 218 | - an ASCII flow; |
| 219 | - an old step → new home table; |
| 220 | - exact strings for every state, errors included; |
| 221 | - repo claims cited with file and line; |
| 222 | - the owner's decisions as options with consequences; |
| 223 | - an imperative checklist at the end. |
| 224 | - **Discard any statistic without a named dataset.** |
| 225 | |
| 226 | ## 4. Present the design |
| 227 | |
| 228 | Show: |
| 229 | |
| 230 | - the ASCII flow; |
| 231 | - what changes from today, as a table; |
| 232 | - the strings for every state; |
| 233 | - the decisions the owner makes, numbered, with options and consequences. |
| 234 | |
| 235 | Put the single costliest consequence on one line they can't miss. When the owner |
| 236 | asks about architecture, explain it with a before/after diagram. Clover's |
| 237 | "that's good. yes, i like it." came after one. |