trykeyline 0.1.0 → 0.1.2
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/.claude-plugin/marketplace.json +1 -1
- package/LICENSE +0 -16
- package/bin/keyline.mjs +2 -1
- package/package.json +1 -1
- package/plugins/keyline/.claude-plugin/plugin.json +1 -1
- package/plugins/keyline/plugin.json +22 -0
- package/plugins/keyline/skills/keyline/SKILL.md +22 -32
- package/plugins/keyline/skills/keyline/commands/audit.md +8 -3
- package/plugins/keyline/skills/keyline/commands/critique.md +3 -26
- package/plugins/keyline/skills/keyline/commands/init.md +5 -4
- package/plugins/keyline/skills/keyline/commands/polish.md +2 -2
- package/plugins/keyline/skills/keyline/commands/refine.md +6 -16
- package/plugins/keyline/skills/keyline/commands/sync.md +1 -3
- package/plugins/keyline/skills/keyline/commands/ux-laws.md +26 -0
- package/plugins/keyline/skills/keyline/domains/color/deriving-a-ramp.md +1 -1
- package/plugins/keyline/skills/keyline/domains/color/guide.md +10 -46
- package/plugins/keyline/skills/keyline/domains/color/status-and-exceptions.md +2 -2
- package/plugins/keyline/skills/keyline/domains/depth/elevation-recipes.md +2 -8
- package/plugins/keyline/skills/keyline/domains/depth/guide.md +12 -41
- package/plugins/keyline/skills/keyline/domains/layout/guide.md +31 -56
- package/plugins/keyline/skills/keyline/domains/layout/measure-and-rhythm.md +16 -16
- package/plugins/keyline/skills/keyline/domains/layout/radius-lines-and-layers.md +2 -2
- package/plugins/keyline/skills/keyline/domains/motion/guide.md +12 -47
- package/plugins/keyline/skills/keyline/domains/motion/patterns.md +1 -1
- package/plugins/keyline/skills/keyline/domains/motion/performance.md +1 -1
- package/plugins/keyline/skills/keyline/domains/patterns/guide.md +20 -62
- package/plugins/keyline/skills/keyline/domains/patterns/iteration.md +1 -9
- package/plugins/keyline/skills/keyline/domains/type/guide.md +13 -37
- package/plugins/keyline/skills/keyline/domains/type/ladders.md +1 -1
- package/plugins/keyline/skills/keyline/domains/type/type-audit.md +5 -8
- package/plugins/keyline/skills/keyline/glass/color/assets/color-tokens.css +34 -165
- package/plugins/keyline/skills/keyline/glass/color/assets/theme.ts +10 -70
- package/plugins/keyline/skills/keyline/glass/color/guide.md +3 -30
- package/plugins/keyline/skills/keyline/glass/color/intent-ramp.md +2 -34
- package/plugins/keyline/skills/keyline/glass/color/theming.md +5 -72
- package/plugins/keyline/skills/keyline/glass/depth/assets/GlassPanel.tsx +14 -121
- package/plugins/keyline/skills/keyline/glass/depth/assets/glass.css +29 -188
- package/plugins/keyline/skills/keyline/glass/depth/depth-cues.md +1 -16
- package/plugins/keyline/skills/keyline/glass/depth/guide.md +4 -73
- package/plugins/keyline/skills/keyline/glass/depth/performance-and-fallbacks.md +3 -11
- package/plugins/keyline/skills/keyline/glass/layout/adaptive-presentations.md +5 -91
- package/plugins/keyline/skills/keyline/glass/layout/assets/SectionNav.tsx +3 -6
- package/plugins/keyline/skills/keyline/glass/layout/assets/layout-tokens.css +11 -138
- package/plugins/keyline/skills/keyline/glass/layout/guide.md +10 -15
- package/plugins/keyline/skills/keyline/glass/layout/measure-and-rhythm.md +4 -6
- package/plugins/keyline/skills/keyline/glass/layout/radius-and-elevation.md +3 -2
- package/plugins/keyline/skills/keyline/glass/motion/assets/DropMenu.tsx +4 -6
- package/plugins/keyline/skills/keyline/glass/motion/assets/motion-presets.ts +10 -184
- package/plugins/keyline/skills/keyline/glass/motion/assets/motion-tokens.css +21 -105
- package/plugins/keyline/skills/keyline/glass/motion/easing-and-duration.md +2 -31
- package/plugins/keyline/skills/keyline/glass/motion/guide.md +10 -41
- package/plugins/keyline/skills/keyline/glass/motion/reduced-motion.md +1 -7
- package/plugins/keyline/skills/keyline/glass/motion/scroll-performance.md +3 -32
- package/plugins/keyline/skills/keyline/glass/motion/shared-element.md +1 -1
- package/plugins/keyline/skills/keyline/glass/motion/sound.md +10 -80
- package/plugins/keyline/skills/keyline/glass/type/assets/prose.tsx +8 -43
- package/plugins/keyline/skills/keyline/glass/type/assets/type-tokens.css +49 -86
- package/plugins/keyline/skills/keyline/glass/type/guide.md +5 -7
- package/plugins/keyline/skills/keyline/glass/type/long-form-prose.md +9 -74
- package/plugins/keyline/skills/keyline/glass/type/scale.md +2 -6
- package/plugins/keyline/skills/keyline/glass/type/weight-and-tracking.md +4 -20
- package/plugins/keyline/skills/keyline/scripts/check/css.mjs +5 -14
- package/plugins/keyline/skills/keyline/scripts/check/design.mjs +3 -1
- package/plugins/keyline/skills/keyline/scripts/check/files.mjs +70 -26
- package/plugins/keyline/skills/keyline/scripts/check/markup.mjs +3 -3
- package/plugins/keyline/skills/keyline/scripts/check/rules.mjs +9 -1
- package/plugins/keyline/skills/keyline/scripts/check.mjs +6 -3
- package/plugins/keyline/skills/keyline/scripts/contrast.mjs +2 -0
- package/plugins/keyline/skills/keyline/scripts/scan.mjs +29 -45
- package/plugins/keyline/skills/keyline/system/design-md.md +4 -4
- package/plugins/keyline/skills/keyline/system/guide.md +4 -8
- package/plugins/keyline/skills/keyline/system/presets.md +16 -16
- package/plugins/keyline/skills/keyline/system/roles.md +8 -8
|
@@ -6,12 +6,7 @@ The constraint also makes the few places motion *is* spent land hard, because no
|
|
|
6
6
|
|
|
7
7
|
## Before you start
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
- **No `DESIGN.md`:** run `/keyline init` for this domain only, do the task, then recommend the full setup.
|
|
12
|
-
- **A role you need has no row:** reuse a value already doing that job; otherwise add one in the project's naming style and record it in `DESIGN.md`.
|
|
13
|
-
- **The task would break a law or move a dial off its preset:** say so and ask; if the user confirms, record it with its reason under `## Decisions`.
|
|
14
|
-
- **Preset `glass`:** the values are in `DESIGN.md`; `glass/motion/guide.md` has the exact recipes behind them.
|
|
9
|
+
Reads `DESIGN.md` `## Motion`.
|
|
15
10
|
|
|
16
11
|
## Laws
|
|
17
12
|
|
|
@@ -21,7 +16,7 @@ Read `DESIGN.md` at the project root: `## Profile` for the preset and any areas
|
|
|
21
16
|
|
|
22
17
|
**Paused means still.** A loop reporting a live state — level bars on a recorder, a stroke travelling round a card while something works — stops or settles low when that state pauses; still moving, it claims the thing is still listening. Only a progress indicator loops through a wait, because waiting is its state. On hover or focus a live indicator morphs in place into the action that ends it — bars into a stop square — so the control's next move appears where the eye already is.
|
|
23
18
|
|
|
24
|
-
Hover travel answers nothing either: a card rising under the pointer claims it moved, or can be picked up
|
|
19
|
+
Hover travel answers nothing either: a card rising under the pointer claims it moved, or can be picked up. Hover is a wash; how far, if at all, a preset lets a hovered thing travel is a dial (`domains/motion/ladder-and-curves.md`).
|
|
25
20
|
|
|
26
21
|
→ Live indicators, pausing and the morph to their action: `domains/motion/patterns.md`
|
|
27
22
|
|
|
@@ -38,7 +33,7 @@ Hover travel answers nothing either: a card rising under the pointer claims it m
|
|
|
38
33
|
| `duration.overlay` | A large region entering or collapsing — a sheet, a panel, a reveal |
|
|
39
34
|
| `duration.theme` | Everything on the page at once |
|
|
40
35
|
|
|
41
|
-
An element tied to a larger change takes its tier: a disclosure chevron runs at `duration.popover` and lands with the panel opening below it. Hover is no exception: a wash across a large card
|
|
36
|
+
An element tied to a larger change takes its tier: a disclosure chevron runs at `duration.popover` and lands with the panel opening below it. Hover is no exception: a wash across a large card takes a longer tier than a row swept in bulk (Dials). `duration.route` is the one tier size doesn't set; law 3 caps it. The numbers are dials; the ordering is not.
|
|
42
37
|
|
|
43
38
|
**`duration.theme` runs only when the page itself switches theme**, under a class held on the root for the length of the switch. Everyday colour transitions leave out the page background and are suspended during a theme change: otherwise an OS switch by media query, which has no class to hold, cross-fades every control at its own duration while the page around it snaps.
|
|
44
39
|
|
|
@@ -78,7 +73,7 @@ Springs are wrong for discrete flips with no travel, anything that must land in
|
|
|
78
73
|
|
|
79
74
|
### 7. Exits get out of the way
|
|
80
75
|
|
|
81
|
-
**Closing is faster than opening, flat, and eases in — no spring, no overshoot, and it travels less far.** Opening answers the user's intent and can afford character; closing comes after they've moved on, so a bounce reads as reluctance and stands in their way, and a disappearing element needn't travel the full distance. In the Glass preset a menu opens on a spring of about 400ms and closes on a 130ms `ease-in` tween. The law is for things leaving; a hover wash fading behind a pointer that has already moved on stands in nobody's way, so its leave may run
|
|
76
|
+
**Closing is faster than opening, flat, and eases in — no spring, no overshoot, and it travels less far.** Opening answers the user's intent and can afford character; closing comes after they've moved on, so a bounce reads as reluctance and stands in their way, and a disappearing element needn't travel the full distance. In the Glass preset a menu opens on a spring of about 400ms and closes on a 130ms `ease-in` tween. The law is for things leaving; a hover wash fading behind a pointer that has already moved on stands in nobody's way, so its leave may run longer than its arrival.
|
|
82
77
|
|
|
83
78
|
### 8. Where identity persists, the element travels
|
|
84
79
|
|
|
@@ -92,29 +87,19 @@ A view switch keeps the reader's place (layout law 9), so **measure the reading
|
|
|
92
87
|
|
|
93
88
|
**Where a group shows both a current item and the one under the pointer — a nav, a segmented control — one highlight travels with the pointer and comes to rest on the current item, rather than a second treatment appearing beside the first.** What current looks like is colour law 7's, never re-picked here, and weight never changes on hover (type law 5). Previewing a choice and reporting one are the same gesture a beat apart, so they share one moving shape (law 8): two signals each doing half the job, never one doing both. Outside such a group, hover is a wash (the dials). Nothing is filled because it looks better.
|
|
94
89
|
|
|
95
|
-
A filled icon is the same outline with its interior painted, cross-faded in place at `duration.popover` on `ease.colour`, so the silhouette never moves. Marks that can't take it — a brand's official solid mark, a chevron with no interior, a lone toggle with nothing to be picked out from — signal another way. **Fill that distinguishes nothing is just weight.** Nor is a step from `text.secondary` to `text.primary` a signal
|
|
90
|
+
A filled icon is the same outline with its interior painted, cross-faded in place at `duration.popover` on `ease.colour`, so the silhouette never moves. Marks that can't take it — a brand's official solid mark, a chevron with no interior, a lone toggle with nothing to be picked out from — signal another way. **Fill that distinguishes nothing is just weight.** Nor is a step from `text.secondary` to `text.primary` a signal (colour law 6).
|
|
96
91
|
|
|
97
92
|
### 10. Reduced motion is a branch with a substitute
|
|
98
93
|
|
|
99
94
|
**Every animated component reads `prefers-reduced-motion` and takes its own reduced path that still communicates the change; a global off switch is a regression.** The preference exists because large-area and accelerating motion causes nausea and dizziness, not to remove visible state: `* { animation: none !important }` strips the signals with the decoration, and a menu appears with no sign it opened.
|
|
100
95
|
|
|
101
|
-
| Original | Reduced path |
|
|
102
|
-
|---|---|
|
|
103
|
-
| Spring slide, re-targeting highlight | A flat tween at `duration.state`; the move stays legible |
|
|
104
|
-
| Scale or squash entrance | A plain fade |
|
|
105
|
-
| Blur cross-fade | A cross-fade; the blur is the trigger, not the fade |
|
|
106
|
-
| Reveal-on-scroll, route fade, ambient loop | Off, with content in its final visible state |
|
|
107
|
-
| Theme cross-fade, programmatic smooth scroll | Instant |
|
|
108
|
-
| Press scale at `duration.instant` | Kept: too small and short to matter |
|
|
109
|
-
| Set piece | Skipped entirely, not softened |
|
|
110
|
-
|
|
111
96
|
Imperative APIs — `scrollIntoView`, `scrollTo`, `Element.animate`, a GSAP timeline, a canvas loop — don't read the preference; pass it in. Motion's `MotionConfig reducedMotion="user"` and React Spring's `skipAnimation` are a floor, not the plan.
|
|
112
97
|
|
|
113
98
|
→ Every substitute in CSS, Motion, GSAP and React Spring, and how to test: `domains/motion/guards.md`
|
|
114
99
|
|
|
115
100
|
### 11. Motion never owns whether content is visible
|
|
116
101
|
|
|
117
|
-
**Any style that hides content until an animation runs must resolve to visible whenever that animation can't run** — no JavaScript, no observer, reduced motion, print, or an element too tall to trip its trigger. The failure is not a plainer page but a correct document the reader can't see.
|
|
102
|
+
**Any style that hides content until an animation runs must resolve to visible whenever that animation can't run** — no JavaScript, no observer, reduced motion, print, or an element too tall to trip its trigger. The failure is not a plainer page but a correct document the reader can't see. The usual causes: an observer threshold a very tall section can't reach, and a class added outside the framework, which a re-render rewrites away.
|
|
118
103
|
|
|
119
104
|
So reveals are one-shot, with a zero threshold and a root margin, re-observed on client navigation, marked by a data attribute the framework doesn't own, and reset by a `<noscript>` style and a print rule. A collapsible animates its height but stays mounted (layout law 11).
|
|
120
105
|
|
|
@@ -124,7 +109,7 @@ So reveals are one-shot, with a zero threshold and a root margin, re-observed on
|
|
|
124
109
|
|
|
125
110
|
### 13. Animate what the compositor can; escalate one element, never a view
|
|
126
111
|
|
|
127
|
-
**Animate `transform` and `opacity`, list every transitioned property by name, justify any layout property you animate, and when the DOM can't carry a transition, move one decorative element to the GPU — never the view.** `transition: all` catches properties you never meant, including layout ones a parent adds later. Animating `width` is defensible only where nothing reflows, as on one absolutely positioned element outside the flow; otherwise use a transform, or the `0fr`↔`1fr` grid track to "animate to auto".
|
|
112
|
+
**Animate `transform` and `opacity`, list every transitioned property by name, justify any layout property you animate, and when the DOM can't carry a transition, move one decorative element to the GPU — never the view.** `transition: all` catches properties you never meant, including layout ones a parent adds later. Animating `width` is defensible only where nothing reflows, as on one absolutely positioned element outside the flow; otherwise use a transform, or the `0fr`↔`1fr` grid track to "animate to auto". The moving wrapper and a translucent surface are separate elements (depth law 9).
|
|
128
113
|
|
|
129
114
|
GPU escalation is for one travelling element with no semantics of its own, never a view of tiles, whose semantics a canvas can't carry and whose textures cost hundreds of megabytes; its setup returns `null` rather than throwing, the path reduced motion and no-WebGL already take.
|
|
130
115
|
|
|
@@ -144,6 +129,7 @@ GPU escalation is for one travelling element with no semantics of its own, never
|
|
|
144
129
|
|
|
145
130
|
| Dial | editorial | product | expressive |
|
|
146
131
|
|---|---|---|---|
|
|
132
|
+
| `duration.instant` | 0 | 0 | 0 |
|
|
147
133
|
| `duration.micro` | 100ms | 80ms | 120ms |
|
|
148
134
|
| `duration.state` | 150ms | 100ms | 200ms |
|
|
149
135
|
| `duration.popover` | 200ms | 150ms | 280ms |
|
|
@@ -198,37 +184,16 @@ Collect evidence, then report:
|
|
|
198
184
|
|
|
199
185
|
Then tab through with reduced motion on, and with JavaScript off, for anything that never appears or appears with no sign it opened. Check hover states on *leave* as well as enter; the leave state is where transition-property mistakes live.
|
|
200
186
|
|
|
201
|
-
Report each breach as one line under `## Open issues`, with the law, the evidence and the reach: *"Law 11 — `.fade-up` has no `<noscript>` reset; content blank with JS off. 23 components."*
|
|
202
|
-
|
|
203
187
|
## Writing back to DESIGN.md
|
|
204
188
|
|
|
205
189
|
Under `## Motion`: ladder rows (role, name here, value, used for); curves; springs by character; the reduced-motion policy in a sentence; each off-ladder entry as a row in the **Named exemptions** table (exemption, values, why — its law 4 class and where it plays), which the detector reads; the sound policy, if any.
|
|
206
190
|
|
|
207
|
-
Under `## Decisions`,
|
|
208
|
-
|
|
209
|
-
Under `## Open issues`: each audit breach, one line with its evidence, removed when fixed; don't fix beyond the task unasked.
|
|
191
|
+
Under `## Decisions`, besides moved dials: a set piece added, sound turned on.
|
|
210
192
|
|
|
211
193
|
## Checklist
|
|
212
194
|
|
|
213
|
-
- [ ] Every animation answers "what changed?"; only an ongoing state loops, and it holds still when that state pauses.
|
|
214
195
|
- [ ] Live indicators morph in place to their action on hover and focus.
|
|
215
|
-
- [ ] `duration
|
|
216
|
-
- [ ]
|
|
217
|
-
- [ ]
|
|
218
|
-
- [ ] `duration.theme` runs only under the page's own switch class; everyday colour transitions leave out the page background and are suspended while the theme changes.
|
|
219
|
-
- [ ] Each off-ladder duration is classed subject, set piece or ambient in `DESIGN.md`.
|
|
220
|
-
- [ ] One `ease.standard`; colour and opacity on `ease.colour`; no overshoot on a filter or floored property.
|
|
221
|
-
- [ ] Springs are `spring.<character>`, only where things re-target or are grabbed, opacity split out.
|
|
222
|
-
- [ ] Exits are shorter than entrances, flat, on `ease.exit`, no spring.
|
|
223
|
-
- [ ] Shared elements re-target, never remount, and skip their mount animation; layout switches keep the reading position.
|
|
224
|
-
- [ ] In a group with a current item, one highlight travels between hovered and current; current looks as colour law 7 says; no weight change on hover; marks that can't take a fill signal another way.
|
|
225
|
-
- [ ] Each animated component has a reduced path that still shows the change; imperative APIs get the preference.
|
|
226
|
-
- [ ] Hidden-until-animated content survives no JS, no observer, reduced motion, print, tall elements and re-renders.
|
|
227
|
-
- [ ] Scroll work is passive, rAF-collapsed and hysteretic, and never hides what touch can't restore.
|
|
228
|
-
- [ ] Only `transform` and `opacity` animate, each property named; GPU escalation is one element and fails to `null`.
|
|
229
|
-
- [ ] Hover-opened elements get a close grace or bridge and cleared timers; focus reveals what hover does.
|
|
230
|
-
- [ ] Set pieces play once a session, gate before first paint, record "seen" on completion, never block the skip link.
|
|
231
|
-
- [ ] Durations, curves and springs match the preset, or a `## Decisions` entry says why not.
|
|
232
|
-
- [ ] Reveal travel, press feedback and route transitions match the preset.
|
|
233
|
-
- [ ] Set pieces and ambient loops are within the preset's allowance; a loop nothing can pause off screen is finite or gone.
|
|
196
|
+
- [ ] `duration.theme` runs only under the page's own switch class; everyday colour transitions leave out the page background.
|
|
197
|
+
- [ ] Shared elements skip their mount animation; layout switches keep the reading position.
|
|
198
|
+
- [ ] Set pieces record "seen" on completion and never block the skip link.
|
|
234
199
|
- [ ] Sound only if the preset allows it, off by default behind a visible, persisted toggle.
|
|
@@ -126,7 +126,7 @@ A wash, with the leave on the resting rule and the arrival on the hovered one, s
|
|
|
126
126
|
.card:hover { background-color: var(--surface-hover); transition-duration: <hover in>; }
|
|
127
127
|
```
|
|
128
128
|
|
|
129
|
-
|
|
129
|
+
Why a wash, and the timings: `domains/motion/ladder-and-curves.md`.
|
|
130
130
|
|
|
131
131
|
## Press
|
|
132
132
|
|
|
@@ -97,7 +97,7 @@ const update = () => {
|
|
|
97
97
|
|
|
98
98
|
The same works on columns with `min-width: 0`. Where supported, `interpolate-size: allow-keywords` lets `height: auto` transition directly.
|
|
99
99
|
|
|
100
|
-
**Transforms and `backdrop-filter`.**
|
|
100
|
+
**Transforms and `backdrop-filter`.** The moving wrapper and a translucent surface are different elements (depth law 9).
|
|
101
101
|
|
|
102
102
|
**`will-change`** only on an element about to animate, removed after; left on everything, it pins memory for layers that never move.
|
|
103
103
|
|
|
@@ -6,12 +6,7 @@ The laws hold under every preset. How much keyboard, how much is remembered and
|
|
|
6
6
|
|
|
7
7
|
## Before you start
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
- **No `DESIGN.md`:** run `/keyline init` for the profile and preset only, do the task, then add a `## Patterns` section and recommend the full setup.
|
|
12
|
-
- **A pattern you need has no entry:** find the nearest one already in the code and reuse it; otherwise define it once and record it under `## Patterns`.
|
|
13
|
-
- **The task would break a law or move a dial off its preset:** say so and ask; if the user confirms, record it with its reason under `## Decisions`.
|
|
14
|
-
- **Preset `glass`:** it carries no pattern values; use the dials of the preset nearest the reader.
|
|
9
|
+
Reads `DESIGN.md` `## Patterns`: the product's nouns, its destructive pattern, its shortcut map, which views are remembered. Write copy in the project's nouns.
|
|
15
10
|
|
|
16
11
|
Boundaries: how a label or figure is set is the type guide's; what colour danger, brand and status take, the colour guide's; where things sit and which views fork, the layout guide's; what a dialog or card is built from, the depth guide's; how long anything takes to move, the motion guide's. This guide decides the flow and the words, and names the owner where the rest is someone else's.
|
|
17
12
|
|
|
@@ -19,15 +14,15 @@ Boundaries: how a label or figure is set is the type guide's; what colour danger
|
|
|
19
14
|
|
|
20
15
|
### 1. A label is as short as its action, in sentence case
|
|
21
16
|
|
|
22
|
-
**A label names the action in the fewest words that still say it: a button reads its verb — "Send", "Save changes", "Record" — not the sentence around it ("Record a voice note").** Labels are scanned, not read; every extra word moves the verb away from where the eye lands, and the tail is the first thing to truncate.
|
|
17
|
+
**A label names the action in the fewest words that still say it: a button reads its verb — "Send", "Save changes", "Record" — not the sentence around it ("Record a voice note").** Labels are scanned, not read; every extra word moves the verb away from where the eye lands, and the tail is the first thing to truncate. A confirm button repeats its dialog's verb, never "OK" or "Yes".
|
|
23
18
|
|
|
24
|
-
**Sentence case everywhere
|
|
19
|
+
**Sentence case everywhere**, labels the code generates from keys included. Title case marks every word as a name, and uppercase strips word shapes. The one display exception is an `expressive` eyebrow, written in sentence case and set in capitals by `text-transform` (type law 7).
|
|
25
20
|
|
|
26
21
|
### 2. A row's second line says what it is and where it's from
|
|
27
22
|
|
|
28
23
|
**Under a title, the second line names the record's type and origin in the product's own nouns — "Task from Riverside", "Note from site walk" — never an event ("Issue added to Riverside").** The title says which one; the reader's next questions are what kind and from where, and those let them triage without opening it. Event phrasing describes something that happened to the record once, in a verb nobody filters by, and often swaps the noun, so the reader wonders whether an "issue" here is a "task" everywhere else. **One noun per kind of thing across the product**, listed in `DESIGN.md`. Time, owner and status take their own slots — a column, a meta line, a glyph — not the sentence. The title stays the strongest line in the row (the type guide, the colour guide).
|
|
29
24
|
|
|
30
|
-
→ Before-and-after labels,
|
|
25
|
+
→ Before-and-after labels, when a label takes an object, generated labels and their acronyms, toasts and error copy: `domains/patterns/copy.md`
|
|
31
26
|
|
|
32
27
|
### 3. Destructive and session-ending actions look alike, and come last
|
|
33
28
|
|
|
@@ -35,11 +30,7 @@ Boundaries: how a label or figure is set is the type guide's; what colour danger
|
|
|
35
30
|
|
|
36
31
|
### 4. A confirmation says what is lost, in the system's own dialog
|
|
37
32
|
|
|
38
|
-
**A confirmation states in plain words what will be lost, uses the product's standard dialog, and asks for proof of intent in proportion to the loss.** The dialog is the system's own (depth law 1).
|
|
39
|
-
|
|
40
|
-
- **Reversible** — no dialog; do it, and offer Undo in the toast.
|
|
41
|
-
- **Irreversible, one item** — a dialog whose button repeats the verb.
|
|
42
|
-
- **Irreversible and large** — a project, an account, a workspace — "Type DELETE to confirm", compared case-insensitively, the input focused on open (not Cancel), the action disabled until it matches, "Deleting…" while it runs, and the dialog held open until it succeeds or says why it failed.
|
|
33
|
+
**A confirmation states in plain words what will be lost, uses the product's standard dialog, and asks for proof of intent in proportion to the loss.** The dialog is the system's own (depth law 1). Proof runs from none for the reversible, which gets Undo, to a typed word for a project, an account or a workspace (→ `domains/patterns/actions-and-forms.md`).
|
|
43
34
|
|
|
44
35
|
**One pattern everywhere**: deleting a project and deleting an account read the same. On close, focus goes back to what opened it (depth law 12).
|
|
45
36
|
|
|
@@ -65,7 +56,7 @@ The conversation carries no avatar per message: the reader's turns sit right-ali
|
|
|
65
56
|
|
|
66
57
|
**A launcher offers only the choices the task has, and a toolbar or a long list holds back what isn't needed every time.** Every option on the path of the most frequent action is something to read before starting: a record launcher asks one question with two answers — which project, or a personal note — not a form. Toolbar filters are icons with tooltips, not a text label on every control. A long admin list groups into collapsed bars, closed by default, each with a summary of what the reader would open it to check ("Admins · 3 of 12 with access"), and a search opens every group it matches.
|
|
67
58
|
|
|
68
|
-
**Hick's law** is why
|
|
59
|
+
**Hick's law** is why, and **progressive disclosure** the cure — the common path visible, the rest one step away (layout law 11 keeps it in the markup). By **Miller's law**, chunk long lists and long strings — three groups of four nav items, `4242 4242 4242 4242` — but don't treat "seven" as a cap that cuts what the product needs.
|
|
69
60
|
|
|
70
61
|
### 9. An empty state offers the first action
|
|
71
62
|
|
|
@@ -99,17 +90,13 @@ Whether the view and span are remembered is layout law 9; list each page that re
|
|
|
99
90
|
|
|
100
91
|
**What an element looks like says what it does, and it does that: a play icon opens a video, a link goes somewhere, and anything that doesn't act doesn't react.** Landing pages and articles are where these promises break, because they are built to look a certain way before anyone decides what each piece does, and a reader who clicks a dead logo or a silent play icon stops trusting the rest. A logo that isn't a link takes no hover state; an email address is a `mailto:` link; "Copy link" is a button, not a link to the page already open; link text names its destination ("Pricing", not "Learn more"). A call to action names what happens next — "Start free", "Book a demo" — so two on one page can't be mistaken for each other, as "Get started" beside "Start free" can. A subscribe or sign-up field has a visible label and says what will arrive and how often.
|
|
101
92
|
|
|
102
|
-
**Conventions are promises too** (Jakob's law):
|
|
93
|
+
**Conventions are promises too** (Jakob's law): the logo goes home, search sits behind ⌘K or a magnifier, the account is at the end of the navigation, a link is underlined or obviously a link. Break a convention only for a gain the reader will feel on first use, and never for novelty alone.
|
|
103
94
|
|
|
104
95
|
→ Calls to action, link text and sign-up lines: `domains/patterns/copy.md`
|
|
105
96
|
|
|
106
97
|
### 15. Every action answers at once, and anything slow says what it's doing
|
|
107
98
|
|
|
108
|
-
**An input is acknowledged within 100ms — a press state, a toggle flipping, a row moving — and any result that takes longer than about 400ms shows what is happening in the place it was asked for.**
|
|
109
|
-
|
|
110
|
-
- **Past ≈ 400ms**, the control says it's working — "Saving…" in the button's own label, the button held at its width.
|
|
111
|
-
- **Past ≈ 1s**, the region that will change shows its shape — a skeleton of the rows coming, not a centred spinner over a blank page.
|
|
112
|
-
- **Past ≈ 10s**, progress is determinate — a count, a step, a bar — with a way to cancel or leave and be told when it's done.
|
|
99
|
+
**An input is acknowledged within 100ms — a press state, a toggle flipping, a row moving — and any result that takes longer than about 400ms shows what is happening in the place it was asked for.** 400ms is the Doherty threshold. The acknowledgement is instant and local (press feedback is the motion guide's), the slow part runs in the background where it can (law 11), and the wait is honest where it can't, its form set by how long it runs (→ `domains/patterns/actions-and-forms.md`, pending states).
|
|
113
100
|
|
|
114
101
|
**The loop closes where it opened**: the result appears where the action was taken, and what changed is visible without reading a toast. A save that succeeds silently, a filter that applies off screen, or an error reported in a corner the reader isn't looking at breaks the loop, and readers repeat the action to find out what happened.
|
|
115
102
|
|
|
@@ -117,13 +104,13 @@ Whether the view and span are remembered is layout law 9; list each page that re
|
|
|
117
104
|
|
|
118
105
|
**Accept what people type in any reasonable form and store one canonical form; show choices rather than ask for things from memory; and let the product carry the complexity the reader would otherwise carry.** Three laws meet here:
|
|
119
106
|
|
|
120
|
-
- **Postel's law** —
|
|
121
|
-
- **Recognition over recall** —
|
|
122
|
-
- **Tesler's law** —
|
|
107
|
+
- **Postel's law** — spaces, dashes, case and a trailing space are valid input, normalised, never rejected for format. Errors are for what's actually wrong, and say how to fix it.
|
|
108
|
+
- **Recognition over recall** — recent and frequent items lead a picker; a command palette lists what it can do before the reader types; labels stay visible above fields; a filter shows its current value, not just its name.
|
|
109
|
+
- **Tesler's law** — default to the likely answer, infer what can be inferred, and never ask for what the product already knows.
|
|
123
110
|
|
|
124
111
|
### 17. A flow shows how near the end is, and the end is designed
|
|
125
112
|
|
|
126
|
-
**A task of several steps shows where the reader is and how much is left, and its last screen is built as carefully as its first.**
|
|
113
|
+
**A task of several steps shows where the reader is and how much is left, and its last screen is built as carefully as its first.** A visible count pulls the reader through (the goal-gradient effect), and the end is what is remembered (the peak-end rule): it says what happened in the product's nouns, shows the result, and offers the next action. A failure at the peak — a payment declined, an upload lost — gets the most careful copy in the product, never a code.
|
|
127
114
|
|
|
128
115
|
→ Pending states, skeletons, forgiving inputs and progress in code: `domains/patterns/actions-and-forms.md`
|
|
129
116
|
|
|
@@ -133,7 +120,7 @@ Whether the view and span are remembered is layout law 9; list each page that re
|
|
|
133
120
|
|---|---|---|---|
|
|
134
121
|
| Label length | 1–3 words | 1–2 words, verb first | A call to action may run to a short phrase |
|
|
135
122
|
| Keyboard | Tab order, skip link, Escape | Palette, list movement, single-key actions, shown in menus | Tab order and Escape |
|
|
136
|
-
| View memory | Reset on arrival | Remembered per page on daily working pages
|
|
123
|
+
| View memory | Reset on arrival | Remembered per page on daily working pages (layout law 9) | Reset on arrival |
|
|
137
124
|
| Optimistic updates | Rare | Default for moves, toggles, renames, reorders | Rare |
|
|
138
125
|
| Proof of intent for large deletes | Typed word | Typed word | Typed word |
|
|
139
126
|
| Empty-state copy | One sentence and the action | One line and the action | A headline, a line and the action |
|
|
@@ -144,22 +131,11 @@ The `glass` preset carries no pattern dials; take them from the preset nearest t
|
|
|
144
131
|
|
|
145
132
|
**Keyboard.** Product readers repeat; editorial and expressive readers arrive, read and leave, so a palette there is a feature nobody discovers. Every preset keeps the floor: everything reachable by Tab, Escape closing one layer.
|
|
146
133
|
|
|
147
|
-
**View memory.** A working reader returns to the same collection daily and set its view for a reason; a visiting reader didn't, and should see the collection as designed.
|
|
148
|
-
|
|
149
134
|
**Toasts.** A toast confirms what the reader can't see happen. A move they watched needs none; a save that failed, an undo window, or a result on another page does.
|
|
150
135
|
|
|
151
136
|
## Iterating on feedback
|
|
152
137
|
|
|
153
|
-
Most product feedback is one step: "one step lighter", "25% smaller", "to 16px".
|
|
154
|
-
|
|
155
|
-
1. **Make the change asked, at the size asked.** Move one step on the existing ladder; don't re-pick the system. The count per row stays unless more per row was asked for.
|
|
156
|
-
2. **After any change to a shared rule, sweep the product** — every route, every component on that rule — **and report what moved.** Partial updates are the commonest bug: some screens took the new value, some didn't. Ask before calling a page done, and never "fix" a page the owner has said is theirs.
|
|
157
|
-
3. **Record the decision** under `## Decisions` (format: `system/design-md.md`).
|
|
158
|
-
4. **Study reference products for how information is structured, not how it looks**: where icons are and aren't, where tags appear, how tables are built, what is boxed and what isn't, what aligns with what.
|
|
159
|
-
5. **Wireframe a new page type before building it**, and share the wireframe.
|
|
160
|
-
6. **Review on a preview harness**: the real app on mock data, every route reachable without a backend, so a whole-product sweep or audit takes minutes.
|
|
161
|
-
|
|
162
|
-
→ The sweep, the report, the log entry, a reference-study worksheet and the harness: `domains/patterns/iteration.md`
|
|
138
|
+
Most product feedback is one step: "one step lighter", "25% smaller", "to 16px". Make exactly that change, at the size asked, sweep everywhere the rule reaches and report what moved, then record it under `## Decisions` (→ `domains/patterns/iteration.md`: the step table, the sweep, references and the preview harness). Wireframe a new page type before building it, and share the wireframe.
|
|
163
139
|
|
|
164
140
|
## Auditing existing code
|
|
165
141
|
|
|
@@ -183,34 +159,16 @@ Most product feedback is one step: "one step lighter", "25% smaller", "to 16px".
|
|
|
183
159
|
| 16 | Inputs that reject spaces, dashes, case or a trailing space; placeholders as labels; pickers with no recent items; questions the product could answer itself | Field, the input it rejects or the question it needn't ask |
|
|
184
160
|
| 17 | Multi-step flows with no position or count; a last screen that says only "Success" or "Done"; failure copy with a code and no next step | Flow, step, and its end state |
|
|
185
161
|
|
|
186
|
-
Click through every flow once with the keyboard alone, and once with the network throttled to failure.
|
|
162
|
+
Click through every flow once with the keyboard alone, and once with the network throttled to failure.
|
|
187
163
|
|
|
188
164
|
## Writing back to DESIGN.md
|
|
189
165
|
|
|
190
166
|
- **`## Patterns`**: the product's nouns, one per kind of thing; the second-line formula; the destructive items and the proof each needs; the shortcut map; which pages remember their view and which default wins; the agent-step conventions.
|
|
191
|
-
- **Decisions**, dated, marked by who decided, with the reason: any dial moved off the preset, a law knowingly broken, or a change a law forced that a later session might undo (marked *law*).
|
|
192
|
-
- **Open issues** for every law the code breaks, with evidence, removed when the fix lands.
|
|
193
167
|
|
|
194
168
|
## Checklist
|
|
195
169
|
|
|
196
|
-
- [ ]
|
|
197
|
-
- [ ]
|
|
198
|
-
- [ ]
|
|
199
|
-
- [ ]
|
|
200
|
-
- [ ]
|
|
201
|
-
- [ ] Streaming text separates committed from forming, follows only while the reader is at the bottom, and is still when paused.
|
|
202
|
-
- [ ] Frequent actions have keys; every drag has a keyboard path; Escape closes one layer; single keys never fire in inputs.
|
|
203
|
-
- [ ] Launchers offer only the task's choices; toolbar filters are icons with tooltips; long lists group and collapse.
|
|
204
|
-
- [ ] Empty user data offers the first action; filtered-empty names the filter.
|
|
205
|
-
- [ ] Staged work has a board in workflow order beside its list; remembered views follow layout law 9 and are listed under `## Patterns`.
|
|
206
|
-
- [ ] Moves are optimistic with a visible rollback; sends, payments and deletes are not.
|
|
207
|
-
- [ ] Dashboards run overview, trends, action items, wireframed first, scoped views on the global pipeline.
|
|
208
|
-
- [ ] Forms lead with the deciding field; errors replace hints; sign-in is a form alone in its column, its route an `expressive` area if the art moves.
|
|
209
|
-
- [ ] Every element does what its form promises: play icons play, inert logos don't react, email addresses are `mailto:` links, copy controls are buttons, calls to action and link text name what happens next, sign-up fields are labelled and say what arrives and how often.
|
|
210
|
-
- [ ] Conventions readers know from other products hold, unless breaking one is a gain felt on first use.
|
|
211
|
-
- [ ] Every input is acknowledged at once; past ≈ 400ms the control says it's working, past ≈ 1s the region shows its shape, past ≈ 10s progress is determinate and cancellable; results appear where they were asked for.
|
|
212
|
-
- [ ] Inputs accept any reasonable form and normalise it; labels stay visible; pickers lead with recent items; the product never asks for what it already knows.
|
|
213
|
-
- [ ] Multi-step flows show position and what's left; the last screen names what happened, shows it and offers the next action; failures at the peak get the most careful copy.
|
|
214
|
-
- [ ] Long lists and long strings are chunked; launchers and toolbars show the common path and disclose the rest.
|
|
215
|
-
- [ ] Feedback was applied at the size asked, swept product-wide, reported, and recorded as a dated decision.
|
|
216
|
-
- [ ] Dials match the preset, or the difference is under `## Decisions`.
|
|
170
|
+
- [ ] Large deletes show "Deleting…" and hold the dialog open until done; focus returns to the opener.
|
|
171
|
+
- [ ] Filtered-empty names the filter and offers to clear it.
|
|
172
|
+
- [ ] Sends, payments and deletes are never optimistic.
|
|
173
|
+
- [ ] A sign-in route whose art moves is listed as an `expressive` area.
|
|
174
|
+
- [ ] Long lists and long strings are chunked.
|
|
@@ -35,15 +35,7 @@ Card title weight 600 → 500 (role `type.card-title`):
|
|
|
35
35
|
|
|
36
36
|
## The decision log
|
|
37
37
|
|
|
38
|
-
Every decision goes under `## Decisions` in `DESIGN.md`, in the format `system/design-md.md` sets.
|
|
39
|
-
|
|
40
|
-
```markdown
|
|
41
|
-
- 2026-10-28 — Card titles at 500, not 600: "unnecessarily heavy" next to the pane title. (User decision.)
|
|
42
|
-
- 2026-10-21 — Boards remember their view per page; folders always open on folders. (User decision.)
|
|
43
|
-
- 2026-10-14 — More colour, each hue with one job: type, status, area, person. (Client feedback.)
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
Read the log before changing anything it covers. A reviewer's instinct to "fix" a decided value is how a product oscillates between two versions.
|
|
38
|
+
Every decision goes under `## Decisions` in `DESIGN.md`, in the format and with the rules `system/design-md.md` sets.
|
|
47
39
|
|
|
48
40
|
## Studying a reference
|
|
49
41
|
|
|
@@ -6,12 +6,7 @@ The organising idea is **a size exists because a role needs it** — not because
|
|
|
6
6
|
|
|
7
7
|
## Before you start
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
- **No `DESIGN.md`:** run `/keyline init` for this domain only, do the task, then recommend the full setup.
|
|
12
|
-
- **A role you need has no row:** reuse a value already doing that job; otherwise add one in the project's naming style and record it in `DESIGN.md`.
|
|
13
|
-
- **The task would break a law or move a dial off its preset:** say so and ask; if the user confirms, record it with its reason under `## Decisions`.
|
|
14
|
-
- **Preset `glass`:** the values are in `DESIGN.md`; `glass/type/guide.md` has the exact recipes behind them.
|
|
9
|
+
Reads `DESIGN.md` `## Type`.
|
|
15
10
|
|
|
16
11
|
## Laws
|
|
17
12
|
|
|
@@ -23,13 +18,13 @@ The ladder has a floor as well as a ceiling. Below the readable floor type is re
|
|
|
23
18
|
|
|
24
19
|
Type inside artwork — an illustration or diagram, an SVG or an HTML mock marked `role="img"` — is exempt from the ladder, as colour law 1 exempts colour there; any label in it a reader must read still clears the readable floor.
|
|
25
20
|
|
|
26
|
-
Cut downward, checking what each remaining step was holding up: removing
|
|
21
|
+
Cut downward, checking what each remaining step was holding up: removing one size often takes others that existed only to sit beside it.
|
|
27
22
|
|
|
28
23
|
→ Per-preset ladders, and adding a role without growing one: `domains/type/ladders.md`
|
|
29
24
|
|
|
30
25
|
### 2. A scale is only a system if every template is on it
|
|
31
26
|
|
|
32
|
-
**No template opens off the ladder, and templates of one kind open alike; a page type with its own hierarchy is opting out of the system, not expressing importance.**
|
|
27
|
+
**No template opens off the ladder, and templates of one kind open alike; a page type with its own hierarchy is opting out of the system, not expressing importance.** Readers feel the opt-out as inconsistency before they notice sizes, and the fix is the existing ladder, not a compromise. An article may open above an index — its title starts a piece, an index's labels a list (the ceiling dial) — but every article opens at one size, and every index at another.
|
|
33
28
|
|
|
34
29
|
Areas on another preset are declared by path in `DESIGN.md`, not drifted into. Inside one every template shares its ladder, and roles crossing the boundary — navigation, `type.ui`, `type.meta`, the footer — keep one set of values, so the chrome doesn't change between marketing site and app.
|
|
35
30
|
|
|
@@ -37,7 +32,7 @@ The same holds for one element: a pane title at 14/600 where every other page's
|
|
|
37
32
|
|
|
38
33
|
### 3. A tier never outranks the heading it sits under
|
|
39
34
|
|
|
40
|
-
**Nothing inside a section — a lead, a pull quote, a keyline, a note — may be larger, heavier or louder than the heading that owns it.** A
|
|
35
|
+
**Nothing inside a section — a lead, a pull quote, a keyline, a note — may be larger, heavier or louder than the heading that owns it.** A keyline a pixel larger than its heading reads as paragraphs shouting over their titles; an in-body heading larger than the page's title inverts the document. Check role pairs — `type.lead` against `type.heading`, `type.heading` against `type.title` — since a violation only shows where the two meet.
|
|
41
36
|
|
|
42
37
|
`type.display`, the one role above `type.title`, obeys it too: one loudest moment, nothing under it competing. Two are two pages' worth of hierarchy on one.
|
|
43
38
|
|
|
@@ -59,7 +54,7 @@ In a row or card the rule runs the other way: **its title is the darkest thing i
|
|
|
59
54
|
|
|
60
55
|
A further role there needs an unused axis, or it isn't a role.
|
|
61
56
|
|
|
62
|
-
The corollary matters more: **when you remove a signal, audit the ones you left in.**
|
|
57
|
+
The corollary matters more: **when you remove a signal, audit the ones you left in.** A pull quote's faint border, invisible on white, survives only while the quote is larger than the body; when the size step goes, it has to become a real bar.
|
|
63
58
|
|
|
64
59
|
Between sizes too, size is the weakest signal in the 11–20px band: a 13 → 14 → 20 ladder at one weight reads flat. **A step up in rank moves weight and tracking with it** — headings tighten as they grow while labels stay at zero — never size alone.
|
|
65
60
|
|
|
@@ -73,7 +68,7 @@ Between sizes too, size is the weakest signal in the 11–20px band: a 13 → 14
|
|
|
73
68
|
|
|
74
69
|
A second family earns its place with a second register — literal text in a code face, a brand display voice, interface text beside a serif reading face — never because "headings should feel different", which size, weight, leading and tracking handle. A code face for a handful of spans is a system stack, not a download; IDs, codes and times rarely need even that — tabular, slashed-zero figures (law 10) set them apart in the text face.
|
|
75
70
|
|
|
76
|
-
Weight is the cheapest second channel for state
|
|
71
|
+
Weight is the cheapest second channel for state (colour law 6): an active row adds `weight.strong` to the colour colour law 7 gives it — only on states that don't follow the pointer (active, current, selected, not hover), since a weight change alters width and shifts neighbours. **Weight carries one state per product:** if unread rows step up beside their dot, current and selected use a fill, a marker or tier, or the step means nothing.
|
|
77
72
|
|
|
78
73
|
### 6. Leading follows the job
|
|
79
74
|
|
|
@@ -126,7 +121,7 @@ The mapping covers user-agent styles: `<cite>`, `<blockquote>`, `<b>`, `<th>` an
|
|
|
126
121
|
| Dial | editorial | product | expressive |
|
|
127
122
|
|---|---|---|---|
|
|
128
123
|
| `type.body` size | 16–18px | 14px | 17–20px |
|
|
129
|
-
| `type.ui` size | body − 1–2px | 13px (12px in dense tables) | 15–16px |
|
|
124
|
+
| `type.ui` size | body − 1–2px | 13px (12px in dense tables) | 15–16px; on any preset, inputs go to 16px on touch widths only |
|
|
130
125
|
| Ceiling: `type.title` ÷ `type.body` | ≤ 2.25 for an article's or page's title; index and chrome titles may sit lower | ≤ 1.6 | ≤ 2.5 |
|
|
131
126
|
| `type.display` | none | none | one per page, derived from the measure; ≥ 1.5 × `type.title` at every width (× `type.heading` where the display is the `h1`) |
|
|
132
127
|
| Distinct sizes above the floor (excluding display and code) | ≤ 7 | ≤ 7 | ≤ 8 |
|
|
@@ -214,38 +209,19 @@ Evidence per law:
|
|
|
214
209
|
- **Loading (12).** Third-party font hosts, `swap` without a metric-matched fallback, weights requested but unused.
|
|
215
210
|
- **Icons (13).** Icon sizes and strokes against the text beside them; sibling controls that differ.
|
|
216
211
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
**Sweep after every type decision** (the sweep: `domains/patterns/iteration.md`). Raw sizes hide a partial type update from grep, so walk every route rendered against the `## Type` table and migrate raw sizes to role tokens as you go. → `domains/type/type-audit.md`
|
|
212
|
+
**Sweep after every type decision** (`domains/patterns/iteration.md`; its type steps, `domains/type/type-audit.md`).
|
|
220
213
|
|
|
221
214
|
## Writing back to DESIGN.md
|
|
222
215
|
|
|
223
216
|
- **`## Type`** — families; a row per role in use (project name, size, leading, tracking, weight, tier); project roles under their canonical parent with their separating axis; each weight's job, and with three the size × use table; each role's icon size. Keep existing names; mark new ones `proposed`.
|
|
224
|
-
- **`## Decisions`** —
|
|
225
|
-
- **`## Open issues`** — each violation with its evidence, removed when fixed.
|
|
217
|
+
- **`## Decisions`** — a third weight and the table that needed it, a raised ceiling and its role, italic for a true italic.
|
|
226
218
|
|
|
227
219
|
Write back whenever the ladder changes shape — a role, size, weight or family added or dropped. A size without a row is how a ladder turns back into a pile of values.
|
|
228
220
|
|
|
229
221
|
## Checklist
|
|
230
222
|
|
|
231
|
-
- [ ]
|
|
232
|
-
- [ ]
|
|
233
|
-
- [ ]
|
|
234
|
-
- [ ]
|
|
235
|
-
- [ ] One element, one set of values on every page; row and card titles are their darkest text.
|
|
236
|
-
- [ ] Every weight and family has a job; no weight changes on hover.
|
|
237
|
-
- [ ] Weight lifts one step, never on neighbours; one weight per set of titles; at most one state on weight.
|
|
238
|
-
- [ ] Active and selected states carry a signal besides colour.
|
|
239
|
-
- [ ] Display, reading and UI each use their own leading curve; fixed-height single-line UI uses 1.
|
|
240
|
-
- [ ] Tracking is in `em`: negative only above the text range, positive on tiny text and capitals, zero on body.
|
|
241
|
-
- [ ] UI and reading copy differ in leading, measure and tier; in-product help text is reading copy.
|
|
242
|
-
- [ ] `font-synthesis: none`; `<strong>` is `weight.strong`; no UA italic or bold leaks past the mapping.
|
|
243
|
-
- [ ] Aligned and live numbers are tabular, and the family ships `tnum`.
|
|
244
|
-
- [ ] Imported prose: one scoped class, existing roles, first-child margin reset, wide content scrolling in its own box.
|
|
245
|
-
- [ ] Fonts self-hosted, `swap`, metric-matched fallback; only used weights requested.
|
|
246
|
-
- [ ] Icons match the size and stroke of their text; inputs are 16px on touch widths.
|
|
247
|
-
- [ ] After a type change, every route swept rendered; no raw sizes left.
|
|
248
|
-
- [ ] Nothing a user must read sits below the readable floor.
|
|
249
|
-
- [ ] Dials match the preset: body size, ceiling ratio, weight and family counts, leading ranges, tracking at the top.
|
|
223
|
+
- [ ] No unclaimed base size; row and card titles are their darkest text.
|
|
224
|
+
- [ ] Weight lifts one step, never on neighbours; one weight per set of titles; at most one state on weight; no weight change on hover.
|
|
225
|
+
- [ ] Imported prose resets its first child's margin and scrolls wide content in its own box.
|
|
226
|
+
- [ ] Inputs are 16px on touch widths; nothing a user must read sits below the readable floor.
|
|
250
227
|
- [ ] Display derived from the measure; every fluid size clamped with a `rem` intercept; no text sized in `vw` alone.
|
|
251
|
-
- [ ] Italic, case (generated labels included), numeral defaults and the unit match the preset or a recorded decision.
|
|
@@ -79,7 +79,7 @@ The recorded third weight, for a dense screen where most lines share two or thre
|
|
|
79
79
|
| 13 | a row's second line, a card's time | nav items, header-bar page title, tabs, buttons, table header labels | — |
|
|
80
80
|
| 12 | timestamps, hints, captions | field labels, a group label's count | — |
|
|
81
81
|
|
|
82
|
-
Its rules: nothing inside a row, card or folder goes above 500 but the state weight; lift by one step, never on two neighbouring lines; every title in a set takes one weight. A board's card titles sit a step lighter than a list's row titles: a board shows many titles at once, and at 500 the whole board reads heavy.
|
|
82
|
+
Where this table is recorded it replaces the ladder's weight column: nav items, tabs and buttons sit lifted throughout, and the current one is marked by its fill (colour law 7), not by a weight. Its rules: nothing inside a row, card or folder goes above 500 but the state weight; lift by one step, never on two neighbouring lines; every title in a set takes one weight. A board's card titles sit a step lighter than a list's row titles: a board shows many titles at once, and at 500 the whole board reads heavy.
|
|
83
83
|
|
|
84
84
|
Expect the first pass to be a step too heavy everywhere. Correct it one step at a time per context, then sweep (`type-audit.md`) — a partial step-down is worse than none.
|
|
85
85
|
|
|
@@ -80,11 +80,8 @@ Use the project's names, and keep the list beside the theme tokens so a new role
|
|
|
80
80
|
|
|
81
81
|
## The sweep
|
|
82
82
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
4. **Check the generated strings** for case while you're there (patterns law 1): field names, column headers, tool labels, dialog titles and toasts that arrive in Title Case from a schema or a config.
|
|
89
|
-
`rg -n "(label|title|header|name):\s*['\"][A-Z][a-z]+ [A-Z][a-z]+" src`
|
|
90
|
-
5. **Report what moved**, by role and by page, and anything left on the old value with its reason, so the change can be checked rather than trusted.
|
|
83
|
+
The sweep is `domains/patterns/iteration.md`'s. For a type role, two steps of its own:
|
|
84
|
+
|
|
85
|
+
- **Grep for the old value** in the role's raw forms (`font-semibold`, `text-[14px]`, `font-weight: 600`) and decide each hit; raw sizes are where a partial update hides.
|
|
86
|
+
- **Check the generated strings** for case while you're there (patterns law 1): field names, column headers, tool labels, dialog titles and toasts that arrive in Title Case from a schema or a config.
|
|
87
|
+
`rg -n "(label|title|header|name):\s*['\"][A-Z][a-z]+ [A-Z][a-z]+" src`
|