@mthanh/vespercli 2.2.0 → 2.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 +6 -3
- package/assets/CATALOG.md +9 -2
- package/assets/claude/.claude-plugin/marketplace.json +9 -9
- package/assets/claude/.claude-plugin/plugin.json +1 -1
- package/assets/claude/agents/code-planner.md +1 -1
- package/assets/claude/agents/code-reviewer.md +1 -1
- package/assets/claude/agents/code-tester.md +1 -1
- package/assets/claude/agents/copywriter.md +1 -1
- package/assets/claude/agents/feature-wrap-document.md +1 -1
- package/assets/claude/agents/janitor.md +1 -1
- package/assets/claude/agents/modernization.md +1 -1
- package/assets/claude/agents/principal-software-engineer.md +1 -1
- package/assets/claude/agents/refine-issue.md +1 -1
- package/assets/claude/agents/se-system-architecture-reviewer.md +1 -1
- package/assets/claude/agents/se-technical-writer.md +1 -1
- package/assets/claude/agents/skill-creator.md +1 -1
- package/assets/claude/agents/task-researcher.md +1 -1
- package/assets/claude/agents/technical-product-manager.md +1 -1
- package/assets/claude/agents/vision-analyst.md +1 -1
- package/assets/claude/agents/vitest.md +1 -1
- package/assets/claude/agents/workspace-learner.md +2 -2
- package/assets/claude/packs/backend/.claude-plugin/plugin.json +1 -1
- package/assets/claude/packs/backend/agents/firebase-developer.md +1 -1
- package/assets/claude/packs/backend/agents/nodejs-express-developer.md +1 -1
- package/assets/claude/packs/docs/.claude-plugin/plugin.json +1 -1
- package/assets/claude/packs/frontend/.claude-plugin/plugin.json +1 -1
- package/assets/claude/packs/frontend/agents/expert-nextjs-developer.md +1 -1
- package/assets/claude/packs/frontend/agents/expert-react-frontend-engineer.md +1 -1
- package/assets/claude/packs/frontend/agents/jest-react-component-analyzer.md +1 -1
- package/assets/claude/packs/frontend/agents/jest-react-scenario-scanner.md +1 -1
- package/assets/claude/packs/frontend/agents/jest-react-test-generator.md +1 -1
- package/assets/claude/packs/frontend/agents/jest-react-test-planner.md +1 -1
- package/assets/claude/packs/frontend/skills/design-taste-frontend/LICENSE +21 -0
- package/assets/claude/packs/frontend/skills/design-taste-frontend/SKILL.md +529 -0
- package/assets/claude/packs/frontend/skills/design-taste-frontend/UPSTREAM.json +7 -0
- package/assets/claude/packs/frontend/skills/design-taste-frontend/assets/app.css +216 -0
- package/assets/claude/packs/frontend/skills/design-taste-frontend/assets/base.css +105 -0
- package/assets/claude/packs/frontend/skills/design-taste-frontend/assets/base.js +37 -0
- package/assets/claude/packs/frontend/skills/design-taste-frontend/assets/charts.js +617 -0
- package/assets/claude/packs/frontend/skills/design-taste-frontend/assets/scenes/stage.css +28 -0
- package/assets/claude/packs/frontend/skills/design-taste-frontend/assets/scenes/stage.js +133 -0
- package/assets/claude/packs/frontend/skills/design-taste-frontend/evals/evals.json +76 -0
- package/assets/claude/packs/frontend/skills/design-taste-frontend/library/app.json +1327 -0
- package/assets/claude/packs/frontend/skills/design-taste-frontend/library/directions.json +1078 -0
- package/assets/claude/packs/frontend/skills/design-taste-frontend/library/heroes.json +1086 -0
- package/assets/claude/packs/frontend/skills/design-taste-frontend/library/motions.json +92 -0
- package/assets/claude/packs/frontend/skills/design-taste-frontend/library/palettes.json +1485 -0
- package/assets/claude/packs/frontend/skills/design-taste-frontend/library/photos.json +7240 -0
- package/assets/claude/packs/frontend/skills/design-taste-frontend/library/sections.json +4429 -0
- package/assets/claude/packs/frontend/skills/design-taste-frontend/library/sites.json +8350 -0
- package/assets/claude/packs/frontend/skills/design-taste-frontend/library/type.json +2024 -0
- package/assets/claude/packs/frontend/skills/design-taste-frontend/references/app-screens.md +1199 -0
- package/assets/claude/packs/frontend/skills/design-taste-frontend/references/colour.md +141 -0
- package/assets/claude/packs/frontend/skills/design-taste-frontend/references/copy.md +177 -0
- package/assets/claude/packs/frontend/skills/design-taste-frontend/references/critique.md +182 -0
- package/assets/claude/packs/frontend/skills/design-taste-frontend/references/imagery.md +791 -0
- package/assets/claude/packs/frontend/skills/design-taste-frontend/references/layout.md +292 -0
- package/assets/claude/packs/frontend/skills/design-taste-frontend/references/motion.md +980 -0
- package/assets/claude/packs/frontend/skills/design-taste-frontend/references/research.md +356 -0
- package/assets/claude/packs/frontend/skills/design-taste-frontend/references/scenes.md +174 -0
- package/assets/claude/packs/frontend/skills/design-taste-frontend/references/tells.md +115 -0
- package/assets/claude/packs/frontend/skills/design-taste-frontend/references/type.md +170 -0
- package/assets/claude/packs/frontend/skills/design-taste-frontend/scripts/assets.mjs +865 -0
- package/assets/claude/packs/frontend/skills/design-taste-frontend/scripts/draw.mjs +584 -0
- package/assets/claude/packs/frontend/skills/design-taste-frontend/scripts/inspect.mjs +303 -0
- package/assets/claude/packs/frontend/skills/design-taste-frontend/scripts/lib/app-draw.mjs +203 -0
- package/assets/claude/packs/frontend/skills/design-taste-frontend/scripts/lib/cdp.mjs +248 -0
- package/assets/claude/packs/frontend/skills/design-taste-frontend/scripts/lib/probe.mjs +909 -0
- package/assets/claude/packs/frontend/skills/design-taste-frontend/scripts/lib/rules.mjs +243 -0
- package/assets/claude/packs/frontend/skills/design-taste-frontend/scripts/lint.mjs +119 -0
- package/assets/claude/packs/frontend/skills/design-taste-frontend/scripts/scenes.mjs +124 -0
- package/assets/claude/packs/graphify/.claude-plugin/plugin.json +1 -1
- package/assets/claude/packs/integrations/.claude-plugin/plugin.json +1 -1
- package/assets/claude/packs/playwright/.claude-plugin/plugin.json +1 -1
- package/assets/claude/packs/playwright/agents/playwright-component-analyzer.md +1 -1
- package/assets/claude/packs/playwright/agents/playwright-scenario-scanner.md +1 -1
- package/assets/claude/packs/playwright/agents/playwright-test-generator.md +1 -1
- package/assets/claude/packs/playwright/agents/playwright-test-planner.md +1 -1
- package/assets/claude/packs/playwright/agents/playwright-tester.md +1 -1
- package/assets/claude/packs/polyglot/.claude-plugin/plugin.json +1 -1
- package/assets/claude/packs/styles/.claude-plugin/plugin.json +1 -1
- package/assets/copilot/agents/code-planner.agent.md +1 -1
- package/assets/copilot/agents/code-reviewer.agent.md +1 -1
- package/assets/copilot/agents/code-tester.agent.md +1 -1
- package/assets/copilot/agents/copywriter.agent.md +1 -1
- package/assets/copilot/agents/feature-wrap-document.agent.md +1 -1
- package/assets/copilot/agents/janitor.agent.md +1 -1
- package/assets/copilot/agents/modernization.agent.md +1 -1
- package/assets/copilot/agents/principal-software-engineer.agent.md +1 -1
- package/assets/copilot/agents/refine-issue.agent.md +1 -1
- package/assets/copilot/agents/se-system-architecture-reviewer.agent.md +1 -1
- package/assets/copilot/agents/se-technical-writer.agent.md +1 -1
- package/assets/copilot/agents/skill-creator.agent.md +1 -1
- package/assets/copilot/agents/task-researcher.agent.md +1 -1
- package/assets/copilot/agents/technical-product-manager.agent.md +1 -1
- package/assets/copilot/agents/vision-analyst.agent.md +1 -1
- package/assets/copilot/agents/vitest.agent.md +1 -1
- package/assets/copilot/agents/workspace-learner.agent.md +2 -2
- package/assets/copilot/packs/backend/agents/firebase-developer.agent.md +1 -1
- package/assets/copilot/packs/backend/agents/nodejs-express-developer.agent.md +1 -1
- package/assets/copilot/packs/frontend/agents/expert-nextjs-developer.agent.md +1 -1
- package/assets/copilot/packs/frontend/agents/expert-react-frontend-engineer.agent.md +1 -1
- package/assets/copilot/packs/frontend/agents/jest-react-component-analyzer.agent.md +1 -1
- package/assets/copilot/packs/frontend/agents/jest-react-scenario-scanner.agent.md +1 -1
- package/assets/copilot/packs/frontend/agents/jest-react-test-generator.agent.md +1 -1
- package/assets/copilot/packs/frontend/agents/jest-react-test-planner.agent.md +1 -1
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/LICENSE +21 -0
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/SKILL.md +529 -0
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/UPSTREAM.json +7 -0
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/assets/app.css +216 -0
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/assets/base.css +105 -0
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/assets/base.js +37 -0
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/assets/charts.js +617 -0
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/assets/scenes/stage.css +28 -0
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/assets/scenes/stage.js +133 -0
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/evals/evals.json +76 -0
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/library/app.json +1327 -0
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/library/directions.json +1078 -0
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/library/heroes.json +1086 -0
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/library/motions.json +92 -0
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/library/palettes.json +1485 -0
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/library/photos.json +7240 -0
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/library/sections.json +4429 -0
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/library/sites.json +8350 -0
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/library/type.json +2024 -0
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/references/app-screens.md +1199 -0
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/references/colour.md +141 -0
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/references/copy.md +177 -0
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/references/critique.md +182 -0
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/references/imagery.md +791 -0
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/references/layout.md +292 -0
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/references/motion.md +980 -0
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/references/research.md +356 -0
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/references/scenes.md +174 -0
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/references/tells.md +115 -0
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/references/type.md +170 -0
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/scripts/assets.mjs +865 -0
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/scripts/draw.mjs +584 -0
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/scripts/inspect.mjs +303 -0
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/scripts/lib/app-draw.mjs +203 -0
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/scripts/lib/cdp.mjs +248 -0
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/scripts/lib/probe.mjs +909 -0
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/scripts/lib/rules.mjs +243 -0
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/scripts/lint.mjs +119 -0
- package/assets/copilot/packs/frontend/skills/design-taste-frontend/scripts/scenes.mjs +124 -0
- package/assets/copilot/packs/playwright/agents/playwright-component-analyzer.agent.md +1 -1
- package/assets/copilot/packs/playwright/agents/playwright-scenario-scanner.agent.md +1 -1
- package/assets/copilot/packs/playwright/agents/playwright-test-generator.agent.md +1 -1
- package/assets/copilot/packs/playwright/agents/playwright-test-planner.agent.md +1 -1
- package/assets/copilot/packs/playwright/agents/playwright-tester.agent.md +1 -1
- package/assets/manifest.json +2 -0
- package/dist/cli.min.js +102 -102
- package/package.json +1 -1
- package/scripts/__snapshots__/generate-claude-assets.test.js.snap +1 -1
- package/scripts/generate-claude-assets.strict.test.js +1 -1
- package/scripts/generate-claude-assets.test.js +6 -6
- package/scripts/packs-layout.test.js +2 -1
|
@@ -0,0 +1,1199 @@
|
|
|
1
|
+
# App screens
|
|
2
|
+
|
|
3
|
+
Dashboards, admin, analytics, settings, inboxes, wallets and builders: the screens people work in.
|
|
4
|
+
Read this file whole before you start one. The page run in `SKILL.md` does not apply to them.
|
|
5
|
+
|
|
6
|
+
A generated dashboard is the average of every dashboard template: a dark or tinted sidebar with a
|
|
7
|
+
coloured pill on the active item, "Welcome back" and a waving hand, four KPI cards each with an icon
|
|
8
|
+
in a tinted circle, a green "+12.5%" and a sparkline, a gradient area chart, a zebra table under
|
|
9
|
+
uppercase headers. Nothing in it is wrong and none of it was decided.
|
|
10
|
+
|
|
11
|
+
This chapter is distilled from a study of 23 real product screens chosen by the owner: 17 products,
|
|
12
|
+
17 light screens and 6 dark, all at desktop width (1440 or 1512px). Each screen was measured from its
|
|
13
|
+
pixels and noted for what works and what fails; the numbers below are those measurements and their
|
|
14
|
+
medians. The products are not named. What separates these screens from the generated kind, in order
|
|
15
|
+
of how much it shows:
|
|
16
|
+
|
|
17
|
+
1. **Colour goes on data, not chrome.** The median screen has about 3% coloured pixels; 17 of 23 stay
|
|
18
|
+
at 5% or less. 12 have no filled primary button at all.
|
|
19
|
+
2. **KPIs are type, not tiles.** No screen puts an icon in a coloured circle on a KPI, and none draws a
|
|
20
|
+
sparkline on one.
|
|
21
|
+
3. **Surfaces are flat.** 17 of 23 give their cards no shadow; separation is a 1px line or one tone
|
|
22
|
+
step.
|
|
23
|
+
4. **There is no hero header.** 9 screens have no heading over 16px; where there is one, its median is
|
|
24
|
+
24px.
|
|
25
|
+
5. **Charts carry almost no chrome.** A single series has no legend; gridlines are 3-7 faint lines or
|
|
26
|
+
none.
|
|
27
|
+
6. **Navigation recedes.** The active item is a neutral grey pill or a change of text colour; a
|
|
28
|
+
coloured left bar appears once.
|
|
29
|
+
7. **Tables are rules and alignment.** No zebra striping, no header bands, numbers right-aligned.
|
|
30
|
+
8. **Data states are honest.** Zeros print as zeros, missing values as a grey dash, and an empty
|
|
31
|
+
section keeps its frame.
|
|
32
|
+
|
|
33
|
+
Taking the template's devices away is half the job, as it is on a page. The other half is substance:
|
|
34
|
+
the product's real data, a screen that answers its one question first, and a grid whose arithmetic
|
|
35
|
+
closes.
|
|
36
|
+
|
|
37
|
+
**A warning learned in testing.** In the first blind round, screens built with this chapter were
|
|
38
|
+
clean, quiet and correct, and they lost to richer screens built without it. The judges' reasons were
|
|
39
|
+
the same every time, and each is now a rule below:
|
|
40
|
+
|
|
41
|
+
- **The first screen was thin.** One large chart of a flat line filled it, and half the blocks the
|
|
42
|
+
brief asked for started below the fold. On a 1440×900 screen, every block the brief names shows its
|
|
43
|
+
header and its first rows (§2.2).
|
|
44
|
+
- **The product was missing.** No name, no workspace, no mark: the screen could have belonged to
|
|
45
|
+
anyone. The shell names the product and the scope (§3.2).
|
|
46
|
+
- **Restraint hid meaning.** A latency rise and a request rise were the same grey. Colour on a change
|
|
47
|
+
says good or bad, not up or down (§5).
|
|
48
|
+
- **There was nothing to do.** No control for the job the screen exists for. The most frequent job is
|
|
49
|
+
one click from the first screen (§2.2).
|
|
50
|
+
- **Rows ended ragged** and **a style's move was over-applied** (a tray around every card, an icon
|
|
51
|
+
rail where people needed labels). Keep the move to where it carries meaning.
|
|
52
|
+
|
|
53
|
+
Quiet is the starting point, not the goal. A screen that a person would trust shows more of the
|
|
54
|
+
product than a template does: its people, its objects, its numbers and the one thing to do next.
|
|
55
|
+
|
|
56
|
+
**Give the product a face.** After four rounds the judges' top complaint was the same on most
|
|
57
|
+
screens: "a well-applied kit, not a product with its own identity" (stock Geist or Inter, a #f8f8f8
|
|
58
|
+
ground, white 12px cards, lime on black). The style's tokens make a screen correct; these make it
|
|
59
|
+
this product's, and choosing them is a step of the run, not a finish (§2.3):
|
|
60
|
+
|
|
61
|
+
- **One face from the sheet, chosen before you build.** Each style lists two or three ways it takes a
|
|
62
|
+
face from the brief: a ground tinted from the product's world, a figure face with character, the
|
|
63
|
+
brand's hue on the main data element. Choose one, write it in your notes next to the screen's
|
|
64
|
+
question, and check that it shows on the first screenshot.
|
|
65
|
+
- **The dealt typeface, really loaded.** A build that fell back to the default face landed on the
|
|
66
|
+
default look; the inspector now fails it.
|
|
67
|
+
- **The product's mark and name** at the top of the shell, drawn for this product (a simple
|
|
68
|
+
monogram or symbol in the accent, from its name or its object), never a black square with a letter.
|
|
69
|
+
- **One element only this product has**, built from its own things: an energy home's power flow, a
|
|
70
|
+
bakery's sell-out strip, a leave planner's cover against the minimum, the pace groups of a running
|
|
71
|
+
club as a unit chart, the couple as three lanes, a deploy's commit as the hero of the overview. The
|
|
72
|
+
sheet lists the library's signature elements whose words appear in the brief; otherwise invent one.
|
|
73
|
+
Name it in your notes next to the screen's question.
|
|
74
|
+
- **The one chart hue on the main data element**: today's line, the booked bars, the current period,
|
|
75
|
+
the margin that breaks. A screen whose only hue is a delta reads as a kit, and the inspector warns
|
|
76
|
+
when a screen with charts carries no hue on its data (`no-data-hue`).
|
|
77
|
+
- **Its people and objects as themselves**: each person gets a stable initial and a pale tint of their
|
|
78
|
+
own hue, with people listed next to each other at least 60 degrees apart. These tints are identity,
|
|
79
|
+
not data: they stay pale and out of the chart legends. Products show their thumbnails, cover art
|
|
80
|
+
shows the cover.
|
|
81
|
+
- **Words of the trade** in labels and empty states ("Waiting on the customer", "Off sick", "Due
|
|
82
|
+
on the 28th"), never the generic noun of a template ("Items", "Records", "Status").
|
|
83
|
+
|
|
84
|
+
**Calendars and timelines** (house rule, from testing; the study has none). People down the left on a
|
|
85
|
+
fixed 160-220px column, grouped under a team subheader rather than repeating the team on every row;
|
|
86
|
+
days across with faint 1px day lines, weekends one tone step darker, and today marked by a 1px line
|
|
87
|
+
in the one data hue with its date in ink. Bars are 20-24px tall at radius 4. One-line names sit on a
|
|
88
|
+
32px pitch; a name with a subline (team, office) needs 40-44px, or the subline touches the next name.
|
|
89
|
+
**Every kind of booking has its own mark**, so sickness reads apart from a holiday at a glance:
|
|
90
|
+
holiday a pale fill, off sick a 1px diagonal hatch, long leave a darker grey step, working away an
|
|
91
|
+
outline, a pending request a dashed outline. A style with a hue budget may add a 3px left edge in the
|
|
92
|
+
hue for the kind the screen is about. Full colour is only for what needs a decision (a request that
|
|
93
|
+
breaks cover). A label sits inside its bar; a bar too short for it shows the kind's code inside and
|
|
94
|
+
the full label in its tooltip, or the label after the bar's end, never over the days before it.
|
|
95
|
+
Holiday markers name their office in a multi-office product. Every swatch in the legend is the mark
|
|
96
|
+
itself, scaled down, and lists only kinds on screen: `Charts.timeline(el, rows, kinds)` draws the bars
|
|
97
|
+
and returns that legend from the same kinds map.
|
|
98
|
+
|
|
99
|
+
## Contents
|
|
100
|
+
|
|
101
|
+
1. When this applies
|
|
102
|
+
2. The run for an app screen
|
|
103
|
+
3. The shell
|
|
104
|
+
4. The canvas and the page title
|
|
105
|
+
5. KPIs
|
|
106
|
+
6. Charts
|
|
107
|
+
7. Tables and lists
|
|
108
|
+
8. Forms and settings
|
|
109
|
+
9. Type and colour
|
|
110
|
+
10. Density
|
|
111
|
+
11. Empty, zero, loading and error states
|
|
112
|
+
12. The phone
|
|
113
|
+
13. House rules for app screens
|
|
114
|
+
14. Tells of generated dashboards
|
|
115
|
+
|
|
116
|
+
## 1. When this applies
|
|
117
|
+
|
|
118
|
+
An app screen is worked in rather than read. This chapter covers:
|
|
119
|
+
|
|
120
|
+
- dashboards and overviews: a seller's day, a project's health, a publication's growth;
|
|
121
|
+
- admin and back office: members, orders, events, a catalogue;
|
|
122
|
+
- analytics and reports, including a generated report with no app around it;
|
|
123
|
+
- settings and billing;
|
|
124
|
+
- list screens to work through: inboxes, queues, tables with filters;
|
|
125
|
+
- wallets and finance homes;
|
|
126
|
+
- builders and editors: flow, form and page builders, canvases;
|
|
127
|
+
- the detail page of one object: an event, a deployment, a customer.
|
|
128
|
+
|
|
129
|
+
A product site that shows its interface is a page; the interface fragments on it follow these rules
|
|
130
|
+
for their insides (mark each fragment's root with `data-ui`). When a request holds both, build each
|
|
131
|
+
with its own run and share one palette and one typeface.
|
|
132
|
+
|
|
133
|
+
The study is 23 desktop screens. It has no phone screens, no loading or error states, one settings
|
|
134
|
+
page, no inbox and no dense operations table (the densest screen shows about 120 data points). Where a
|
|
135
|
+
rule below goes past the study, it says **house rule**.
|
|
136
|
+
|
|
137
|
+
## 2. The run for an app screen
|
|
138
|
+
|
|
139
|
+
Do these in order. The first three steps decide whether the screen is any good.
|
|
140
|
+
|
|
141
|
+
### 2.1 Inventory the data and the jobs
|
|
142
|
+
|
|
143
|
+
The page run inventories the subject's world; an app screen inventories its data. Write in your notes,
|
|
144
|
+
in 8 to 12 lines:
|
|
145
|
+
|
|
146
|
+
- **the objects** the screen shows (deployments, invoices, members, events, conversations) and their
|
|
147
|
+
fields, with units;
|
|
148
|
+
- **realistic magnitudes**: how many objects, a typical amount, the range of a rate, how values move
|
|
149
|
+
over a day, a month, a year, and for a new account how small they really are;
|
|
150
|
+
- **the people**: who opens this screen, how often (a glance once a day, or an eight-hour session),
|
|
151
|
+
on what device;
|
|
152
|
+
- **the jobs**: what they do next from here (approve, reply, pay, ship, invite), and which job comes
|
|
153
|
+
up most;
|
|
154
|
+
- **the product's own things**: its name and mark, the workspace or account it is scoped to, the people
|
|
155
|
+
in it (two partners, a team of six, the club's members), and the objects people recognise by sight
|
|
156
|
+
(product photographs in a shop, cover art in a media tool, a map of the route). These are what make
|
|
157
|
+
a screen belong to this product instead of to a template; plan where each one appears.
|
|
158
|
+
|
|
159
|
+
Then write the data itself: a small dataset in a JSON or JS file that the screen renders from, with
|
|
160
|
+
believable names, amounts that add up to their totals, dates in order and a unit on every figure.
|
|
161
|
+
Totals are computed from the rows, never typed in separately. Small numbers stay small: the studied
|
|
162
|
+
screens show new accounts with 1, 6 or 9 of something, drawn honestly at their real size. Write the
|
|
163
|
+
figures that must agree as assertions in the data file (`console.assert(sold - cancelled === rsvps)`,
|
|
164
|
+
the bins sum to the total, the parts to the whole) and read the console: in testing, a ticket table
|
|
165
|
+
that did not reconcile with its own KPI cost a judge's trust in the whole screen. Checks that need
|
|
166
|
+
computed values (allowance after a request, cover per day) go in the script that computes them.
|
|
167
|
+
|
|
168
|
+
**Data that tells the truth** (house rules, from testing; judges checked every one of these):
|
|
169
|
+
|
|
170
|
+
- **A fact shown twice is one variable.** A time window, a total or a state that appears in two cards
|
|
171
|
+
(the battery full 13:30-16:30 in the KPI label, the shaded span and the battery card) is one value in
|
|
172
|
+
the data file, and the copy and the chart annotation are both built from it. Two cards that
|
|
173
|
+
disagree by half an hour cost more trust than a missing card.
|
|
174
|
+
- **Totals and deltas come from the parts as shown.** Sum the rounded pennies the screen displays,
|
|
175
|
+
never round the unrounded total separately: £21.68 + £8.34 − £3.81 is £26.21, and a screen that
|
|
176
|
+
says £26.22 is caught. A change is the difference of the two values on screen (£5.28 against
|
|
177
|
+
£5.22 is +£0.06, not +£0.07).
|
|
178
|
+
- **Every relative figure names its baseline** in the same phrase: "3 h 40 m before close", "45 m
|
|
179
|
+
earlier than last Sunday", "+5 on the usual Monday". "Early", "up" or a bare "+5" next to another
|
|
180
|
+
time or figure reads as measured against that one.
|
|
181
|
+
- **One name per time.** Shops close at 15:00 and the tills are cashed up at 15:12; the header and
|
|
182
|
+
the card use the same words for the same moment, and an error state rewrites the status line.
|
|
183
|
+
- **If a caption has to say which bars are which, encode it in the chart instead**: a marked period in
|
|
184
|
+
a second tone with its own legend entry, a signed axis, a label on the mark.
|
|
185
|
+
|
|
186
|
+
### 2.2 Name the screen's one question
|
|
187
|
+
|
|
188
|
+
Every screen answers one question first: "Did today's sales come in?", "Which deploy broke?", "Who is
|
|
189
|
+
waiting for a reply?", "How much of this month's plan is left?". Write it in one line. It decides
|
|
190
|
+
three things:
|
|
191
|
+
|
|
192
|
+
- **what is biggest.** In the study the largest block is always the one that carries the screen's
|
|
193
|
+
question, whatever form it takes (a chart, a plan, a ring, a list). The same holds for figures:
|
|
194
|
+
the largest figure on the screen answers the question the title row's sentence answers. In testing,
|
|
195
|
+
an 88% sun ratio at 32px out-shouted the 24px charging window the title led with;
|
|
196
|
+
- **what comes first** in the reading order;
|
|
197
|
+
- **what is left out.** The studied settings page shows three usage numbers and links to the
|
|
198
|
+
analytics screen instead of drawing a chart; four screens draw no chart at all because a few
|
|
199
|
+
numbers say it.
|
|
200
|
+
|
|
201
|
+
Then name the screen's **one finding**: the fact in today's data that most needs attention ("9 no-shows
|
|
202
|
+
while 8 people waited for a place", "the 23:28 deploy doubled the error rate", "eating out is £36 over").
|
|
203
|
+
Put it where it is read first, as the line under the title or the subline of the headline figure,
|
|
204
|
+
next to the action it drives. In testing, the finding that mattered sat in a 14px caption at the
|
|
205
|
+
bottom of a card and the screen read as flat.
|
|
206
|
+
|
|
207
|
+
**Do not rebuild a studied screen.** When the product is of the same kind as a screen in the study (a
|
|
208
|
+
finance home, a deploy overview), its arrangement is the trap: judges recognised the copies at once.
|
|
209
|
+
Take the structure from the product's own things instead: for a couple's budget, Mia, Joint and Tom
|
|
210
|
+
as three columns running through accounts, plan and bills; for a running club, the pace groups.
|
|
211
|
+
|
|
212
|
+
Then list the screen's blocks as the answers to its next questions, one line each, the way the page
|
|
213
|
+
run lists claims. A block with no question is deleted. This is how you avoid the stock order of KPI
|
|
214
|
+
row, big chart, two small charts, table.
|
|
215
|
+
|
|
216
|
+
Three more lines, each tested:
|
|
217
|
+
|
|
218
|
+
- **Everything the brief names is on the first screen.** At 1440×900, every block the brief asks for
|
|
219
|
+
shows its header and its first rows or its figure. Size the headline block to the question (about
|
|
220
|
+
200-360px tall), cap long lists at 4-6 rows with "View all", and put time-sensitive blocks (bills
|
|
221
|
+
due, SLAs running out, a failed deploy) before long tables. A chart whose line is flat for most of
|
|
222
|
+
the window does not get the full width: give it two-thirds and put the next answer beside it.
|
|
223
|
+
- **The most frequent job is one click away.** Name it ("pack the orders due today", "reply to the
|
|
224
|
+
oldest breach", "redeploy the failed build") and put its control where the answer shows: a primary
|
|
225
|
+
button in the title row, an action on the row that needs it, a "View logs" on the failed item. A
|
|
226
|
+
screen with no control for its main job reads as a report, not as a tool.
|
|
227
|
+
- **Show the evidence beside the answer.** A judge trusts "Error rate 0.28%" more with its spike
|
|
228
|
+
annotated ("peaked at 3.9% after the 23:28 deploy, reverted") than with the number alone. One line
|
|
229
|
+
of explanation on the event that matters is worth more than a second chart.
|
|
230
|
+
|
|
231
|
+
### 2.3 Choose a style
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
node <skill>/scripts/draw.mjs --app --kind <kind> --brief "<one line about the product>" \
|
|
235
|
+
--screens <screens> [--theme light|dark] [--keep palette,type] --options 3
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
This deals up to three styles from `library/app.json` (fewer when only two suit the kind and the
|
|
239
|
+
theme). `draw.mjs --app --list kinds` (or `styles`, `screens` or `signatures`) prints the choices; the
|
|
240
|
+
screens are `overview`, `analytics`, `list`, `detail`, `settings`, `wallet`,
|
|
241
|
+
`builder`, `inbox`, `home` and `report`. The library holds seven styles, each distilled from the
|
|
242
|
+
studied screens that share its move:
|
|
243
|
+
|
|
244
|
+
| Style | Theme | For | The move |
|
|
245
|
+
| --- | --- | --- | --- |
|
|
246
|
+
| `achromatic-ledger` | light | money homes, reports, settings with usage | No colour in the chrome; charts in ink; one small signal where a figure changed |
|
|
247
|
+
| `framed-sheet` | light | B2B analytics, developer platforms, builders | One tinted L-frame; the page on a white sheet inset 8px, no shadow |
|
|
248
|
+
| `accent-ladder` | light | creator and small-business admin with plans | The full hue on small marks only; its pale tints on every area |
|
|
249
|
+
| `editorial-greeting` | light | team and personal homes | The greeting as the h1 in a centred 12-column column; every figure at regular weight |
|
|
250
|
+
| `pastel-consumer` | light | wallets, budgeting | Pale same-hue tiles under one large radius; quiet money polarity |
|
|
251
|
+
| `true-black-flat` | dark | community, events, media | Elevation by lightness alone; colour only on data |
|
|
252
|
+
| `data-terminal` | dark | markets, monitoring | Every selection is the same 1px accent line; signs, not colour, on numbers |
|
|
253
|
+
|
|
254
|
+
Choose by how the product is used (long sessions or a quick look, money or media, a team or one
|
|
255
|
+
person, day or night), not by what is most familiar, and write one line on why. Then deal the sheet:
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
node <skill>/scripts/draw.mjs --app <the same arguments, without --options> --style <id>
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
The sheet gives the style's tokens and type, its shell and one pattern for each screen you named.
|
|
262
|
+
Keep the style's one move intact and take every other value from the defaults in this file. Redraw
|
|
263
|
+
(`--redraw style | shell | screen:<name>`) only for a reason you can state: it contradicts the brand,
|
|
264
|
+
or the product is used in a way the style does not suit. With an existing brand, pass
|
|
265
|
+
`--keep palette,type`, map its colours onto the roles in §9 and keep the style's colour budget.
|
|
266
|
+
|
|
267
|
+
**Then choose its face, before any markup.** The sheet's "Its face" list gives two or three ways this
|
|
268
|
+
style takes a face from the brief, and "Signature elements" lists the library's elements whose words
|
|
269
|
+
appear in the brief (a power flow for an energy home, a sell-out strip for a bakery, a cover matrix
|
|
270
|
+
and a kind-encoded timeline for a leave planner). Write in your notes, next to the screen's question:
|
|
271
|
+
the face you chose, the signature element (from the sheet, or your own built from the product's
|
|
272
|
+
things), and where each appears on the first screen. A style dealt to two products must not give them
|
|
273
|
+
the same face: in four rounds, the screens that skipped this step were scored as the same kit.
|
|
274
|
+
|
|
275
|
+
### 2.4 Build the shell
|
|
276
|
+
|
|
277
|
+
Build the frame first, empty: the sidebar or rail, the top bar if the shell has one, the canvas with
|
|
278
|
+
its gutters, the title row (§3 and §4). `<skill>/assets/app.css` is a neutral start for all of it:
|
|
279
|
+
copy it into the project and put the sheet's tokens in its `:root`. Look at it at 1440 and at 390 before any data goes in. Do the
|
|
280
|
+
grid arithmetic now and write it in a comment: the column count, the gutter, and the sum that proves
|
|
281
|
+
the cards land on the canvas edges.
|
|
282
|
+
|
|
283
|
+
### 2.5 Put in the data
|
|
284
|
+
|
|
285
|
+
Render every block from the dataset; draw the charts from it too, with `<skill>/assets/charts.js`
|
|
286
|
+
(`Charts.line`, `Charts.bars`, `Charts.diverging`, `Charts.ring`, `Charts.barList`, `Charts.plan`,
|
|
287
|
+
`Charts.bullet`, `Charts.timeline`, `Charts.matrix`, `Charts.timeStrip`; the file's header lists their
|
|
288
|
+
options) or your own SVG to the rules of §6, never a chart library's defaults and never a picture of a
|
|
289
|
+
chart. The newer helpers return `{ svg, legend }`: put that legend in the card's header rather than
|
|
290
|
+
drawing your own, so each swatch is the mark it explains. Format every figure by §7.4: separators, fixed decimals per
|
|
291
|
+
metric, a sign on every change, units as smaller grey suffixes, tabular figures, right alignment in
|
|
292
|
+
columns. Use the product's own words for labels. No placeholder data: the inspector fails lorem ipsum,
|
|
293
|
+
Acme, John Doe and their kind. Proof is not invented here either: no vanity totals, no "+12%" on an
|
|
294
|
+
account that is a week old.
|
|
295
|
+
|
|
296
|
+
### 2.6 Build the states
|
|
297
|
+
|
|
298
|
+
For every block, build its empty, zero, loading and error state (§11); for every row and control, its
|
|
299
|
+
hover, selected, focus and disabled state. Look at each one in the browser. A screen that only works
|
|
300
|
+
with full data is half built.
|
|
301
|
+
|
|
302
|
+
### 2.7 The check
|
|
303
|
+
|
|
304
|
+
```bash
|
|
305
|
+
node <skill>/scripts/lint.mjs --app <source files or folder>
|
|
306
|
+
node <skill>/scripts/inspect.mjs --app <url or path/to/index.html>
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
A sheet dealt with `--app` switches both tools to the app rules by itself. The inspector opens the
|
|
310
|
+
screen at 1440, 768 and 390 and measures what this chapter asks for: an h1 (and reports it as the
|
|
311
|
+
screen's hero); a sidebar that folds on the phone; the canvas used to its right edge; panel shadows
|
|
312
|
+
and borders; the number of corner radii; cards in one row that end apart, where a column of cards
|
|
313
|
+
stacked with the gutter counts as one block (`ragged-row`); a blank band inside a card of over 40px,
|
|
314
|
+
or over 64px before a new section's heading (`panel-void`); icons in tinted squares; numeric alignment and tabular figures; chart hues; colour
|
|
315
|
+
share, and a screen with charts but no hue on its data (`no-data-hue`); placeholder data; text under
|
|
316
|
+
11px; and the page rules that still hold (contrast, gradients, the banned palettes, emoji). Fix every
|
|
317
|
+
`FAIL`. Treat each `WARN` as wrong unless you can defend it to a designer in one sentence.
|
|
318
|
+
|
|
319
|
+
Then look at the screenshots, every width, and answer these in writing. This is the critique for an
|
|
320
|
+
app screen: the caps in `critique.md` for pictures, motion and the page's live element are page rules
|
|
321
|
+
and do not apply here.
|
|
322
|
+
|
|
323
|
+
1. Is the screen's question answered by the biggest thing on it, and is that read first? Is the
|
|
324
|
+
largest figure the one that answers the title row's sentence?
|
|
325
|
+
2. Does every block share the screen's edges? Is there a dead strip on one side, a card stopping
|
|
326
|
+
short, an orphan cell, a stretched card with a blank band (a legend pinned to its foot, four rows
|
|
327
|
+
in a card kept at its neighbour's height)?
|
|
328
|
+
3. Is colour only on data, on status and on the one primary action, and does the main data element
|
|
329
|
+
carry the one hue? Does the face you chose show on the first screen?
|
|
330
|
+
4. Do the numbers add up, and do they line up digit for digit? List every fact that appears twice
|
|
331
|
+
and check that the copies agree; recompute each total and change from the values as displayed;
|
|
332
|
+
check that every relative figure names what it is against.
|
|
333
|
+
5. Does every zero look like a zero and every missing value like a dash? Does every count badge sit
|
|
334
|
+
on a queue that needs action, with its noun clear from the label?
|
|
335
|
+
6. Does every legend swatch match the mark it explains, and does any caption have to say which bars
|
|
336
|
+
are which (then encode it in the chart)? Does any label collide with a line or another label?
|
|
337
|
+
7. On the phone, is the navigation folded away, and does each block still answer its question?
|
|
338
|
+
|
|
339
|
+
Fix the worst three, inspect again, look again. Three rounds at most. Judge the pictures: if a problem
|
|
340
|
+
shows in a screenshot, it is real, whatever the code says.
|
|
341
|
+
|
|
342
|
+
### 2.8 Report
|
|
343
|
+
|
|
344
|
+
Tell the user, briefly: the style dealt (name and seed) and any redraws with their reasons; the face
|
|
345
|
+
you chose and the signature element; each screen's one question; any check you allowed and why (for example `--allow icon-chips` for node-type
|
|
346
|
+
tiles in a builder); and the sample data that must be replaced with real data, listed so it can be
|
|
347
|
+
found.
|
|
348
|
+
|
|
349
|
+
App screens have no motion floor. Motion is feedback: press, hover, focus, a menu or a sheet opening,
|
|
350
|
+
a row arriving. Nothing on the screen performs an entrance (house rule).
|
|
351
|
+
|
|
352
|
+
## 3. The shell
|
|
353
|
+
|
|
354
|
+
### 3.1 Five archetypes
|
|
355
|
+
|
|
356
|
+
| Shell | In the study | What it is |
|
|
357
|
+
| --- | --- | --- |
|
|
358
|
+
| **Open plane** | 5 screens | A labelled sidebar on the page ground (or within 1-2% of it), separated by nothing or by one 1px hairline. No top bar: the header and the cards sit on the ground. The canvas is fluid with a 24-64px gutter, or a centred column. |
|
|
359
|
+
| **Tinted frame, white sheet** | 8 screens | Sidebar and top bar share one tinted ground (#f6f6f6-#f9fbfc) with no rule between them; the page sits on a white sheet inset 8px from the window's right and bottom edges, radius 10-16 (median 16), a 1px #eaeaea-#ededed edge and no shadow. Variants: a flush L-frame, the inset sheet, and floating panels inset 8-12px with a 12px gap. |
|
|
360
|
+
| **Ruled T-frame** | 4 screens | A 210-240px sidebar and a 64px top bar on one ground, divided only by 1px rules. The workspace switcher sits at the top bar's right end behind a full-height divider. Three of the four are dark. |
|
|
361
|
+
| **Icon rail** | 3 screens | An unlabelled rail 50-60px wide (median 55); 15-18px icons on a 34-49px pitch; the active item marked by colour or by a 2% tint band; groups split by 20px hairlines. It saves about 180px of width. |
|
|
362
|
+
| **No sidebar** | 3 screens | A 46-48px top bar over a centred 1088-1208px column with 152-212px gutters; the logo sits on the column's left edge. For reports, viewers and products with few destinations. |
|
|
363
|
+
|
|
364
|
+
All six dark screens use one ground everywhere, divided by 1px rules of #161616-#232323 or by nothing.
|
|
365
|
+
No screen in the study puts a dark or saturated sidebar against a light canvas (0 of 17).
|
|
366
|
+
|
|
367
|
+
### 3.2 Sidebar
|
|
368
|
+
|
|
369
|
+
- **Width.** Labelled sidebars run 210-292px; the median is 230 and most sit at 224-240. One floating
|
|
370
|
+
sidebar card appears (280px wide, 40px in from the window edge).
|
|
371
|
+
- **Rows.** A 32px hit area on a 34px pitch is the mode (7 screens); the roomy versions run 40-52px on
|
|
372
|
+
a 42-60px pitch. Icons are 14-20px, median 16, outline at about 1.5px stroke on 14 of 16 screens.
|
|
373
|
+
Labels are 14px at 400 on 12 of 16, in ink or in a grey of #4b4d4f-#63666e, about 8-10px after the
|
|
374
|
+
icon, with the label column at x 36-48.
|
|
375
|
+
- **Active item.** A neutral grey pill with the label unchanged, on 8 screens: radius 4-16 (median 8),
|
|
376
|
+
inset 8-14px from the sidebar's edges, a fill of about #e9e9e9-#ededed. On dark, brightness alone:
|
|
377
|
+
the label goes from #bbb to #fff (3 screens). Colour alone on the icon or label (3, all of them
|
|
378
|
+
rails or a floating card). A tinted accent fill (3). A left accent bar once in 23. The weight
|
|
379
|
+
changes on 2. Default: the grey pill on light, brightness on dark.
|
|
380
|
+
- **Groups.** Sentence-case grey labels at 12-13px, never uppercase (9 screens), with 22-56px of air
|
|
381
|
+
above and 13-33px to the first item; or hairlines instead (4). Utilities such as settings and help
|
|
382
|
+
pushed to the bottom (5).
|
|
383
|
+
- **Top and bottom.** The workspace or account switcher at the top of the sidebar (7 screens), at its
|
|
384
|
+
bottom (2), or in the top bar. The bottom holds a user row (8) or one upsell (8); one of those
|
|
385
|
+
upsells is a filled accent button.
|
|
386
|
+
- **The product is named** (house rule, from testing). The product's mark and name sit at the top of
|
|
387
|
+
the sidebar or rail, and the scope (workspace, team, project, account) is shown as a switcher or a
|
|
388
|
+
breadcrumb. A screen whose product cannot be named from the screenshot reads as a template.
|
|
389
|
+
- **Counts on nav items** (house rule, from testing). A count appears only on a queue that needs
|
|
390
|
+
action, and its noun is clear from the label: "Requests 5", "Price changes 3". A bare "Range and
|
|
391
|
+
prices 9" left the judge asking nine of what.
|
|
392
|
+
- **Labels by default.** A labelled sidebar unless the product has five destinations or fewer and the
|
|
393
|
+
screen needs the width (a research or monitoring view); an icon rail always carries the product's
|
|
394
|
+
mark at the top, a tooltip and an accessible name on every icon. Nav items are other screens, never
|
|
395
|
+
anchors into the current page (a sidebar that scroll-spies one long page was marked down twice).
|
|
396
|
+
|
|
397
|
+
### 3.3 Top bar
|
|
398
|
+
|
|
399
|
+
14 of 23 screens have one; the default is none. Heights fall into two groups: 44-51px (median about
|
|
400
|
+
48) on light chrome, and 64px, usually with a 1px rule. A top bar must hold something real: search,
|
|
401
|
+
the workspace switcher, or the page or object name. Search sits centred on the window at 548x32 with
|
|
402
|
+
a shortcut hint (2 screens), or at 457-537x36 in a no-sidebar bar. The right cluster is inset 24-46px
|
|
403
|
+
from the edge. Two screens leave about 1070px of their top bar blank; both are flagged for it.
|
|
404
|
+
|
|
405
|
+
### 3.4 Right rail and pinned columns
|
|
406
|
+
|
|
407
|
+
One screen has a right rail: a fixed 384px column in a `1fr 384px` grid with a 24px gap, starting
|
|
408
|
+
level with the first card rather than with the title, its section headings outside the cards and 8px
|
|
409
|
+
above each. Use one only for a stable secondary stream: recent items, the details of the selected
|
|
410
|
+
object, share links. A pinned left column appears once: a 306px accounts card at the viewport height
|
|
411
|
+
minus 72px, so net worth stays in view while the rest of the screen scrolls.
|
|
412
|
+
|
|
413
|
+
Five screens float a button (24-56px), and one of those buttons covers the content it sits on and is
|
|
414
|
+
flagged. House rule: no floating button unless it is the screen's one primary action and covers
|
|
415
|
+
nothing at any width.
|
|
416
|
+
|
|
417
|
+
## 4. The canvas and the page title
|
|
418
|
+
|
|
419
|
+
### 4.1 Width and gutters
|
|
420
|
+
|
|
421
|
+
- **Fluid** (14 screens): side padding 17-64px, median 29, with 24 and 36-40 the common values;
|
|
422
|
+
content 1120-1312px wide, median about 1204.
|
|
423
|
+
- **Centred** (8 screens): 624, 864, 1088, 1100, 1152, about 1190 and 1208px; median about 1126.
|
|
424
|
+
Data pages land at 1100-1250 either way. Only two personal homes go narrow (624 and 864), and both
|
|
425
|
+
are flagged for wasting the width.
|
|
426
|
+
- **Top offset**, from the canvas top to the title: 20-88px, median about 36. Tools sit at 20-36;
|
|
427
|
+
greeting homes at 50-88.
|
|
428
|
+
- **One gutter.** Use one gap value horizontally and vertically. Mixed gutters (12 against 16, 20
|
|
429
|
+
against 24, 16 against 12) are flagged on 8 screens.
|
|
430
|
+
|
|
431
|
+
### 4.2 One left edge, one right edge
|
|
432
|
+
|
|
433
|
+
The strongest screens run a single left edge from the header to the last row. One indents its page
|
|
434
|
+
header by the cards' 24px padding, so the title, the card titles, the numbers and the chart all start
|
|
435
|
+
on one line. Row rules may bleed 7-8px past the text column while the text stays on it.
|
|
436
|
+
|
|
437
|
+
The grid's arithmetic closes: 3 x 372 + 2 x 17 = 2 x 568 + 16 = 1152; 12 x 77 + 11 x 16 = 1100;
|
|
438
|
+
4 x 144 + 3 x 16 = 624; a second-row card exactly as wide as the two cards above it
|
|
439
|
+
(251 + 24 + 515). Write your sum down.
|
|
440
|
+
|
|
441
|
+
Failures to avoid, all from the study: cards stopping 120px short of the sheet's right edge; a 0px
|
|
442
|
+
right gutter against a 40px left one; a column centred on the window instead of on the area beside
|
|
443
|
+
the sidebar (204px on its left, 444px on its right); a medallion 108px off the column's axis. The
|
|
444
|
+
inspector warns when the content stops well short of the right edge.
|
|
445
|
+
|
|
446
|
+
**Dead space from a grid that does not fit the data** is the commonest failure in the study (10
|
|
447
|
+
screens): four KPI tiles in a three-column grid, orphaning the fourth; one card alone in a
|
|
448
|
+
three-column row beside 810px of nothing; a card stretched to its neighbour's height with 250px of
|
|
449
|
+
blank under its legend. Choose the column count from the number of items, let a lone card span, and
|
|
450
|
+
do not stretch a card's frame over empty space.
|
|
451
|
+
|
|
452
|
+
**Cards that share a row share a bottom edge.** In testing, rows whose cards stopped 26-190px apart
|
|
453
|
+
were marked down every time, by judges and by the inspector (`ragged-row`). Balance the row by its
|
|
454
|
+
content first: move a list's rows so the two columns hold the same number, cap both lists at the same
|
|
455
|
+
count, or pair blocks of similar height. Two cards stacked in one column beside a tall card count as
|
|
456
|
+
one block: they balance when the column ends level. Only when the contents cannot balance, stack the
|
|
457
|
+
two blocks, or let the shorter card fill the row height with its content top-aligned and the footer
|
|
458
|
+
action (a "View all", a total) pinned to its bottom so the extra height is not a hole.
|
|
459
|
+
|
|
460
|
+
**A stretched card stretches only when it has content to fill.** Only an action or a total may be
|
|
461
|
+
pinned to a stretched card's foot; a legend or a note stays directly under its chart. In testing, a
|
|
462
|
+
cover card stretched to its neighbour with its legend pinned to the bottom left 60px of blank under
|
|
463
|
+
the last row, and a sell-out card left 45px above its links. When the content is short, let the card
|
|
464
|
+
keep its own height (`align-items: start` on the row), move its footer link into its header, or give
|
|
465
|
+
the row a block of similar height. A filtered block shrinks to its rows, or keeps a fixed number of
|
|
466
|
+
rows with one sentence in the empty ones; four rows over 270px of empty card is a hole. The inspector
|
|
467
|
+
warns on a blank band of over 40px inside a card (`panel-void`).
|
|
468
|
+
|
|
469
|
+
**Narrow blocks do not span the canvas.** A table of five columns or fewer, or a list of six rows or
|
|
470
|
+
fewer, runs to about 760px at 1440 and pairs with the next block; stretched to 1300px it leaves
|
|
471
|
+
400-600px voids between a name and its first figure.
|
|
472
|
+
|
|
473
|
+
### 4.3 The title
|
|
474
|
+
|
|
475
|
+
- **Every screen has one h1**; the inspector fails a screen without one. 14 screens set it in the
|
|
476
|
+
canvas at 18-48px, median and mode 24, at 600-700 (700 on 8). The rest have nothing over 16px: a
|
|
477
|
+
breadcrumb or the top bar names the page. Then the breadcrumb's last item is the h1, at 16px, and
|
|
478
|
+
the screen's name is still the first thing read.
|
|
479
|
+
- **A noun, not a greeting**: "Analytics", "Overview", the project's or the object's name. 3 of 23
|
|
480
|
+
greet, and one adds an emoji, which goes. A greeting suits a personal or team home only.
|
|
481
|
+
- **An optional second line**: one 14-16px grey sentence about the data or the object (the finding,
|
|
482
|
+
the period, the scope), never about the interface ("the filters narrow every block…", "this page
|
|
483
|
+
shows…" read as instructions, not a product), or a 12px line
|
|
484
|
+
naming the data's source.
|
|
485
|
+
- **Right of the title**: actions only when they are real (10 screens); otherwise nothing. A freshness
|
|
486
|
+
stamp ("Updated Jul 27, 4:09 PM", with a refresh button) on 6.
|
|
487
|
+
- **The primary action.** 12 of 23 have no filled primary button; 5 make it near-black (#1d1f20,
|
|
488
|
+
#1f2937) or inverted white on dark; 4 fill it with the brand hue. One primary per screen.
|
|
489
|
+
|
|
490
|
+
### 4.4 Tabs, filters and the date range
|
|
491
|
+
|
|
492
|
+
- **The date range** at page level (7 screens) or on each card (7), never both. A card that states its
|
|
493
|
+
own period puts it in its header, right-aligned, in grey.
|
|
494
|
+
- **Underline tabs** (8 screens) always sit on a full-width 1px rule; the indicator is 1-4px (median
|
|
495
|
+
2), as wide as the label or running 8-11px past it.
|
|
496
|
+
- **A segmented track** once: 48px, #f3f4f6, a white 36px active pill, and the date select inside its
|
|
497
|
+
right end, so tabs and range read as one row. A segmented control is as wide as its options, and full
|
|
498
|
+
width only below about 480px: three options spread across a 680px tablet card read as a progress bar.
|
|
499
|
+
- **Control height** in title and filter rows: 28-40px, median 34, clustering at 32 and 36.
|
|
500
|
+
- **Order**: scope on the left (the date first, then the filters), utility and refresh on the right.
|
|
501
|
+
- **Compound filters** that read as a sentence ("Date | Jun 14 - Jul 13 | Daily"), 28px tall and 8px
|
|
502
|
+
apart, once.
|
|
503
|
+
- **To the first card**: 13-64px, median 24.
|
|
504
|
+
|
|
505
|
+
## 5. KPIs
|
|
506
|
+
|
|
507
|
+
- **No tile of its own.** 11 of the 20 screens with headline numbers give a KPI no tile: bare text on
|
|
508
|
+
the page or on a card (5), or one container split by 1px hairlines (6). 9 use one card per KPI,
|
|
509
|
+
61-147px tall (median about 108). The default is one container split by 1px dividers into equal
|
|
510
|
+
columns. 7 screens have no KPI row at all and put each headline number in the card that explains
|
|
511
|
+
it, which is often better.
|
|
512
|
+
- **Count.** 1-6 per row, median 3-4. The count matches the grid: four KPIs get four columns.
|
|
513
|
+
- **Size.** Values 16-40px, median 26, mode 24. Values in their own tile run larger (median 30) than
|
|
514
|
+
in a shared strip (median 24). Nothing at 48px or over. Labels 12-16px, median 14; the value is
|
|
515
|
+
about 1.7 times the label.
|
|
516
|
+
- **Weight.** An even split: 400 on 8 screens, 600 on 6, 700-800 on 6. A large number at regular
|
|
517
|
+
weight under a semibold label is the common pattern. Bold for money only.
|
|
518
|
+
- **Order.** Label above the value on 14 screens; labels grey (#6b6b6b-#aaa) on 13; sentence case.
|
|
519
|
+
- **Nothing else.** No icon in a coloured circle (0 of 23), no sparkline (0 of 23), no tinted tile.
|
|
520
|
+
An info icon beside the label is fine (5 screens). Units are a smaller grey suffix: "5 mins" at 24
|
|
521
|
+
over 14, "2 m 24 s", "5 /10".
|
|
522
|
+
- **The answer figure leads.** When one figure is the screen's answer (a balance, net worth, the
|
|
523
|
+
portfolio's value), it is 30-36px and at least 1.3 times its sibling figures (those at 18-24px). In
|
|
524
|
+
testing, a 24px portfolio value beside two 24px figures left the screen without a lead. No other
|
|
525
|
+
figure on the screen is larger: the biggest number answers the title row's sentence, so a
|
|
526
|
+
secondary ratio in another card stays at the siblings' size.
|
|
527
|
+
- **One figure, one place.** A figure shown in the strip is not repeated in a legend beside it, and a
|
|
528
|
+
KPI strip whose every cell names a panel below (RSVPs, then an RSVPs panel) is dropped: lead each
|
|
529
|
+
panel with its own number instead.
|
|
530
|
+
- **A second job.** KPIs may be the chart's series tabs or the list's type filter (the selected card
|
|
531
|
+
takes a 1.5px border). As tabs, the selected one carries a 2px rule or the active fill and an ink
|
|
532
|
+
label; the others keep a grey label and their value in ink, at 400 against the selected one's 500.
|
|
533
|
+
A grey value reads as disabled: in testing, three shops' takings set in grey because they were tabs
|
|
534
|
+
read as secondary, though they were the brief's first ask. When the tabs are the per-entity
|
|
535
|
+
breakdown the brief asks for, grey nothing and let the rule alone mark the selection. On a phone the
|
|
536
|
+
tabs become a 2-up grid with the selected cell filled, or a row that scrolls sideways; never an
|
|
537
|
+
underline floating inside the grid (`app.css` does both).
|
|
538
|
+
|
|
539
|
+
### Deltas
|
|
540
|
+
|
|
541
|
+
- Optional: 9 of the 20 KPI screens show one; 11 do not.
|
|
542
|
+
- 10-15px (median 14), never larger than the label. Text or a small glyph on 6 screens; a pale pill
|
|
543
|
+
on 3.
|
|
544
|
+
- **The window in words**: "vs prior 30 days", "in the last 90 days", "from 0 (last 4 weeks)" (7 of
|
|
545
|
+
the 9).
|
|
546
|
+
- **Colour only the number**, or set the whole delta in grey.
|
|
547
|
+
- **Colour says good or bad, not up or down** (house rule, from testing). Every metric has a good
|
|
548
|
+
direction: latency, error rate, cost, churn and time-to-reply are better when they fall. A change
|
|
549
|
+
in the bad direction puts `--negative` on the number (or a small down-pointing glyph in that
|
|
550
|
+
colour); a change in the good direction is `--positive` or grey. A judge read a 2.5× rise in errors
|
|
551
|
+
set in the same grey as a rise in visits as hiding the screen's only bad news.
|
|
552
|
+
- **Zero or undefined change is grey.** The study's commonest KPI failure is a zero or undefined change
|
|
553
|
+
shown as a signal: three identical green "up 100%" pills grown from zero, a ">999%", a bold red
|
|
554
|
+
"0.00%", a green "+0". When the prior period was zero, write "+4 (new)"; when there is nothing to
|
|
555
|
+
compare, a short grey dash where the delta would be.
|
|
556
|
+
|
|
557
|
+
## 6. Charts
|
|
558
|
+
|
|
559
|
+
### 6.1 Which chart for which question
|
|
560
|
+
|
|
561
|
+
| Question | Form | In the study |
|
|
562
|
+
| --- | --- | --- |
|
|
563
|
+
| Is it moving over time? | One line; an area only with a fill of 15% or less | 9 screens |
|
|
564
|
+
| How much per period? | Columns with square corners | 3 |
|
|
565
|
+
| How is it distributed? | A histogram with equal bins | 1 (its unequal bins are flagged) |
|
|
566
|
+
| Who ranks? | A sorted horizontal bar list, or the row's fill as the bar in a one-figure list | 3 |
|
|
567
|
+
| What share? | A thin ring, or a 100% stacked bar with 2px seams; five parts at most | 5 |
|
|
568
|
+
| How far to the target? | A progress bar, both ends labelled, the fill the true ratio | 4 |
|
|
569
|
+
| How much of the plan is used? | A track as long as the plan, the spent part filled, what is already committed as a lighter segment, an overrun past the track's end in the negative colour (`Charts.plan`) | house rule |
|
|
570
|
+
| Has it drifted from its target? | One row per part: the current share as a bar with a 1px tick at the target (`Charts.bullet`); never two stacked bars to compare | house rule |
|
|
571
|
+
| Where? | A map with a list beside it; the list carries the magnitudes | 1 |
|
|
572
|
+
| Per period, and the running total? | The two side by side at equal width, with the same dates | 1 |
|
|
573
|
+
| Which way did it flow, and how much? | Columns above and below one zero line on one scale, the axis signed and captioned on each side ("Sold" above, "Bought" below), a marked period in a second tone with its own legend entry (`Charts.diverging`) | house rule |
|
|
574
|
+
| Who is away when? | A timeline of people by day, each kind of booking its own mark (`Charts.timeline`) | house rule |
|
|
575
|
+
| Is there enough cover? | A team-by-day matrix of slack against the minimum (+2, +1, 0, −1), one hue ramping toward the negative colour, the headcount on hover (`Charts.matrix`) | house rule |
|
|
576
|
+
| When in the day, against last time? | One row per item on a shared opening-to-closing axis: a 2px grey track, an ink dot for today, a hollow tick for the comparison day (`Charts.timeStrip`) | house rule |
|
|
577
|
+
|
|
578
|
+
Three more, from testing:
|
|
579
|
+
|
|
580
|
+
- **The pair of per-period bars and the running total is used once per screen**, and only when the
|
|
581
|
+
total crosses a line that matters (capacity, a target). Three such pairs in six charts read as one
|
|
582
|
+
pattern stamped out.
|
|
583
|
+
- **A series that is flat except for one event** gets at most two-thirds of the width and about 140px of
|
|
584
|
+
height, or a range capped at about twice its reference line with the off-scale peak labelled
|
|
585
|
+
(`Charts.line({ max })`). A full-width plot that is 85% empty was the biggest block on a first
|
|
586
|
+
screen and was marked down.
|
|
587
|
+
- **A forecast is not a fact**: after today the line is dashed and the end value is labelled
|
|
588
|
+
(`Charts.line({ today, endLabel })`), with the gap to the target bracketed when there is one.
|
|
589
|
+
- **What the brief asks to see over time is drawn on the first screen.** KPI cells may switch the chart
|
|
590
|
+
only between metrics the brief did not name.
|
|
591
|
+
|
|
592
|
+
When there are only a few numbers, draw no chart: four screens skip it, and the settings page links
|
|
593
|
+
to the analytics screen with "View more".
|
|
594
|
+
|
|
595
|
+
### 6.2 One question, one series
|
|
596
|
+
|
|
597
|
+
One series per chart is the norm; three is the most any screen draws. To show another metric, switch
|
|
598
|
+
it with a control (a segmented control, a dropdown, the KPIs as tabs) instead of overlaying lines.
|
|
599
|
+
Plots run 112-264px tall (median about 195) and 316-1136px wide (median about 570), an aspect of 1.8
|
|
600
|
+
to 5.2.
|
|
601
|
+
|
|
602
|
+
### 6.3 Axes and gridlines
|
|
603
|
+
|
|
604
|
+
- **Gridlines** run horizontally only on 7 of the 12 cartesian charts, both ways on 3, and not at all
|
|
605
|
+
on 2. Use 3-5 (the study runs 3-7, median 4-5): 1px, solid, about #e5e5e5 on light (range
|
|
606
|
+
#cfcfd2-#f2f2f2), #2b2b2b on #111. Dashed lines are allowed in chart grids (4 screens: 3/3, 4/4,
|
|
607
|
+
3/2.5) and nowhere else on the screen.
|
|
608
|
+
- **No y-axis line.** The baseline is the one heavier line (2px on two screens, 1px on one); full axes
|
|
609
|
+
on one.
|
|
610
|
+
- **Y ticks**: 4-7, median 5, at 11-16px (median 12) in grey (#5f5f5f-#6c6c6c), on the left (8
|
|
611
|
+
screens) or the right (2). Round, even steps (0/5/10/15%; 0-600 by 150), the top tick above the
|
|
612
|
+
maximum, integers for counts, and zero as the baseline for bars and counts.
|
|
613
|
+
- **Never without a scale.** Two screens draw no y-scale and show magnitude only on hover; both are
|
|
614
|
+
flagged. So are uneven ticks (0/3/6/10), a 0.8 tick on a count, a top tick equal to the maximum so
|
|
615
|
+
the line hits the plot's edge, and a cumulative axis that starts at 1.
|
|
616
|
+
- **Axis text no larger than the data.** 15-16px ticks beside 14px values are flagged as louder than
|
|
617
|
+
the numbers.
|
|
618
|
+
- **X labels**: 4-8 per chart, flat, never rotated (40 degrees is flagged), the first and last pulled
|
|
619
|
+
inside the plot, on one step all the way: a forced closing label after 14:00 on a 90-minute step
|
|
620
|
+
left a short last gap that a judge measured. Choose a step that lands on the end (hourly from 08:00
|
|
621
|
+
to 15:00) or leave the end unlabelled. Labelling only the two ends hides when things happened. Irregular dates on a
|
|
622
|
+
categorical axis are flagged: time goes on a time scale.
|
|
623
|
+
|
|
624
|
+
### 6.4 Marks
|
|
625
|
+
|
|
626
|
+
- **Lines** 1-3px, median 2, in straight segments. Four screens smooth their lines, and one smoothed
|
|
627
|
+
curve invents values between daily totals (flagged), so draw straight segments. No point markers,
|
|
628
|
+
except a hover dot (8px on one screen).
|
|
629
|
+
- **Fill**: none on 7 of 10 time charts. At most a flat tint of about 14%, or a fade from the line to
|
|
630
|
+
transparent over 150-200px.
|
|
631
|
+
- **Bars** have square corners (4 screens), or at most a 4px top radius with a square bottom on the
|
|
632
|
+
baseline. Stacked segments are split by a 1-2px seam.
|
|
633
|
+
- **Colour.** One hue per chart. The accent touches only data on 8 screens, and data ink is under 3%
|
|
634
|
+
of the pixels on most. Neutral series are fine and often better: a near-black line that turns pale
|
|
635
|
+
grey after the cursor; a white line against a red one; signs instead of colour ("+$24,000,000").
|
|
636
|
+
But the one hue, when the style has one, goes on the screen's main data element (today's series,
|
|
637
|
+
the booked bars, the current period, the margin that breaks), not on a secondary chart or a delta:
|
|
638
|
+
in testing, an all-ink screen with no hue on any of its data read as a kit.
|
|
639
|
+
One subject keeps one hue across the screen: the same subscribers drawn pink in one chart and indigo
|
|
640
|
+
in the next is flagged. Unrelated hues on one screen (three, five) are flagged every time. Status
|
|
641
|
+
colours are for status. The inspector warns over four hues and fails over six.
|
|
642
|
+
- **Legends.** None for a single series (9 charts): the title or the dropdown names it. Otherwise five
|
|
643
|
+
items at most, as a 5-8px dot with a 12-14px grey label in the card's header, or as a small table
|
|
644
|
+
(dot, name, value, change) that makes the legend carry data. Never list a series that has no data
|
|
645
|
+
(flagged). Every swatch is the mark it explains, scaled down: the legend dot is the line's colour,
|
|
646
|
+
a hatched bar's swatch is hatched. A swatch drawn separately from the mark drifted from it in testing
|
|
647
|
+
(a black outline with a red edge explaining a red outline); the helpers return the legend built from
|
|
648
|
+
the same style object as the marks.
|
|
649
|
+
- **Rings** only for three to five parts of a whole that are not already listed beside them (a ring
|
|
650
|
+
redrawing the spent, due and left figures of the tile next to it was marked redundant). Never
|
|
651
|
+
labelled on the slices; the total sits in the centre or beside the ring. The
|
|
652
|
+
screens noted for their rings use thin strokes: 3-5px on a 90-154px ring, 8px on 182px. Two others
|
|
653
|
+
use 28 and 37px.
|
|
654
|
+
- **Progress bars** are 4-24px tall (median 8), fully rounded, with both ends labelled ("Skilled 200"
|
|
655
|
+
and "Expert 2,000"); the fill is the true ratio, so 303 on that scale fills 22px of 392. A zero has
|
|
656
|
+
no stub (a 6px stub at zero is flagged).
|
|
657
|
+
- **Tooltips** are bare text or a plain box without an arrow: label and value on one line.
|
|
658
|
+
- **Annotate the event that matters.** A step or a spike more than about three times the usual change
|
|
659
|
+
gets a 1px marker and a 12px label naming its cause ("Deploy a3f09c1", "Newsletter featured");
|
|
660
|
+
reference lines (a budget, an SLO, a start time) are 1px dashed with their label at the end. In
|
|
661
|
+
testing, an unexplained jump was the first thing a judge asked about. `Charts.line`,
|
|
662
|
+
`Charts.bars` and `Charts.diverging` take `annotations` and `reference`.
|
|
663
|
+
- **Labels never collide.** Annotation labels sit in rows above the plot, each beside the top of its
|
|
664
|
+
own leader line, and no leader line runs through another label; the rows are reserved only when a
|
|
665
|
+
label exists, so a chart without one has no dead band above it. The "Now" label of a forecast goes
|
|
666
|
+
on whichever side of its line the series does not cross. Lay labels out after the fonts load, or
|
|
667
|
+
the label set changes between loads (it did in testing). The helpers do all of this; give a label
|
|
668
|
+
that may not fit a `short` form.
|
|
669
|
+
- **Use the helper, then extend it.** Draw charts with `assets/charts.js` and add what a chart needs to
|
|
670
|
+
it, rather than writing new axis code: in testing, every chart written from scratch on a phone put
|
|
671
|
+
its y labels on top of its line.
|
|
672
|
+
- **Short and empty histories are drawn honestly**: a flat zero line with one spike, missing bars for
|
|
673
|
+
empty periods, no padded y-range, no "No data" picture. Do not give one point the screen's largest
|
|
674
|
+
plot, though: a lone dot in a full-size grid reads as barren (flagged once).
|
|
675
|
+
|
|
676
|
+
## 7. Tables and lists
|
|
677
|
+
|
|
678
|
+
### 7.1 Rows
|
|
679
|
+
|
|
680
|
+
- Single-line data rows: 36-53px, median 45.
|
|
681
|
+
- Two-line rows with media: 56-92px, median 72. The pitch is the media's height plus 24-32px
|
|
682
|
+
(48 + 24, 48 + 32, 50 + 30).
|
|
683
|
+
- Key-value and legend rows inside cards: 21-32px.
|
|
684
|
+
- In a two-line cell, line 2 sits about 21px below line 1 (19-23), one size smaller (12-14px) and
|
|
685
|
+
grey. Two-line labels need a 40-44px pitch at least: on a 32px pitch a subline nearly touched the
|
|
686
|
+
next row's name and the list ran together (house rule, from testing).
|
|
687
|
+
- Overview lists show 2-5 rows.
|
|
688
|
+
|
|
689
|
+
### 7.2 Header
|
|
690
|
+
|
|
691
|
+
- 11-14px, median 12, mostly regular weight, grey, sentence case (9 of the 11 headed tables). The one
|
|
692
|
+
uppercase header in the study is flagged as louder than the data.
|
|
693
|
+
- **No fill band** (0 of 11) and **no rule under it** on 8 of 11. Where there is a rule, it is the
|
|
694
|
+
strongest line in the table (#e5e7eb over #f3f4f6 row rules).
|
|
695
|
+
- Header row 36-40px.
|
|
696
|
+
- Numeric headers are right-aligned and flush with their values; a header that stops 15px short of
|
|
697
|
+
its column is flagged. A header over a control aligns with the control it labels (centred over a
|
|
698
|
+
column of steppers), and a delta beside a stepper gets its own narrow unlabelled column; three
|
|
699
|
+
alignments in one header row were flagged.
|
|
700
|
+
- A sort glyph on the active column only.
|
|
701
|
+
|
|
702
|
+
### 7.3 Dividers
|
|
703
|
+
|
|
704
|
+
- **No zebra striping** (0 of 23).
|
|
705
|
+
- No row dividers on about half the lists; they rely on a 61-92px pitch or on 2-8px gaps between
|
|
706
|
+
filled rows.
|
|
707
|
+
- When present: 1px, 3-7% darker than the surface (#ededed-#f4f4f4 on white; #161616 on #000,
|
|
708
|
+
#1b1a1f on #131217).
|
|
709
|
+
- Extent: bleeding 8-9px past the text edge; starting at the text column and skipping the media; or
|
|
710
|
+
the full inner width. Pick one per screen.
|
|
711
|
+
|
|
712
|
+
### 7.4 Figures and alignment
|
|
713
|
+
|
|
714
|
+
- **Numbers right-aligned**, in tabular figures or a monospace. Every left-aligned numeric column and
|
|
715
|
+
every column of proportional digits in the study is flagged (durations "00:00:12" and "00:00:04"
|
|
716
|
+
that jitter, cents that drift).
|
|
717
|
+
- **Fixed decimals per metric**: money 2, percentages 1 or 2, counts none. Thousands separators
|
|
718
|
+
everywhere ("$16,531.54"); abbreviate only in a capacity line ("12.7k of 20.0k"). A sign on every
|
|
719
|
+
change ("-$0.09", "+10,100 (+0.20%)"). No space after the currency sign (one screen's "$ 89.00"
|
|
720
|
+
beside "$15.00" is flagged).
|
|
721
|
+
- **The identity column gets the most width**, about a third to a half of the table, and it is never
|
|
722
|
+
the one cut off at desktop width: shorten names editorially first (drop the issuer every row
|
|
723
|
+
shares, the share class, "Ltd") and use the same short name at every width.
|
|
724
|
+
- **One right edge per row or card**: every right-aligned figure inside a card or row ends on the same
|
|
725
|
+
padding line (a days-in-stage figure 18px short of the value above it reads as a second edge).
|
|
726
|
+
- **Two measures stack in one cell** rather than taking two columns: a count over its 12px grey
|
|
727
|
+
percentage, a date over its time, a money value over the amount in units, both lines on one right
|
|
728
|
+
edge.
|
|
729
|
+
- **Dates** in ISO form and right-aligned where rows are compared ("2024-02-15"); in words for
|
|
730
|
+
recency ("Today", "Yesterday", "6 days").
|
|
731
|
+
- **IDs** in a monospace at body size, truncated to about 8 characters with an ellipsis and a copy
|
|
732
|
+
icon 12px after.
|
|
733
|
+
- Truncate to one line with an ellipsis; never break inside a word.
|
|
734
|
+
- **A breakdown in a narrow card** ("Headingley 6 · Chapel Allerton 5 · Meanwood 3") goes in fixed
|
|
735
|
+
mini-columns, or each item is `nowrap` with its separator attached to the next item, so no line ends
|
|
736
|
+
on a dangling "·".
|
|
737
|
+
- **An edited cell shows that it changed** (house rule, from testing). In an editable grid a changed
|
|
738
|
+
value carries a mark (a dot, a tinted border), and the column header or a caption names the
|
|
739
|
+
baseline ("vs the usual Monday"); a bare grey "+5" beside a stepper was read as noise.
|
|
740
|
+
|
|
741
|
+
### 7.5 Ink inside rows
|
|
742
|
+
|
|
743
|
+
- Only the identity and the key number get the primary ink; everything else is grey ("5" in ink,
|
|
744
|
+
" /10" in grey).
|
|
745
|
+
- A missing value is a grey dash; a real zero is printed ("$0", "0.00%", "0% (0)").
|
|
746
|
+
- The sign lives in the text, not in the colour: income green with a "+", expenses in ink, no red on
|
|
747
|
+
every negative.
|
|
748
|
+
- Link colour on the name cell only, with no underline.
|
|
749
|
+
|
|
750
|
+
### 7.6 Status pills
|
|
751
|
+
|
|
752
|
+
- 15-28px tall (median 20), text 9-14px in the study (median 12) at 500; nothing under 11px here. A
|
|
753
|
+
full pill or a 3-5px tag.
|
|
754
|
+
- A pale tint with dark text of the same hue, optionally a 1px border one step darker: #dcfae5 with
|
|
755
|
+
#04250e, #ffedea with #831c1e.
|
|
756
|
+
- Neutral states are monochrome chips with a glyph ("Public" with a globe).
|
|
757
|
+
- A state machine uses one hue at three intensities: grey for off, the full hue for the call to
|
|
758
|
+
action, a dark tint for running. A saturated fill with white text only for that one call to action,
|
|
759
|
+
and only while it is rare: when more than about a fifth of the visible rows carry it, it becomes a
|
|
760
|
+
stripe of black blobs louder than the data (marked down in testing); use the pale pair or a 6px dot
|
|
761
|
+
with an ink label instead.
|
|
762
|
+
- **One status mark per row.** A tag and a badge that say the same thing are flagged.
|
|
763
|
+
- **A chip is never squeezed.** Tags and pills are `flex: none; white-space: nowrap`: in testing a
|
|
764
|
+
table column collapsed an environment chip to a 12px box with its word spilling out.
|
|
765
|
+
|
|
766
|
+
### 7.7 Media
|
|
767
|
+
|
|
768
|
+
16px logos in dense rows; 24-32px avatars; 48-50px in two-line rows. Circles for people, tokens and
|
|
769
|
+
companies; a 2-3px radius for artwork and flags; 8px for photographs. One fixed media slot down the
|
|
770
|
+
list so the text starts on one edge (a 50px slot with the text 16px after it). Media-to-text gap
|
|
771
|
+
10-16px, median 12.
|
|
772
|
+
|
|
773
|
+
### 7.8 Actions and paging
|
|
774
|
+
|
|
775
|
+
- **No pagination on an overview** (0 of 23). Cap the rows and link out: "View all" in the section
|
|
776
|
+
header, a 30px outlined button under the list, a full-width 32px bar. State the total ("3 tracks").
|
|
777
|
+
- Row actions: none on 9 screens; otherwise one kebab at the far right. Reserve a trailing action
|
|
778
|
+
column only when most rows carry the action; otherwise the action is an ink text action on the
|
|
779
|
+
row's second line and the figures stay flush to the card edge. When a row needs doing
|
|
780
|
+
(a bill to pay, an order to pack, a failed deploy), its action is a visible ghost button or an ink
|
|
781
|
+
text action in one fixed trailing column, at the same pitch for every row; never muted grey text,
|
|
782
|
+
and never stacked under the amount so the rows change height.
|
|
783
|
+
- Checkboxes only where bulk actions exist (one screen: 18px, 2px stroke, 3px radius).
|
|
784
|
+
- Hover and selected: a 1px outline at 6px radius overhanging the panel by 1px, or a darker border
|
|
785
|
+
with a 1px ring. No hover that changes the fill was seen. In a list that drives a detail pane (an
|
|
786
|
+
inbox, a queue), the selected row takes the `--active` fill of the nav pill instead, so it cannot be
|
|
787
|
+
mistaken for a focus ring or a hover (house rule, from testing).
|
|
788
|
+
- Toolbar: one search, 30-36px tall (256x30, 252x36, 316x32).
|
|
789
|
+
- **A full list screen** (house rule; the study has none): state the total above the table, keep the
|
|
790
|
+
header row in view while scrolling, and page or load more at the end with the range shown
|
|
791
|
+
("1-50 of 1,284").
|
|
792
|
+
|
|
793
|
+
### 7.9 Lists that carry data
|
|
794
|
+
|
|
795
|
+
- **The row fill is the bar**: the row's rounded background (radius 8) as wide as its share of the
|
|
796
|
+
largest share; 44px rows, 2px gaps. Only in a one-figure ranking list (a label and one value): in a
|
|
797
|
+
row with several columns or two lines, the fill's edge cuts through the words (failed in testing).
|
|
798
|
+
Planned against spent is a separate 6-8px track under the label (`Charts.plan`).
|
|
799
|
+
- **Bar list**: a 64px pitch, a label line, then a 10px pill bar with the value 5px after its end; the
|
|
800
|
+
longest bar about 88% of the width; one colour, no track.
|
|
801
|
+
- **Inline bars in a list are thin and grey** unless they are the screen's main series: 2-3px at
|
|
802
|
+
most. A ranked list of money in a narrow card carries a 2px proportional bar under each label, grey
|
|
803
|
+
with the top item in ink (`Charts.barList(el, rows, { thin: true })`), so "most costly first" is
|
|
804
|
+
seen and not only read. In testing, six 4px black bars were the loudest marks on the screen.
|
|
805
|
+
- **A timeline draws its comparison.** When the brief asks "against last Sunday", the comparison is a
|
|
806
|
+
mark on the same axis (`Charts.timeStrip`: an ink dot for today, a hollow tick for the comparison
|
|
807
|
+
day), not only a line of text.
|
|
808
|
+
- **Legend as table**: dot, name, pill, value and change on a 57px pitch.
|
|
809
|
+
- **Key-value well**: a tinted well, radius 8, 32px rows, label left, figure right.
|
|
810
|
+
- **Feed as row cards**: 63px tall, 8px gaps, radius 14, a fill one step lighter and a border one step
|
|
811
|
+
darker than the panel, a relative date on the right.
|
|
812
|
+
- **Tree**: no dividers, 8px of indent per level, ink against grey by level, a pitch of about 30px,
|
|
813
|
+
about 45px between groups.
|
|
814
|
+
|
|
815
|
+
## 8. Forms and settings
|
|
816
|
+
|
|
817
|
+
The study holds forms on three screens and one settings page, so this section rests on little. It is
|
|
818
|
+
enough for the defaults.
|
|
819
|
+
|
|
820
|
+
### 8.1 Fields
|
|
821
|
+
|
|
822
|
+
- **Label above the field**, 14px at 500, 8-10px gap. No floating labels and no placeholder standing
|
|
823
|
+
in for a label.
|
|
824
|
+
- **Inputs** 38-40px in forms (radius 8-10); toolbar and filter controls 28-40px, median 32. One
|
|
825
|
+
control height per context.
|
|
826
|
+
- Inputs stay white with a 1px #e5e7eb-#e8e8e8 border even on a grey panel; filter and select
|
|
827
|
+
controls take a border one step darker (#cdcfcf-#d1d5db).
|
|
828
|
+
- A leading icon at 14px, 13px in from the edge, with the text starting at 38px.
|
|
829
|
+
- **Spacing**: 24px from a description to the first label, 16px between fields, 16px to the Save
|
|
830
|
+
button.
|
|
831
|
+
- **A joined input and action** (a read-only link and its Copy button) share a border and square
|
|
832
|
+
their inner corners.
|
|
833
|
+
- **Toggles** 28x16 to 33x20. The on colour is a semantic green or near-black, not the brand accent.
|
|
834
|
+
- **Disabled** controls stay legible and say why they are disabled: the study's disabled Save
|
|
835
|
+
(#cecece on #f4f4f4, about 1.4:1) and its plan-locked panel at 30% opacity are flagged as
|
|
836
|
+
unreadable.
|
|
837
|
+
|
|
838
|
+
### 8.2 Settings layout
|
|
839
|
+
|
|
840
|
+
- Each section is a row: a label column (about 450px: a 16/500 title and a 14px grey description)
|
|
841
|
+
beside a panel (about 700px, #fafafa, radius 16, padding 16, no border, no shadow). The title's cap
|
|
842
|
+
top aligns with the panel's first line, 6-8px below the panel's top.
|
|
843
|
+
- Sections are split by a full-width 1px rule with 32px above and below.
|
|
844
|
+
- A switch row: a 14/500 title, a status badge 8px after it, a 14px grey description, and the toggle
|
|
845
|
+
on the right, 16px from the edge and centred on the title line.
|
|
846
|
+
- A plan-gated feature: a 48px tinted strip with a 32px button directly above the locked panel; the
|
|
847
|
+
panel stays readable.
|
|
848
|
+
- Narrow containers stack: label, 10px, field, then 26px to the next pair.
|
|
849
|
+
- Do not leave the label column empty beside a tall panel (a 250px void is flagged): put the section's
|
|
850
|
+
help or a summary of its current values there, or narrow the column.
|
|
851
|
+
- **Destructive actions** (house rule; none in the study) go last, in a section of their own, as a
|
|
852
|
+
text or outlined button in the negative colour, with the consequence in words and a confirmation
|
|
853
|
+
that names the object.
|
|
854
|
+
- **One view per area** (house rule, from testing). When settings span several areas (general,
|
|
855
|
+
members, billing, notifications), each sidebar item opens its own view (a hash route is enough in
|
|
856
|
+
a static build), with the area's name as the h1. One long page of every area, with the sidebar
|
|
857
|
+
scrolling to anchors, put the first area the brief named four screens down and was marked down.
|
|
858
|
+
- **One save model per view**: every control saves itself and shows a quiet "Saved" stamp, or one
|
|
859
|
+
Save per panel at the panel's bottom right. Never a mix of both on one view.
|
|
860
|
+
- **Show what the setting produces.** Beside the control that changes it, a small preview of the
|
|
861
|
+
result (the invite email, the notification as it will arrive, the plan's next invoice) is the
|
|
862
|
+
product-specific substance a settings screen otherwise lacks.
|
|
863
|
+
- A settings view opens with a usage strip only when usage is its question (a plan or quota view),
|
|
864
|
+
and its figures stay smaller than its h1.
|
|
865
|
+
|
|
866
|
+
### 8.3 Buttons
|
|
867
|
+
|
|
868
|
+
Controls run 27-40px tall (median 34; 32 is the commonest), with a 6-8px radius in the tight styles
|
|
869
|
+
and full pills in the soft ones. One filled primary per screen, usually near-black; a secondary is
|
|
870
|
+
white with a 1px border; a tertiary is text. The controls in one row share one height.
|
|
871
|
+
|
|
872
|
+
## 9. Type and colour
|
|
873
|
+
|
|
874
|
+
### 9.1 Type
|
|
875
|
+
|
|
876
|
+
- **One grotesk.** All 23 screens use a neo-grotesk, and 14 use that one family alone. A second face
|
|
877
|
+
always has one job: a monospace for every number or for IDs only, a serif for one greeting, a brand
|
|
878
|
+
face kept to the wordmark or the switcher. Never three. Axis ticks, chart notes and labels stay in
|
|
879
|
+
the text face even when IDs are in a monospace.
|
|
880
|
+
- **App type is not display type.** The h1 stays at 18-32px and no figure reaches 48px: in testing, a
|
|
881
|
+
50px serif title and a 76px balance made a budgeting screen read as a landing page (the inspector
|
|
882
|
+
warns at 34px and 48px).
|
|
883
|
+
- **Sizes**:
|
|
884
|
+
|
|
885
|
+
| Role | Range in the study | Median |
|
|
886
|
+
| --- | --- | --- |
|
|
887
|
+
| Page title | 14-48 | 24 |
|
|
888
|
+
| KPI value | 16-40 | 24 |
|
|
889
|
+
| Card title (500-600) | 14-24 | 16 |
|
|
890
|
+
| Body, nav, cells | 13-16 | 14 |
|
|
891
|
+
| Labels, meta | 11-14 | 12 |
|
|
892
|
+
| Axis ticks | 11-16 | 12 |
|
|
893
|
+
| Pills, badges | 9-14 | 11-12 (house floor 11) |
|
|
894
|
+
|
|
895
|
+
A screen uses 4-9 sizes, median 6. The cleanest scales in the study are 12/14/18/24, 12/14/16/30
|
|
896
|
+
and 12/14/16/24.
|
|
897
|
+
- **Weights**: a median of 3 per screen; 10 of 23 never go above 600; 700 does one job per screen
|
|
898
|
+
(money, the greeting or the title).
|
|
899
|
+
- **Figures**: tabular on every number in a table, in a KPI, or anywhere it updates. Check that the
|
|
900
|
+
face really has tabular figures: `font-variant-numeric: tabular-nums` must change its digit widths;
|
|
901
|
+
if it does not, take another face.
|
|
902
|
+
- **Case**: sentence case on about 19 of 23; uppercase content labels on 4 only. Tracking 0, and
|
|
903
|
+
negative only on large type (-0.02em at 32px). Line height 20px for 14px text, 24px for 16px.
|
|
904
|
+
- **Dark** screens set body at 13px on three, and titles at 18-20/600 or 26-28/700.
|
|
905
|
+
|
|
906
|
+
### 9.2 Colour on light screens
|
|
907
|
+
|
|
908
|
+
- **Ground models**: white cards on an off-white ground (10 screens; #f3f5f7 to #fdfdfd, median
|
|
909
|
+
#f9f9f9-#f9fafb); grey panels on white (6); a framed sheet (7).
|
|
910
|
+
- **The sidebar is never dark or saturated** (0 of 17): it matches the page, sits 1-3 levels off it,
|
|
911
|
+
or is white on a grey page.
|
|
912
|
+
- **Lines in three steps.** Card edges median #eaeaea, the working band #e5e7eb-#ededed (about 1.2:1 on
|
|
913
|
+
white). Row rules one step lighter, #efefef-#f4f4f4. Control borders one step darker, median
|
|
914
|
+
#d1d5db. #cbcecd on cards reads heavy; #f5f5f5 disappears.
|
|
915
|
+
- **Text in three tiers.** Primary about #111 (range #000 to a tinted #272446). Secondary about #606060
|
|
916
|
+
(#3a3b3b-#8e8e8e). Tertiary in the study runs #969696-#9f9d9b and placeholders #9ca3af-#b0b2b6,
|
|
917
|
+
which is 2.5-3:1 on white and under the house floor. House rule: every tier that carries words
|
|
918
|
+
reaches 4.5:1 on the surface it sits on, placeholders included; #6b6b6b is about the lightest grey
|
|
919
|
+
that holds on white and on #f9fafb.
|
|
920
|
+
- **Accent placement**: on data only with greyscale chrome (4 screens), on actions only (2), or no
|
|
921
|
+
accent at all (2). The primary button is usually near-black. Every screen with more than one accent
|
|
922
|
+
family is flagged.
|
|
923
|
+
- **Status**: positive greens in the study run #16a34a-#40a670, which is under 4.5:1 as text; use a
|
|
924
|
+
darker green such as #247b50 (5.2:1) for text, and the pale pairs for pills: positive #dcfae5 with
|
|
925
|
+
#04250e, negative #ffedea with #831c1e, a notice #fffbeb with a #fde68a border and #92400e text, a
|
|
926
|
+
count badge #c4242a-#dc3532.
|
|
927
|
+
|
|
928
|
+
### 9.3 Colour on dark screens
|
|
929
|
+
|
|
930
|
+
- **Ground**: #000 (3 screens), #111 (2), #171719 (1). No navy and no slate.
|
|
931
|
+
- **Surfaces**, three ways: a lighter step with no border (#111 on #000, nested panels at
|
|
932
|
+
#222-#2a2a2a); the ground's own fill with a 1px line (#2e2e2e on #111); darker than the ground with
|
|
933
|
+
a soft shadow (once: #131217 on #171719 with 0 12px 28px rgba(0,0,0,.2)).
|
|
934
|
+
- **Lines**: structural lines 22-31 levels above the ground (#1a1a1a on #000, #2e2e2e on #111,
|
|
935
|
+
#222224 on #171719); interactive outlines brighter, #373737-#4c4c4c, so an outlined button reads as
|
|
936
|
+
clickable without a fill.
|
|
937
|
+
- **Text**: #fff; secondary about #aaa (#82848a-#bbb); tertiary about #888. #4c4c4f (about 2:1) is
|
|
938
|
+
flagged. The house floor of 4.5:1 holds here too. Two greys at most, and far enough apart to read
|
|
939
|
+
as two: about #b4b4b4 for secondary text and #949494 for meta (in testing, #aaaaaa, #969696 and
|
|
940
|
+
#bbbbbb on one screen read as one grey used three ways).
|
|
941
|
+
- **Accent** on data only, or on one selected state. Active nav by brightness. Emphasis without
|
|
942
|
+
colour: an inverted white pill, a grey-filled button (#212121), an outline.
|
|
943
|
+
- **Status** as a hue on a dark tint of itself: #3fc07a on #172a1d; #44a282 on #1b2828. **When the
|
|
944
|
+
accent is green or yellow-green, `--positive` is the accent** (a lime accent: lime on a dark lime
|
|
945
|
+
tint), or the sign carries the meaning in neutral ink; a mint "+£3.81" beside a lime "Sold" read as
|
|
946
|
+
two greens. The same holds on light screens.
|
|
947
|
+
- **Colour share** at or under 3% on all six.
|
|
948
|
+
|
|
949
|
+
### 9.4 Surfaces, radius, icons, spacing
|
|
950
|
+
|
|
951
|
+
- **Edges.** A 1px border separates surfaces on 12 of the 17 light screens; three use a fill step
|
|
952
|
+
alone and one a shadow alone. A border or a shadow, never both. The shadows that exist are faint
|
|
953
|
+
(alpha .06 or less at 0 2px 8px; once 0 1px 4px at .12). Real shadows are for what floats: a menu,
|
|
954
|
+
a popover, a tooltip, a composer.
|
|
955
|
+
- **Radius is bimodal**: tight, 4-8px (9 screens, plus square cards on one), or soft, 16-24px (10);
|
|
956
|
+
11-12px on only 3. Controls follow the cards: 6px with tight cards, full pills with soft ones.
|
|
957
|
+
Nested radii step down (20, 10, 8, 5, 4). The inspector warns over three panel radii.
|
|
958
|
+
- **Group, don't box.** A set of KPIs is one card split by 1px dividers, or a bare strip with 48-52px
|
|
959
|
+
vertical dividers.
|
|
960
|
+
- **Icons**: outline on 22 of 23; nav icons 14-20px (median 16) at about 1.5px; inline icons 12-14px;
|
|
961
|
+
about 10px to the label; grey (#454545-#73737f in a light nav, white or #81858a-#999 on dark). Never
|
|
962
|
+
in a saturated circle (0 of 23). A container, if any, is neutral (a #f0f0f0 disc) or codes a node
|
|
963
|
+
type in a builder.
|
|
964
|
+
- **Spacing** on a 4px base: card gap 6-24px (median 16); card padding 12-34px (median 20); section
|
|
965
|
+
gap 24-64px; control height 27-40px (median 34).
|
|
966
|
+
|
|
967
|
+
### 9.5 Default tokens
|
|
968
|
+
|
|
969
|
+
Each style in `library/app.json` carries its own tokens. These are the study's medians for anything a
|
|
970
|
+
style does not set, with the greys moved to pass 4.5:1.
|
|
971
|
+
|
|
972
|
+
The names match the sheet `draw.mjs --app` prints and `assets/app.css`, a neutral start set to these
|
|
973
|
+
defaults (shell, title row, panels, the divided KPI strip, tables, pills, controls, tabs, empty states
|
|
974
|
+
and the phone fold). `assets/charts.js` draws the charts of §6 in SVG from your data (line, bars,
|
|
975
|
+
diverging columns, ring, bar list, plan, bullet, timeline, cover matrix and time strip), with these
|
|
976
|
+
rules built in and its colours read from these tokens.
|
|
977
|
+
|
|
978
|
+
```css
|
|
979
|
+
:root {
|
|
980
|
+
/* light */
|
|
981
|
+
--ground: #f9fafb; --surface: #ffffff; --raised: #f9f9f9; --active: #eeeeee;
|
|
982
|
+
--border: #e8e8e8; --rule: #f2f2f2; --control: #d1d5db;
|
|
983
|
+
--text: #111111; --muted: #5f6368; --faint: #6b6b6b; /* placeholders use --faint */
|
|
984
|
+
--primary: #1d1f20; /* near-black fill, white label */
|
|
985
|
+
--accent: /* one hue, about 3% of pixels: the data, plus at most one control */;
|
|
986
|
+
--positive: #247b50; --pill-positive-bg: #dcfae5; --pill-positive-ink: #04250e;
|
|
987
|
+
--negative: #c4242a; --pill-negative-bg: #ffedea; --pill-negative-ink: #831c1e;
|
|
988
|
+
--pill-warning-bg: #fffbeb; --pill-warning-ink: #92400e; /* notice border #fde68a */
|
|
989
|
+
--grid: #e5e5e5; --chart-span: 0.06; /* the opacity of a shaded span in a chart */
|
|
990
|
+
|
|
991
|
+
--radius-card: 8px; --radius-control: 6px; --radius-chip: 4px; /* soft styles: 20 / 14 / 999 */
|
|
992
|
+
--gap: 16px; --card-pad: 20px; --pad: 24px;
|
|
993
|
+
--nav-row: 34px; --control-height: 32px; --row-height: 48px;
|
|
994
|
+
--font: "Inter", system-ui, sans-serif; /* one grotesk */
|
|
995
|
+
--fs-title: 24px; --fs-section: 16px; --fs-kpi: 24px; --fs-body: 14px; --fs-small: 12px;
|
|
996
|
+
}
|
|
997
|
+
:root[data-theme="dark"] {
|
|
998
|
+
--ground: #000000; --surface: #111111; --raised: #222222; --active: #222222;
|
|
999
|
+
--border: #1a1a1a; --rule: #161616; --control: #444444; /* on a #111 ground the border is #2e2e2e */
|
|
1000
|
+
--text: #ffffff; --muted: #b4b4b4; --faint: #949494; /* two greys that read apart */
|
|
1001
|
+
--primary: #ffffff; /* inverted: white fill, black label */
|
|
1002
|
+
--positive: #3fc07a; --pill-positive-bg: #172a1d; --pill-positive-ink: #3fc07a; /* a green accent replaces these */
|
|
1003
|
+
--negative: #e5566f; --pill-negative-bg: #2c1a20; --pill-negative-ink: #e5566f; /* the study's #d4405d, lifted for 4.5:1 */
|
|
1004
|
+
--grid: #2b2b2b; --chart-span: 0.12;
|
|
1005
|
+
}
|
|
1006
|
+
.num { font-variant-numeric: tabular-nums; }
|
|
1007
|
+
td.num, th.num { text-align: right; }
|
|
1008
|
+
```
|
|
1009
|
+
|
|
1010
|
+
## 10. Density
|
|
1011
|
+
|
|
1012
|
+
- The studied screens hold 6 to about 120 data points, median about 25.
|
|
1013
|
+
- **Sparse** (6-25): homes, settings, a single object. Card padding 20-24px, rows 56-92px, body
|
|
1014
|
+
14-16px.
|
|
1015
|
+
- **Medium** (25-50): analytics overviews, finance homes, list screens. Rows 44-56px, padding
|
|
1016
|
+
16-24px.
|
|
1017
|
+
- **Dense** (about 120, one screen): research and monitoring, read in long sessions. A 13px body,
|
|
1018
|
+
28px list rows and 42px table rows, framed with generous air: 100px gutters, 64px between bands,
|
|
1019
|
+
32px of card padding.
|
|
1020
|
+
- Density is three settings moved together: row pitch, padding and type size. Do not shrink the type
|
|
1021
|
+
and keep the padding.
|
|
1022
|
+
- **Placed space reads as calm; leftover space reads as unfinished.** In the study, emptiness looks
|
|
1023
|
+
deliberate when it comes from a fixed grid and repeated gaps, and accidental when it comes from a
|
|
1024
|
+
grid that does not fit the data, a column that is empty in every row (a 300px dead band), a mostly
|
|
1025
|
+
empty top bar, or a card stretched to its neighbour's height.
|
|
1026
|
+
- **Design for the data the account has as well as the data it will have.** Several studied screens
|
|
1027
|
+
were built for a busy account and show a new one: a 673x240 plot for a line that sits on zero for
|
|
1028
|
+
two thirds of its length. Keep the honest drawing, but size the block to the question, not to the
|
|
1029
|
+
data the product hopes for.
|
|
1030
|
+
|
|
1031
|
+
## 11. Empty, zero, loading and error states
|
|
1032
|
+
|
|
1033
|
+
- **A real zero** is printed in the normal style: "$0", "0", "0%", "0.00%", "0% (0)" (10 screens). A
|
|
1034
|
+
zero may be dimmed to grey when the caption beside it becomes the next step ("$0.00", then
|
|
1035
|
+
"Automate your savings with up to 3.50% APY").
|
|
1036
|
+
- **Missing or not applicable** is a grey dash: an em dash, a "-", a 6x2px mark. Never a dash at full
|
|
1037
|
+
value size: "--" at 24px reads as loading (flagged).
|
|
1038
|
+
- **Counts follow the view, and so does the frame.** Counts shown in scope (tabs, KPI tiles, "12
|
|
1039
|
+
open") are computed from the rows in the current view or filter and recomputed on every switch. A
|
|
1040
|
+
filtered block shrinks to its rows and its row-mate aligns to the top, or the block keeps a fixed
|
|
1041
|
+
number of rows with one empty-state sentence; each view's subline is computed for that view.
|
|
1042
|
+
- **An empty side card fills with the reference data**, not one dashed box in 400px of white: before
|
|
1043
|
+
anything has sold out, last Sunday's sell-out times as a quiet list under "Nothing has sold out yet
|
|
1044
|
+
today".
|
|
1045
|
+
- **Red is a signal, not a texture**: one red mark per object at most, on the overdue or failing fact;
|
|
1046
|
+
thirteen red strings on one board read as noise, and a list of deals needing attention does not
|
|
1047
|
+
repeat the same flags on the board beside it.
|
|
1048
|
+
- **An empty section keeps its frame and its header** and adds one sentence spanning the block (in a
|
|
1049
|
+
row grid, `grid-column: 1 / -1`; a message squeezed into one 34px column broke word by word in
|
|
1050
|
+
testing): a 1px dashed box, radius
|
|
1051
|
+
8, about 38px tall ("No channel usage in this range."), or a bordered box with an add link
|
|
1052
|
+
("+ Liability account"). In a builder, an empty slot is a dashed 1px box on the canvas colour.
|
|
1053
|
+
- **An empty chart is drawn**: the zero line, missing bars for empty periods, no padded range, no
|
|
1054
|
+
picture.
|
|
1055
|
+
- **First run** (the whole screen empty): keep the frame and the title, and put the first action where
|
|
1056
|
+
the data will appear, with a setup progress at its true percentage if there are steps (one screen
|
|
1057
|
+
shows "Complete your setup" at 67%; another a four-cell getting-started strip above its tables).
|
|
1058
|
+
- **Loading** (house rule; not in the study): the final layout with each value replaced by a flat grey
|
|
1059
|
+
bar at its real size (a 24px value gets a 24px-tall bar; rows keep their pitch), labels and headers
|
|
1060
|
+
shown at once, no shimmer gradient, and no shift of the layout when the data lands. A refresh of
|
|
1061
|
+
data already on screen keeps the old values and updates the freshness stamp.
|
|
1062
|
+
- **Error** (house rule; not in the study): inside the block that failed, never as a full-screen
|
|
1063
|
+
banner. One sentence saying what failed and when the data was last good ("Couldn't load
|
|
1064
|
+
deployments. Last updated 09:14."), and a Retry text button. The negative colour only on a small
|
|
1065
|
+
icon or in the pill pair.
|
|
1066
|
+
- **Stale or static data**: a freshness stamp with a refresh button (6 screens). A snapshot that
|
|
1067
|
+
cannot refresh says so in one quiet notice (once: #fffbeb, a 1px #fde68a border, 12px #92400e
|
|
1068
|
+
text). A notice tint is never a ground; the inspector reads a pale amber ground as cream.
|
|
1069
|
+
- **Limits and usage**: a bar at the true ratio with both ends labelled ("12.7k of 20.0k").
|
|
1070
|
+
|
|
1071
|
+
## 12. The phone
|
|
1072
|
+
|
|
1073
|
+
The study has no phone screens. This section is house rule, built from the skill's phone rules
|
|
1074
|
+
(`layout.md` §9) and from what the desktop screens imply. The inspector fails a sidebar that still
|
|
1075
|
+
takes more than 30% of a phone's width.
|
|
1076
|
+
|
|
1077
|
+
- **Navigation folds.** The sidebar becomes a 48px top bar with the screen's name, a menu button that
|
|
1078
|
+
opens a full-screen sheet (nav, workspace switcher, account) and at most one action; or a bottom
|
|
1079
|
+
bar of four or five destinations with short labels. An icon rail becomes that bottom bar.
|
|
1080
|
+
- **Margins** 16-20px; touch targets at least 44px tall; data and labels at 14px, sublines no smaller
|
|
1081
|
+
than 12px.
|
|
1082
|
+
- **The title stays**, at 20-24px. Header actions move into a kebab, except the one primary.
|
|
1083
|
+
- **Filters** collapse into one row of chips or a Filters sheet; tabs scroll sideways inside their own
|
|
1084
|
+
row, never the page. The first list row starts in the top 60% of the phone screen: three rows of
|
|
1085
|
+
filter controls above it pushed the list off the first screen in testing.
|
|
1086
|
+
- **KPIs**: a divided container becomes a 2-column grid, or a list with the label on the left and the
|
|
1087
|
+
value on the right. Never four squeezed columns. In a 2-column grid the count after any full-width
|
|
1088
|
+
lead is even; otherwise use three narrow columns or a divided list, or let the last cell take the
|
|
1089
|
+
full width (`app.css` does that for an odd count). A lone "Sold 3.18 kWh" beside an empty half-row
|
|
1090
|
+
was flagged.
|
|
1091
|
+
- **At most one row of controls above a chart**: an office select and a week switch share one row.
|
|
1092
|
+
Two stacked full-width segmented controls pushed the data down in testing.
|
|
1093
|
+
- **Charts** go full width, 160-200px tall, with 3-4 x labels and a legend of dots above, set in a
|
|
1094
|
+
2-column grid (or behind a "Key" disclosure) when it would wrap to three lines. The y ticks keep
|
|
1095
|
+
their own lane at the left (or move to the right edge); a tick label never sits on the line.
|
|
1096
|
+
- **Row actions on a phone** are text actions or one compact trailing button, with one filled bulk
|
|
1097
|
+
action for the list ("Approve 3 that fit"); five 44px grey Approve blocks turned a list into a stack
|
|
1098
|
+
of buttons.
|
|
1099
|
+
- **When a strip collapses, drop the item least relevant to the screen's main action**, not the last
|
|
1100
|
+
in source order: the live price stays on an energy screen whose plan depends on it.
|
|
1101
|
+
- **Tables become lists of two-line rows below about 640px**: the identity and the key number on line
|
|
1102
|
+
1, the other fields the brief names in 13px grey on line 2 ("fra1 · 1m 38s"), the one action at the
|
|
1103
|
+
right. Fields move to line 2; they are never dropped. A table that must stay a table scrolls inside
|
|
1104
|
+
its own frame with its first column fixed; the page never scrolls sideways.
|
|
1105
|
+
- **The tablet (641-1100px) is its own band**: the sidebar folds to the top bar, but tables keep four
|
|
1106
|
+
or five columns with secondary fields as sublines, two narrow panels stack once either would be
|
|
1107
|
+
under about 340px, and the identity column is never the one truncated while another has room.
|
|
1108
|
+
- **Blocks that carry an action move up, not down**: a right rail with an action (low stock and its
|
|
1109
|
+
Reorder, bills due and Pay) becomes a one-line summary row above the list ("5 items low · Review"),
|
|
1110
|
+
never a block under twenty orders.
|
|
1111
|
+
- **Several panes** (a list and its detail, an inbox): one region at a time. Choosing a row pushes the
|
|
1112
|
+
detail; back returns to the list at its scroll position.
|
|
1113
|
+
- **Settings**: the label column stacks above its panel.
|
|
1114
|
+
- **A right rail** moves under the main column or into a tab.
|
|
1115
|
+
- **Builders** show the work read-only, with the palette as a bottom sheet if editing stays.
|
|
1116
|
+
- Check 390px in the inspector's screenshots every round.
|
|
1117
|
+
|
|
1118
|
+
## 13. House rules for app screens
|
|
1119
|
+
|
|
1120
|
+
The house rules in `SKILL.md` were written for pages that are read once. An app screen is read every
|
|
1121
|
+
day, and part of what those rules ban is the structure of a working screen. These relax, with limits:
|
|
1122
|
+
|
|
1123
|
+
| Allowed on app screens | Limit |
|
|
1124
|
+
| --- | --- |
|
|
1125
|
+
| **1px borders** on cards, panels, tables and controls | About 1.1-1.3:1 against the ground on light (#e5e7eb-#ededed on white); #1a1a1a on #000, #2e2e2e on #111. Controls one step stronger. A border or a shadow, never both. |
|
|
1126
|
+
| **Row rules** in tables and lists | 1px, 3-7% darker than the surface. No zebra, no header band. |
|
|
1127
|
+
| **Dashed lines** | In chart grids and empty slots only. |
|
|
1128
|
+
| **Small labels** above values | 12-14px, sentence case, grey at 4.5:1. Meta and axis text 11-12px. Nothing under 11px. At most one tracked uppercase label on a screen (a switcher's context label). |
|
|
1129
|
+
| **Rows of identical cards** | Peer metrics or peer objects only: 3-6 across, equal widths, one gap, no orphan, edges aligned across rows, no icon on top. Prefer one divided card; mixed spans beat a uniform grid. |
|
|
1130
|
+
| **Monospace** | IDs, keys and code; or every figure, as one style's decision. Otherwise tabular figures in the text face. |
|
|
1131
|
+
| **Pills** | Inside rows and beside a value only: 16-24px tall, a pale tint with dark text of the same hue. Never above a heading. |
|
|
1132
|
+
| **Index numbers** | Only as data: a rank ("1."), a node number. |
|
|
1133
|
+
| **Icons** | 14-20px outline, one set, grey: in the nav, before a label, or as a single affordance (kebab, chevron, info). A container only if it is neutral, or node-type tiles in a builder (pass `--allow icon-chips` and give the reason in the report). |
|
|
1134
|
+
| **Shadows** | On what floats: a menu, a popover, a tooltip, a composer, a dialog. A resting card gets at most a small blur under 8% black. |
|
|
1135
|
+
| **A second typeface** | With one job: a mono for IDs or figures, a serif for one greeting. |
|
|
1136
|
+
| **A gradient** | Only as an area fade under one line chart; a flat tint of about 14% is safer. |
|
|
1137
|
+
|
|
1138
|
+
Still banned, as on pages, and checked:
|
|
1139
|
+
|
|
1140
|
+
| Banned | Instead |
|
|
1141
|
+
| --- | --- |
|
|
1142
|
+
| Gradients on grounds, buttons, cards, text and KPI tiles (the study's two gradient buttons are flagged) | Flat fills |
|
|
1143
|
+
| Glows, glass, backdrop blur | Opaque surfaces one tone step from the ground |
|
|
1144
|
+
| An icon in a coloured circle or tinted square on every KPI or card (0 of 23) | A label and a number |
|
|
1145
|
+
| Rainbow charts: more than four hues, a hue per bar, one subject in two hues | One hue per chart, neutrals for the rest |
|
|
1146
|
+
| Sparklines on KPIs (0 of 23) | The trend in its own chart, or nowhere |
|
|
1147
|
+
| Emoji in greetings, labels, nav or empty states | Words |
|
|
1148
|
+
| Lorem ipsum, Acme, John Doe, "User 1"; vanity figures ("10,000+ teams"); totals that do not add up | Believable sample data computed from rows, listed in the report |
|
|
1149
|
+
| Status colour on a zero or undefined change | Grey, or the change in words ("+4 (new)") |
|
|
1150
|
+
| A dark or saturated sidebar on a light screen; a navy or slate dark theme | The page ground for the sidebar; true neutral darks |
|
|
1151
|
+
| The accent on chrome: a tinted nav row with a left bar, coloured tab pills, a brand fill on every button | The accent on data and at most one control; a near-black primary |
|
|
1152
|
+
| Uppercase tracked table headers, zebra rows, header bands | 12px grey sentence-case headers; rules or space |
|
|
1153
|
+
| Left-aligned numbers, proportional figures in columns | Right-aligned tabular figures |
|
|
1154
|
+
| A hero header, a greeting with an emoji, an illustrated welcome banner | A noun title at 24px |
|
|
1155
|
+
| Pagination under a five-row overview list | Capped rows, "View all", the total |
|
|
1156
|
+
| Violet and indigo accents; cream with terracotta | The dealt style's palette |
|
|
1157
|
+
| A landing-page title (over 32px) or a figure at 48px or more | An 18-32px title; figures at 16-40px |
|
|
1158
|
+
| Icons in boxes repeated down a list or on top of every peer card, tinted or neutral | One plain 16px icon where it helps, or none |
|
|
1159
|
+
| Every row a different hue, a "left" amount in green on every budget row | Grey for what is fine; colour only on the rows at risk or over |
|
|
1160
|
+
| A screen that names no product and offers no action | The product's mark and scope in the shell; its main job one click away |
|
|
1161
|
+
|
|
1162
|
+
**On violet and indigo.** 10 of the 23 studied screens use violet or indigo, always as a data hue or a
|
|
1163
|
+
single control. The ban is the owner's taste, not a finding of the study: the library deals other
|
|
1164
|
+
hues for the styles that came from those screens, and the inspector's palette check stays on.
|
|
1165
|
+
|
|
1166
|
+
## 14. Tells of generated dashboards
|
|
1167
|
+
|
|
1168
|
+
Each line sets a habit of generated dashboards against what the 23 screens do instead.
|
|
1169
|
+
|
|
1170
|
+
| Tell | What replaces it |
|
|
1171
|
+
| --- | --- |
|
|
1172
|
+
| A dark navy or tinted sidebar with a coloured active pill and a left bar | The sidebar on the page ground; a neutral grey pill, or the label brightening on dark. A left bar appears once in 23. |
|
|
1173
|
+
| "Welcome back, Alex" with a waving hand and a subtitle | A noun title at 24/600. Three screens greet; the one emoji goes. |
|
|
1174
|
+
| Four KPI cards, each with an icon in a tinted circle | One container split by hairlines, label over value. No icons on any of the 23. |
|
|
1175
|
+
| A green "+12.5%" pill on every KPI | A delta on 9 of 20 screens, in words with its window; grey for zero; "+4 (new)" from zero. |
|
|
1176
|
+
| A sparkline on every KPI | None on any of the 23. The trend has its own chart. |
|
|
1177
|
+
| KPI values at 36-48px, bold, in the brand colour | 24-30px at 400-600 in ink; nothing at 48. |
|
|
1178
|
+
| A gradient area chart with a smoothed spline and a dot on every point | A 2px straight line, no fill on 7 of 10, no markers. |
|
|
1179
|
+
| A rainbow palette, a hue per bar or per chart | One hue per chart; the accent on data only; four hues at most on a screen. |
|
|
1180
|
+
| Gridlines every 20px, axis lines on both sides, a legend for one series | 3-5 faint lines, no y-axis line, no legend for a single series; round ticks above the maximum. |
|
|
1181
|
+
| A fat donut with labels on the slices and a big total in the hole | A thin ring, no slice labels, the legend as a table with the values. |
|
|
1182
|
+
| Cards with a 16-24px radius, a 1px border and a large soft shadow | A border or a tone step, no shadow; a tight or a soft radius, chosen once. |
|
|
1183
|
+
| A zebra table under uppercase tracked headers, with a checkbox, an avatar, a status chip and a kebab on every row | Rules and alignment: 12px grey headers, one status mark, one action where it is needed. |
|
|
1184
|
+
| Left-aligned numbers in proportional digits | Right-aligned tabular figures, fixed decimals, units in grey. |
|
|
1185
|
+
| Saturated status chips with white text | Pale tints with dark text of the same hue. |
|
|
1186
|
+
| The accent on every button, tab and link | No filled primary on 12 of 23; near-black where there is one. |
|
|
1187
|
+
| A top bar with search, a bell and an avatar on every screen, or one left mostly empty | No top bar on 9 of 23; when there is one, it carries search, the switcher or the object's name. |
|
|
1188
|
+
| Export, Share and a date picker clustered by the title | Actions only when they are real; a freshness stamp instead. |
|
|
1189
|
+
| Placeholder people and companies, round vanity totals, growth on a week-old account | The product's own data, small numbers at their real size, totals summed from the rows. |
|
|
1190
|
+
| Pagination under a short list | Capped rows and "View all". |
|
|
1191
|
+
| An equal four-up grid whatever the data, with orphan cells and stretched cards | A column count chosen by the item count; spans that change by row and land on the same lines. |
|
|
1192
|
+
| Neon on dark, glowing borders, glass | True neutral darks, lightness steps, colour on the data. |
|
|
1193
|
+
| The kit's own face: Geist or Inter on #f8f8f8 with white 12px cards and no hue on the data, or lime on black | One face taken from the brief (a ground from the product's world, a figure face with character, the brand's hue on the main data element) and one element only this product has. |
|
|
1194
|
+
| A coloured icon per category in a list | One grey icon set; colour, if any, on the numbers. |
|
|
1195
|
+
| An illustration and "No data yet" in an empty chart | The zero line drawn, and one sentence in the frame. |
|
|
1196
|
+
|
|
1197
|
+
A screen with every tell removed and nothing put in their place is a tidy template. What fills the
|
|
1198
|
+
space is the product: its own data at its real size, the screen's one question answered by its
|
|
1199
|
+
biggest block, and a grid whose sums close.
|