altitude-design 0.2.1 → 0.3.0
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/README.md +41 -6
- package/dist/adapters/codemirror.cjs +88 -0
- package/dist/adapters/codemirror.cjs.map +7 -0
- package/dist/adapters/codemirror.js +67 -0
- package/dist/adapters/codemirror.js.map +7 -0
- package/dist/adapters/react-flow.css +102 -0
- package/dist/adapters/tiptap.css +71 -0
- package/dist/altitude.css +3121 -244
- package/dist/altitude.iife.js +33 -5
- package/dist/altitude.no-fonts.css +3121 -244
- package/dist/chart-themes.cjs +195 -0
- package/dist/chart-themes.cjs.map +7 -0
- package/dist/chart-themes.js +165 -0
- package/dist/chart-themes.js.map +7 -0
- package/dist/cli/altitude.mjs +134 -0
- package/dist/guidance/README.md +32 -0
- package/dist/guidance/agent-setup.md +22 -0
- package/dist/guidance/app-skeleton.md +17 -0
- package/dist/guidance/evidence.json +95 -0
- package/dist/guidance/index.json +493 -0
- package/dist/guidance/llms.txt +20 -0
- package/dist/guidance/manifest.json +92 -0
- package/dist/guidance/pattern.schema.json +181 -0
- package/dist/guidance/patterns/agent-action.json +77 -0
- package/dist/guidance/patterns/agent-action.md +39 -0
- package/dist/guidance/patterns/assistant-conversation.json +77 -0
- package/dist/guidance/patterns/assistant-conversation.md +50 -0
- package/dist/guidance/patterns/async-collection.json +71 -0
- package/dist/guidance/patterns/async-collection.md +29 -0
- package/dist/guidance/patterns/audit-log.json +75 -0
- package/dist/guidance/patterns/audit-log.md +27 -0
- package/dist/guidance/patterns/auth.json +86 -0
- package/dist/guidance/patterns/auth.md +29 -0
- package/dist/guidance/patterns/billing.json +80 -0
- package/dist/guidance/patterns/billing.md +29 -0
- package/dist/guidance/patterns/consequential-action.json +76 -0
- package/dist/guidance/patterns/consequential-action.md +27 -0
- package/dist/guidance/patterns/developer-settings.json +79 -0
- package/dist/guidance/patterns/developer-settings.md +29 -0
- package/dist/guidance/patterns/edit-record.json +74 -0
- package/dist/guidance/patterns/edit-record.md +51 -0
- package/dist/guidance/patterns/import.json +77 -0
- package/dist/guidance/patterns/import.md +31 -0
- package/dist/guidance/patterns/members.json +77 -0
- package/dist/guidance/patterns/members.md +27 -0
- package/dist/guidance/patterns/onboarding.json +78 -0
- package/dist/guidance/patterns/onboarding.md +31 -0
- package/dist/guidance/patterns/review-submit.json +72 -0
- package/dist/guidance/patterns/review-submit.md +27 -0
- package/dist/guidance/patterns/screen-layout.json +79 -0
- package/dist/guidance/patterns/screen-layout.md +40 -0
- package/dist/guidance/patterns/settings.json +78 -0
- package/dist/guidance/patterns/settings.md +32 -0
- package/dist/guidance/patterns/sync.json +77 -0
- package/dist/guidance/patterns/sync.md +31 -0
- package/dist/guidance/principles.md +23 -0
- package/dist/guidance/references/build/checks/agent-action-pattern.mjs +57 -0
- package/dist/guidance/references/build/checks/agent-setup.mjs +78 -0
- package/dist/guidance/references/build/checks/assistant-conversation-pattern.mjs +49 -0
- package/dist/guidance/references/build/checks/audit-log-pattern.mjs +63 -0
- package/dist/guidance/references/build/checks/auth-pattern.mjs +67 -0
- package/dist/guidance/references/build/checks/billing-pattern.mjs +63 -0
- package/dist/guidance/references/build/checks/developer-settings-pattern.mjs +76 -0
- package/dist/guidance/references/build/checks/guidance.mjs +71 -0
- package/dist/guidance/references/build/checks/import-pattern.mjs +69 -0
- package/dist/guidance/references/build/checks/members-pattern.mjs +71 -0
- package/dist/guidance/references/build/checks/onboarding-pattern.mjs +54 -0
- package/dist/guidance/references/build/checks/pattern-types.mjs +13 -0
- package/dist/guidance/references/build/checks/pattern-workflows.mjs +226 -0
- package/dist/guidance/references/build/checks/primary-scope.mjs +49 -0
- package/dist/guidance/references/build/checks/render-tells.mjs +72 -0
- package/dist/guidance/references/build/checks/screen-layout-pattern.mjs +111 -0
- package/dist/guidance/references/build/checks/semantics.mjs +72 -0
- package/dist/guidance/references/build/checks/settings-pattern.mjs +73 -0
- package/dist/guidance/references/build/checks/sync-pattern.mjs +62 -0
- package/dist/guidance/references/build/checks/tells-lint.mjs +164 -0
- package/dist/guidance/references/build/fixtures/pattern-workflows.tsx +83 -0
- package/dist/guidance/references/build/fixtures/patterns/agent-action.jsx +60 -0
- package/dist/guidance/references/build/fixtures/patterns/app-skeleton.jsx +94 -0
- package/dist/guidance/references/build/fixtures/patterns/assistant-conversation.jsx +79 -0
- package/dist/guidance/references/build/fixtures/patterns/audit-log.jsx +81 -0
- package/dist/guidance/references/build/fixtures/patterns/auth.jsx +150 -0
- package/dist/guidance/references/build/fixtures/patterns/billing.jsx +96 -0
- package/dist/guidance/references/build/fixtures/patterns/developer-settings.jsx +95 -0
- package/dist/guidance/references/build/fixtures/patterns/import.jsx +102 -0
- package/dist/guidance/references/build/fixtures/patterns/members.jsx +106 -0
- package/dist/guidance/references/build/fixtures/patterns/onboarding.jsx +70 -0
- package/dist/guidance/references/build/fixtures/patterns/screen-layout-decision.jsx +74 -0
- package/dist/guidance/references/build/fixtures/patterns/screen-layout-editor.jsx +56 -0
- package/dist/guidance/references/build/fixtures/patterns/screen-layout-report.jsx +42 -0
- package/dist/guidance/references/build/fixtures/patterns/settings.jsx +73 -0
- package/dist/guidance/references/build/fixtures/patterns/sync.jsx +78 -0
- package/dist/guidance/references/project/components/src/pattern-async-collection.tsx +57 -0
- package/dist/guidance/references/project/components/src/pattern-consequential-action.tsx +77 -0
- package/dist/guidance/references/project/components/src/pattern-edit-record.tsx +127 -0
- package/dist/guidance/references/project/components/src/pattern-review-submit.tsx +47 -0
- package/dist/guidance/references/project/components/src/settings.tsx +79 -0
- package/dist/guidance/references/scripts/build-framework-fixture.mjs +20 -0
- package/dist/guidance/rules.json +653 -0
- package/dist/guidance/visual/Elevation.md +194 -0
- package/dist/guidance/visual/Fundamentals.md +83 -0
- package/dist/guidance/visual/Research.md +1620 -0
- package/dist/index.cjs +18792 -1925
- package/dist/index.cjs.map +4 -4
- package/dist/index.js +18792 -1925
- package/dist/index.js.map +4 -4
- package/dist/tokens.css +84 -84
- package/dist/tokens.json +301 -128
- package/dist/types/adapter-codemirror.d.ts +13 -0
- package/dist/types/agent-fleet.d.ts +166 -0
- package/dist/types/ai-label.d.ts +30 -0
- package/dist/types/app-shell.d.ts +83 -0
- package/dist/types/area-chart.d.ts +80 -0
- package/dist/types/artifact.d.ts +65 -0
- package/dist/types/bar-chart.d.ts +83 -0
- package/dist/types/bar-list.d.ts +35 -0
- package/dist/types/breadcrumb.d.ts +62 -0
- package/dist/types/chart-brush.d.ts +35 -0
- package/dist/types/chart-themes.d.ts +229 -0
- package/dist/types/chart.d.ts +570 -0
- package/dist/types/checklist.d.ts +71 -0
- package/dist/types/code-block.d.ts +32 -0
- package/dist/types/collections.d.ts +111 -4
- package/dist/types/color-picker.d.ts +38 -0
- package/dist/types/command.d.ts +6 -3
- package/dist/types/comment-thread.d.ts +48 -0
- package/dist/types/confirmation.d.ts +60 -0
- package/dist/types/context-menu.d.ts +17 -0
- package/dist/types/controls.d.ts +100 -17
- package/dist/types/conversation.d.ts +130 -0
- package/dist/types/copy-button.d.ts +19 -0
- package/dist/types/core.d.ts +139 -10
- package/dist/types/data-grid.d.ts +76 -0
- package/dist/types/date-picker.d.ts +96 -0
- package/dist/types/diff-view.d.ts +54 -0
- package/dist/types/dot-plot.d.ts +54 -0
- package/dist/types/edit-region.d.ts +121 -0
- package/dist/types/feature-gate.d.ts +22 -0
- package/dist/types/filter-bar.d.ts +65 -0
- package/dist/types/formatted-number.d.ts +38 -0
- package/dist/types/heatmap.d.ts +64 -0
- package/dist/types/in-place.d.ts +24 -0
- package/dist/types/index.d.ts +158 -15
- package/dist/types/inline-citation.d.ts +35 -0
- package/dist/types/inline-edit.d.ts +71 -0
- package/dist/types/input-otp.d.ts +37 -0
- package/dist/types/item-group.d.ts +104 -0
- package/dist/types/line-chart.d.ts +116 -0
- package/dist/types/link.d.ts +11 -0
- package/dist/types/markdown.d.ts +88 -0
- package/dist/types/meter.d.ts +43 -0
- package/dist/types/modal-state.d.ts +62 -0
- package/dist/types/nav.d.ts +8 -1
- package/dist/types/notifications.d.ts +42 -0
- package/dist/types/number-input.d.ts +30 -0
- package/dist/types/overlays.d.ts +51 -17
- package/dist/types/page-header.d.ts +27 -0
- package/dist/types/pagination.d.ts +29 -0
- package/dist/types/palette.d.ts +64 -0
- package/dist/types/password-input.d.ts +22 -0
- package/dist/types/pattern-assistant-conversation.d.ts +55 -0
- package/dist/types/pattern-async-collection.d.ts +34 -0
- package/dist/types/pattern-consequential-action.d.ts +53 -0
- package/dist/types/pattern-edit-record.d.ts +72 -0
- package/dist/types/pattern-review-submit.d.ts +43 -0
- package/dist/types/permission-matrix.d.ts +34 -0
- package/dist/types/plan-picker.d.ts +40 -0
- package/dist/types/prompt-input.d.ts +106 -0
- package/dist/types/property-list.d.ts +67 -0
- package/dist/types/question.d.ts +64 -0
- package/dist/types/relative-time.d.ts +21 -0
- package/dist/types/removal-receipt.d.ts +1180 -0
- package/dist/types/resizable.d.ts +48 -0
- package/dist/types/roving.d.ts +44 -0
- package/dist/types/save-bar.d.ts +38 -0
- package/dist/types/saved-views.d.ts +72 -0
- package/dist/types/scatter-chart.d.ts +60 -0
- package/dist/types/schedule.d.ts +80 -0
- package/dist/types/secret-field.d.ts +33 -0
- package/dist/types/select.d.ts +44 -2
- package/dist/types/separator.d.ts +11 -0
- package/dist/types/settings.d.ts +39 -0
- package/dist/types/sheet.d.ts +1 -1
- package/dist/types/sparkline.d.ts +46 -0
- package/dist/types/split-button.d.ts +21 -0
- package/dist/types/stat.d.ts +54 -0
- package/dist/types/stepper.d.ts +6 -3
- package/dist/types/suggestions.d.ts +29 -0
- package/dist/types/suspense.d.ts +12 -1
- package/dist/types/sync-indicator.d.ts +24 -0
- package/dist/types/tag-input.d.ts +65 -0
- package/dist/types/terminal.d.ts +33 -0
- package/dist/types/thread-list.d.ts +58 -0
- package/dist/types/time-input.d.ts +33 -0
- package/dist/types/timeline.d.ts +38 -0
- package/dist/types/toggle.d.ts +46 -0
- package/dist/types/toolbar.d.ts +34 -0
- package/dist/types/tour.d.ts +23 -0
- package/dist/types/trace.d.ts +65 -0
- package/dist/types/tree.d.ts +71 -0
- package/dist/types-cjs/adapter-codemirror.d.cts +13 -0
- package/dist/types-cjs/agent-fleet.d.cts +166 -0
- package/dist/types-cjs/ai-label.d.cts +30 -0
- package/dist/types-cjs/app-shell.d.cts +83 -0
- package/dist/types-cjs/area-chart.d.cts +80 -0
- package/dist/types-cjs/artifact.d.cts +65 -0
- package/dist/types-cjs/bar-chart.d.cts +83 -0
- package/dist/types-cjs/bar-list.d.cts +35 -0
- package/dist/types-cjs/breadcrumb.d.cts +62 -0
- package/dist/types-cjs/chart-brush.d.cts +35 -0
- package/dist/types-cjs/chart-themes.d.cts +229 -0
- package/dist/types-cjs/chart.d.cts +570 -0
- package/dist/types-cjs/checklist.d.cts +71 -0
- package/dist/types-cjs/code-block.d.cts +32 -0
- package/dist/types-cjs/collections.d.cts +246 -0
- package/dist/types-cjs/color-picker.d.cts +38 -0
- package/dist/types-cjs/command.d.cts +66 -0
- package/dist/types-cjs/comment-thread.d.cts +48 -0
- package/dist/types-cjs/confirmation.d.cts +60 -0
- package/dist/types-cjs/context-menu.d.cts +17 -0
- package/dist/types-cjs/controls.d.cts +360 -0
- package/dist/types-cjs/conversation.d.cts +130 -0
- package/dist/types-cjs/copy-button.d.cts +19 -0
- package/dist/types-cjs/core.d.cts +256 -0
- package/dist/types-cjs/data-grid.d.cts +76 -0
- package/dist/types-cjs/date-picker.d.cts +96 -0
- package/dist/types-cjs/diff-view.d.cts +54 -0
- package/dist/types-cjs/dot-plot.d.cts +54 -0
- package/dist/types-cjs/edit-region.d.cts +121 -0
- package/dist/types-cjs/empty.d.cts +24 -0
- package/dist/types-cjs/feature-gate.d.cts +22 -0
- package/dist/types-cjs/filter-bar.d.cts +65 -0
- package/dist/types-cjs/formatted-number.d.cts +38 -0
- package/dist/types-cjs/heatmap.d.cts +64 -0
- package/dist/types-cjs/in-place.d.cts +24 -0
- package/dist/types-cjs/index.d.cts +154 -0
- package/dist/types-cjs/inline-citation.d.cts +35 -0
- package/dist/types-cjs/inline-edit.d.cts +71 -0
- package/dist/types-cjs/input-otp.d.cts +37 -0
- package/dist/types-cjs/item-group.d.cts +104 -0
- package/dist/types-cjs/line-chart.d.cts +116 -0
- package/dist/types-cjs/link.d.cts +11 -0
- package/dist/types-cjs/markdown.d.cts +88 -0
- package/dist/types-cjs/meter.d.cts +43 -0
- package/dist/types-cjs/modal-state.d.cts +62 -0
- package/dist/types-cjs/nav.d.cts +25 -0
- package/dist/types-cjs/notifications.d.cts +42 -0
- package/dist/types-cjs/number-input.d.cts +30 -0
- package/dist/types-cjs/overlays.d.cts +170 -0
- package/dist/types-cjs/page-header.d.cts +27 -0
- package/dist/types-cjs/pagination.d.cts +29 -0
- package/dist/types-cjs/palette.d.cts +64 -0
- package/dist/types-cjs/password-input.d.cts +22 -0
- package/dist/types-cjs/pattern-assistant-conversation.d.cts +55 -0
- package/dist/types-cjs/pattern-async-collection.d.cts +34 -0
- package/dist/types-cjs/pattern-consequential-action.d.cts +53 -0
- package/dist/types-cjs/pattern-edit-record.d.cts +72 -0
- package/dist/types-cjs/pattern-review-submit.d.cts +43 -0
- package/dist/types-cjs/permission-matrix.d.cts +34 -0
- package/dist/types-cjs/pile.d.cts +27 -0
- package/dist/types-cjs/plan-picker.d.cts +40 -0
- package/dist/types-cjs/prompt-input.d.cts +106 -0
- package/dist/types-cjs/property-list.d.cts +67 -0
- package/dist/types-cjs/question.d.cts +64 -0
- package/dist/types-cjs/relative-time.d.cts +21 -0
- package/dist/types-cjs/removal-receipt.d.cts +1180 -0
- package/dist/types-cjs/resizable.d.cts +48 -0
- package/dist/types-cjs/roving.d.cts +44 -0
- package/dist/types-cjs/save-bar.d.cts +38 -0
- package/dist/types-cjs/saved-views.d.cts +72 -0
- package/dist/types-cjs/scatter-chart.d.cts +60 -0
- package/dist/types-cjs/schedule.d.cts +80 -0
- package/dist/types-cjs/secret-field.d.cts +33 -0
- package/dist/types-cjs/select.d.cts +109 -0
- package/dist/types-cjs/separator.d.cts +11 -0
- package/dist/types-cjs/settings.d.cts +39 -0
- package/dist/types-cjs/sheet.d.cts +27 -0
- package/dist/types-cjs/sparkline.d.cts +46 -0
- package/dist/types-cjs/split-button.d.cts +21 -0
- package/dist/types-cjs/stat.d.cts +54 -0
- package/dist/types-cjs/stepper.d.cts +26 -0
- package/dist/types-cjs/suggestions.d.cts +29 -0
- package/dist/types-cjs/suspense.d.cts +85 -0
- package/dist/types-cjs/sync-indicator.d.cts +24 -0
- package/dist/types-cjs/tag-input.d.cts +65 -0
- package/dist/types-cjs/terminal.d.cts +33 -0
- package/dist/types-cjs/thread-list.d.cts +58 -0
- package/dist/types-cjs/time-input.d.cts +33 -0
- package/dist/types-cjs/timeline.d.cts +38 -0
- package/dist/types-cjs/toggle.d.cts +46 -0
- package/dist/types-cjs/toolbar.d.cts +34 -0
- package/dist/types-cjs/tour.d.cts +23 -0
- package/dist/types-cjs/trace.d.cts +65 -0
- package/dist/types-cjs/tree.d.cts +71 -0
- package/package.json +89 -9
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# Elevation
|
|
2
|
+
|
|
3
|
+
Elevation in Altitude is not decoration. It's a channel of information with one consistent meaning, so a person can read it without being taught.
|
|
4
|
+
|
|
5
|
+
## The model: the ground is the record
|
|
6
|
+
|
|
7
|
+
- **Ground (level 0) is what's settled**: committed content, the page, the record. It doesn't move.
|
|
8
|
+
- **Above the ground is what's live.** Anything raised is in play right now: something you can press, something in your hand, something waiting to be confirmed, something that just arrived, something asking for attention. The higher it sits, the more temporary it is and the more it claims you: a button < a menu < a toast < a dialog.
|
|
9
|
+
- **Below the ground is an opening.** Anything sunk is waiting to receive something: a field to type into, a slot to drop into, a track for a thumb, or a problem to fill in (an invalid field).
|
|
10
|
+
|
|
11
|
+
Every signal on this page is a case of that one idea. When a new component needs elevation, ask which of the three it is: settled, live, or an opening.
|
|
12
|
+
|
|
13
|
+
## Four tiers you can read, eight levels you can feel
|
|
14
|
+
|
|
15
|
+
People reliably tell apart only a few depth categories at a glance; measured in Altitude's own rendering, adjacent levels in the same tier can differ by less than one just-noticeable difference (see **Research**, E1). So meaning lives in **tiers**, and the finer **levels** are for motion: a one-level climb on hover is felt even when the two levels couldn't be told apart side by side.
|
|
16
|
+
|
|
17
|
+
| Tier | Levels | Surface · shadow | Means |
|
|
18
|
+
|---|---|---|---|
|
|
19
|
+
| **Sunk** | −2 trench, −1 well | `surface-trench`/`trench`, `surface-well`/`well` | An opening: fill it, drop into it, slide along it. |
|
|
20
|
+
| **Ground** | 0 | `surface-ground`, `elev-0` | Settled. Read it. Badges, alerts, ghost buttons, skeletons, disabled and pressed controls. |
|
|
21
|
+
| **Raised** | 1 raised, 2 lifted | `surface-raised`/`elev-1`, `surface-lifted`/`elev-2` | Live in the page: cards, buttons, thumbs, the selected option. Level 2 is the primary action and the hover state. |
|
|
22
|
+
| **Floating** | 3 floating, 4 overlay, 5 modal | `surface-floating`/`elev-3` … `surface-modal`/`elev-5` | Above the page: menus, tooltips, things in your hand, toasts, the dialog. |
|
|
23
|
+
|
|
24
|
+
Rules that follow:
|
|
25
|
+
|
|
26
|
+
- Never give two things different meanings by putting them one level apart within a tier. If they must read differently, put them in different tiers, or add a word.
|
|
27
|
+
- Never encode an amount in height. A pile's thickness is three bins; the number goes in its badge. In a chart, amounts are length and position on a flat plot (see [Charts](Charts.md)).
|
|
28
|
+
- Use `Surface level={n}` to place anything. Never pair one level's surface with another level's shadow.
|
|
29
|
+
|
|
30
|
+
## How a level is drawn
|
|
31
|
+
|
|
32
|
+
- **Cast shadow.** Each level is four layers: a top rim, a hairline ring, a key shadow and an ambient shadow. Offset and blur grow with height, because displacement is what reads as height. The structure never changes, so any level animates into any other.
|
|
33
|
+
- **The hairline fades as you climb**; the cast shadow takes over the separating.
|
|
34
|
+
- **Tonal lift in dark schemes.** Shadows barely show on dark grounds, so in Nightfall each level is also a step lighter. Shadows are always darker than the ground; height is never drawn with a light glow.
|
|
35
|
+
- **One camera.** Everything is seen from slightly in front of and above the page. Under a raised face you see its front wall; inside an opening you see its back wall, just below the top edge. Buttons and steps show the first; empty fields and the accordion's compartment show the second.
|
|
36
|
+
- **Visible thickness.** Pressable things (buttons, keys, breadcrumb steps) show their height as a wall under the face: `wall-1` (2px) at level 1, `wall-2` (4px) at level 2, 1px more on hover, none when pressed. It's the same cue as the cast shadow, displacement read as height, made solid.
|
|
37
|
+
- **Shading polarity.** Pressable things carry `--alt-sheen`, a 2–5 L* light-to-dark face gradient (convex), and wells carry a dark top edge (concave). That polarity is the cue the visual system reads before attention; pressing flattens the sheen.
|
|
38
|
+
- **Detached shadows.** A disc that leaves the page (a live avatar) casts its own shadow on the ground beneath it; the gap between them, and how small and faint the shadow gets, is the height. A contact shadow reads as resting and a detached one as floating, and moving a shadow alone is enough to make people see an object rise (Kersten et al., see **Research**).
|
|
39
|
+
- **One light, straight above.** Shadows fall only downward, so layouts mirror cleanly for right-to-left languages.
|
|
40
|
+
|
|
41
|
+
## What height tells you
|
|
42
|
+
|
|
43
|
+
| Signal | Encoding | Where |
|
|
44
|
+
|---|---|---|
|
|
45
|
+
| **Importance** | primary 2 · secondary 1 · ghost 0, drawn as wall thickness (4px, 2px, none); a page header has one slot for the primary | `Button`, `PageHeader` |
|
|
46
|
+
| **Affordance** | raised + wall + sheen = press it; sunk = fill it | every control |
|
|
47
|
+
| **Interactivity** | only things that act lift on hover | `Card interactive`, `Surface interactive` |
|
|
48
|
+
| **Selection** | every choice is built like the Switch: off is an empty trench; on pours the accent in and sets a raised white mark on it (the switch and radio thumb, the checkbox's check). A radio group is one switch with several positions, so its single thumb slides to the chosen option. In folder tabs the chosen tab and its panel are one raised sheet on top of the others | `Switch`, `Checkbox`, `RadioGroup`, `Tabs`, the chosen day in `Calendar`, the chosen swatch in `ColorPicker`, the current page in `Pagination`, the chosen plan in `PlanPicker` (whose current and recommended plans are plates, not height) |
|
|
49
|
+
| **Presence** | people who are here rest on the page at level 1 (a filled lamp when active, an empty ring when idle); offline people are plates flush in the page, grey; someone live lifts off their shadow and drifts | `Avatar` |
|
|
50
|
+
| **Loading** | content to come is an imprint pressed into the page; it rises out of the imprint when it lands. Components whose content is still undefined (or a promise) draw their own imprint, at their own size, from their own Suspense boundary. Under `loading="breath"` (experimental) the imprint breathes in depth instead of being swept by light, raised content rises a level past its rest and settles, and flush content fills past the ground | `Skeleton`, `Await` (Suspense-native `Avatar`, `Badge`, `Card`, `DataTable`) |
|
|
51
|
+
| **Status** | status that informs is a tinted sheet resting on the page (paper edge, contact shadow); status that asks for action is a raised card; dismissing lifts the sheet off; several make a stack whose peeking sheets show their tones; a page banner is the same sheet laid edge to edge across the top | `Alert`, `AlertStack` (`placement="page"`) |
|
|
52
|
+
| **Labels** | a label is part of the record: an indicator plate set flush into the page, with a lamp for status that relights when it changes; only a count, which wants your attention, floats; an AI label is a plate too, never a glow, and lifts because it opens its explanation | `Badge`, `Tag`, `TagInput`, `AILabel`, `InlineCitation` |
|
|
53
|
+
| **Code** | code to read and copy is the record: flush with a `line` rim, mono, no shadow; highlighted lines are `accent-soft` bands; code still arriving has a dashed rule and says "Writing…" | `CodeBlock` |
|
|
54
|
+
| **A saved view** | views are folder tabs whose active tab is one raised sheet with the table; a changed view is a draft: a dot and "modified" on its tab, with Save view, Save as new view and Reset beside the tabs | `SavedViews` |
|
|
55
|
+
| **A change between versions** | both versions are the record: flush with a `line` rim; additions are `positive-soft` with `+` and "Added", removals `critical-soft`, struck through, with `−` and "Removed"; never colour alone | `DiffView` |
|
|
56
|
+
| **A divider** | a divider is part of the page: 1px of `line` on the ground with no shadow or wall, never `line-control`; a word between two lines ("or") is read, its lines are drawn | `Separator`, `ItemSeparator` |
|
|
57
|
+
| **Navigation in text** | a link is text in the record and never lifts, since lifting a word would break its line: `accent-ink` with an underline that thickens on hover, the focus ring, and an icon plus "(opens in a new tab)" when it leaves the app | `Link` |
|
|
58
|
+
| **Latched** | a button that stays on is a choice: on, its face is cut into a shallow well with `accent-soft` poured in and its label in `accent-ink`; off is the ghost or secondary slab it started as; pointing at an on toggle previews off. One choice among several is segmented Tabs without panels | `Toggle`, `ToggleGroup` |
|
|
59
|
+
| **Disclosure** | closed sections are lids flush on the page; opening one lifts the lid into a card and reveals a compartment sunk into it; a table row's read-only detail opens flush beneath it instead, because a row can't lift into a card without breaking the columns | `Accordion`, `DataTable` |
|
|
60
|
+
| **Editing in place** | a value being edited stays where it is while its well opens around it; a record being edited lifts into a static raised card whose padding was already there, so it rises without moving, with its neighbours still in view; the write hovers while pending, drops to a trench on failure, and the accepted values settle back with one afterglow | `InlineEdit`, `EditRegion`, a `BoardCard` renamed or edited in place, a `DataTable` row and its region rising as one slab |
|
|
61
|
+
| **Completeness** | an empty field is a hole cut into the page, its back wall showing; once it holds a value the floor rises flush, so a form shows which fields still need filling. A select fills when a value is chosen; a combobox too, because a typed query isn't a value; a date field when it holds a whole date, not a partial one, and a time field when it holds a whole time. A textarea with a limit fills from the floor as it nears it; a tag field fills with its first tag | `Input`, `Textarea`, `Select`, `Combobox`, `TagInput`, `DatePicker`, `TimeInput`, `PromptInput`; per character in `InputOTP` |
|
|
62
|
+
| **A span** | a chosen range is a sunk track between two raised ends: in a range Slider, two thumbs with the raised fill between them, the fill lifting on hover because dragging it moves both; in a DateRangePicker, the same build laid across the weeks, the track previewing to the day under the pointer while the end is being chosen | `Slider` (a range), `DateRangePicker` |
|
|
63
|
+
| **An unsaved draft at page scope** | the draft is in your hand: a bar floating at level 3 at the bottom edge, once a change has settled; saving hovers as pending, saved lowers it away as the fields settle, a failed save drops it to a trench and keeps the draft | `SaveBar` |
|
|
64
|
+
| **Editing in a list** | one slat at a time is lifted into its editor while its neighbours stay flush and readable; the add slat is an opening at the end of the list | `ItemGroup` |
|
|
65
|
+
| **Pressables in an opening** | a number field is a well that fills, and its steppers are small raised slabs in its end cap because you press them; at a limit a stepper lies flush and faint | `NumberInput` |
|
|
66
|
+
| **Something to take away** | a secret shown once is an opening (a sunk well, though it holds text) with copy beside it, until you confirm you've saved it; then it fills flush and masks to its tail, settled in the record; revoking it is held | `SecretField` |
|
|
67
|
+
| **Validity** | an invalid field sinks to trench depth on `critical-soft` | `Input`, `Select`, `Combobox`, `Field` |
|
|
68
|
+
| **The record, in rows** | a table's rows lie flush; selected rows are tinted and raised one level, interactive rows lift on hover, matches rise and misses sink when filtering in place, and a row in hand floats at level 3 over the slot it will land in | `Table`, `Tree` |
|
|
69
|
+
| **The record, in cells** | in a grid, a cell being edited opens into a well in its flush row; when the value lands the floor rises flush and settles; the active cell is a ring and a range a tint, never a height | `DataGrid` |
|
|
70
|
+
| **Who can do what** | a grid on the ground; editable grants are Checkboxes; inherited and fixed grants are flush stamped checks, decided rather than disabled; the active cell is a ring | `PermissionMatrix` |
|
|
71
|
+
| **Send becomes Stop** | while an agent is generating, the composer's level-2 Send becomes Stop in the same slot and size, held as the live action; nothing moves | `PromptInput` |
|
|
72
|
+
| **Receptacles** | a board's columns are flush at rest and open into wells only while a card is carried; the one under the card deepens to a trench; a collapsed column is a pile that still takes drops | `Board` |
|
|
73
|
+
| **Progress** | the steps of a process are plates on one ground line: done steps are flush in the record with a stamped check, the current one stands raised on its wall, steps to come are imprints; advancing presses one down and raises the next out of its imprint; an agent's steps read the same way, with a failed step in a trench and no spinners | `Stepper`, `Trace` |
|
|
74
|
+
| **A history** | events stand on a ground line turned upright, flush entries stamped onto it; a new event arrives lifted and settles; one you caused hovers until it lands or drops to a trench with Retry; one that links lifts when pointed at | `Timeline` |
|
|
75
|
+
| **Done is pressed into the record** | checking an item stamps it like a completed step: muted, struck through, and kept in place in the record rather than removed; a resolved comment thread is stamped the same way, collapsed to one line | `Checklist`, a resolved `CommentThread` |
|
|
76
|
+
| **A condition** | a filter is a segmented plate stamped into the bar; each segment lifts when pointed at because it opens a picker, and a condition still waiting for its value keeps that segment as an opening; a group of conditions is a flush 1px `line-control` bracket with its own all/any | `FilterBar` |
|
|
77
|
+
| **A span being drawn** | dragging across empty time draws a well the length of the new event, which rises into an event to be named when released; while an event is carried, time opens and the slot under it deepens to a trench as long as the event | `Schedule` |
|
|
78
|
+
| **Properties of a record** | a record's properties lie on the ground; an editable value is one plate that lifts when pointed at, a read-only one never does, and an unset value is a small opening naming what to add | `PropertyList` |
|
|
79
|
+
| **Recency** | new or changed content arrives tinted and lifted, then settles to rest over `dur-settle` (afterglow) | `settle` on `Surface`, `Card`. A chart read against a snapshot (`since` on `ChartContainer`) gives what changed while you were away the same afterglow on arrival, up to four marks (more, and the "3 changed since …" caption takes it); after that a flat tick or hollow ring at the old value and the words remain |
|
|
80
|
+
| **Commitment** | a pending write hovers (after `dur-grace`), a confirmed one lands, a failed one drops into a trench | `status` on `Surface`, `Card`; for the whole app or document, a `SyncIndicator` plate whose lamp relights |
|
|
81
|
+
| **Proposed** | an action an agent proposes isn't dispatched, so it's raised (status that asks for action), never pending; approving makes it a pending write that hovers, then lands or fails; rejected stays flush and muted in the record | `Confirmation` |
|
|
82
|
+
| **Suggested** | a value proposed for a field is a ghost of the value in `ink-faint`, never in the value, so an empty field with a ghost stays an opening; Tab accepts and the floor rises with one afterglow | `suggestion` on `Input`, `Textarea` |
|
|
83
|
+
| **Proposed changes to a record** | a field with a proposed value is raised, the current value struck beside the proposed one; nothing is saved until it's accepted, then it hovers as pending and settles | `proposed` on `PropertyListItem` |
|
|
84
|
+
| **Streaming** | an answer still arriving isn't the record yet and isn't a pending write (nothing you sent is in flight), so it rests on the ground with a dashed rule, "Generating…" and a caret; when it completes the rule goes solid and it settles once | `Message` in a `Conversation` |
|
|
85
|
+
| **An answer's text** | Markdown is the record's typography and adds no height: prose, headings, lists, inline code (a 1px rim), tables (flush rows) and quotes (a 2px rule) all sit on the ground; fenced code is `CodeBlock`, `[n]` is `InlineCitation`, the only part that lifts; an image rises out of a sunk imprint; while streaming, an open fence writes on a dashed rule and a half-received table row isn't drawn | `Markdown` |
|
|
86
|
+
| **What went with a message** | a sent attachment was uploaded before the message went, so it's part of the record and never pending: images are 64px thumbnails in a 1px rim, other files the composer's Tag plates, settled, with type and size; one that opens lifts a level when pointed at, as any plate that acts; an expired one says "No longer available" | `MessageAttachments` |
|
|
87
|
+
| **Editing a sent message** | the person's message opens in place as a Textarea well (sunk) inside its sheet; editing is local input, not a pending write, so nothing hovers; "Send edit" is secondary, leaving the composer's Send the view's one primary; once sent the message is flush again with "Edited" and "Version 2 of 2", and the earlier branch is kept | `MessageActions onEdit`, `Message edited` |
|
|
88
|
+
| **A queued message** | written while the agent works but not dispatched, so it doesn't hover (pending is for a write in flight): the person's accent-soft sheet on the ground with a dashed `line-control` rim, "Queued · 1 of 2", between the thread and the composer; sent, it becomes an ordinary message in the log | `ConversationQueue`, `PromptInput onQueue` |
|
|
89
|
+
| **A checkpoint** | a divider with a word between its lines ("Checkpoint · Before editing 6 files · 2:14 PM") on the ground; Restore is a ghost button; while restoring the label hovers as pending, restored it settles once ("Restored", with "Return to where you were" when there's real recovery), and a failure sinks into a trench with Retry | `ConversationCheckpoint` |
|
|
90
|
+
| **Suggestions** | prompts to start from or follow up with are affordances: small secondary buttons at level 1 with their wall, lifting to 2 when pointed at, never the view's level-2 primary (the composer's Send); starters sit in an EmptyState, follow-ups under the answer, and follow-ups cross-fade in rather than rise | `Suggestions` |
|
|
91
|
+
| **Subagents** | Stepper has one current step; in parallel several are live at once, and each is raised on its wall because each is in play: the same meaning several times, with a word carrying the count ("3 in parallel · 2 of 3 done") in a group with a 1px `line-control` bracket; a nested run sits behind an Accordion lid that says how it's going | `TraceParallel`, nested `Trace` |
|
|
92
|
+
| **Reasoning still arriving** | not yet the record, like a streaming answer: on the ground under a dashed `line-control` rule with "Thinking…" on its lid, never lifted or glowing, no shimmer or ticking counter; complete it's "Thought for 12s"; redacted reasoning is said flush, with no lid | `TraceReasoning status` |
|
|
93
|
+
| **A command running** | CodeBlock's flush frame with a process's states: running isn't the record yet (a dashed `line-control` rule, "Running", Stop at level 1); finished, the rule goes solid with one afterglow and the exit is said ("Exited with 1 · 4.2s", a critical rule when non-zero); stderr lines carry a critical mark; "Jump to latest output" floats at 3 | `Terminal` |
|
|
94
|
+
| **A question from the agent** | Confirmation's raised card asking for an answer instead of approval: nothing is dispatched, so it's raised, not pending; options are trenches, your own answer a well, Answer the one primary; answered it presses to the ground as one muted line ("You chose: Staging") | `Question`, `QuestionSet` |
|
|
95
|
+
| **Editing a proposal** | the requested card stays raised while its fields open in place inside it (wells), as EditRegion does; an edited proposal carries an "Edited" plate by its title, and once approved it lands as before with "edited and approved by you" | `Confirmation edit` |
|
|
96
|
+
| **A change to review** | a hunk awaiting a decision is proposed, so it's raised at level 1 around its lines (PropertyList's proposed value), with Accept and Reject; deciding lowers it to the record: accepted flush with one afterglow, rejected muted and collapsed to one line | `DiffView review` |
|
|
97
|
+
| **Conversations** | a record of conversations with live rows: destinations on the ground, the current one on the raised pill; working isn't pending, so it never hovers (a lamp plate says "Working"); needing you is a caution plate and a word, because a row can't lift into a card inside a nav; unread is a dot and weight 600 | `ThreadList` |
|
|
98
|
+
| **A fleet of agents** | a roster of the agents on one job, grouped by what they need from you: rows are the record, flush, lifting when pointed at because they open; the open agent is selected (`accent-soft`, raised one level); working never hovers (a lamp plate); needing you is a caution plate and "waiting 6 min", not a lift, because the queue holds the raised card; stalled is a caution plate in the working group, a suspicion rather than a request; done is stamped with a check and folded away; a clash over a file is a flush `caution-soft` strip naming the file and the other agent; agents an agent started hang in a 1px `line-control` bracket | `AgentFleet` |
|
|
99
|
+
| **Decisions agents are waiting on** | status that asks for action: each request is a raised card (level 1) that arrives lifted and settles, oldest first; nothing has been dispatched, so nothing hovers; its answers are secondary and ghost, so the view keeps one primary; nothing waiting is said flush with a check, because an all-clear is settled, not an opening | `AgentRequests` |
|
|
100
|
+
| **Where agents' time went** | a chart, so nothing has height: each agent's working, waiting-on-you (hatched `caution`), waiting-on-another-agent (dashed outline) and failed time are equal flat bars on its lane, named in a key in words; a 1px `line-control` "Now" rule ends the record; the takeaway leads with the time agents waited on you | `AgentLanes` |
|
|
101
|
+
| **What the agent is making** | a pane on the ground beside the conversation; being written isn't the record yet (a dashed rule at its edge, "Writing… version 3"), complete goes solid with one afterglow; viewing an earlier version is a mode, so a flush strip with words, not a lift; the reference in a message is a plate that acts | `Artifact` |
|
|
102
|
+
| **Pointing the agent at things** | the @ and / list floats at level 3 like Combobox's, rising above the composer, grouped with headings; a chosen mention or command is a flush plate in the composer's context row, its "@label" kept in the text | `PromptInput mentionable`, `commands` |
|
|
103
|
+
| **Dictating** | listening is latched, a Toggle's "on" (a shallow well with accent-soft), with a steady lamp and "Listening": no pulse, no waveform, no level meter in height; interim words are a ghost in `ink-faint`, like a suggestion, so the field stays an opening until they're final | `PromptInputDictate` |
|
|
104
|
+
| **Possession** | whatever is in a hand floats at level 3, tilted; a collaborator's hold wears their `presence-*` colour and name | `heldBy`, `SortableList`, `BoardCard heldBy`, a held `ResizableHandle` grip, a `DataTable` selection's floating action bar |
|
|
105
|
+
| **Readiness to receive** | receptacles open (sink) only while something could be dropped into them, and deepen under the pointer | `DropZone` (its queued files: uploading in a Progress trench, processing hovering, done settling, failed in a trench), the slot in `SortableList`, a slot or a node to drop into in `Tree` |
|
|
106
|
+
| **Emptiness** | a region with nothing in it yet is an opening, a well with a dashed rim that the first record will fill; pointing at its action deepens it to a trench | `EmptyState` |
|
|
107
|
+
| **Relevance** | filtering lifts matches and sinks misses instead of removing them, so positions survive | `relevance` on `Surface`, `Card`, `TableRow`, driven by `FilterBar` |
|
|
108
|
+
| **Overflow** | edges curve away where content continues; a header rises when content passes under it | `ScrollArea`, a sticky `PageHeader` |
|
|
109
|
+
| **Quantity** | a group shows 0–3 sheets beneath it (2–3, 4–9, 10+ items), with the exact number in a badge; hovering it fans the sheets a little; click it and its items fan out from under the top card, each its own card, floating over the page below without moving anything | `Pile` |
|
|
110
|
+
| **Where you are** | the app's frame lies on the ground (sidebar, top bar and page divided by `line`); destinations lift when pointed at, the current one sits on a raised pill that glides between them, only a count floats; collapsing to a rail changes width, not level; the top bar rises while content passes under it | `AppShell`, `Sidebar` |
|
|
111
|
+
| **Hierarchy** | a stack: going deeper lays a sheet on top, going back lifts it off; the breadcrumb is a staircase: every step stands on the same ground line, outlined face and wall together, and each deeper place is a taller step; the view sits on a pile as thick as you are deep; a route-based app's `Breadcrumb` is the same staircase without the pile | `Drilldown`, `Breadcrumb` |
|
|
112
|
+
| **Anticipation** | an opening responds before the pointer arrives: an empty field deepens to receive, and holds that depth while it's focused; a bottom sheet's finger pull opens. Raised things never anticipate: they wait until the pointer is on them | `Input`, `Textarea`, `Select`, `Combobox`, `Sheet` |
|
|
113
|
+
| **Feedforward** | hovering shows what a click will do before it does it: the ghost of the check a box would get, the radio thumb where it would land, a tab's sheet peeking up, a closed lid's ghost | `Checkbox`, `RadioGroup`, `Tabs`, `Accordion` |
|
|
114
|
+
| **A press that confirms** | copying presses the button to the ground for `dur-linger` with a check and "Copied", announced politely while it keeps its name; no rise and no afterglow, since nothing new arrived on the page | `CopyButton` |
|
|
115
|
+
| **A row of tools** | a toolbar lies on the ground and its tools are ghosts that lift when pointed at; latched tools are Toggles; what doesn't fit moves into a floating "More tools" menu, where toggles stay checkable | `Toolbar` |
|
|
116
|
+
| **An action with alternatives** | one slab with two faces sharing one wall, parted by a 1px notch; it moves as one slab: pointing at either face lifts both and pressing either presses both, so the faces never split into two heights; the face under the pointer is tinted to say which action a click takes; the alternatives float in a menu | `SplitButton` |
|
|
117
|
+
| **Consequence** | a destructive action is pushed *through* the ground: hold until it sinks to a trench; once done it lies flat and can't be pressed again | `HoldButton` |
|
|
118
|
+
| **Prediction** | likely menu items arrive first; the rest fade in over `dur-onset` | `predicted` on `DropdownMenu` and `ContextMenu` items |
|
|
119
|
+
| **The subject of a menu** | the thing right-clicked keeps its level and takes a 2px `accent-ink` outline while its menu floats at level 3, so a flush row never lifts out of its table | `ContextMenu` |
|
|
120
|
+
| **Recency of messages** | toasts sink one level per newer toast behind them | `Toaster` |
|
|
121
|
+
| **An inbox** | the bell is live and only its count floats; the panel floats at level 3; the list lies on the ground; unread is a mark (a dot and weight 600), never a height; a new notification arrives lifted and settles | `NotificationCenter` |
|
|
122
|
+
| **Focus of the moment** | the page recedes while a dialog or the command palette is at the summit; only one of them at a time | `Dialog`, `CommandPalette` with `AltitudeProvider` |
|
|
123
|
+
| **Ranking** | the best match is on top; when results change, the rows that stay are carried to their new places, and only the top few new ones rise | `CommandPalette` |
|
|
124
|
+
| **Amounts** | never height: length and position on a flat plot standing on the ground line; marks have no shadow, wall, sheen or lift, and only the chart's chrome (readout, legend toggles, brush, drill-down) uses height | every chart, drawn in `ChartContainer`: `BarChart`'s bars stand on the ground line and hang below it when negative; `LineChart`'s lines lie on the plot, and when zero isn't on its axis the plot's foot is a gridline, not ground. `AreaChart`'s bands stack on the ground line, flat and parted by 2px lines in the plot's colour, never a gradient. The readout (`ChartTooltip`) is the one floating part, at level 3; its crosshair and ringed points stay on the ground. While data loads the plot is an imprint (sunk, `surface-well`, in the chart's shape, no labels); with no data it's an `EmptyState` opening; a refetch leaves the chart on the ground at half strength. A `Sparkline` is a word-sized line or row of bars on the ground, as tall as the text beside it, with no axes, gridlines or readout. A legend that toggles (`ChartLegend`) is a row of choices built like Checkboxes: keys lift when pointed at, and each swatch is a trench the series colour fills while it's shown. A `Heatmap`'s cells lie flat in steps of the `data-seq` ramp (or `data-div` around a midpoint), parted by 2px of the plot's colour; a cell with no data is a 1px `line` outline, not a well, because it isn't waiting for anything; with no crosshair in a grid, the cell under the readout is outlined in 2px `ink`. A `ScatterChart`'s dots lie flat, at least 8px, a shape per group and a 2px ring of the plot's colour so overlapping dots stay apart; the dot under the readout is drawn again on top, whole, not raised (see [Charts](Charts.md)). A `DotPlot`'s dots are the same, on 1px `line` row guides, with no ground line when zero isn't on its axis; a spread is a flat band of the series colour at 16%, and a dumbbell joins a hollow "from" dot to a filled "to" dot with a 2px `ink-muted` link |
|
|
125
|
+
| **Focus** | what a chart is about can't rise, because its marks are amounts; it keeps its colour while everything else takes one flat neutral, and says so in words | a chart type's `focus`: the focused series or records keep their `data-*` slot, the rest are flat `data-context`, their end labels and legend keys in `ink-muted`; "Highlighted: …" leads the generated summary and each focused legend key says "highlighted"; the readout and the keyboard path list focused series first. A change of focus cross-fades fills over `dur-travel-1`. A filter's misses still recede to 35%, so context and a miss stay two readings. Under forced colours context is `GrayText` at full strength |
|
|
126
|
+
| **Read against the record before** | the earlier period is the record too, so it lies flat beside the present, quieter, and its difference is said in words | `compare` on `BarChart` (a 2px `ink` tick across each bar at its earlier value, 4px past it each side; a stack compares its total) and `LineChart` (a 1.5px solid `ink-muted` trace under the series, named at its end in `ink-muted`). The readout adds "August 2,180 · +10.6%", each point's name "Up 11% from August", the table an earlier column and a "vs" column, the summary how many rose and fell. They glide with the data; under forced colours they're solid `CanvasText`, never dotted |
|
|
127
|
+
| **A reading set down** | the readout is live, so it floats; pinned, it's a note set down on the record, so it lands on the ground like a label and settles with the afterglow | `pinnable` on `LineChart`, `BarChart` and `AreaChart`: a pinned reading is a `Badge` plate at the top of the plot (a pin icon, its words, a 1px `line-control` leader to its x), landing from level 3 to the ground over `dur-travel-3`, then the afterglow; its ghost remove button lifts one level when pointed at. Two pins say their difference under the x axis on a 1px `line-control` bracket. Each pin is a named group ("Pinned Mar 9, 2026: 38 Opened") and pinning is announced |
|
|
128
|
+
| **A menu as a sheet** | on a narrow touch screen a menu opens at the bottom edge, where the thumb is; it's the same temporary choice, so it stays at the menu's level, not a sheet's | `DropdownMenu` and `Select` with `presentation="auto"` under 640px and a coarse pointer: `surface-floating` at `elev-3`, full width less 8px, clear of the safe areas, a head with the title and Close, 44px rows, the page dimmed at half the scrim. Roles, keyboard and announcements are the menu's. `Combobox` stays under its field |
|
|
129
|
+
| **A headline number** | a number is the record, so a stat lies flush on its card or the page at no level; a changed value cross-fades and settles with the afterglow, never counting up; its change is a word and an arrow, and wears a status plate only when you say which direction is good | `Stat`, `StatGroup` |
|
|
130
|
+
| **A number in a line** | a number in a sentence or cell is the record: flush, in tabular figures, its exact value on hand when it's abbreviated; a change cross-fades and takes a ground-level tint that decays, since a word can't lift; it never counts | `FormattedNumber` |
|
|
131
|
+
| **A moment** | a timestamp is part of the record, plain text on the ground; time passing changes its words and nothing else, while a new moment takes a ground-level tint; its exact time is a Tooltip | `RelativeTime` |
|
|
132
|
+
| **A reading in a range** | a meter's reading is the record: a flush track with the reading drawn as flat ink across it, never Progress's raised fill in a trench; thresholds are notches at the rim; past them the fill turns caution or critical and the state is said in a Badge whose lamp relights; segments are flat fills parted by 2px | `Meter`, a password's strength in `PasswordInput` |
|
|
133
|
+
| **A ranked list** | rows are the record, flush with line dividers; each carries a flat tint of data-1 as long as its value against the largest, behind a label that wraps; only rows that act lift one level on hover, and their bars stay flat on them; re-ranked rows are carried, never reshuffled | `BarList` |
|
|
134
|
+
| **Marks that act** | a mark can't lift without misstating its value, so where a click selects or drills, hover is a 2px `ink` outline, a pointer and the action in the readout (height stays with the readout); marks that don't act don't respond. The selection keeps its colour and the rest recede to 35%; a drill lays the child chart on `Drilldown`'s pile | `onSelect`, `selected` and `drill` on `BarChart`, `LineChart`, `AreaChart`, `Heatmap` and `ScatterChart` |
|
|
135
|
+
| **Filtered in place** | matches keep their colour and misses recede to 35% where they stand, the axis held; marks can't rise, so a chart spends relevance as contrast only. The frame says "4 of 12 match" | `relevance` on `BarChart`, `LineChart`, `AreaChart`, `Heatmap` and `ScatterChart`; rows rise and sink in `BarList` |
|
|
136
|
+
| **Live data** | a chart's marks can't lift, so a new or changed mark's afterglow is a 2px `ink` outline that decays over `dur-settle`, with its value for the first second; a whole refresh tints the "Updated" caption on the ground instead. Pausing is a `Switch` | `live` on `ChartContainer` |
|
|
137
|
+
| **Read against** | references and annotations lie on the ground with the marks: a reference is a 1px solid `ink-muted` line (or `caution` / `critical` with its icon), a band a flat `line` fill under the marks, an annotation a `Badge` plate flush at the top of the plot, in headroom above the data, with a 1px `line-control` leader; no label or plate covers a mark. Only an annotation that acts lifts, one level, as a button | `ChartReference`, `ChartAnnotation` |
|
|
138
|
+
| **Not yet the record** | projected and incomplete data lies on the ground with the record, never raised (a pending write hovers, but a hovering bar misstates its value): bars are their colour hatched at 45° on the plot's own with no solid fill, a projection keeping its outline; lines are dashed with hollow points; areas are hatched; an uncertainty band is a flat low-opacity fill. A 1px `line-control` rule named "Today" marks where the record ends, and every mark says "So far" or "Projected" in its name, readout and table row. Under forced colours the outline is dotted, as a pending write's is | `status` on `BarChart`, `LineChart` and `AreaChart`; `band` on `LineChart` |
|
|
139
|
+
| **A window on the record** | an overview in a trench, the series a flat line in it; the chosen window a raised lens (level 1, `accent` rim, clear face) whose grips are a range Slider's thumbs, level 2 on hover and 3 held; outside it the overview recedes | `ChartBrush` |
|
|
140
|
+
| **Panes beside each other** | panes lie on the ground, parted by 1px of `line`; only the grip is live: flush at rest, lifting when pointed at, floating at level 3 while held; collapsing changes size, not level | `ResizablePanelGroup` |
|
|
141
|
+
| **A note pointing at the page** | a tour step floats at level 3 beside its target, which takes a ring; it never dims the page (receding belongs to the summit) and isn't modal | `Tour` |
|
|
142
|
+
| **A task beside the page** | a sheet is laid over the page at level 4, anchored to an edge: above menus, below the summit; it rises at its edge and is lifted off when you're done | `Sheet` |
|
|
143
|
+
|
|
144
|
+
## Rules
|
|
145
|
+
|
|
146
|
+
- **Push up, fill down.** Never style an input as raised or a button as sunk. The one exception is a toggle that's on: it's a choice, so it's built like the Switch (a shallow well the accent pours into), not like a held press, which would read as loading.
|
|
147
|
+
- **Choices are switches.** Switch, Checkbox and RadioGroup share one build: a trench track that the accent pours into when it's on, with a raised white mark on top. When only one option can be chosen there is only one mark, and it travels.
|
|
148
|
+
- **Hover is a promise.** A lift on hover means clicking does something. Static surfaces never lift; interactive ones always do.
|
|
149
|
+
- **One primary per view.** The primary action rests at level 2, and a view has one: a page, a dialog, a sheet or a popover. `AltitudeProvider devChecks` warns in development when two are visible in one view (`ALT-VISUAL-002`).
|
|
150
|
+
- **Pressing returns to ground; loading holds it there.** Disabled things are flush and stay flush. A feature locked behind a plan isn't disabled: it stays live and opens the upgrade (`FeatureGate`).
|
|
151
|
+
- **Labels never lift.** Badges are stamped into the ground and informational alerts rest on it; only an alert that asks for action is raised, and only a count (which wants you) floats.
|
|
152
|
+
- **Anticipate, don't perform.** Only openings anticipate, and only by deepening (at most 2px), only near the pointer, never for touch, and gone under reduced motion. Nothing raised moves before the pointer is on it, and nothing follows the pointer across its face: a control that drifts on its own reads as a fault. No lean, no tilt and no page-wide parallax.
|
|
153
|
+
- **One summit.** Only one thing sits at level 5: a Dialog or the CommandPalette. Never open a dialog from a dialog, and never open a sheet from either (a sheet paints beneath the summit). (Apple's Liquid Glass guidance, "avoid glass on glass", is the same rule.)
|
|
154
|
+
- **Don't stack floating on floating.** A menu inside a popover inside a sheet loses the reading of height; flatten the inner one.
|
|
155
|
+
- **Spend rises carefully.** A rising onset grabs attention. Things that merely changed state cross-fade; things that need noticing rise. Altitude staggers afterglows so no more than four begin at once.
|
|
156
|
+
- **A mode isn't a height.** When the whole app is in a mode (test mode, viewing as a customer, read-only), the ground itself is different, which height can't say. It's said in words and a border: a flush strip naming it, a frame around the viewport, and a plate in every dialog and sheet (`AltitudeProvider mode`).
|
|
157
|
+
- **Height never travels alone.** Every signal above also has a word, an icon, an ARIA state or a border, so it survives a screen reader, forced colors and low vision.
|
|
158
|
+
|
|
159
|
+
## States that don't rise
|
|
160
|
+
|
|
161
|
+
Some states feel as if they deserve height, and don't get it. They're persistent states, not live ones, and altitude is importance *right now*. Giving them height breaks "tiers carry meaning".
|
|
162
|
+
|
|
163
|
+
| State | Not | Instead |
|
|
164
|
+
|---|---|---|
|
|
165
|
+
| **Unread** | raised, or tinted until read | settles like everything else: a dot, weight 600, and "Unread" in its name (`NotificationCenter`) |
|
|
166
|
+
| **Invited, awaiting someone else** | pending (hovering) | ground, with a `Badge` "Invited". Pending is only a write you dispatched that's still in flight (#167) |
|
|
167
|
+
| **Recommended, most popular** | a lifted card | a "Recommended" plate on the ground; only its call to action is level 2 (`PlanPicker`) |
|
|
168
|
+
| **Current plan, current item** | extra height beyond selection | the word "Current" and `aria-current`; the selection build where it's a choice |
|
|
169
|
+
| **Locked behind a plan** | disabled (flush, faint) | live: it lifts on hover and opens the upgrade, with a lock and the plan's name (`FeatureGate`) |
|
|
170
|
+
| **A mode (test, viewing as someone, read-only)** | a raised banner | a word and a viewport border: `AltitudeProvider mode` |
|
|
171
|
+
| **Proposed by an agent** | pending (hovering) | raised, asking for action; pending only once approved (#153) |
|
|
172
|
+
| **Streaming text** | lifted or glowing | on the ground under the "not yet the record" rule; it settles once, when it's done (#151) |
|
|
173
|
+
|
|
174
|
+
The rule an agent can look up is `ALT-VISUAL-003` (`altitude explain ALT-VISUAL-003`).
|
|
175
|
+
|
|
176
|
+
## Accessible elevation
|
|
177
|
+
|
|
178
|
+
- **Forced colors** (Windows High Contrast) strips every shadow. Altitude falls back to borders by tier: dashed for sunk (thicker for trench), none for ground, 1px for raised, 2px for floating, double for modal; pending is dotted, failed is a thick dash.
|
|
179
|
+
- **`prefers-contrast: more`** (or `AltitudeProvider contrast="more"`) turns shadows into hard ink slabs whose thickness is the height: 2px under a raised surface, up to 7px under a dialog. Wells get a solid inner top edge.
|
|
180
|
+
- **Reduced motion** keeps every level, tint and shadow change and removes travel and scale (`--alt-travel: 0`). The pending hover stops breathing and simply holds at level 2.
|
|
181
|
+
|
|
182
|
+
## Paint order
|
|
183
|
+
|
|
184
|
+
`z-floating`, `z-overlay`, `z-modal` and `z-toast` follow altitude, with one exception: toasts paint above a dialog so status is never hidden behind it, even though they are visually one level lower.
|
|
185
|
+
|
|
186
|
+
## Small actions in their context
|
|
187
|
+
|
|
188
|
+
[Actions in place](ActionsInPlace.md) applies these existing signals to everyday work. `InlineEdit` keeps a single value in its location: its well opens under the value's own text, using the existing field and button treatments. Only a dispatched save uses pending, a known failure retains input, and accepted canonical content settles back to the ground.
|
|
189
|
+
|
|
190
|
+
An item that leaves its list is **left in place, then closed** ([RemovalReceipt](components/RemovalReceipt/README.md)): the result shows in the item's slot, on the ground, at the item's height, so nothing moves while it's read. It's a trace of what happened, not a live surface, so it doesn't rise; only its exit lifts off, as an Alert's does. Its Undo is backed by the application's real inverse operation and a durable recovery destination, and moves to a Toast once the slot has closed. A Dialog can keep its background stationary while retaining the level 5 panel, dimming, isolation and focus ownership. This adds no elevation tier and changes no meaning of the record.
|
|
191
|
+
|
|
192
|
+
## On a phone
|
|
193
|
+
|
|
194
|
+
No tier changes meaning on touch; see **Mobile**. Hover doesn't exist there, so a pressable's first signal is the press itself, at once. A thing picked up by a touch hold is carried exactly as a mouse carries it (Floating, level 3, `surface-floating` and `elev-3`, with `aria-pressed` or `aria-grabbed` and the "Picked up …" announcement). A menu opened as a bottom sheet keeps its tier (level 3, not 4: it's the same temporary choice) and only changes the edge it comes from.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Fundamentals
|
|
2
|
+
|
|
3
|
+
Generated interfaces don't only look alike ([Distinctiveness](Distinctiveness.md) covers that). They also break rules that design settled long ago: they give every action the same weight, split related things apart, label buttons "Submit" and links "Learn more", leave popovers without a close button and add countdown timers nobody asked for. Altitude is made for apps that agents write, so its rules have to hold against those failures as well as against the look.
|
|
4
|
+
|
|
5
|
+
This chapter lists the established laws and standards that generated interfaces are documented as breaking, how they break them, and the Altitude rule that answers each. Where Altitude had no answer, the rule was added (see "What this added"). The evidence is in **Research** ("Generated interfaces break established rules").
|
|
6
|
+
|
|
7
|
+
## Why the rules break
|
|
8
|
+
|
|
9
|
+
- **Polish hides problems.** People rate attractive interfaces as easier to use before they've used them (the aesthetic-usability effect: Kurosu & Kashimura, 1995; Tractinsky, Katz & Ikar, 2000). Generated screens are polished by default, so they pass a glance and fail in use. Nielsen Norman Group found AI prototypes "good from afar": poor grouping, emphasis on what the task doesn't need, and layouts force-fitted into a template.
|
|
10
|
+
- **Form gets built, function doesn't.** Asked for 48 implicit principles, five generative UI tools built most of the structural and styling ones and almost none of the functional ones (system status, user control, error recovery): four of five scored 0.06 or less on that tier.
|
|
11
|
+
- **Syntax without meaning.** Generated code has the attribute but not the meaning: a button named "Submit", a link named "Read more", `alt="image"`. These pass automated checks. In 300 generated interfaces, generic button and link names were over half of the semantic accessibility failures.
|
|
12
|
+
- **The web's defaults include its bad habits.** Models reproduce what's common, and that includes deceptive patterns. Asked for a webshop, ChatGPT added an average of five to every site without being asked or giving a warning.
|
|
13
|
+
|
|
14
|
+
So "it renders and looks finished" proves nothing. Each rule below has to be checked against the built screen (Distinctiveness, rule 7).
|
|
15
|
+
|
|
16
|
+
## The laws, and where Altitude answers them
|
|
17
|
+
|
|
18
|
+
### Perception and layout
|
|
19
|
+
|
|
20
|
+
| Law | How generated interfaces break it | Altitude's answer |
|
|
21
|
+
|---|---|---|
|
|
22
|
+
| **Proximity** (Gestalt): things near each other read as a group | Large gaps inside a group and none between groups; one spacing value everywhere | Distinctiveness rule 4 (tight within a group, wider between groups); padding grows with altitude; LA6 render check |
|
|
23
|
+
| **Focal point and isolation** (von Restorff): the one different thing is the one remembered | Every button, CTA and stat at the same weight; emphasis on information the task doesn't need | Law 1 (altitude is importance, one thing at level 5); `ALT-VISUAL-002` one primary per view; LA4, LA7 |
|
|
24
|
+
| **Hick–Hyman law**: decision time grows with the number of equal choices | Rows of equal-weight actions and options | One primary action; the rest secondary, ghost or in an overflow menu (`ALT-VISUAL-002`) |
|
|
25
|
+
| **Fitts's law** and WCAG 2.5.8 target size | Small targets, dense icon rows, inline links with no padding | Theming ("Density and target size"), Mobile, the 24px minimum and the phone check |
|
|
26
|
+
| **Jakob's law**: people expect a control to work like the ones they know | A pattern from the wrong domain (a "profile" built as a social profile); novelty to look designed | Distinctiveness rules 1 and 2; Screen layout chooses the frame from the task |
|
|
27
|
+
| **Measure**: reading suffers when lines run long | Body text the full width of a wide pane | Type: prose runs 45 to 75 characters a line (added) |
|
|
28
|
+
| **Typographic hierarchy** | A new size or weight wherever it "feels right" | The type tokens; weight before size; never 700 |
|
|
29
|
+
|
|
30
|
+
### Interaction (Nielsen's heuristics, Norman's signifiers)
|
|
31
|
+
|
|
32
|
+
| Law | How generated interfaces break it | Altitude's answer |
|
|
33
|
+
|---|---|---|
|
|
34
|
+
| **Visibility of system status** | No pending, saved, failed or stale state; success shown on a timer | Law 5; `ALT-EDIT-001`, `ALT-STATUS-001`, `ALT-SYNC-001`; pending only once a write is dispatched |
|
|
35
|
+
| **User control and freedom** | No cancel, no undo, popovers without a close button | `ALT-REVIEW-001`, Actions in place; every overlay can be dismissed (Honesty, added) |
|
|
36
|
+
| **Error prevention and recovery** | Raw error strings; submit disabled with no reason given | Content rules for errors; `ALT-EDIT-002`, `ALT-ACTION-001`; don't disable submit to say a form is invalid (added) |
|
|
37
|
+
| **Consistency and standards** | Fonts, radii and spacing drift between pages | One source per token; CN1 lint |
|
|
38
|
+
| **Recognition rather than recall** | A placeholder as the only label, gone once typing starts | Every field has a visible label (added) |
|
|
39
|
+
| **Signifiers** (Norman): what can be pressed must look it, and what looks pressable must be | Flat controls nobody finds; raised or underlined elements that do nothing | Law 2 (push up, fill down); law 4 (a surface lifts only if clicking it does something); everything that looks pressable does something (added) |
|
|
40
|
+
| **Response time** (0.1s, 1s, 10s) | Spinners for everything, or nothing for slow work | Motion's durations; `Await`'s grace before an imprint shows |
|
|
41
|
+
|
|
42
|
+
### Accessibility (WCAG 2.2)
|
|
43
|
+
|
|
44
|
+
| Criterion | How generated interfaces break it | Altitude's answer |
|
|
45
|
+
|---|---|---|
|
|
46
|
+
| **1.4.3 Contrast**, **1.4.1 Use of colour** | Muted text that fails AA; status by colour alone | Every text token clears 4.5:1 on all eight surfaces; law 7; CO7 |
|
|
47
|
+
| **2.4.4 Link purpose**, **2.4.6 Headings and labels**, **2.5.3 Label in name**, **1.1.1 Non-text content**, **3.3.2 Labels** | "Submit", "Click", "Learn more", "Read more", `alt="image"`, "Field 1", headings unrelated to their section | Buttons start with a verb; and now links, icon-only buttons, images, fields and headings each name what they are (Content, added); `ALT-SEM-002`; CP5 lint |
|
|
48
|
+
| **1.3.1 Info and relationships** | No landmarks, no heading order, sections that are only visual | One `h1` per view, levels that don't skip, a `main` landmark (Content, added) |
|
|
49
|
+
| **2.4.7 Focus visible** | Focus rings removed for looks | The focus rules; CM7 |
|
|
50
|
+
| **4.1.3 Status messages** | Changes announced only visually | `ALT-STATUS-001`, `WorkflowStatus` |
|
|
51
|
+
| **1.4.4 Resize**, **1.4.10 Reflow** | Fixed-width layouts that break at 320px or 200% | The framework's journey checks; Mobile; `checks/phone.mjs` |
|
|
52
|
+
|
|
53
|
+
### Honesty
|
|
54
|
+
|
|
55
|
+
| Rule | How generated interfaces break it | Altitude's answer |
|
|
56
|
+
|---|---|---|
|
|
57
|
+
| **No deceptive patterns** (Brignull's catalogue; Mathur et al.'s taxonomy) | Over a third of generated ecommerce components carry one: missing terms at sign-up, urgency with no deadline, popovers with no close button, the business's choice drawn bigger, costly options pre-selected. Newsletter, discount and membership components are the worst | Law 1: importance is the person's, never the business's (added); Honesty (added); `ALT-HONEST-001`; BH3. E89 had already ruled that a recommended plan gets a plate, not height |
|
|
58
|
+
| **Truthful content** | Invented metrics, ratings, testimonials and user counts presented as real | Show real data or say there's none (added); CP6; `Await` renders the real data as it arrives, never a stand-in |
|
|
59
|
+
|
|
60
|
+
## What this added
|
|
61
|
+
|
|
62
|
+
- **Law 1**: importance is the person's task, never the business's preference.
|
|
63
|
+
- **Honesty**, a new section in the design guide: real deadlines only, declining as findable as accepting in any offer the product makes, nothing costly pre-selected, every overlay dismissable with a visible way out, terms beside the action, leaving no harder than joining, real reviews and numbers.
|
|
64
|
+
- **Content**: links name where they go; icon-only buttons name the action; every field has a visible label; alt text describes the image; headings describe their section, with one `h1` and landmarks; real data or none.
|
|
65
|
+
- **Type**: prose runs 45 to 75 characters a line.
|
|
66
|
+
- **States**: don't disable submit to say a form is invalid; everything that looks pressable does something.
|
|
67
|
+
- **Tells**: CP5 (generic link and button names, linted), CM9 (placeholder as the only label; the previews that broke it were fixed in #394), BH3 (deceptive patterns), BH4 (controls that look live but do nothing), CP6 (invented data presented as real).
|
|
68
|
+
- **Framework rules** `ALT-HONEST-001` and `ALT-SEM-002`, so agents using the installed guidance get them too.
|
|
69
|
+
|
|
70
|
+
## Still open
|
|
71
|
+
|
|
72
|
+
- **Deceptive patterns and heading structure have no automated check.** They're reviewed by people. A render check for overlays without a close control is a candidate.
|
|
73
|
+
- **None of this is tested with people.** The study in Distinctiveness (#326) should include whether people find Altitude screens' decline and cancel paths as quickly as their accept paths.
|
|
74
|
+
|
|
75
|
+
## For agents building with Altitude
|
|
76
|
+
|
|
77
|
+
Before saying a screen is done, check it against this chapter as well as the tells:
|
|
78
|
+
|
|
79
|
+
1. One thing leads, and it's what the person came to do.
|
|
80
|
+
2. Every link, button, field, image and heading names what it is, in words that make sense out of context.
|
|
81
|
+
3. Every state the pattern lists is built, and the screen says what's happening.
|
|
82
|
+
4. Nothing hurries, hides, pre-selects or traps, and declining is as easy as accepting.
|
|
83
|
+
5. Every number, name and review on screen is real, or the screen says there's nothing yet.
|