@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,159 @@
|
|
|
1
|
+
# Layout — conditional decision material
|
|
2
|
+
|
|
3
|
+
Layout is a hypothesis about reading order, task order, and relationships. No single scan
|
|
4
|
+
pattern, hierarchy signal, grid unit, density, or breakpoint is universally correct. State
|
|
5
|
+
the condition, predict the effect, render real content, and revise from evidence.
|
|
6
|
+
|
|
7
|
+
## Start from the experience spine
|
|
8
|
+
|
|
9
|
+
Before choosing a visual arrangement, write the dependency chain: what the user must notice,
|
|
10
|
+
understand, compare, decide, and do. The DOM and keyboard order should follow that meaningful
|
|
11
|
+
sequence even when CSS creates a different spatial composition. W3C Focus Order and technique
|
|
12
|
+
C27 both make this source-order relationship an accessibility requirement, not a stylistic
|
|
13
|
+
preference.
|
|
14
|
+
|
|
15
|
+
Use hierarchy signals in combination. Size, weight, contrast, position, grouping, imagery,
|
|
16
|
+
and motion can all attract or suppress attention; their effect depends on surrounding mass,
|
|
17
|
+
content, language, viewport, and user intent. There is no authoritative universal ranking
|
|
18
|
+
among them. Predict the first three attention stops, then inspect fixed-viewport squint and
|
|
19
|
+
sharp renders.
|
|
20
|
+
|
|
21
|
+
## Gestalt as testable grouping hypotheses
|
|
22
|
+
|
|
23
|
+
- **Proximity:** closer items may be perceived as a unit. Keep an internal relationship
|
|
24
|
+
distinguishable from the gap to neighboring groups, then test at actual density.
|
|
25
|
+
- **Similarity:** shared treatment may imply shared function or category. Deliberately vary
|
|
26
|
+
treatment when the semantic role differs.
|
|
27
|
+
- **Closure:** space, background, edge alignment, or an incomplete contour may establish a
|
|
28
|
+
group without a border. Add containment only when the boundary is otherwise ambiguous.
|
|
29
|
+
- **Common fate:** elements moving together may be interpreted as related. Choreograph only
|
|
30
|
+
relationships the content supports.
|
|
31
|
+
|
|
32
|
+
These are predictions, not pixel prescriptions. A compact data table and an editorial story
|
|
33
|
+
can need very different gaps while preserving the same grouping logic.
|
|
34
|
+
|
|
35
|
+
## Scan behavior is conditional
|
|
36
|
+
|
|
37
|
+
NN/g's F-shaped pattern describes a recurring behavior on text-heavy web content, especially
|
|
38
|
+
when people scan rather than read every word. It is not a universal template and does not
|
|
39
|
+
prove that every key action belongs at a particular coordinate. Use it as a warning: weak
|
|
40
|
+
front-loading, uninformative headings, and long undifferentiated text make important content
|
|
41
|
+
easy to miss. Strengthen information scent and meaningful headings before forcing an
|
|
42
|
+
F-shaped composition.
|
|
43
|
+
|
|
44
|
+
Other tasks produce other paths: comparison can move across aligned rows, search can jump to
|
|
45
|
+
landmarks, and sparse storytelling can follow media or an explicit sequence. Do not claim a
|
|
46
|
+
"Z-pattern law" without task-specific evidence. Record the expected path and verify it with
|
|
47
|
+
content, hierarchy, focus order, and interaction evidence.
|
|
48
|
+
|
|
49
|
+
## Grid and alignment
|
|
50
|
+
|
|
51
|
+
A grid coordinates edges, columns, and intervals so relationships remain legible. Carbon's
|
|
52
|
+
2x Grid is one documented system that combines a 2x mini unit, 8px base unit, columns,
|
|
53
|
+
gutters, and margins; it is an example of a coherent system, not proof that every product
|
|
54
|
+
must use those values. Apple similarly frames layout through platform context, safe areas,
|
|
55
|
+
readability, and adaptation rather than a single web grid.
|
|
56
|
+
|
|
57
|
+
Choose a base interval that fits the existing system, platform, type metrics, target density,
|
|
58
|
+
and device-pixel behavior. Optical corrections, borders, glyph geometry, and compact control
|
|
59
|
+
anatomy can legitimately fall outside it. The useful rule is traceability: repeated values
|
|
60
|
+
belong to a scale; deviations name the visible problem they solve.
|
|
61
|
+
|
|
62
|
+
An alignment break earns its cost when it reinforces the experience spine or concept. If
|
|
63
|
+
several elements break different edges without a shared reason, the result usually weakens
|
|
64
|
+
relationships. Compare an aligned and a deliberately broken candidate rather than treating
|
|
65
|
+
either as inherently sophisticated.
|
|
66
|
+
|
|
67
|
+
## Density and visual mass
|
|
68
|
+
|
|
69
|
+
Density depends on frequency of use, expertise, task speed, content volume, screen size, and
|
|
70
|
+
error cost. High density can support scanning and comparison for expert, frequent workflows;
|
|
71
|
+
lower density can support comprehension, onboarding, reading, or infrequent decisions.
|
|
72
|
+
"More whitespace" and "more information" are not goals by themselves.
|
|
73
|
+
|
|
74
|
+
Map visual mass, not just element count. Large dark areas, saturated media, dense type,
|
|
75
|
+
borders, and repeated cards can outweigh their semantic importance. Predict which regions
|
|
76
|
+
dominate at desktop and mobile, render real copy/data, and correct accidental competition.
|
|
77
|
+
|
|
78
|
+
## Responsive recomposition
|
|
79
|
+
|
|
80
|
+
WCAG Reflow requires content to work without loss of information or functionality and
|
|
81
|
+
without two-dimensional scrolling at the specified narrow equivalent, except for content
|
|
82
|
+
that genuinely needs two dimensions. This is an outcome requirement, not a mandate for a
|
|
83
|
+
particular breakpoint set.
|
|
84
|
+
|
|
85
|
+
Add breakpoints where content, controls, relationships, or readable measures fail—not at a
|
|
86
|
+
fixed list of device labels. At each transition decide explicitly whether regions:
|
|
87
|
+
|
|
88
|
+
- stack while preserving dependency;
|
|
89
|
+
- change order while keeping DOM/focus order meaningful;
|
|
90
|
+
- collapse behind a disclosed control;
|
|
91
|
+
- become horizontally scrollable because two-dimensional context is essential;
|
|
92
|
+
- switch from simultaneous comparison to a staged flow.
|
|
93
|
+
|
|
94
|
+
Test widths between named targets as well as the targets themselves. Fixed viewport renders
|
|
95
|
+
show hierarchy and cropping; optional full-page renders show page continuity but cannot
|
|
96
|
+
replace viewport evidence.
|
|
97
|
+
|
|
98
|
+
## Cards and repeated modules
|
|
99
|
+
|
|
100
|
+
Cards are appropriate when each item is a portable unit with a meaningful boundary. They are
|
|
101
|
+
not a default composition. Repeated modules should expose the information users compare and
|
|
102
|
+
distinguish true priority without manufacturing a featured item. One containment signal may
|
|
103
|
+
be enough; borders, shadows, and tinted backgrounds used together can add noise, but dense or
|
|
104
|
+
low-contrast contexts may need more than one signal.
|
|
105
|
+
|
|
106
|
+
Ask whether section dependency would be clearer as a list, table, annotated narrative,
|
|
107
|
+
split view, or continuous document before choosing cards.
|
|
108
|
+
|
|
109
|
+
## Forms and task order
|
|
110
|
+
|
|
111
|
+
A single vertical flow often reduces ambiguous traversal, but compact, semantically coupled
|
|
112
|
+
fields can share a row when their relationship and responsive order stay clear. Labels,
|
|
113
|
+
instructions, errors, and controls must remain associated programmatically and visually.
|
|
114
|
+
Choose label placement from available width, translation length, scan burden, and error
|
|
115
|
+
recovery—not from a universal completion-time claim.
|
|
116
|
+
|
|
117
|
+
Build only reachable states. Empty, loading, error, success, disabled, and offline layouts
|
|
118
|
+
must preserve the primary task, explain what changed, and provide an applicable next action.
|
|
119
|
+
Do not invent states to make a checklist appear complete.
|
|
120
|
+
|
|
121
|
+
## Media and memorable moments
|
|
122
|
+
|
|
123
|
+
Assign media a job: establish domain, carry evidence, explain structure, demonstrate state,
|
|
124
|
+
or create a concept-bearing moment. Decorative media should not claim hierarchy needed by
|
|
125
|
+
the task. Distinctiveness can aid recall, but "exactly one memorable element" is not a law;
|
|
126
|
+
the number and intensity depend on page length, narrative beats, and competing tasks.
|
|
127
|
+
|
|
128
|
+
## Composition recipes are hypotheses
|
|
129
|
+
|
|
130
|
+
The files under `core/composition/` are candidate mechanisms, not templates or defaults.
|
|
131
|
+
Their breakpoint values and token slots are demonstration values. A composer may cite a
|
|
132
|
+
recipe only after its condition gate matches the experience spine and must rewrite its
|
|
133
|
+
structure, values, and responsive transitions for the actual content. Candidate sketches
|
|
134
|
+
should compare meaningful axes rather than merely choosing different recipes.
|
|
135
|
+
|
|
136
|
+
## Decision record
|
|
137
|
+
|
|
138
|
+
For every consequential layout choice record:
|
|
139
|
+
|
|
140
|
+
1. condition and user task;
|
|
141
|
+
2. predicted attention/dependency effect;
|
|
142
|
+
3. chosen mechanism and rejected alternative;
|
|
143
|
+
4. desktop and mobile recomposition;
|
|
144
|
+
5. fixed-viewport evidence and resulting correction.
|
|
145
|
+
|
|
146
|
+
## Authoritative sources
|
|
147
|
+
|
|
148
|
+
- [NN/g — F-Shaped Pattern of Reading on the Web](https://www.nngroup.com/articles/f-shaped-pattern-reading-web-content/)
|
|
149
|
+
— conditional behavior for scanning text-heavy content, not a universal page template.
|
|
150
|
+
- [W3C — Understanding Reflow](https://www.w3.org/WAI/WCAG22/Understanding/reflow.html)
|
|
151
|
+
— responsive outcome and exceptions for genuinely two-dimensional content.
|
|
152
|
+
- [W3C — Understanding Focus Order](https://www.w3.org/WAI/WCAG22/Understanding/focus-order.html)
|
|
153
|
+
— meaningful sequential navigation.
|
|
154
|
+
- [W3C Technique C27](https://www.w3.org/WAI/WCAG22/Techniques/css/C27)
|
|
155
|
+
— matching DOM order to visual order.
|
|
156
|
+
- [Carbon Design System — 2x Grid](https://carbondesignsystem.com/guidelines/2x-grid/)
|
|
157
|
+
— one documented grid system and its parts.
|
|
158
|
+
- [Apple Human Interface Guidelines — Layout](https://developer.apple.com/design/human-interface-guidelines/layout)
|
|
159
|
+
— platform-aware layout and adaptation guidance.
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
# Motion — decision material
|
|
2
|
+
|
|
3
|
+
Motion in UI is not decoration. It is a communication channel — one that operates faster
|
|
4
|
+
than reading and carries information the visual state alone cannot. Used correctly, it
|
|
5
|
+
confirms what happened, shows what belongs together, and tells the eye where to look next.
|
|
6
|
+
Used incorrectly, it competes with the content for attention and loses.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Duration: what the research says
|
|
11
|
+
|
|
12
|
+
Nielsen's 1993 response time research establishes three thresholds that remain empirically
|
|
13
|
+
reliable across interface contexts:
|
|
14
|
+
|
|
15
|
+
**Under 100ms**: perceived as instantaneous. No transition is needed or helpful — adding
|
|
16
|
+
one makes a fast action feel slow, because the animation is the only delay. A hover state
|
|
17
|
+
change, a button press response, a tooltip appearing: if these resolve in under 100ms,
|
|
18
|
+
animating them costs more than it buys.
|
|
19
|
+
|
|
20
|
+
**100–300ms**: the transition zone. Perceptible, processable, not distracting. This is
|
|
21
|
+
where UI transitions belong — tab switches, modal entrances, panel slides, state changes
|
|
22
|
+
the user initiated and expects to see confirmed. Material Design's motion research places
|
|
23
|
+
navigation transitions at 200–300ms. Fast enough to feel responsive; long enough to read
|
|
24
|
+
as an intentional event, not a glitch.
|
|
25
|
+
|
|
26
|
+
**300–400ms**: the edge of interactive. Above this, the user has moved on cognitively
|
|
27
|
+
before the animation resolves. Transitions over 400ms feel broken unless they are
|
|
28
|
+
communicating a spatial relationship (a bottom sheet rising into position from below) or
|
|
29
|
+
the concept demands it (a luxury product whose register is unhurried).
|
|
30
|
+
|
|
31
|
+
**Above 400ms**: attention-consuming. Every millisecond above 400 spends attention budget
|
|
32
|
+
without certain return. Micro-interactions, hover effects, and state changes must never
|
|
33
|
+
exceed 400ms. Entrance animations for content on first load can reach 600ms if the page is
|
|
34
|
+
itself the delivery — a portfolio case study, a campaign page — but not if the page is a
|
|
35
|
+
tool the user came to use.
|
|
36
|
+
|
|
37
|
+
The single most common error is 500ms ease-in-out applied uniformly. This number is wrong
|
|
38
|
+
for three independent reasons: too slow for micro-interactions, too fast for meaningful
|
|
39
|
+
spatial motion, and the uniform easing removes any semantic distinction between different
|
|
40
|
+
kinds of change. Everything becomes the same sentence in the same tone of voice.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Easing: the semantics of the curve
|
|
45
|
+
|
|
46
|
+
The easing curve is not an aesthetic choice. It carries a specific meaning about what kind
|
|
47
|
+
of event just occurred. Using ease-in where ease-out belongs is not a stylistic difference
|
|
48
|
+
— it communicates the wrong thing.
|
|
49
|
+
|
|
50
|
+
**ease-out** (fast start, gradual deceleration): an object arriving. The quick onset reads
|
|
51
|
+
as responsive — something arrived immediately because the system responded to you. The
|
|
52
|
+
gradual end reads as the object finding its place, settling. Use for: elements entering
|
|
53
|
+
from outside the viewport, overlays appearing, content loading in, drawer panels opening.
|
|
54
|
+
This is the "responsive" easing curve: it tells the user that the system heard them
|
|
55
|
+
immediately.
|
|
56
|
+
|
|
57
|
+
**ease-in** (gradual start, fast finish): an object leaving. The slow start reads as
|
|
58
|
+
reluctance; the fast finish reads as completion. Use for: dismissals, removals, transitions
|
|
59
|
+
out of a context. Almost never correct for entrances — a slow start reads as latency, which
|
|
60
|
+
reads as a slow system, which reads as broken.
|
|
61
|
+
|
|
62
|
+
**ease-in-out** (gradual start, gradual finish): an object transitioning between two
|
|
63
|
+
significant states. The equal deceleration at both ends signals that the before state and
|
|
64
|
+
the after state both matter — this is a state transition, not an arrival or departure.
|
|
65
|
+
Use for: position changes, size changes, content crossfades where both the source and
|
|
66
|
+
destination are meaningful.
|
|
67
|
+
|
|
68
|
+
**linear**: no easing. Use for opacity changes on hover states only — eased opacity on a
|
|
69
|
+
hover feels sluggish in a way that is hard to name but immediate to feel. Also correct for
|
|
70
|
+
looping animations (a spinner, a progress bar) where acceleration and deceleration would
|
|
71
|
+
produce visible stuttering on each cycle.
|
|
72
|
+
|
|
73
|
+
A design system that uses a single easing curve for all motion has a vocabulary of one word.
|
|
74
|
+
It can make things move, but it cannot say anything different about different movements.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Choreography: the rules
|
|
79
|
+
|
|
80
|
+
**Entrance animations fire once.** On first load, and not again. If they replay on scroll,
|
|
81
|
+
the user eventually understands that scrolling triggers a performance, and they stop
|
|
82
|
+
scrolling slowly enough to watch it. The animation then delays their reading without
|
|
83
|
+
informing it. Scroll-triggered entrance is appropriate only when the interface is a
|
|
84
|
+
*presentation* — a long-scroll narrative, a portfolio case study — not when it is a
|
|
85
|
+
product the user came to use.
|
|
86
|
+
|
|
87
|
+
**Sibling stagger: 40–80ms offset.** When related elements enter together, staggering their
|
|
88
|
+
arrivals reads the group as a sequence — semantically correct when the elements have an
|
|
89
|
+
implied order. Below 40ms the stagger is imperceptible and the stagger code is wasted.
|
|
90
|
+
Above 80ms it becomes a waterfall: the user reads each element individually before the
|
|
91
|
+
next arrives, turning a group reveal into a slow-loading list.
|
|
92
|
+
|
|
93
|
+
**Hover feedback: under 150ms.** A hover state that takes more than 150ms to reach its
|
|
94
|
+
final state reads as slow. At 80–120ms with ease-out, the system reads as immediate and
|
|
95
|
+
precise. The user's pointer moved; the interface answered. Rauno Freiberg's web interface
|
|
96
|
+
guidelines (interfaces.rauno.me) specify that animation duration should not exceed 200ms
|
|
97
|
+
for interactions to feel immediate — 150ms for hover is the stricter constraint.
|
|
98
|
+
|
|
99
|
+
**Animate only `transform` and `opacity`.** Animating `width`, `height`, `top`, `left`,
|
|
100
|
+
or any property that triggers layout recalculation causes the browser to reflow and repaint
|
|
101
|
+
the document on every frame. The GPU cannot help. At 60 frames per second, this causes
|
|
102
|
+
visible jank on mid-range hardware. `transform: translate()` and `opacity` are composited
|
|
103
|
+
off the main thread — they animate at 60fps on all reasonable hardware without touching
|
|
104
|
+
layout. This is not a performance tradeoff to weigh against visual quality; it is a hard
|
|
105
|
+
rule with no exceptions.
|
|
106
|
+
|
|
107
|
+
**No scroll-jacking.** The user controls scroll. Intercepting scroll events to drive
|
|
108
|
+
animations or reposition content removes control from the user in a way they can feel but
|
|
109
|
+
not name — which is worse than a failure they can describe. NN/g ("Parallax Scrolling",
|
|
110
|
+
2013) measured it: usability scores drop, and users who notice report frustration without
|
|
111
|
+
being able to articulate what broke. The concept must be extraordinary to justify the cost.
|
|
112
|
+
|
|
113
|
+
**`prefers-reduced-motion` is not optional.** WCAG 2.1 criterion 2.3.3 (Level AAA) requires a
|
|
114
|
+
mechanism to disable non-essential animation. In practice: one media query wraps the
|
|
115
|
+
entire motion layer, and in its presence, all transitions reduce to instant opacity changes
|
|
116
|
+
or disappear entirely. Not because most users trigger it — because those who need it need
|
|
117
|
+
it completely. A motion system that does not honour it is broken for those users,
|
|
118
|
+
regardless of how thoughtfully it was built for everyone else.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## The motion budget: where to spend it
|
|
123
|
+
|
|
124
|
+
Every page has an attention budget. Motion spends it. The question is not "what should
|
|
125
|
+
move" — it is "what earns the most from being seen moving."
|
|
126
|
+
|
|
127
|
+
The answer is almost always: one thing per context. The first-load entrance of the primary
|
|
128
|
+
content. The hover state of the primary CTA. The transition between two major views. A page
|
|
129
|
+
where everything moves is a screensaver: the eye has no hierarchy to follow, so it follows
|
|
130
|
+
nothing in particular.
|
|
131
|
+
|
|
132
|
+
Material Design's motion research (2023): assign motion to the element that carries the
|
|
133
|
+
most meaning at the moment the animation fires. A form submission success animation is
|
|
134
|
+
wasted if the success state is not the most important thing happening at that moment. Make
|
|
135
|
+
the most important thing move; make everything else still. Still elements make moving
|
|
136
|
+
elements visible; a page where everything moves makes nothing visible.
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Parallax and scroll-linked animation: the restraint case
|
|
141
|
+
|
|
142
|
+
Scroll-linked parallax — backgrounds moving at a different rate than foreground content as
|
|
143
|
+
the user scrolls — became a signature technique of the early 2010s and has since produced
|
|
144
|
+
measurable usability damage.
|
|
145
|
+
|
|
146
|
+
NN/g's research ("What Parallax Lacks", nngroup.com) documents three specific problems:
|
|
147
|
+
users scroll quickly to scan for keywords of interest; parallax animations require slow
|
|
148
|
+
scrolling to be processed, and users who scroll at their normal speed miss the animated
|
|
149
|
+
content entirely. The animation becomes invisible to the audience it was designed for.
|
|
150
|
+
Second: banner blindness — users who have seen parallax repeatedly have learned to classify
|
|
151
|
+
it as decorative noise and ignore it. Third: for users with vestibular disorders, the
|
|
152
|
+
dissociation between their scroll movement and the movement on screen reliably triggers
|
|
153
|
+
discomfort or nausea. `prefers-reduced-motion: reduce` removes this for users who set it;
|
|
154
|
+
it does not help users who have not discovered the setting.
|
|
155
|
+
|
|
156
|
+
The performance case is equally clear. In 2024, real-world examples of parallax-heavy pages
|
|
157
|
+
showed Largest Contentful Paint (LCP) times exceeding 8 seconds and poor INP (Interaction
|
|
158
|
+
to Next Paint) scores — Core Web Vitals failures that affect search ranking as well as
|
|
159
|
+
user experience.
|
|
160
|
+
|
|
161
|
+
Condition → choice → reason: use scroll-linked animation only when the content is itself
|
|
162
|
+
a scroll-narrative (a case study, a product demo that teaches while scrolling) and the
|
|
163
|
+
concept explicitly requires it. For product UI, remove all parallax. The budget it consumes
|
|
164
|
+
returns nothing.
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Microinteractions: the Saffer framework
|
|
169
|
+
|
|
170
|
+
Dan Saffer's *Microinteractions: Designing with Details* (O'Reilly, 2013) defines the
|
|
171
|
+
four-component structure that governs every small moment in a UI:
|
|
172
|
+
|
|
173
|
+
**Trigger**: what initiates the microinteraction. Either a user action (clicking a button,
|
|
174
|
+
focusing an input, swiping) or a system condition (a value threshold crossed, a timer
|
|
175
|
+
expiring, a notification arriving). The trigger must be discoverable — hidden triggers are
|
|
176
|
+
interaction debt, not delight.
|
|
177
|
+
|
|
178
|
+
**Rules**: what happens after the trigger fires. The complete behaviour of the system in
|
|
179
|
+
response — what changes, in what order, by how much. Every edge case the rules don't
|
|
180
|
+
cover produces unexpected behaviour the user did not expect and the designer did not intend.
|
|
181
|
+
|
|
182
|
+
**Feedback**: the signal to the user that their action was received and the rule is
|
|
183
|
+
executing. Feedback can be visual (a checkbox check animates in), auditory (a success
|
|
184
|
+
tone), haptic (a vibration), or motion-based (a button compresses on press). Absent
|
|
185
|
+
feedback, the user cannot confirm their action was registered and will repeat it — the
|
|
186
|
+
mechanism behind double-submissions on slow forms.
|
|
187
|
+
|
|
188
|
+
**Loops and modes**: how long the microinteraction runs and whether it changes behaviour
|
|
189
|
+
on repetition. A "like" animation that runs once is a loop of one. A notification badge
|
|
190
|
+
that counts up is a loop that runs until cleared. A mode is a variant of the
|
|
191
|
+
microinteraction that activates under a different state (the muted mode of a volume
|
|
192
|
+
control).
|
|
193
|
+
|
|
194
|
+
The design implication: every interactive element should be audited against these four
|
|
195
|
+
components. If any component is missing or undefined, the interaction is incomplete. Missing
|
|
196
|
+
feedback is the most common defect — it produces the user experience of interacting with
|
|
197
|
+
a broken system.
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## Skeleton screens vs spinners: the performance perception research
|
|
202
|
+
|
|
203
|
+
Loading states are not equally effective at managing the perception of time. The choice
|
|
204
|
+
between a spinner and a skeleton screen changes what the user believes about the system's
|
|
205
|
+
responsiveness.
|
|
206
|
+
|
|
207
|
+
**Spinners** communicate system activity: "I am working." They provide no information
|
|
208
|
+
about what is coming, how much there is, or how long it will take. Under any uncertainty
|
|
209
|
+
about wait duration, spinners increase anxiety — the user cannot estimate, and estimation
|
|
210
|
+
is how humans manage waiting.
|
|
211
|
+
|
|
212
|
+
**Skeleton screens** communicate structural presence: "The layout is here; the content is
|
|
213
|
+
arriving." By showing the shape of the content before the content loads, the skeleton
|
|
214
|
+
gives the brain a structure to place the incoming data. Research comparing skeleton screens
|
|
215
|
+
to spinners and progress bars (NN/g, "Skeleton Screens vs. Progress Bars vs. Spinners",
|
|
216
|
+
2020) shows that skeleton screens are perceived as faster even at identical actual load
|
|
217
|
+
times, and studies show they can reduce abandonment by up to 30% by communicating that
|
|
218
|
+
progress is already happening.
|
|
219
|
+
|
|
220
|
+
Condition → choice → reason: use skeleton screens for page-level content loads where the
|
|
221
|
+
layout is predictable (a list of cards, a article page, a dashboard grid). Use spinners for
|
|
222
|
+
short indeterminate operations where the structural result cannot be previewed (file upload
|
|
223
|
+
progress, authentication, payment processing). Never use a skeleton where the actual
|
|
224
|
+
layout will be substantially different from the skeleton — a skeleton that does not match
|
|
225
|
+
what loads is more disorienting than a spinner that made no promises.
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## The FLIP technique: performance as a design constraint
|
|
230
|
+
|
|
231
|
+
FLIP (First, Last, Invert, Play) is a browser animation technique that enables smooth
|
|
232
|
+
transitions between arbitrary layout states by computing the difference between two static
|
|
233
|
+
positions and animating that difference as a `transform`, rather than animating the layout
|
|
234
|
+
property directly.
|
|
235
|
+
|
|
236
|
+
The technique: record the element's position before the change (First). Apply the change
|
|
237
|
+
and record the new position (Last). Apply a `transform` that moves the element back to its
|
|
238
|
+
First position instantly (Invert). Animate the transform to zero (Play — which visually
|
|
239
|
+
moves the element from its old to its new position while only touching `transform`).
|
|
240
|
+
|
|
241
|
+
The design consequence: FLIP enables animations that would otherwise require animating
|
|
242
|
+
layout properties — a card expanding to fill the screen, an item reordering in a list, a
|
|
243
|
+
grid reconfiguring. Without FLIP, these are either unanimated (abrupt, disorienting) or
|
|
244
|
+
animated with layout-touching properties (jank, dropped frames). FLIP makes them smooth
|
|
245
|
+
at 60fps.
|
|
246
|
+
|
|
247
|
+
The constraint: FLIP only works when the start and end states are both valid layout states.
|
|
248
|
+
A design that requires animating through an intermediate state that is not a valid layout
|
|
249
|
+
state cannot use FLIP. This is a genuine design constraint — some transitions need to be
|
|
250
|
+
re-designed so that their start and end states are both in CSS, not procedurally computed.
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## Motion cookbook
|
|
255
|
+
|
|
256
|
+
The implementation primitives that put this theory into practice — split-text entrance,
|
|
257
|
+
scroll-reveal, stagger orchestrator, sticky scene, section colour inversion, marquee,
|
|
258
|
+
magnetic hover, page loader, number counter, image hover distortion, view transitions,
|
|
259
|
+
and parallax — are in `core/motion/recipes/`. The easing token vocabulary (--ease-out-expo,
|
|
260
|
+
--ease-out-back, --ease-spring, and the full curated set) is in `core/motion/easing.md`.
|
|
261
|
+
Recipes reference the theory here; the hand wires the recipe parameters from the board's
|
|
262
|
+
motion studies.
|
|
263
|
+
|
|
264
|
+
## Sources
|
|
265
|
+
|
|
266
|
+
- Nielsen, "Response Times: The 3 Important Limits" (1993) — 0.1s / 1s / 10s thresholds
|
|
267
|
+
and their perceptual basis
|
|
268
|
+
- Material Design, Motion (2023) — duration guidelines, easing system, choreography rules,
|
|
269
|
+
budget allocation
|
|
270
|
+
- NN/g, "Parallax Scrolling" / "What Parallax Lacks" (2013, nngroup.com) — usability
|
|
271
|
+
evidence against scroll position–driven animation; banner blindness and goal-oriented
|
|
272
|
+
scanning
|
|
273
|
+
- WCAG 2.1, criterion 2.3.3 — Animation from Interactions; the accessibility baseline
|
|
274
|
+
- Saffer, *Microinteractions: Designing with Details* (O'Reilly, 2013) — trigger/rules/
|
|
275
|
+
feedback/loops framework for small interaction design
|
|
276
|
+
- NN/g, "Skeleton Screens vs. Progress Bars vs. Spinners" (2020) — perceived performance
|
|
277
|
+
comparison; skeleton screen abandonment reduction evidence
|
|
278
|
+
- Rauno Freiberg, Web Interface Guidelines (interfaces.rauno.me) — 200ms interaction
|
|
279
|
+
ceiling, animation proportional to trigger size
|
|
280
|
+
- Fast Company, "Why parallax scrolling needs to die" (2019) — performance and cognitive
|
|
281
|
+
load argument
|
|
282
|
+
- Gamache, "Parallax Done Right" (Medium, 2014) — performance constraints and the GPU
|
|
283
|
+
compositing argument for transform-only animation
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# Typography: prove the text that will ship
|
|
2
|
+
|
|
3
|
+
Typography starts with the reader, task, register, and actual copy. A font name or ratio is
|
|
4
|
+
not a decision until the target-language specimen shows what it does to meaning, hierarchy,
|
|
5
|
+
wrapping, loading, and fallback.
|
|
6
|
+
|
|
7
|
+
## Evidence order
|
|
8
|
+
|
|
9
|
+
Work in this order:
|
|
10
|
+
|
|
11
|
+
1. Read the target-language copy deck and identify productive and expressive roles.
|
|
12
|
+
2. Name the task and register: dense scanning, long reading, transactional UI, editorial
|
|
13
|
+
authority, playful showpiece, or another evidenced need.
|
|
14
|
+
3. Study cited typography references for visible anatomy and behavior, not brand prestige.
|
|
15
|
+
4. Build neutral specimens with the real headline, body, labels, CTA, numerals, punctuation,
|
|
16
|
+
dates, prices, identifiers, and the longest representative strings.
|
|
17
|
+
5. Render at 1280x900 and 390x844 after `document.fonts.ready`.
|
|
18
|
+
6. Record requested and computed browser evidence, then judge the visible result.
|
|
19
|
+
|
|
20
|
+
Do not start from a generic font-name default. A familiar family can still be wrong for the
|
|
21
|
+
copy, language coverage, voice, or production constraints.
|
|
22
|
+
|
|
23
|
+
## Role map
|
|
24
|
+
|
|
25
|
+
Separate two jobs:
|
|
26
|
+
|
|
27
|
+
- **Productive type** carries navigation, body, metadata, forms, tables, states, and repeated
|
|
28
|
+
actions. It needs calm differentiation, durable glyph coverage, and predictable density.
|
|
29
|
+
- **Expressive type** carries a concept-bearing display line or rare editorial moment. Its
|
|
30
|
+
face and weight must contribute meaning; size alone cannot supply the concept.
|
|
31
|
+
|
|
32
|
+
One family can cover both roles. Two families can be justified when their visible anatomy
|
|
33
|
+
creates a useful distinction. Start with one or two families and add another only when a
|
|
34
|
+
specimen proves the existing set cannot express a required role.
|
|
35
|
+
|
|
36
|
+
## Target-language and glyph coverage
|
|
37
|
+
|
|
38
|
+
List the scripts and symbols that the product actually uses. For a Korean product this often
|
|
39
|
+
includes Hangul syllables and jamo, Latin names and URLs, Arabic numerals, currency, dates,
|
|
40
|
+
punctuation, arrows, and product-specific symbols. Test the real strings.
|
|
41
|
+
|
|
42
|
+
Browser `document.fonts.check()` can show only that the browser considers a requested face
|
|
43
|
+
ready for a sample; it does not prove glyph coverage. FontFace status reports declared-face
|
|
44
|
+
loading state. Computed CSS can show the requested/computed family, size, weight, and line
|
|
45
|
+
height. None identifies the physical font that painted every glyph.
|
|
46
|
+
Visible tofu, style jumps, mismatched punctuation, or a fallback-shaped substring is a
|
|
47
|
+
failure even when the API reports loaded.
|
|
48
|
+
|
|
49
|
+
Hangul line breaking is a contextual author choice. W3C KLREQ describes both word-based and
|
|
50
|
+
character-based practices. Test the chosen `word-break` and wrapping policy with actual copy
|
|
51
|
+
at the intended container widths; do not enforce one policy for every Korean interface.
|
|
52
|
+
|
|
53
|
+
## Visible anatomy and voice
|
|
54
|
+
|
|
55
|
+
Compare what is visible in the specimen:
|
|
56
|
+
|
|
57
|
+
- Hangul square density, counters, terminals, stroke modulation, and punctuation alignment;
|
|
58
|
+
- Latin x-height, width, apertures, numeral shapes, and compatibility with Hangul color;
|
|
59
|
+
- the rhythm of mixed Korean, Latin, and numeral lines;
|
|
60
|
+
- whether the face sounds aligned with the recorded register rather than merely “modern.”
|
|
61
|
+
|
|
62
|
+
Reject an alternative by naming the visible condition and consequence. “Too generic” is not
|
|
63
|
+
enough; “the narrow Latin numerals create a second texture inside Korean prices” is evidence.
|
|
64
|
+
|
|
65
|
+
## Size, measure, and line height
|
|
66
|
+
|
|
67
|
+
Choose size from reading distance, role, actual copy, and container. Useful starting ranges
|
|
68
|
+
are hypotheses to render, not mandates: body text often begins around the mid-teens in CSS
|
|
69
|
+
pixels, compact UI may begin lower, and display roles may begin much larger. Adjust only from
|
|
70
|
+
specimen evidence.
|
|
71
|
+
|
|
72
|
+
Likewise, a body line height around 1.4–1.7 can be a starting test. KLREQ's 160% example is
|
|
73
|
+
an example, not a universal Korean requirement. Display lines often need tighter leading,
|
|
74
|
+
but the specimen must show that stacked glyphs, accents, and wrapping remain clear.
|
|
75
|
+
|
|
76
|
+
Record desktop and mobile container widths, line counts, deliberate breaks, accidental
|
|
77
|
+
orphans, clipping, and the relationship between primary, secondary, and CTA text. Never hide
|
|
78
|
+
a heading's overflow to make a failed proof look clean.
|
|
79
|
+
|
|
80
|
+
## Weight, axes, and optical size
|
|
81
|
+
|
|
82
|
+
Request only weights the source provides. Compare requested and computed weights and inspect
|
|
83
|
+
whether the visible face actually changes. A synthetic bold or faux italic fails when it
|
|
84
|
+
distorts the intended anatomy.
|
|
85
|
+
|
|
86
|
+
For variable fonts, record the file, supported axes, requested values, and relevant named
|
|
87
|
+
instances. Test intermediate weights rather than assuming the browser interpolates as
|
|
88
|
+
intended. Variable fonts can reduce requests in some deployments, but are not inherently
|
|
89
|
+
smaller than every static subset.
|
|
90
|
+
|
|
91
|
+
When the face provides an `opsz` axis, test `font-optical-sizing: auto` against an explicit
|
|
92
|
+
setting. MDN documents the mechanism; the actual specimen decides whether it helps this
|
|
93
|
+
face, copy, and size.
|
|
94
|
+
|
|
95
|
+
## Fallback, loading, CLS, and performance
|
|
96
|
+
|
|
97
|
+
Record source, licence, hosting choice, formats, unicode subsets, preload decision, and
|
|
98
|
+
`font-display` behavior. Build a fallback stack that covers the same scripts. Compare its
|
|
99
|
+
metrics and wraps with the primary face; use metric overrides only with measured source data.
|
|
100
|
+
|
|
101
|
+
Test:
|
|
102
|
+
|
|
103
|
+
- first render and post-font render for layout shift;
|
|
104
|
+
- fallback and primary wraps at both proof viewports;
|
|
105
|
+
- unavailable, slow, and failed font states;
|
|
106
|
+
- whether critical text stays readable while loading;
|
|
107
|
+
- the network cost of the files and subsets actually shipped.
|
|
108
|
+
|
|
109
|
+
web.dev's font guidance is a starting reference for preload, subsetting, and layout shift.
|
|
110
|
+
Performance claims belong to measured project output, never a fixed file-size promise.
|
|
111
|
+
|
|
112
|
+
## Typography proof record
|
|
113
|
+
|
|
114
|
+
`.omd/type-proof.md` records:
|
|
115
|
+
|
|
116
|
+
- role map and target task/register;
|
|
117
|
+
- family source, licence, hosting, scripts, glyphs, weights, and axes;
|
|
118
|
+
- actual copy specimens;
|
|
119
|
+
- requested and computed family/weight evidence;
|
|
120
|
+
- desktop/mobile line, wrap, clip, orphan, and hierarchy observations;
|
|
121
|
+
- fallback/loading/CLS/performance plan;
|
|
122
|
+
- alternatives rejected with visible evidence;
|
|
123
|
+
- a fingerprint of copy, font family/files, weights/axes, and container widths.
|
|
124
|
+
|
|
125
|
+
Changing any fingerprint input invalidates the proof. After a structure is selected, repeat
|
|
126
|
+
the proof inside the real production container before the visual craft checkpoint.
|
|
127
|
+
|
|
128
|
+
## Sources
|
|
129
|
+
|
|
130
|
+
- W3C, *Requirements for Hangul Text Layout and Typography (KLREQ)*.
|
|
131
|
+
- web.dev, *Font best practices*.
|
|
132
|
+
- MDN, *CSS Font Loading API* and *font-optical-sizing*.
|
|
133
|
+
- U.S. Web Design System, typography guidance.
|
|
134
|
+
- Carbon Design System, productive and expressive type roles.
|