@3xhaust/oh-my-design 0.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.ko.md +282 -0
- package/README.md +282 -0
- package/adapters/build.ts +184 -0
- package/adapters/claude.ts +111 -0
- package/adapters/codex.ts +68 -0
- package/adapters/tokens.ts +21 -0
- package/adapters/tool-map.json +7 -0
- package/bin/omd-install.ts +76 -0
- package/bin/omd.ts +1774 -0
- package/core/asset-sourcing/index.ts +187 -0
- package/core/coach/index.ts +98 -0
- package/core/composition/app-shell-workbench.md +168 -0
- package/core/composition/asymmetric-diagonal-grid.md +178 -0
- package/core/composition/bento-grid.md +223 -0
- package/core/composition/editorial-index-labels.md +173 -0
- package/core/composition/form-wizard-stepper.md +132 -0
- package/core/composition/master-detail-flow.md +129 -0
- package/core/composition/section-inversion.md +182 -0
- package/core/composition/sidebar-margin-annotation.md +184 -0
- package/core/composition/split-screen-hero.md +224 -0
- package/core/composition/sticky-sidebar-scroll.md +219 -0
- package/core/composition/typographic-hero.md +100 -0
- package/core/composition-contract/index.ts +233 -0
- package/core/composition-contract/visual-richness.ts +101 -0
- package/core/config/index.ts +27 -0
- package/core/copy/index.ts +296 -0
- package/core/craft/finish-pass.md +356 -0
- package/core/craft/index.ts +33 -0
- package/core/design/index.ts +581 -0
- package/core/design/interaction-states.ts +189 -0
- package/core/eval-harness/index.ts +225 -0
- package/core/evidence/final.ts +444 -0
- package/core/evidence/task.ts +459 -0
- package/core/figma/client.ts +312 -0
- package/core/figma/diff.ts +261 -0
- package/core/figma/responsive.ts +310 -0
- package/core/figma/system.ts +466 -0
- package/core/figma/types.ts +185 -0
- package/core/frame/check-ux.ts +180 -0
- package/core/frame/index.ts +39 -0
- package/core/frame/write.ts +168 -0
- package/core/graphics/css-illustration-primitives.md +189 -0
- package/core/graphics/duotone-image-presets.md +173 -0
- package/core/graphics/gradient-mesh.md +178 -0
- package/core/graphics/noise-grain-texture.md +150 -0
- package/core/graphics/placeholder-policy.md +185 -0
- package/core/graphics/svg-geometric-patterns.md +145 -0
- package/core/history/index.ts +39 -0
- package/core/install/detect.ts +32 -0
- package/core/install/install.ts +321 -0
- package/core/install/patch-claude.ts +109 -0
- package/core/install/patch-codex.ts +82 -0
- package/core/interaction/index.ts +101 -0
- package/core/interaction/recipes/signature-lighting.md +203 -0
- package/core/ir/dom.ts +352 -0
- package/core/ir/normalize.ts +177 -0
- package/core/motion/easing.md +151 -0
- package/core/motion/energy.ts +188 -0
- package/core/motion/recipes/image-hover-distortion.md +198 -0
- package/core/motion/recipes/magnetic-hover.md +229 -0
- package/core/motion/recipes/marquee.md +202 -0
- package/core/motion/recipes/number-counter.md +242 -0
- package/core/motion/recipes/page-loader.md +240 -0
- package/core/motion/recipes/parallax.md +233 -0
- package/core/motion/recipes/scroll-reveal.md +210 -0
- package/core/motion/recipes/section-color-inversion.md +217 -0
- package/core/motion/recipes/split-text-entrance.md +222 -0
- package/core/motion/recipes/stagger-orchestrator.md +227 -0
- package/core/motion/recipes/sticky-scene-transition.md +246 -0
- package/core/motion/recipes/view-transitions.md +239 -0
- package/core/probe/index.ts +186 -0
- package/core/probe/schema.json +46 -0
- package/core/protocol/composition-contract.md +192 -0
- package/core/protocol/copy-deck.md +96 -0
- package/core/protocol/human-design-loop.md +447 -0
- package/core/protocol/slop-review.md +71 -0
- package/core/ref/batch.ts +94 -0
- package/core/ref/blueprint.ts +199 -0
- package/core/ref/distance.ts +225 -0
- package/core/ref/invariants.ts +162 -0
- package/core/ref/signal.ts +37 -0
- package/core/ref/store.ts +122 -0
- package/core/render/index.ts +607 -0
- package/core/rules/attribution.ts +159 -0
- package/core/rules/builtin/contrast.yaml +8 -0
- package/core/rules/builtin/focus.yaml +8 -0
- package/core/rules/builtin/hit-area.yaml +8 -0
- package/core/rules/builtin/ko.yaml +6 -0
- package/core/rules/builtin/motion.yaml +80 -0
- package/core/rules/builtin/slop.yaml +365 -0
- package/core/rules/builtin/spacing.yaml +9 -0
- package/core/rules/builtin/system.yaml +42 -0
- package/core/rules/builtin/token.yaml +8 -0
- package/core/rules/builtin/ux.yaml +125 -0
- package/core/rules/engine.ts +88 -0
- package/core/rules/leakage.ts +72 -0
- package/core/rules/motion-spec.ts +204 -0
- package/core/site/index.ts +100 -0
- package/core/slop/index.ts +427 -0
- package/core/slop/text-slop.ts +220 -0
- package/core/source-seal/index.ts +174 -0
- package/core/stack/index.ts +53 -0
- package/core/target/index.ts +183 -0
- package/core/theory/color.md +285 -0
- package/core/theory/components.md +272 -0
- package/core/theory/craft.md +270 -0
- package/core/theory/expressive.md +213 -0
- package/core/theory/imagegen.md +105 -0
- package/core/theory/layout.md +159 -0
- package/core/theory/motion.md +283 -0
- package/core/theory/typography.md +134 -0
- package/core/theory/ux.md +580 -0
- package/core/theory/voice.md +595 -0
- package/core/types.ts +684 -0
- package/package.json +40 -0
- package/src/agents/composer.agent.yaml +174 -0
- package/src/agents/eye.agent.yaml +208 -0
- package/src/agents/framer.agent.yaml +52 -0
- package/src/agents/glance.agent.yaml +19 -0
- package/src/agents/hand.agent.yaml +200 -0
- package/src/agents/scout.agent.yaml +71 -0
- package/src/agents/sketch.agent.yaml +64 -0
- package/src/agents/typesetter.agent.yaml +52 -0
- package/src/agents/writer.agent.yaml +63 -0
- package/src/skills/omd-coach/SKILL.md +40 -0
- package/src/skills/omd-critique/SKILL.md +77 -0
- package/src/skills/omd-figma/SKILL.md +256 -0
- package/src/skills/omd-humanize/SKILL.md +160 -0
- package/src/skills/omd-scout/SKILL.md +77 -0
- package/src/skills/omd-ultradesign/SKILL.md +521 -0
|
@@ -0,0 +1,580 @@
|
|
|
1
|
+
# UX — decision material
|
|
2
|
+
|
|
3
|
+
Visual design is downstream of use. A page that looks extraordinary but leaves the user
|
|
4
|
+
unable to complete the task they arrived with has failed. The pipeline measures colour,
|
|
5
|
+
type, spacing, and motion; this file governs the layer underneath all of them — how the
|
|
6
|
+
thing works: what the user came to do, how they move through it, where errors land, and
|
|
7
|
+
what they remember when they leave.
|
|
8
|
+
|
|
9
|
+
The sources here are checkable. Every claim traces to a named paper, a published study,
|
|
10
|
+
or a documented design system constraint. "Research suggests" without a citation is not
|
|
11
|
+
evidence — it is a claim that the pipeline's own reasoning would reject anywhere else.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Task-first framing
|
|
16
|
+
|
|
17
|
+
The first question is not "what should this page look like." It is: what did the user
|
|
18
|
+
come here to do, and does everything on the screen serve that task or obstruct it?
|
|
19
|
+
|
|
20
|
+
Nielsen's first heuristic — Visibility of System Status — is often read as a rule about
|
|
21
|
+
loading spinners. It is actually a broader claim about the relationship between user
|
|
22
|
+
intent and interface response: the system must help the user understand where they are,
|
|
23
|
+
what has happened, and what can happen next. A user who cannot identify the primary action
|
|
24
|
+
within three seconds of arriving has been failed by the design before they began.
|
|
25
|
+
|
|
26
|
+
Condition → choice → reason: before choosing any visual direction, name the primary task
|
|
27
|
+
in one sentence. If the task cannot be named, the frame is not done. The single most
|
|
28
|
+
important action on any screen should be visually singular — one primary button per view,
|
|
29
|
+
as specified by Material Design and Carbon Design System not as a preference but as an
|
|
30
|
+
explicit structural constraint. Two filled buttons of equal visual weight cancel each other;
|
|
31
|
+
the user cannot determine which path the system wants them to take, which is equivalent to
|
|
32
|
+
offering no direction at all.
|
|
33
|
+
|
|
34
|
+
**Three brief questions anchor the frame:**
|
|
35
|
+
|
|
36
|
+
1. What task does the user arrive with? (Not what the product offers — what the user
|
|
37
|
+
came to accomplish.)
|
|
38
|
+
2. What is the most frequent action on this screen? (The primary action must be the most
|
|
39
|
+
visually reachable.)
|
|
40
|
+
3. What is the costliest error? (The design must make the recovery path from that error
|
|
41
|
+
visible, not the error prevention alone.)
|
|
42
|
+
|
|
43
|
+
These questions are not rhetorical. They produce concrete constraints. If the costliest
|
|
44
|
+
error is purchasing the wrong product, the design needs a clear change-of-mind path before
|
|
45
|
+
and after checkout — not just a confirm dialog. If the most frequent action is search, the
|
|
46
|
+
search field must reach the top of the page at every viewport, not hide behind a menu.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Surface types: a work surface is not a landing page
|
|
51
|
+
|
|
52
|
+
The fourth anchor question, answered at frame time and recorded as `uxSurface`: what kind
|
|
53
|
+
of surface is this? The taxonomy has four values, and the choice selects the composition
|
|
54
|
+
grammar for everything downstream.
|
|
55
|
+
|
|
56
|
+
- **marketing** — the surface persuades. A visitor arrives undecided; the page argues a
|
|
57
|
+
proposition with evidence and asks for one action. The scroll IS the experience: a
|
|
58
|
+
message ladder where each section answers the question the previous one raised.
|
|
59
|
+
- **product** — the surface serves a repeated task loop. The user arrives with work to do,
|
|
60
|
+
often for the hundredth time; the screen is a tool they operate, not an argument they
|
|
61
|
+
read. Dashboards, consoles, CRUD and admin screens, editors, settings, search results,
|
|
62
|
+
inboxes, checkout steps.
|
|
63
|
+
- **editorial** — the surface is read. Documentation, articles, long-form content. Reading
|
|
64
|
+
order, measure, and typographic rhythm dominate.
|
|
65
|
+
- **mixed** — a real product with a marketing shell (a landing page plus an app; a docs
|
|
66
|
+
site with a signup path). Name which screens belong to which grammar instead of applying
|
|
67
|
+
one grammar to all of them.
|
|
68
|
+
|
|
69
|
+
The misclassification failure is one-directional in practice: generated products default
|
|
70
|
+
to the marketing grammar everywhere, because most public web pages a model has seen are
|
|
71
|
+
marketing pages. The result is documented in every heuristic audit of AI-generated
|
|
72
|
+
"apps": a hero section above an admin table, decorative gradients on data screens, all
|
|
73
|
+
information atomized into equal-weight cards, a giant value proposition where the user
|
|
74
|
+
needed their queue. Nielsen's eighth heuristic (aesthetic and minimalist design) states
|
|
75
|
+
the standard: every element competes with the elements that serve the user's current
|
|
76
|
+
task. A hero on a work surface is not neutral decoration — it costs one full viewport of
|
|
77
|
+
queue visibility on every single visit.
|
|
78
|
+
|
|
79
|
+
**Product-surface grammar.** When `uxSurface` is `product`, these conditions replace the
|
|
80
|
+
marketing defaults:
|
|
81
|
+
|
|
82
|
+
1. **The dominant first-viewport anchor is the work object itself** — the table, queue,
|
|
83
|
+
canvas, form, or data view the task loop operates on. Real (or representative fixture)
|
|
84
|
+
data at realistic density is the hero. A value statement is at most one line of
|
|
85
|
+
orientation, never a display-scale headline.
|
|
86
|
+
2. **The spine is a task loop, not a message ladder**: orient (where am I, what changed)
|
|
87
|
+
→ locate (find the object: navigation, search, filters) → act (the frequent action,
|
|
88
|
+
reachable within the first viewport) → feedback (visible state change within 400ms,
|
|
89
|
+
see §Feedback) → next/recover (the loop restarts, or the costliest error is undone).
|
|
90
|
+
Sections are screen regions with jobs in this loop; their order follows task order,
|
|
91
|
+
not persuasion order.
|
|
92
|
+
3. **Density follows task frequency, not whitespace fashion** (see layout.md §Density):
|
|
93
|
+
an expert repeated-scan surface earns compact rows and visible volume; onboarding and
|
|
94
|
+
first-run earn air. Marketing whitespace on a queue screen hides the user's work.
|
|
95
|
+
4. **Navigation is the model of the product** (§Navigation below): persistent, labeled by
|
|
96
|
+
the user's nouns, marking where the user is. A marketing page can hide navigation
|
|
97
|
+
behind a CTA; a product cannot.
|
|
98
|
+
5. **Reachable states are part of the surface, not an appendix**: loading, empty (first
|
|
99
|
+
run AND filtered-to-zero are different states with different copy), error with
|
|
100
|
+
recovery, success confirmation, disabled-with-reason. The empty state is the first
|
|
101
|
+
thing a new user sees — design it as the front door (§First-run below).
|
|
102
|
+
6. **Chrome is quiet, data is loud.** Persuasive typography scale belongs to marketing;
|
|
103
|
+
on a work surface the type scale serves scanning (see components.md on tables and
|
|
104
|
+
forms), and one accent color marks the primary action, not the decoration.
|
|
105
|
+
|
|
106
|
+
**Editor/canvas surfaces** add: the canvas owns the viewport; panels collapse; tool state
|
|
107
|
+
is always visible. **Settings surfaces** add: grouped by user intent, one column, each
|
|
108
|
+
change confirmed or explicitly saved, destructive actions separated and guarded
|
|
109
|
+
(§Flows: dead ends). **Onboarding** add: pull-based, minimum viable configuration to first
|
|
110
|
+
value (§First-run), progress visible, every step escapable.
|
|
111
|
+
|
|
112
|
+
Condition → choice → reason: name `uxSurface` at frame time; if the brief mixes surfaces,
|
|
113
|
+
split screens by grammar and record the split. A composer or reviewer who receives
|
|
114
|
+
`product` and still reaches for a hero-plus-feature-cards structure is not making a taste
|
|
115
|
+
choice; it is a classification defect with a named cause.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Navigation and information architecture
|
|
120
|
+
|
|
121
|
+
Navigation communicates structure before the label is read. The hierarchy of a navigation
|
|
122
|
+
system — what appears at the top level, what is nested, what is hidden behind disclosure —
|
|
123
|
+
is an argument about what matters most to the user.
|
|
124
|
+
|
|
125
|
+
The misapplication of Miller's Law to navigation is documented in `components.md` and not
|
|
126
|
+
repeated here. The correct constraint is visual, not mnemonic: navigation items compete
|
|
127
|
+
with content for attention. The practical ceiling for top-level navigation is five to seven
|
|
128
|
+
items, limited not by working memory capacity but by the visual threshold below which
|
|
129
|
+
labels compress too much to scan reliably.
|
|
130
|
+
|
|
131
|
+
Jakob's Law (Jakob Nielsen, 2000) provides the underlying principle: users spend most of
|
|
132
|
+
their time on other websites. They arrive with a mental model built from everything they
|
|
133
|
+
have used before. A navigation system that places settings under "Preferences," a help
|
|
134
|
+
section under "Support," and account management under "Profile" matches the mental model
|
|
135
|
+
of existing products — it is not copying, it is honoring the model the user already has.
|
|
136
|
+
Breaking from convention requires a reason that benefits the user, not a reason that
|
|
137
|
+
benefits the brand's desire to feel unique.
|
|
138
|
+
|
|
139
|
+
Condition → choice → reason: when a navigation structure departs from the established
|
|
140
|
+
pattern for its domain (hamburger menus on mobile, tab bars for primary sections, top nav
|
|
141
|
+
for tools), record the reason. The departure costs the user's existing mental model; the
|
|
142
|
+
design must buy that cost with something the user actually gains.
|
|
143
|
+
|
|
144
|
+
**Flat versus deep hierarchies.** A flat IA — everything accessible within two clicks —
|
|
145
|
+
reduces cognitive load but increases breadth. A deep IA — organized into nested
|
|
146
|
+
categories — reduces breadth but demands correct first-click choices from the user. The
|
|
147
|
+
research on information architecture (Rosenfeld, Morville, and Arango, "Information
|
|
148
|
+
Architecture for the Web and Beyond," fourth edition) argues that structure should follow
|
|
149
|
+
mental model, not content volume. The right depth is the depth that matches how users
|
|
150
|
+
think about the domain, not how the team organized the database.
|
|
151
|
+
|
|
152
|
+
**Mobile navigation.** On narrow viewports, the primary action must remain reachable with
|
|
153
|
+
a thumb in the natural grip position — roughly the bottom third of the screen. Navigation
|
|
154
|
+
systems that push primary actions above the fold at 1280px viewport but behind a top menu
|
|
155
|
+
at 375px have not been designed for mobile; they have been designed for desktop and scaled
|
|
156
|
+
down. WCAG 2.1 added touch-target and orientation requirements; WCAG 2.2 added an explicit
|
|
157
|
+
minimum target size of 24×24 CSS pixels. These are floors, not aspirations — a 44×44px
|
|
158
|
+
touch target (Apple HIG, Material Design) is the established usable minimum.
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Flows: steps, defaults, and dead ends
|
|
163
|
+
|
|
164
|
+
A flow is a sequence of states with a defined entry and a defined end. The design of a
|
|
165
|
+
flow fails in three characteristic ways: it has too many steps, it has states with no exit,
|
|
166
|
+
or it defaults to the wrong choice.
|
|
167
|
+
|
|
168
|
+
**The step count problem.** Baymard Institute's large-scale checkout usability research
|
|
169
|
+
(baymard.com) documents that the average e-commerce checkout contains 23.48 form elements
|
|
170
|
+
and 14.88 form fields, while an optimized checkout can function with 7–8 form fields. The
|
|
171
|
+
result is that 18% of US online shoppers have abandoned an order specifically because the
|
|
172
|
+
checkout process was too long or complicated. The design constraint is not "as few steps
|
|
173
|
+
as possible" — it is "only the steps the user's task requires." A step that exists because
|
|
174
|
+
an engineer needed the data, not because the user needs to make a decision, is an obstacle
|
|
175
|
+
dressed as a form field.
|
|
176
|
+
|
|
177
|
+
**Defaults must be chosen for the frequent case.** Every input with a default value is an
|
|
178
|
+
argument about what most users will want. A country selector that defaults to the United
|
|
179
|
+
States on a Korean product is not a neutral choice — it is a wrong choice for most users.
|
|
180
|
+
Defaults should be set by observing what most users select when given no pre-selection,
|
|
181
|
+
then pre-selecting that. A form that forces every user to actively override a wrong default
|
|
182
|
+
has transferred its own design debt onto the user's attention.
|
|
183
|
+
|
|
184
|
+
**Dead ends are unforgivable.** Every state in a flow must have an exit. An error state
|
|
185
|
+
with no recovery path, a success screen with no next action, a form that submits
|
|
186
|
+
successfully but returns no confirmation, a modal with no close target: these are design
|
|
187
|
+
defects with the same severity as a broken link. Nielsen's third heuristic, User Control
|
|
188
|
+
and Freedom, is the formal statement: users need a clearly marked emergency exit to leave
|
|
189
|
+
unwanted states without going through a lengthy process. Undo and Redo support at the
|
|
190
|
+
system level; a Cancel or Back button at the screen level; a clearly labeled dismiss action
|
|
191
|
+
at the modal level — these are not polish, they are load-bearing elements of any flow.
|
|
192
|
+
|
|
193
|
+
**Every state needs a designed state.** A view that the user can reach must be designed —
|
|
194
|
+
not just the happy path, but every branch. Loading, empty, error, success, disabled,
|
|
195
|
+
and offline are each required in the design contract (`design.md`), not because a
|
|
196
|
+
checklist demands it, but because a user who hits an undesigned state experiences
|
|
197
|
+
something the designer never saw and therefore never fixed.
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## Forms: what this file adds
|
|
202
|
+
|
|
203
|
+
The core form guidance lives in `components.md` — validation timing (blur not keystroke),
|
|
204
|
+
the single-column layout research, and the Baymard inline-validation findings. This section
|
|
205
|
+
adds what is missing there: the multi-step versus single-page decision and error recovery.
|
|
206
|
+
|
|
207
|
+
**Multi-step versus single-page forms.** The decision is not aesthetic. A single-page form
|
|
208
|
+
shows the user the full cost upfront — every field visible, every requirement readable
|
|
209
|
+
before the first character is typed. This is appropriate when the form is short (under
|
|
210
|
+
eight fields) and the relationship between fields is visible. A multi-step form reveals
|
|
211
|
+
the cost progressively — each step introduces its own subset of fields, with a visible
|
|
212
|
+
progress indicator. This is appropriate when the total field count is high (8+), when
|
|
213
|
+
later fields depend on earlier answers, or when the user's mental load at any single step
|
|
214
|
+
would otherwise be too high to complete.
|
|
215
|
+
|
|
216
|
+
The Baymard research on checkout usability found that the median checkout flow at
|
|
217
|
+
5.1 steps performs better for abandonment than single-page long forms, specifically because
|
|
218
|
+
users can see their progress — a visible progress indicator reduces perceived effort even
|
|
219
|
+
when actual effort is identical. The measurement is not the number of clicks; it is
|
|
220
|
+
whether the user understands, at every step, how far they have come and how far remains.
|
|
221
|
+
|
|
222
|
+
**Error recovery, not error prevention alone.** Nielsen's fifth heuristic, Error
|
|
223
|
+
Prevention, is often implemented as disabling submit buttons until all fields are valid.
|
|
224
|
+
This prevents the error state but removes the user's ability to understand what is wrong:
|
|
225
|
+
they cannot submit the form to see all errors at once. The better implementation: allow
|
|
226
|
+
submission, then present all validation errors simultaneously, each with a specific message
|
|
227
|
+
and a clear path to correction. "Please fill in all required fields" is not an error
|
|
228
|
+
message; it is an announcement. "Email address is required — please enter the address you
|
|
229
|
+
would like the confirmation sent to" is an error message.
|
|
230
|
+
|
|
231
|
+
Nielsen's ninth heuristic, Help Users Recognize, Diagnose, and Recover from Errors,
|
|
232
|
+
specifies the standard in three parts: error messages must use plain language (no codes,
|
|
233
|
+
no jargon), they must identify the problem precisely, and they must suggest a constructive
|
|
234
|
+
solution. A red field border communicates that something is wrong; the message tells the
|
|
235
|
+
user what to do next. Both are required.
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## Feedback and system status
|
|
240
|
+
|
|
241
|
+
The Doherty Threshold (Doherty and Thadani, IBM Systems Journal, 1982) established that
|
|
242
|
+
computer and user productivity increases when response time falls below 400 milliseconds.
|
|
243
|
+
Below 400ms, the user remains in the flow of the task; above 400ms, attention drifts and
|
|
244
|
+
the cost of re-engaging accumulates. The threshold is not a performance target in the
|
|
245
|
+
infrastructure sense — it is a design target in the perception sense: any action the user
|
|
246
|
+
initiates must produce visible acknowledgment within 400 milliseconds.
|
|
247
|
+
|
|
248
|
+
The acknowledgment does not need to be the result. It needs to be evidence that the system
|
|
249
|
+
received the action and is working on it. A button that submits a form and produces no
|
|
250
|
+
visual change for 800 milliseconds has failed the Doherty Threshold; the user does not
|
|
251
|
+
know if the click registered, and the uncertainty produces re-clicks, double submissions,
|
|
252
|
+
and frustration. The fix is an intermediate feedback state — a loading indicator, a button
|
|
253
|
+
state change, an inline spinner — that fires within the first 200–300ms and persists until
|
|
254
|
+
the result arrives.
|
|
255
|
+
|
|
256
|
+
Condition → choice → reason: every interactive element must change state within 400ms of
|
|
257
|
+
activation. Button pressed states must be instantaneous (<100ms, perceived as instant per
|
|
258
|
+
Nielsen's 1993 response-time research). Loading states that persist beyond 400ms require
|
|
259
|
+
a visible progress indicator. Loading states beyond one second require either a skeleton
|
|
260
|
+
screen (when the structure is known) or an explicit progress mechanism. The `motion.md`
|
|
261
|
+
theory file covers skeleton versus spinner evidence.
|
|
262
|
+
|
|
263
|
+
**Optimistic UI.** When an action has a high likelihood of success and a low cost of
|
|
264
|
+
reversal, update the UI immediately and reverse it if the server response fails. A "liked"
|
|
265
|
+
button that fills immediately and reverts on error provides better feedback than one that
|
|
266
|
+
waits for the server. The trade: the design must also handle the failure case, showing
|
|
267
|
+
a clear error and restoring the prior state. Optimistic UI without a failure state is
|
|
268
|
+
a bet on infrastructure reliability that the design should not make silently.
|
|
269
|
+
|
|
270
|
+
**Skeletons, spinners, and shimmer.** Cross-reference `motion.md`. The research basis:
|
|
271
|
+
skeleton screens reduce perceived waiting time (Bill Chung, IBM Design, 2014 internal
|
|
272
|
+
research; later replicated in Nielsen Norman Group guidance) by giving the user something
|
|
273
|
+
structurally meaningful to look at. A spinner communicates waiting; a skeleton communicates
|
|
274
|
+
progress toward a specific layout. Use skeletons when the destination structure is known.
|
|
275
|
+
Use spinners when it is not. Never use a full-page loading spinner where a partial skeleton
|
|
276
|
+
is available.
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
## Cognitive load and progressive disclosure
|
|
281
|
+
|
|
282
|
+
Cognitive Load Theory (Sweller, 1988, "Cognitive load during problem solving: Effects on
|
|
283
|
+
learning," Cognition and Instruction) established that human working memory has a limited
|
|
284
|
+
capacity for simultaneously processing new information. In UI terms: every element on the
|
|
285
|
+
screen that requires interpretation draws from a finite pool. When the pool is empty, users
|
|
286
|
+
make errors, skip steps, or leave.
|
|
287
|
+
|
|
288
|
+
Hick's Law (Hick, 1952; Hyman, 1953) provides the measurable version for choice: decision
|
|
289
|
+
time increases logarithmically with the number of choices. The implication for UI is not
|
|
290
|
+
"never give users choices" — it is that each choice presented at the wrong moment, or
|
|
291
|
+
without sufficient context, adds cognitive cost the user may not pay. A dashboard that
|
|
292
|
+
shows forty actions on first load forces the user to evaluate forty options before they
|
|
293
|
+
can do anything; a dashboard that reveals the most common action first, then surfaces
|
|
294
|
+
advanced actions on demand, respects the cost of choice.
|
|
295
|
+
|
|
296
|
+
Progressive disclosure is the design technique that follows: reveal information and options
|
|
297
|
+
progressively, at the moment they are relevant, rather than all at once. The term was
|
|
298
|
+
popularized in UI design by Jakob Nielsen; the underlying mechanism derives from Sweller's
|
|
299
|
+
finding that reducing extraneous cognitive load frees working memory for the task at hand.
|
|
300
|
+
|
|
301
|
+
Condition → choice → reason: secondary actions, advanced settings, and destructive
|
|
302
|
+
operations should not be visible at the same level as the primary action. The visual
|
|
303
|
+
treatment communicates the hierarchy (see `components.md` for button hierarchy); the
|
|
304
|
+
information architecture communicates the depth. A settings panel that presents all
|
|
305
|
+
settings at once has made every setting equally important, which means none of them is.
|
|
306
|
+
|
|
307
|
+
**The cost of hiding versus showing.** Progressive disclosure has a failure mode: hiding
|
|
308
|
+
information the user needs right now increases time to task completion and error rates.
|
|
309
|
+
The decision is not always to hide — it is to order. The most needed information appears
|
|
310
|
+
first, in the most prominent position, at full visibility. Information that is needed only
|
|
311
|
+
sometimes appears second. Information that is rarely needed is accessible but not
|
|
312
|
+
prominent. The order is determined by the frequency of the task, not by the structure
|
|
313
|
+
of the database.
|
|
314
|
+
|
|
315
|
+
---
|
|
316
|
+
|
|
317
|
+
## First-run experience and empty states
|
|
318
|
+
|
|
319
|
+
The first time a user encounters a product is the moment the design most frequently
|
|
320
|
+
betrays them. A product that is genuinely useful in use but shows an empty container
|
|
321
|
+
on first run has lost the user at the door.
|
|
322
|
+
|
|
323
|
+
Empty states are not failure states — they are opportunity states. Nielsen Norman Group's
|
|
324
|
+
research on empty states (nngroup.com/articles/empty-state-interface-design) documents
|
|
325
|
+
that in-context guidance displayed when the user has started a task is more effective
|
|
326
|
+
than forced tutorials, because in-context help can be applied immediately and is retained
|
|
327
|
+
better. An empty list that says "No items found" has communicated nothing useful; an empty
|
|
328
|
+
list that says "Add your first item — it only takes a minute" with a visible action to do
|
|
329
|
+
so has used the empty state as a launch point.
|
|
330
|
+
|
|
331
|
+
The Carbon Design System's guidance on empty states formalizes three positive-framing
|
|
332
|
+
principles: state the situation in direct terms ("Start by adding data assets"), follow
|
|
333
|
+
with a specific action, and avoid negative framing ("You don't have any…" → "Add your
|
|
334
|
+
first…"). Negative framing communicates absence; positive framing communicates possibility.
|
|
335
|
+
|
|
336
|
+
**First-run onboarding.** The research distinction between forced tutorial and contextual
|
|
337
|
+
guidance applies at the flow level. Forced tutorials — full-screen walkthroughs that must
|
|
338
|
+
be completed before the user can use the product — consistently produce lower retention
|
|
339
|
+
than contextual guidance because they demand attention before the user has experienced the
|
|
340
|
+
product's value. The user is being taught before they have a reason to learn.
|
|
341
|
+
|
|
342
|
+
Condition → choice → reason: onboarding should be pull-based, not push-based. When the
|
|
343
|
+
product cannot be used without initial configuration, a first-run experience is justified;
|
|
344
|
+
its goal is to achieve the minimum viable configuration to reach the product's core value
|
|
345
|
+
in the shortest possible flow. When the product can be used immediately, defer tutorial
|
|
346
|
+
content until the user encounters a gap — an empty state, an error, a feature they have
|
|
347
|
+
not yet used. The moment of encounter is when the instruction is relevant and retained.
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
|
|
351
|
+
## The peak-end rule: shaping memory
|
|
352
|
+
|
|
353
|
+
How a user remembers an experience differs from how they experienced it moment to moment.
|
|
354
|
+
Kahneman, Fredrickson, Schreiber, and Redelmeier (1993, "When More Pain Is Preferred to
|
|
355
|
+
Less: Adding a Better End," Psychological Science) demonstrated in a cold-water experiment
|
|
356
|
+
that retrospective evaluations of aversive experiences correlate almost entirely with two
|
|
357
|
+
moments: the peak intensity and the final moment. Duration of the experience had nearly
|
|
358
|
+
zero effect on the retrospective rating.
|
|
359
|
+
|
|
360
|
+
The UI application: users' satisfaction with a flow is disproportionately determined by
|
|
361
|
+
the most emotionally significant moment (the peak) and the final moment (the end). A
|
|
362
|
+
checkout that is slightly tedious but ends with a genuine confirmation — "Your order is
|
|
363
|
+
confirmed, and it will arrive Thursday" — will be remembered more positively than a
|
|
364
|
+
checkout that is efficient but ends abruptly without acknowledgment.
|
|
365
|
+
|
|
366
|
+
Condition → choice → reason: design the end of every significant flow as a deliberate
|
|
367
|
+
moment, not an afterthought. A form submission that ends on the same page with no
|
|
368
|
+
visible change has failed the ending. A checkout that ends on a confirmation screen that
|
|
369
|
+
restates the user's decision and names the next step has turned an administrative
|
|
370
|
+
transaction into a moment the user will remember as smooth. The peak is harder to
|
|
371
|
+
engineer but equally important: identify the single highest-stakes interaction in the flow
|
|
372
|
+
and make it worthy of that status — not dramatic for its own sake, but clear, responsive,
|
|
373
|
+
and in control.
|
|
374
|
+
|
|
375
|
+
**Negative peaks compound.** A single humiliating error message, a timeout that loses all
|
|
376
|
+
form data, a confirmation dialog phrased in legalese — these become the peak that the user
|
|
377
|
+
remembers, because they are the most emotionally salient moment. Protecting against
|
|
378
|
+
negative peaks is not about eliminating error conditions; it is about ensuring that the
|
|
379
|
+
system's response to error is more helpful than the error itself was frustrating.
|
|
380
|
+
|
|
381
|
+
---
|
|
382
|
+
|
|
383
|
+
## Accessibility as a UX floor
|
|
384
|
+
|
|
385
|
+
The WCAG 2.1 POUR framework — Perceivable, Operable, Understandable, Robust — is a
|
|
386
|
+
taxonomy of UX requirements, not a separate accessibility checklist. The Operable
|
|
387
|
+
principle (Guideline 2.1) requires that all functionality be operable via keyboard, which
|
|
388
|
+
is also required for power users, for users in situations where a mouse is unavailable,
|
|
389
|
+
and for any context where the primary input is not a pointer. The Understandable principle
|
|
390
|
+
(Guideline 3) requires that information and operation be comprehensible — clear error
|
|
391
|
+
messages, predictable page behavior, and consistent navigation: these overlap exactly with
|
|
392
|
+
Nielsen heuristics 4, 8, and 9.
|
|
393
|
+
|
|
394
|
+
Treating accessibility requirements as distinct from UX requirements produces work that
|
|
395
|
+
satisfies both poorly. The touch target minimum (44×44px Apple HIG, 24×24px WCAG 2.2
|
|
396
|
+
AA Level) is not an accessibility accommodation — it is a usability requirement for anyone
|
|
397
|
+
using a touch screen at any level of dexterity. Focus ring visibility is not an
|
|
398
|
+
accessibility accommodation — it is required for anyone navigating by keyboard, which
|
|
399
|
+
includes power users in every domain.
|
|
400
|
+
|
|
401
|
+
Condition → choice → reason: accessibility requirements are UX requirements with formal
|
|
402
|
+
documentation. When a design decision would fail WCAG 2.2 AA, it would also fail a
|
|
403
|
+
usability review. Use WCAG criteria as test conditions against which to evaluate UX
|
|
404
|
+
decisions, not as a separate compliance checklist applied after the design is complete.
|
|
405
|
+
|
|
406
|
+
---
|
|
407
|
+
|
|
408
|
+
## Korean market specifics
|
|
409
|
+
|
|
410
|
+
The Korean mobile market is among the most mobile-first in the world; smartphone
|
|
411
|
+
penetration and usage time per day consistently exceed global averages. This has direct
|
|
412
|
+
UX implications: assumptions about hover interactions, large-viewport layouts, and
|
|
413
|
+
desktop-primary navigation patterns are wrong for the majority of Korean users.
|
|
414
|
+
|
|
415
|
+
Toss (Viva Republica) provides the most documented Korean fintech UX case study. The
|
|
416
|
+
product's founding insight was that the existing Korean banking UX required fourteen steps
|
|
417
|
+
to transfer money — certificate download, USB authentication, mandatory desktop browser.
|
|
418
|
+
Toss's 2015 MVP reduced this to a single swipe by treating the existing complexity not as
|
|
419
|
+
an unavoidable technical constraint (Tesler's Law: every system has irreducible complexity)
|
|
420
|
+
but as complexity that had been pushed to the user by systems that could carry it
|
|
421
|
+
themselves. Toss carried the complexity in the system and left the user with one decision:
|
|
422
|
+
amount and recipient.
|
|
423
|
+
|
|
424
|
+
Tesler's Law (Larry Tesler, Xerox PARC, ~1984) — also called the Law of Conservation of
|
|
425
|
+
Complexity — states that every application has an irreducible complexity, and the only
|
|
426
|
+
question is who holds it: the system or the user. A designer who simplifies the user's
|
|
427
|
+
interface by adding complexity to the engineer's task has made the right trade. A designer
|
|
428
|
+
who passes complexity to the user to save engineering time has made the wrong one.
|
|
429
|
+
|
|
430
|
+
Condition → choice → reason: when a flow feels complex, identify whether the complexity
|
|
431
|
+
is intrinsic (the task genuinely requires these decisions) or extrinsic (the system is
|
|
432
|
+
pushing its own implementation constraints onto the user). Intrinsic complexity can be
|
|
433
|
+
helped with progressive disclosure and better defaults. Extrinsic complexity should be
|
|
434
|
+
eliminated. The question is not "how do we make this multi-step form less annoying" but
|
|
435
|
+
"which of these steps exists for the user's benefit and which exists for the system's."
|
|
436
|
+
|
|
437
|
+
---
|
|
438
|
+
|
|
439
|
+
## Heuristic audit checklist
|
|
440
|
+
|
|
441
|
+
The following ten questions are drawn from Nielsen's ten usability heuristics (Nielsen
|
|
442
|
+
and Molich, 1990, refined Nielsen, 1994) and rendered as checkable conditions. Each is a
|
|
443
|
+
question, not a test — a design that fails one is not necessarily wrong, but the
|
|
444
|
+
failure must be a deliberate choice with a recorded reason.
|
|
445
|
+
|
|
446
|
+
1. **System status**: Does the user always know what state the system is in? Can they see,
|
|
447
|
+
within 400ms of any action, that the action was received?
|
|
448
|
+
|
|
449
|
+
2. **Real-world match**: Does the interface speak the user's language, using words and
|
|
450
|
+
concepts from their domain rather than the system's implementation? Does the order of
|
|
451
|
+
information match the order of the user's mental model?
|
|
452
|
+
|
|
453
|
+
3. **Exit paths**: Can the user undo any non-trivial action? Is there a visible exit from
|
|
454
|
+
every state — including error states, modals, multi-step flows, and loading states that
|
|
455
|
+
run longer than expected?
|
|
456
|
+
|
|
457
|
+
4. **Consistency**: Do the same words, icons, and behaviors mean the same thing throughout
|
|
458
|
+
the product? Does the product follow the conventions of the platform and domain?
|
|
459
|
+
|
|
460
|
+
5. **Error prevention**: Are the most common and costly errors made harder to commit —
|
|
461
|
+
through constraints, defaults, and confirmation dialogs for irreversible actions?
|
|
462
|
+
|
|
463
|
+
6. **Recognition over recall**: Can the user identify their next action without memorizing
|
|
464
|
+
it? Are relevant options visible at the point of need?
|
|
465
|
+
|
|
466
|
+
7. **Efficiency for experts**: Do frequent users have a faster path — keyboard shortcuts,
|
|
467
|
+
saved preferences, bulk actions — without burdening first-time users with that
|
|
468
|
+
complexity?
|
|
469
|
+
|
|
470
|
+
8. **Minimalist design**: Does every element on the screen serve the user's current task?
|
|
471
|
+
Is there any element whose absence would make the design clearer?
|
|
472
|
+
|
|
473
|
+
9. **Error recovery**: When errors occur, are the messages in plain language, specific
|
|
474
|
+
about what went wrong, and constructive about what to do next?
|
|
475
|
+
|
|
476
|
+
10. **Help when needed**: When the product requires documentation, is it available in
|
|
477
|
+
context at the moment the user needs it — not in a separate page they must find?
|
|
478
|
+
|
|
479
|
+
---
|
|
480
|
+
|
|
481
|
+
## Harness enforcement status
|
|
482
|
+
|
|
483
|
+
The following principles from this file have been converted into deterministic harness
|
|
484
|
+
checks that `omd check` runs on every build. Principles not listed here remain advisory
|
|
485
|
+
— they require human or eye-agent judgment and cannot be reliably measured from the IR.
|
|
486
|
+
|
|
487
|
+
**Enforced — fires a violation on measurable evidence:**
|
|
488
|
+
|
|
489
|
+
- §Task-first framing → `UX-TWO-PRIMARIES` (slop): two or more interactive buttons sharing
|
|
490
|
+
the same authored fill in one container cancel the hierarchy signal. Measurable from
|
|
491
|
+
node.fill.authored + node.computed.isInteractive + node.box.h + node.parent grouping.
|
|
492
|
+
|
|
493
|
+
- §Task-first framing → `UX-ACTION-BELOW-FOLD` (ux): the only interactive controls are
|
|
494
|
+
entirely below the fold at the capture viewport. Measurable from node.box.y vs
|
|
495
|
+
ir.meta.viewportHeight (recorded by dom.ts at capture time). Guard: silent when any
|
|
496
|
+
interactive element is within the first viewport, so long-scroll pages with a visible
|
|
497
|
+
nav do not fire.
|
|
498
|
+
|
|
499
|
+
- §Accessibility as a UX floor → `UX-NO-KEYBOARD-PATH` (ux): every interactive control has
|
|
500
|
+
tabindex="-1", making the page unreachable by keyboard. Measurable from node.focusable
|
|
501
|
+
(recorded by dom.ts from el.tabIndex per node). WCAG 2.1 §2.1.1.
|
|
502
|
+
|
|
503
|
+
- §Task-first framing + §Surface types (the four anchor questions) → `FRAME-UX-INCOMPLETE`
|
|
504
|
+
(ux): the frame artifact exists but does not record what task the user arrives with, the
|
|
505
|
+
most frequent action, the costliest error, or the surface classification. Measurable as
|
|
506
|
+
field presence in the frame's YAML frontmatter. Scope: artifact completeness only — the
|
|
507
|
+
harness cannot verify the build serves the named task or fits the named surface (that
|
|
508
|
+
requires the eye agent's task-first walk).
|
|
509
|
+
|
|
510
|
+
- §Forms: error recovery → `DESIGN-FORM-NO-ERROR` (system): the page has form inputs but
|
|
511
|
+
no visible error-state affordance. Measurable from node.name class patterns, node.text
|
|
512
|
+
error vocabulary, node.role === 'alert', and node.ariaInvalid. Strengthened to detect
|
|
513
|
+
ARIA-correct implementations (role=alert, aria-invalid) that do not use class-name
|
|
514
|
+
conventions.
|
|
515
|
+
|
|
516
|
+
**Still advisory — requires human or eye-agent judgment:**
|
|
517
|
+
|
|
518
|
+
- §Navigation and information architecture: whether a navigation structure matches the
|
|
519
|
+
user's mental model for the domain. Requires domain knowledge the IR does not contain.
|
|
520
|
+
|
|
521
|
+
- §Flows: dead ends: whether every reachable state has an exit. Requires simulating user
|
|
522
|
+
flows across states, not reading the resting DOM.
|
|
523
|
+
|
|
524
|
+
- §Flows: defaults chosen for the frequent case. Requires knowing the user population's
|
|
525
|
+
preferences, not the rendered page's current value.
|
|
526
|
+
|
|
527
|
+
- §Feedback and system status (Doherty Threshold, 400ms): whether every interactive
|
|
528
|
+
element changes state within 400ms. Requires timing measurements under interaction,
|
|
529
|
+
not a static IR snapshot.
|
|
530
|
+
|
|
531
|
+
- §Cognitive load and progressive disclosure: whether secondary actions are visually
|
|
532
|
+
subordinate to the primary action. Requires semantic understanding of the hierarchy
|
|
533
|
+
intent, not structural measurement alone.
|
|
534
|
+
|
|
535
|
+
- §First-run experience and empty states: whether empty states are designed. Requires
|
|
536
|
+
rendering the page in its empty data state, which the static IR cannot do.
|
|
537
|
+
|
|
538
|
+
- §The peak-end rule: whether the end of each flow is deliberately designed. Requires
|
|
539
|
+
task simulation and emotional salience evaluation, not structural measurement.
|
|
540
|
+
|
|
541
|
+
- §Korean market specifics: whether hover-first patterns are avoided on mobile. Partially
|
|
542
|
+
covered by WCAG touch-target rules (hit-area.yaml) but interaction-pattern analysis
|
|
543
|
+
requires the eye agent's task walk.
|
|
544
|
+
|
|
545
|
+
- Nielsen heuristics 2, 4, 7, 8, 10 (real-world match, consistency, efficiency, minimalism,
|
|
546
|
+
help): all require semantic content understanding that the IR does not provide.
|
|
547
|
+
|
|
548
|
+
---
|
|
549
|
+
|
|
550
|
+
## Official evidence map and layer ownership
|
|
551
|
+
|
|
552
|
+
- **W3C form notifications** — https://www.w3.org/WAI/tutorials/forms/notifications/ —
|
|
553
|
+
writer supplies specific error/success text; hand associates messages with fields and
|
|
554
|
+
exposes status changes; probes exercise primary and recovery paths.
|
|
555
|
+
- **GOV.UK error messages** — https://design-system.service.gov.uk/components/error-message/
|
|
556
|
+
— writer says what went wrong and how to fix it without blame; hand preserves input and
|
|
557
|
+
keeps the message adjacent to the field.
|
|
558
|
+
- **Carbon buttons** — https://carbondesignsystem.com/components/button/usage/ — hand keeps
|
|
559
|
+
one clear primary action and uses button hierarchy consistently; eye checks whether the
|
|
560
|
+
frequent action remains reachable on mobile.
|
|
561
|
+
- **Carbon empty states** — https://carbondesignsystem.com/patterns/empty-states-pattern/ —
|
|
562
|
+
writer supplies a cause and useful next action only when an empty state is reachable;
|
|
563
|
+
hand does not fabricate emptiness for static or navigation-only surfaces.
|
|
564
|
+
- **WCAG 2.2** — https://www.w3.org/TR/WCAG22/ — hand owns native semantics, keyboard/focus,
|
|
565
|
+
target size, status announcements, and reduced-motion implementation; probes provide
|
|
566
|
+
evidence for reachable paths; eye makes no interaction claim without those results.
|
|
567
|
+
- **web.dev INP** — https://web.dev/articles/inp — hand produces immediate visible feedback
|
|
568
|
+
and prevents delayed duplicate actions; performance measurement covers click, tap, and
|
|
569
|
+
keyboard interactions across the page lifecycle.
|
|
570
|
+
- **web.dev offline data** — https://web.dev/learn/pwa/offline-data — hand implements offline
|
|
571
|
+
storage/recovery only when the product actually supports an offline path; otherwise the
|
|
572
|
+
copy deck records offline as inapplicable with a reason.
|
|
573
|
+
|
|
574
|
+
The acceptance split is: frame names the primary task, frequent action, and costliest error;
|
|
575
|
+
writer supplies primary/recovery language; hand implements native behavior, visible feedback,
|
|
576
|
+
value preservation, duplicate-submit protection, reachable exits, and mobile reach; explicit
|
|
577
|
+
primary/recovery probes measure applicable paths; eye interprets only supplied evidence.
|
|
578
|
+
Static IR rules cannot safely decide task success, semantic recovery, emotional consequence,
|
|
579
|
+
or whether a state applies, so those remain prompt/probe/eval responsibilities rather than
|
|
580
|
+
broad regex gates.
|