pigment-mcp 0.11.0 → 0.14.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/cli.js +1 -1
- package/content/registry.json +21 -3
- package/content/shots.json +46 -0
- package/content/templates/inkleaf/1.1.0/CHANGELOG.md +197 -0
- package/content/templates/inkleaf/1.1.0/agent/instructions.md +44 -0
- package/content/templates/inkleaf/1.1.0/components/avatar.md +8 -0
- package/content/templates/inkleaf/1.1.0/components/badge.md +8 -0
- package/content/templates/inkleaf/1.1.0/components/button.md +16 -0
- package/content/templates/inkleaf/1.1.0/components/card.md +14 -0
- package/content/templates/inkleaf/1.1.0/components/checkbox.md +11 -0
- package/content/templates/inkleaf/1.1.0/components/dialog.md +10 -0
- package/content/templates/inkleaf/1.1.0/components/empty-state.md +8 -0
- package/content/templates/inkleaf/1.1.0/components/index.json +18 -0
- package/content/templates/inkleaf/1.1.0/components/navigation.md +26 -0
- package/content/templates/inkleaf/1.1.0/components/select.md +10 -0
- package/content/templates/inkleaf/1.1.0/components/switch.md +11 -0
- package/content/templates/inkleaf/1.1.0/components/table.md +25 -0
- package/content/templates/inkleaf/1.1.0/components/tabs.md +12 -0
- package/content/templates/inkleaf/1.1.0/components/text-field.md +12 -0
- package/content/templates/inkleaf/1.1.0/components/toast.md +8 -0
- package/content/templates/inkleaf/1.1.0/dist/agent.md +967 -0
- package/content/templates/inkleaf/1.1.0/dist/tokens.css +283 -0
- package/content/templates/inkleaf/1.1.0/dist/tokens.json +462 -0
- package/content/templates/inkleaf/1.1.0/manifest.json +77 -0
- package/content/templates/inkleaf/1.1.0/principles/visual-language.md +493 -0
- package/content/templates/inkleaf/1.1.0/tokens/primitives.json +214 -0
- package/content/templates/inkleaf/1.1.0/tokens/semantic.dark.json +69 -0
- package/content/templates/inkleaf/1.1.0/tokens/semantic.light.json +69 -0
- package/content/templates/margin-notes/1.2.0/CHANGELOG.md +130 -0
- package/content/templates/margin-notes/1.2.0/agent/instructions.md +44 -0
- package/content/templates/margin-notes/1.2.0/components/badge.md +9 -0
- package/content/templates/margin-notes/1.2.0/components/button.md +11 -0
- package/content/templates/margin-notes/1.2.0/components/callout.md +9 -0
- package/content/templates/margin-notes/1.2.0/components/card.md +11 -0
- package/content/templates/margin-notes/1.2.0/components/checkbox.md +21 -0
- package/content/templates/margin-notes/1.2.0/components/chip.md +9 -0
- package/content/templates/margin-notes/1.2.0/components/code-block.md +9 -0
- package/content/templates/margin-notes/1.2.0/components/dialog.md +9 -0
- package/content/templates/margin-notes/1.2.0/components/empty-state.md +9 -0
- package/content/templates/margin-notes/1.2.0/components/index.json +22 -0
- package/content/templates/margin-notes/1.2.0/components/media-frame.md +9 -0
- package/content/templates/margin-notes/1.2.0/components/navigation.md +11 -0
- package/content/templates/margin-notes/1.2.0/components/segmented-control.md +9 -0
- package/content/templates/margin-notes/1.2.0/components/select.md +9 -0
- package/content/templates/margin-notes/1.2.0/components/switch.md +9 -0
- package/content/templates/margin-notes/1.2.0/components/table.md +31 -0
- package/content/templates/margin-notes/1.2.0/components/tabs.md +9 -0
- package/content/templates/margin-notes/1.2.0/components/text-field.md +11 -0
- package/content/templates/margin-notes/1.2.0/components/toast.md +9 -0
- package/content/templates/margin-notes/1.2.0/dist/agent.md +707 -0
- package/content/templates/margin-notes/1.2.0/dist/tokens.css +301 -0
- package/content/templates/margin-notes/1.2.0/dist/tokens.json +462 -0
- package/content/templates/margin-notes/1.2.0/manifest.json +108 -0
- package/content/templates/margin-notes/1.2.0/principles/visual-language.md +228 -0
- package/content/templates/margin-notes/1.2.0/tokens/primitives.json +611 -0
- package/content/templates/margin-notes/1.2.0/tokens/semantic.dark.json +200 -0
- package/content/templates/margin-notes/1.2.0/tokens/semantic.light.json +199 -0
- package/content/templates/night-cartridge/1.3.0/CHANGELOG.md +516 -0
- package/content/templates/night-cartridge/1.3.0/agent/instructions.md +40 -0
- package/content/templates/night-cartridge/1.3.0/components/badge.md +5 -0
- package/content/templates/night-cartridge/1.3.0/components/button.md +13 -0
- package/content/templates/night-cartridge/1.3.0/components/card.md +7 -0
- package/content/templates/night-cartridge/1.3.0/components/checkbox.md +7 -0
- package/content/templates/night-cartridge/1.3.0/components/dialog.md +7 -0
- package/content/templates/night-cartridge/1.3.0/components/empty-state.md +5 -0
- package/content/templates/night-cartridge/1.3.0/components/index.json +17 -0
- package/content/templates/night-cartridge/1.3.0/components/navigation.md +18 -0
- package/content/templates/night-cartridge/1.3.0/components/select.md +7 -0
- package/content/templates/night-cartridge/1.3.0/components/switch.md +7 -0
- package/content/templates/night-cartridge/1.3.0/components/table.md +17 -0
- package/content/templates/night-cartridge/1.3.0/components/tabs.md +7 -0
- package/content/templates/night-cartridge/1.3.0/components/text-field.md +7 -0
- package/content/templates/night-cartridge/1.3.0/components/toast.md +7 -0
- package/content/templates/night-cartridge/1.3.0/dist/agent.md +717 -0
- package/content/templates/night-cartridge/1.3.0/dist/tokens.css +196 -0
- package/content/templates/night-cartridge/1.3.0/dist/tokens.json +226 -0
- package/content/templates/night-cartridge/1.3.0/manifest.json +99 -0
- package/content/templates/night-cartridge/1.3.0/principles/visual-language.md +367 -0
- package/content/templates/night-cartridge/1.3.0/tokens/primitives.json +520 -0
- package/content/templates/night-cartridge/1.3.0/tokens/semantic.dark.json +220 -0
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -34993,7 +34993,7 @@ var init_package = __esm({
|
|
|
34993
34993
|
"package.json"() {
|
|
34994
34994
|
package_default = {
|
|
34995
34995
|
name: "@pigment/mcp",
|
|
34996
|
-
version: "0.
|
|
34996
|
+
version: "0.14.0",
|
|
34997
34997
|
private: true,
|
|
34998
34998
|
type: "module",
|
|
34999
34999
|
description: "MCP server for Pigment design systems: tokens, rules, component specs and installation guides for your coding agent.",
|
package/content/registry.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"templates": [
|
|
3
3
|
{
|
|
4
4
|
"id": "margin-notes",
|
|
5
|
-
"latest": "1.
|
|
5
|
+
"latest": "1.2.0",
|
|
6
6
|
"versions": [
|
|
7
7
|
{
|
|
8
8
|
"version": "1.0.0",
|
|
@@ -15,24 +15,36 @@
|
|
|
15
15
|
"status": "published",
|
|
16
16
|
"publishedAt": "2026-10-14T08:33:30.334Z",
|
|
17
17
|
"sha256": "f6a26186965b8425d7b1ea620c737f58e8e907746b1550fb32a7b4bf98b6fa04"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"version": "1.2.0",
|
|
21
|
+
"status": "published",
|
|
22
|
+
"publishedAt": "2026-10-19T01:41:09.029Z",
|
|
23
|
+
"sha256": "99fb52e92bdc3b35b474a873f4bb4657e81d4e326cd26f8de56c1dc0b4a225f2"
|
|
18
24
|
}
|
|
19
25
|
]
|
|
20
26
|
},
|
|
21
27
|
{
|
|
22
28
|
"id": "inkleaf",
|
|
23
|
-
"latest": "1.
|
|
29
|
+
"latest": "1.1.0",
|
|
24
30
|
"versions": [
|
|
25
31
|
{
|
|
26
32
|
"version": "1.0.0",
|
|
27
33
|
"status": "published",
|
|
28
34
|
"publishedAt": "2026-10-14T00:22:11.356Z",
|
|
29
35
|
"sha256": "950225ff2a2540952b0acbdd499d07d8f78576262299a979d5d831145f51174b"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"version": "1.1.0",
|
|
39
|
+
"status": "published",
|
|
40
|
+
"publishedAt": "2026-10-19T05:40:05.888Z",
|
|
41
|
+
"sha256": "e2a38ffc279853fcb8b6de07028f16127319053e8b779f02a981ec396f26f85c"
|
|
30
42
|
}
|
|
31
43
|
]
|
|
32
44
|
},
|
|
33
45
|
{
|
|
34
46
|
"id": "night-cartridge",
|
|
35
|
-
"latest": "1.
|
|
47
|
+
"latest": "1.3.0",
|
|
36
48
|
"versions": [
|
|
37
49
|
{
|
|
38
50
|
"version": "1.0.0",
|
|
@@ -51,6 +63,12 @@
|
|
|
51
63
|
"status": "published",
|
|
52
64
|
"publishedAt": "2026-10-18T13:46:07.189Z",
|
|
53
65
|
"sha256": "82dcfe93ef26940ddbb6a3d6bf15c4ab4539638de605ee9b206512e42a98ad63"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"version": "1.3.0",
|
|
69
|
+
"status": "published",
|
|
70
|
+
"publishedAt": "2026-10-19T07:10:06.232Z",
|
|
71
|
+
"sha256": "8dfc70ec02127dbf36f6c439290c2fc4a64fe4efef971ac76ec48522411f2717"
|
|
54
72
|
}
|
|
55
73
|
]
|
|
56
74
|
},
|
package/content/shots.json
CHANGED
|
@@ -35,6 +35,24 @@
|
|
|
35
35
|
"settings.mobileLight": "/showcase/margin-notes/1.1.0/settings/settings-profile-mobile-light.png",
|
|
36
36
|
"settings.mobileDark": "/showcase/margin-notes/1.1.0/settings/settings-profile-mobile-dark.png"
|
|
37
37
|
},
|
|
38
|
+
"margin-notes@1.2.0": {
|
|
39
|
+
"blog.desktopLight": "/showcase/margin-notes/1.2.0/blog/home-desktop-light.png",
|
|
40
|
+
"blog.desktopDark": "/showcase/margin-notes/1.2.0/blog/home-desktop-dark.png",
|
|
41
|
+
"blog.mobileLight": "/showcase/margin-notes/1.2.0/blog/home-mobile-light.png",
|
|
42
|
+
"blog.mobileDark": "/showcase/margin-notes/1.2.0/blog/home-mobile-dark.png",
|
|
43
|
+
"commerce.desktopLight": "/showcase/margin-notes/1.2.0/commerce/home-desktop-light.png",
|
|
44
|
+
"commerce.desktopDark": "/showcase/margin-notes/1.2.0/commerce/home-desktop-dark.png",
|
|
45
|
+
"commerce.mobileLight": "/showcase/margin-notes/1.2.0/commerce/home-mobile-light.png",
|
|
46
|
+
"commerce.mobileDark": "/showcase/margin-notes/1.2.0/commerce/home-mobile-dark.png",
|
|
47
|
+
"dashboard.desktopLight": "/showcase/margin-notes/1.2.0/dashboard/home-desktop-light.png",
|
|
48
|
+
"dashboard.desktopDark": "/showcase/margin-notes/1.2.0/dashboard/home-desktop-dark.png",
|
|
49
|
+
"dashboard.mobileLight": "/showcase/margin-notes/1.2.0/dashboard/home-mobile-light.png",
|
|
50
|
+
"dashboard.mobileDark": "/showcase/margin-notes/1.2.0/dashboard/home-mobile-dark.png",
|
|
51
|
+
"settings.desktopLight": "/showcase/margin-notes/1.2.0/settings/settings-profile-desktop-light.png",
|
|
52
|
+
"settings.desktopDark": "/showcase/margin-notes/1.2.0/settings/settings-profile-desktop-dark.png",
|
|
53
|
+
"settings.mobileLight": "/showcase/margin-notes/1.2.0/settings/settings-profile-mobile-light.png",
|
|
54
|
+
"settings.mobileDark": "/showcase/margin-notes/1.2.0/settings/settings-profile-mobile-dark.png"
|
|
55
|
+
},
|
|
38
56
|
"inkleaf@1.0.0": {
|
|
39
57
|
"blog.desktopLight": "/showcase/inkleaf/1.0.0/blog/home-desktop-light.png",
|
|
40
58
|
"blog.desktopDark": "/showcase/inkleaf/1.0.0/blog/home-desktop-dark.png",
|
|
@@ -53,6 +71,24 @@
|
|
|
53
71
|
"settings.mobileLight": "/showcase/inkleaf/1.0.0/settings/settings-profile-mobile-light.png",
|
|
54
72
|
"settings.mobileDark": "/showcase/inkleaf/1.0.0/settings/settings-profile-mobile-dark.png"
|
|
55
73
|
},
|
|
74
|
+
"inkleaf@1.1.0": {
|
|
75
|
+
"blog.desktopLight": "/showcase/inkleaf/1.1.0/blog/home-desktop-light.png",
|
|
76
|
+
"blog.desktopDark": "/showcase/inkleaf/1.1.0/blog/home-desktop-dark.png",
|
|
77
|
+
"blog.mobileLight": "/showcase/inkleaf/1.1.0/blog/home-mobile-light.png",
|
|
78
|
+
"blog.mobileDark": "/showcase/inkleaf/1.1.0/blog/home-mobile-dark.png",
|
|
79
|
+
"commerce.desktopLight": "/showcase/inkleaf/1.1.0/commerce/home-desktop-light.png",
|
|
80
|
+
"commerce.desktopDark": "/showcase/inkleaf/1.1.0/commerce/home-desktop-dark.png",
|
|
81
|
+
"commerce.mobileLight": "/showcase/inkleaf/1.1.0/commerce/home-mobile-light.png",
|
|
82
|
+
"commerce.mobileDark": "/showcase/inkleaf/1.1.0/commerce/home-mobile-dark.png",
|
|
83
|
+
"dashboard.desktopLight": "/showcase/inkleaf/1.1.0/dashboard/home-desktop-light.png",
|
|
84
|
+
"dashboard.desktopDark": "/showcase/inkleaf/1.1.0/dashboard/home-desktop-dark.png",
|
|
85
|
+
"dashboard.mobileLight": "/showcase/inkleaf/1.1.0/dashboard/home-mobile-light.png",
|
|
86
|
+
"dashboard.mobileDark": "/showcase/inkleaf/1.1.0/dashboard/home-mobile-dark.png",
|
|
87
|
+
"settings.desktopLight": "/showcase/inkleaf/1.1.0/settings/settings-profile-desktop-light.png",
|
|
88
|
+
"settings.desktopDark": "/showcase/inkleaf/1.1.0/settings/settings-profile-desktop-dark.png",
|
|
89
|
+
"settings.mobileLight": "/showcase/inkleaf/1.1.0/settings/settings-profile-mobile-light.png",
|
|
90
|
+
"settings.mobileDark": "/showcase/inkleaf/1.1.0/settings/settings-profile-mobile-dark.png"
|
|
91
|
+
},
|
|
56
92
|
"night-cartridge@1.0.0": {
|
|
57
93
|
"blog.desktopLight": "/showcase/night-cartridge/1.0.0/blog/home-desktop-light.png",
|
|
58
94
|
"blog.desktopDark": "/showcase/night-cartridge/1.0.0/blog/home-desktop-dark.png",
|
|
@@ -91,6 +127,16 @@
|
|
|
91
127
|
"settings.desktopDark": "/showcase/night-cartridge/1.2.0/settings/settings-profile-desktop-dark.png",
|
|
92
128
|
"settings.mobileDark": "/showcase/night-cartridge/1.2.0/settings/settings-profile-mobile-dark.png"
|
|
93
129
|
},
|
|
130
|
+
"night-cartridge@1.3.0": {
|
|
131
|
+
"blog.desktopDark": "/showcase/night-cartridge/1.3.0/blog/home-desktop-dark.png",
|
|
132
|
+
"blog.mobileDark": "/showcase/night-cartridge/1.3.0/blog/home-mobile-dark.png",
|
|
133
|
+
"commerce.desktopDark": "/showcase/night-cartridge/1.3.0/commerce/home-desktop-dark.png",
|
|
134
|
+
"commerce.mobileDark": "/showcase/night-cartridge/1.3.0/commerce/home-mobile-dark.png",
|
|
135
|
+
"dashboard.desktopDark": "/showcase/night-cartridge/1.3.0/dashboard/home-desktop-dark.png",
|
|
136
|
+
"dashboard.mobileDark": "/showcase/night-cartridge/1.3.0/dashboard/home-mobile-dark.png",
|
|
137
|
+
"settings.desktopDark": "/showcase/night-cartridge/1.3.0/settings/settings-profile-desktop-dark.png",
|
|
138
|
+
"settings.mobileDark": "/showcase/night-cartridge/1.3.0/settings/settings-profile-mobile-dark.png"
|
|
139
|
+
},
|
|
94
140
|
"graphite-blueprint@1.0.0": {
|
|
95
141
|
"blog.desktopLight": "/showcase/graphite-blueprint/1.0.0/blog/home-desktop-light.png",
|
|
96
142
|
"blog.desktopDark": "/showcase/graphite-blueprint/1.0.0/blog/home-desktop-dark.png",
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 1.1.0
|
|
4
|
+
|
|
5
|
+
Inkleaf now fits any product. The rules that were written around example screens are rewritten for the kind of
|
|
6
|
+
screen they describe, and a few that quietly removed content are fixed. The look itself is unchanged.
|
|
7
|
+
|
|
8
|
+
- Missing images: ask what the image stands for. An image that stands for a thing becomes a drawing of that thing on
|
|
9
|
+
a plate or stage; an image that stands for information (a diagram, comparison, flow or chart) becomes a ghosted UI
|
|
10
|
+
preview on a media stage shaped like its caption, never a single pictogram. A missing image is never removed.
|
|
11
|
+
- Card grids of items that each have their own subject (entries, articles, products, places, listings) show a plate on
|
|
12
|
+
every card, even when the data has no image field. Link lists, resources and settings groups stay text-only.
|
|
13
|
+
- Long-form pages: the lead image or drawing spans the text column; the contents list sits beside the text from
|
|
14
|
+
`breakpoint.lg` and collapses to a disclosure below it.
|
|
15
|
+
- Transaction summaries sit in a narrow sticky side column on wide screens and after the main content on narrow ones.
|
|
16
|
+
- Stretched panels fill their height with their main content, with no empty band. Short metric cards sit at least two
|
|
17
|
+
per row at every width.
|
|
18
|
+
- Stage colours follow the rotation rule only; no screen is tied to a colour. Offer and choice cards replace plan
|
|
19
|
+
cards in the rules.
|
|
20
|
+
- A switch that applies immediately needs no Save button; inside a form it follows the form's submit.
|
|
21
|
+
- Drawings: the failure examples are general (a small object read as a ball, a held object read as a head, a folded
|
|
22
|
+
item losing its defining detail) and the list of banned subjects is replaced by one rule: skip the first object
|
|
23
|
+
anyone would draw for the task unless the screen is literally about it.
|
|
24
|
+
|
|
25
|
+
## 1.1.0-rc.3
|
|
26
|
+
|
|
27
|
+
Internal candidate: one regression fixed in general terms. Tokens and signature recipes unchanged.
|
|
28
|
+
|
|
29
|
+
- Imagery: new rule deciding which cards get a plate before looking at the data. A grid of items that each have their
|
|
30
|
+
own subject shows a plate on every card even when the data has no image field (the item's own drawing, the same one
|
|
31
|
+
on its detail page); the missing-image rules decide what goes on the plate, not whether there is one. Text-only
|
|
32
|
+
cards are for link lists, resources, settings groups and metadata rows. Mirrored in the Card grid and Long-form
|
|
33
|
+
content rows of Applying the concept and in the Card media variant.
|
|
34
|
+
- Verification: "Every card grid of subject items has a plate on every card, whether or not the data has images."
|
|
35
|
+
|
|
36
|
+
## 1.1.0-rc.2
|
|
37
|
+
|
|
38
|
+
Internal candidate: two regressions from the generalization rewrite are fixed in general terms. Tokens and
|
|
39
|
+
signature recipes unchanged.
|
|
40
|
+
|
|
41
|
+
- Imagery: the missing-image rule splits by what the image is for. A thing (an item, someone's object, a page's
|
|
42
|
+
subject) becomes its own drawing on a plate or drawing stage; information (a diagram, screenshot, comparison,
|
|
43
|
+
chart, flow) becomes a ghosted preview on a media stage, shaped like its caption, with a recipe (raised card,
|
|
44
|
+
subtle tiles, skeleton bars, hairlines, no text). Never one object drawing under a caption about a structure
|
|
45
|
+
(also in the Never list, stage Where, the Long-form content row and Layout adaptation).
|
|
46
|
+
- Layout adaptation: "stat rows wrap evenly whatever their count" becomes a density floor: short metric cards sit at
|
|
47
|
+
least two per row at every width (4 make 2x2 under `breakpoint.md`; odd counts end with three in the last row);
|
|
48
|
+
only cards holding a chart, a list or a form take a full row on a phone.
|
|
49
|
+
- Verification: "At 390px, no full-width card holds only one number" and "Read each figure's caption: the figure
|
|
50
|
+
must show what the caption describes".
|
|
51
|
+
|
|
52
|
+
## 1.1.0-rc.1
|
|
53
|
+
|
|
54
|
+
Internal candidate: the package is rewritten for any product instead of the four test apps
|
|
55
|
+
(`pipeline/claude-study/overfit-review-2026-10-19.md`). Design language, tokens and signature recipes unchanged.
|
|
56
|
+
|
|
57
|
+
- Layout adaptation: the featured-post and article lines (which omitted figures without an image) become a
|
|
58
|
+
featured-item rule and a long-form page rule; an image placeholder becomes the item's own drawing, never removed.
|
|
59
|
+
- Layout adaptation: cart and checkout becomes a transaction summary in a narrow sticky side column; store grid
|
|
60
|
+
becomes image card grids; the chart-card and stat-card lines become a stretched-panel rule (main content takes
|
|
61
|
+
the height) and stat rows that wrap evenly whatever their count.
|
|
62
|
+
- Applying the concept: Settings, Dashboard, Store and Article rows describe what any product of that kind has
|
|
63
|
+
(Store is now "Item list and detail", Article "Long-form content"); no stage colors per screen.
|
|
64
|
+
- Pastel stage Where: the per-screen color map is replaced by the rotation rule; plan cards become offer or choice
|
|
65
|
+
cards (rule 6, Where, Limits, Typography, card spec, Verification).
|
|
66
|
+
- Pictogram recipe: the misreads seen in past runs and the run-derived subject ban list become general failure
|
|
67
|
+
modes and a "skip the stock symbol for the task" rule; the key example is replaced.
|
|
68
|
+
- Switch: "applies immediately, never behind a Save button" becomes "a switch that applies immediately needs no
|
|
69
|
+
Save; inside a form, it follows the form's submit".
|
|
70
|
+
- "Every app" becomes "every product screen"; card "Numbered trio" becomes "Numbered steps (any count)"; badge and
|
|
71
|
+
stat examples use neutral placeholders; the empty-state first-run stage takes the rotation color.
|
|
72
|
+
|
|
73
|
+
## 1.0.0
|
|
74
|
+
|
|
75
|
+
First release of Inkleaf: warm ink on cream paper, a text serif for headings and a quiet sans for everything
|
|
76
|
+
else, with almost no color. Its personality comes from hand-drawn brush-ink pictograms that draw themselves in
|
|
77
|
+
once, frame by frame, and from soft pastel stages that hold product UI. Everything settles slowly.
|
|
78
|
+
|
|
79
|
+
- Ten defining rules and a Never list: paper and ink grounds, one warm accent kept to focus rings and a single
|
|
80
|
+
hero drawing, serif headings in sentence case, depth from 1px rings and tonal bands instead of shadows.
|
|
81
|
+
- Five signature recipes: brush-ink pictograms played once as a stepped sprite, pastel stages and plates,
|
|
82
|
+
serif headings that fade in word by word, a hand-drawn "working" glyph instead of a spinner, and ink-and-paper
|
|
83
|
+
ring controls.
|
|
84
|
+
- Drawing rules an agent can follow: one subject per drawing taken from the app's own domain; hands built from
|
|
85
|
+
long, separate hairpin fingers in four poses (present, grip, pinch, point), no pose on more than a third of an
|
|
86
|
+
app's hands, with a wrist that runs off the edge of its plate or stage; a one-word test for every drawing; and
|
|
87
|
+
each product drawn as itself when it has no photo, in the same plate color on every screen.
|
|
88
|
+
- Large drawings keep a solid, unbroken line that swells in the middle and thins at the ends, like a brush. Plates
|
|
89
|
+
and stages size their drawing by height, at most 416px, so no object is cut off at an edge.
|
|
90
|
+
- Motion tokens for slow settles (750 to 1000ms), stepped loops and hover rings; under reduced motion every
|
|
91
|
+
drawing shows its final frame and nothing stays hidden.
|
|
92
|
+
- 14 specified components, avatar and empty state included, with designed hover, focus, disabled, loading and
|
|
93
|
+
error states, and layout rules for dashboards, stores, articles and settings.
|
|
94
|
+
- Light and dark themes with Source Serif 4, Instrument Sans and JetBrains Mono, all openly licensed.
|
|
95
|
+
|
|
96
|
+
## 0.1.0-rc.4
|
|
97
|
+
|
|
98
|
+
Fourth candidate, answering the third critic round: drawings show the product they stand for, fill their stages,
|
|
99
|
+
draw hands that read as hands, and stop converging on the same office objects; card stages fit their content and
|
|
100
|
+
plan cards stay visible on mobile; content is never hidden without script.
|
|
101
|
+
|
|
102
|
+
- Missing images: was "the category's drawing on a plate"; now each item's own subject on its plate and the same
|
|
103
|
+
drawing on its detail stage, a category drawing only when one object is true of every item; Never adds one
|
|
104
|
+
product's drawing on another product's card or detail page.
|
|
105
|
+
- Drawing size: the drawing box on a drawing stage or plate was 50% of the inner width; it is now 80% of the full
|
|
106
|
+
width, absolutely centered, so the ink spans 45 to 60%; the Never item names ink, not box.
|
|
107
|
+
- Hands: the demo's diverging wrist strokes that stopped at y 113-114 are replaced by palm sides that run on as a
|
|
108
|
+
near-parallel wrist off the bottom edge; step 1 requires wrists 18 to 26 units apart leaving the box; the
|
|
109
|
+
silhouette test adds "reads as a creature: the wrist is wrong"; Never adds hands that read as creatures.
|
|
110
|
+
- Stages: `aspect-ratio: 16 / 9` moved from `.stage` to `.stage--media`; card and chart stages hug their content
|
|
111
|
+
with `space.48` (`space.24` mobile) padding; under `breakpoint.md` cards on a stage stack in source order, all
|
|
112
|
+
fully visible, in dashboard and settings alike; never a horizontal strip.
|
|
113
|
+
- Subjects: step 1 names the app's domain over generic office work and bans a steaming mug, magnifier, receipt,
|
|
114
|
+
envelope, lost glove, sock or mitten unless the screen is about it; no two drawings in one app share a
|
|
115
|
+
silhouette; header drawings are compared side by side at 48px; straight-edged subjects (set squares, rulers,
|
|
116
|
+
frames) are out unless every edge is bowed. Not-found drawings come from the app's domain, not "something lost".
|
|
117
|
+
- Block rise: was "below-the-fold blocks start hidden"; now only script hides a block (`is-rise-ready`), blocks in
|
|
118
|
+
view on load are never hidden, and no script, print and reduced motion show final states.
|
|
119
|
+
- Verification: grid cards' drawings name their product; plan cards fully visible at 390px; card stages hug
|
|
120
|
+
content; drawings checked on the real screens, never in preview pages or scratch files; `components.md` lists
|
|
121
|
+
each drawing's subject by screen.
|
|
122
|
+
- Budget: SVG path data written without spaces; the stacked-table CSS block became one sentence; the Select menu
|
|
123
|
+
points at the Navigation menu; shorter pictogram and stage Where lines, blog and article layout lines, button
|
|
124
|
+
Use, rule 9 and several Never and Verification items.
|
|
125
|
+
|
|
126
|
+
## 0.1.0-rc.3
|
|
127
|
+
|
|
128
|
+
Third candidate, answering the second critic round: no more empty pastel blocks, stages keep their proportions,
|
|
129
|
+
drawings read at small sizes and include hands more often, and a handful of product-screen details are pinned.
|
|
130
|
+
|
|
131
|
+
- Missing images: a grid image without a photo was a plate with a `size.iconLg` category icon bottom-left; it is
|
|
132
|
+
now a 4:3 plate holding the category's drawing at 50% of its width, final frame, one drawing per category; a
|
|
133
|
+
grid without categories drops the media slot. Article figures without an image are omitted.
|
|
134
|
+
- Stages: proportion now 16:9 to 1:1 (`.stage` gets `aspect-ratio: 16 / 9` as a minimum), never a banner; new
|
|
135
|
+
drawing stage (`stage--drawing`, 4:3, drawing at 50% of the inner width) for the blog home featured post and
|
|
136
|
+
for article or product images that are missing; a drawing on a stage spans 45 to 60% of its width.
|
|
137
|
+
- Rule 4: was "every section opens with a pictogram"; now prose sections open with a `size.pictoLg` drawing,
|
|
138
|
+
list sections (more posts, related, archive) open with the h2 alone, and a second opener in one viewport is
|
|
139
|
+
`size.pictoMd`.
|
|
140
|
+
- Pictogram recipe: the fixed subject list is replaced by a subject-picking method (task verb, three held
|
|
141
|
+
objects from the app's domain, clearest silhouette not yet drawn); no vehicles or toys, no subject the spec
|
|
142
|
+
names; at least half of each app's drawings include a hand; the defining feature is drawn first and oversized;
|
|
143
|
+
rectangular bodies are 2 to 4 bowed strokes; a 48px silhouette test.
|
|
144
|
+
- Never list: adds a plate or stage holding only an icon or nothing, a stage flatter than 16:9, and a drawing
|
|
145
|
+
under 45% of its stage or plate.
|
|
146
|
+
- Button: full width (`.btn--block`) keeps flex centering, never `display: block`.
|
|
147
|
+
- Navigation: new Menu entry (items `size.control`, `font: inherit`, start-aligned; sign out after a hairline,
|
|
148
|
+
same size).
|
|
149
|
+
- Table: toolbar row spec (title and count head, chips and visually labelled search `space.16` below); stacked
|
|
150
|
+
mobile tables hide the header row and sort with a native select.
|
|
151
|
+
- Avatar: tile color was "hashed from the name"; now (sum of char codes) mod 3 over sage, lilac and apricot.
|
|
152
|
+
- Motion: below-the-fold blocks start hidden and rise on entry; only reduced motion starts them final.
|
|
153
|
+
- Verification: stages and plates never empty, stage proportions, blog featured drawing stage, centered button
|
|
154
|
+
labels at 390px, silhouette test and hand share.
|
|
155
|
+
- Budget cuts: duplicated limits in the glyph, write-in and ring-control recipes, the connector-draw motion line,
|
|
156
|
+
the browser-chrome Never item (covered by components), card padding in Spacing, and assorted wording.
|
|
157
|
+
|
|
158
|
+
## 0.1.0-rc.2
|
|
159
|
+
|
|
160
|
+
Second candidate, answering the first critic round: pictograms animate as one visible stepped strip, the working
|
|
161
|
+
glyph is honest, and product-screen layouts get explicit rules.
|
|
162
|
+
|
|
163
|
+
- Pictogram recipe: per-frame `cel-flash`/`cel-hold` animations replaced by one sprite strip (`celStrip`) stepped
|
|
164
|
+
with `steps(n, jump-none)`; pre-play state shows the first stroke, never a blank frame; reduced motion shows the
|
|
165
|
+
final frame. Drawing limits: no straight segment over 15 units, boxy subjects bowed; `size.pictoSm` version with
|
|
166
|
+
5 to 7 strokes at 4.0 to 5.0 units and a 6/5 fill offset; the cup construction demo replaced by a hand holding
|
|
167
|
+
an egg (object, palm, thumb, noodle fingers, wrist).
|
|
168
|
+
- Never list: automation detection to skip animations; artificial delays for a working state; glyph beside a
|
|
169
|
+
button; a second `role="status"`; text or summaries on a stage; small card adrift on a stage; repeated centered
|
|
170
|
+
placeholder icons. Rule 9: glyph only while a real request is pending, inside the control.
|
|
171
|
+
- Motion: in-view-on-load entrances play immediately; nothing hidden more than one frame after entering view.
|
|
172
|
+
- Stage limits: holds a chart, media, pictogram, plan cards or ghosted preview; card at least 60% of inner width.
|
|
173
|
+
- Layout: product-screen header grid (drawing, h1, lede on one left edge, `body` lede), panel rows stretch with
|
|
174
|
+
titles inside cards, cart and checkout columns, store grid at 2 columns under `breakpoint.md`, article table of
|
|
175
|
+
contents after the lede on mobile, article h2 `h4` and h3 `h5`.
|
|
176
|
+
- Components: Avatar spec added (40px, `radius.tile`); stat change colored by meaning; toast reuses an existing
|
|
177
|
+
status region; footer inverse band only with two or more link groups; header product name aligned to sidebar
|
|
178
|
+
text; table row hover on raised cards uses `color.surface.subtle`; missing images use a bottom-left category
|
|
179
|
+
icon in grids and a `size.pictoXl` drawing on detail stages.
|
|
180
|
+
- Reduced motion: entrances never hide content; everything renders in its final state.
|
|
181
|
+
- Budget cuts: the streaming caret companion, the FAQ, toast and dialog rows of Applying the concept, the radius
|
|
182
|
+
list (now one line), duplicate button-hover lines in Interaction and two Never items already covered by rules 2
|
|
183
|
+
and 3.
|
|
184
|
+
|
|
185
|
+
## 0.1.0-rc.1
|
|
186
|
+
|
|
187
|
+
First release candidate of Inkleaf, derived from the approved reference analysis (captured 2026-10-13).
|
|
188
|
+
|
|
189
|
+
- Tokens: warm paper and ink neutrals, a single warm accent for focus, send square, working glyph and one hero
|
|
190
|
+
drawing; four stage pastels with derived night values; pictogram ink and fills; derived moss, ochre and harbor
|
|
191
|
+
status colors beside the observed brick error; Source Serif 4, Instrument Sans and JetBrains Mono; pixel-named
|
|
192
|
+
spacing; radii 4 to 32; ring widths 1 and 2px; hover, float and overlay shadows; motion from 83ms frames to
|
|
193
|
+
1200ms breaths on a settle curve; breakpoints 834, 992 and 1200.
|
|
194
|
+
- Principles: ten rules, a Never list, and five signature recipes (cel-drawn ink pictogram, pastel stage, serif
|
|
195
|
+
write-in heading, written-loop working glyph, ink-and-paper ring controls), Interaction, Motion with reduced
|
|
196
|
+
motion, and an Applying the concept table covering 16 contexts including dashboards, tables, settings and stores.
|
|
197
|
+
- Components: the 12 required plus empty state, all specified with states.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
## New project
|
|
2
|
+
|
|
3
|
+
1. Inspect the stack; propose an installation plan and wait for approval.
|
|
4
|
+
2. Copy `dist/tokens.css` into global styles (or map `dist/tokens.json` into the theme); never retype values. Dark follows `prefers-color-scheme` unless `[data-theme]` overrides it.
|
|
5
|
+
3. Load Source Serif 4 400/500, Instrument Sans 400/500, JetBrains Mono 400 (`font-display:swap`). Root: the brush filters, global `:focus-visible`, the reduced-motion block, `html, body{overflow-x:clip}`, body `color.surface.default`, `color.text.primary`, sans `font.size.body`, and `pre, code, kbd, samp{font-family:var(--font-family-mono); font-size:var(--font-size-small)}`.
|
|
6
|
+
4. Build the signature elements first, as reusable pieces: pictogram (stepped strip, play once, boil), stage, drawing stage and plate, write-in heading, working glyph and breathing dot, ring-control classes.
|
|
7
|
+
5. Build the components with every state; place the signature elements per Applying the concept.
|
|
8
|
+
6. Create `design-system/` with `VERSION` (system id and the spec's update date, e.g. `inkleaf, updated 2026-01-31`), the tokens, and `components.md`: conventions, where each signature element is used, each drawing's subject by screen and its one word.
|
|
9
|
+
7. Add to `AGENTS.md` and `CLAUDE.md` (create if missing): "UI work follows design-system/ — read it before building screens."
|
|
10
|
+
|
|
11
|
+
## Existing project
|
|
12
|
+
|
|
13
|
+
1. Audit styling, components, routes and tests; propose a migration plan (what changes, what stays) and wait for approval.
|
|
14
|
+
2. Map the tokens onto existing variables; a brand action color becomes `color.action.primary`, never the accent.
|
|
15
|
+
3. Build the signature elements, then restyle one representative screen as a sample (header pictogram, written-in h1, its stage where allowed) and wait for review.
|
|
16
|
+
4. Continue screen by screen, one commit each. Never add delays, toasts or `role="status"` regions the screen did not have. Missing images follow Imagery (a thing becomes its drawing, information a ghosted preview); spinners the glyph.
|
|
17
|
+
5. Preserve routes, logic, API contracts, form fields, validation, test ids, text used by tests and accessibility attributes. Restyle existing markup; never replace native inputs.
|
|
18
|
+
6. Finish with `design-system/` and the pointer lines from New project.
|
|
19
|
+
|
|
20
|
+
## Ongoing development
|
|
21
|
+
|
|
22
|
+
- Read `design-system/` first; semantic tokens and existing components, no hard-coded values.
|
|
23
|
+
- Every new screen gets the signature elements its context calls for; a screen without them is unfinished. New pictograms get new subjects.
|
|
24
|
+
- Uncovered needs: compose from tokens and note it in `components.md`; conflicting requests (brand color, spinner, bold headings): present options.
|
|
25
|
+
|
|
26
|
+
## Verification
|
|
27
|
+
|
|
28
|
+
- Build and tests pass; no raw colors, sizes or radii outside the token files.
|
|
29
|
+
- Review under reduced-motion emulation (every block, frame and heading final); never change code, motion or config to review.
|
|
30
|
+
- Each screen at 1440px and 390px, light and dark: no sideways scroll; statuses and row actions visible; product headers identical; panel rows share edges; button labels vertically centered; no text in the browser's bare `monospace` or `serif`.
|
|
31
|
+
- Stages and plates hold content (never a flat block or lone icon); drawing and media stages 16:9 to 1:1, card and chart stages hug content; at 390px every card on a stage is fully visible. An item's drawing and plate color are the same wherever the item appears. Every card grid of subject items has a plate on every card, whether or not the data has images.
|
|
32
|
+
- Zoom one plate and one drawing stage to 200% at 1440px: strokes continuous, no notches, full in the middle and thin at the ends, ink within the weight targets; the featured drawing never outweighs the h1. On every plate and stage each wrist reaches the edge, the object stays at least `space.16` inside every edge, and at most 35% of the height is empty above the drawing.
|
|
33
|
+
- At 390px, no full-width card holds only one number; short metric cards sit two or more per row.
|
|
34
|
+
- Read each figure's caption: the figure must show what the caption describes; a caption about a layout, list, board or comparison never sits under a single object drawing.
|
|
35
|
+
- Tab through every screen (focus always visible); click every checkbox, radio and switch (each toggles).
|
|
36
|
+
- Pictograms: original subjects, none banned, no two alike in one app; every drawing, plates included, passes the one-word test; frames = strokes + 3, none repeated; each steps in as one strip (never blank, no marks from a neighboring frame) and holds. h1s write in once; the glyph runs only during real requests.
|
|
37
|
+
- Line up the app's hands: at least half the drawings; long, separate fingers; no pose on over a third; neighboring plates differ.
|
|
38
|
+
- Check drawings on the real screens; never create preview pages, galleries or scratch files.
|
|
39
|
+
- Walk the ten rules and the Never list. Report files changed, what you could not apply, and your decisions.
|
|
40
|
+
|
|
41
|
+
## Rollback
|
|
42
|
+
|
|
43
|
+
- Each screen is its own commit and can be reverted alone.
|
|
44
|
+
- Tokens, fonts, root setup and signature pieces are separate commits, reverted last.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
### Avatar
|
|
2
|
+
|
|
3
|
+
**Anatomy.** A `size.control` (40px) square tile, `radius.tile`, serif initials `font.size.h5`, 400,
|
|
4
|
+
`color.text.primary`; a photo fills the tile, clipped. Tile color: (sum of the name's char codes) mod 3 picks
|
|
5
|
+
`color.stage.sage`, `color.stage.lilac` or `color.stage.apricot` (header account avatar too).
|
|
6
|
+
Never smaller, except the header account button (`size.controlSm`). Stacks overlap by `space.8` with a 2px `color.surface.default` ring.
|
|
7
|
+
|
|
8
|
+
**States.** Linked: focus-visible outline, no hover change. `alt=""` beside a visible name, otherwise the name.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
### Badge
|
|
2
|
+
|
|
3
|
+
**Anatomy.** Height `space.24`, padding 0 `space.8`, `radius.badge`, `font.size.caption`, 500, gap `space.6`.
|
|
4
|
+
|
|
5
|
+
**Variants.** Outline: inset 1px `color.border.control` ring, `color.text.secondary`. Stone:
|
|
6
|
+
`color.action.tertiary`, `color.text.primary`. Status: outline plus a `space.6` dot and text in `color.status.*`;
|
|
7
|
+
running dots breathe; never a filled status color or pastel. Count: `radius.full`, `space.20` min, ink fill,
|
|
8
|
+
`color.text.onAction`, `aria-label` naming the count and what it counts ("3 unread"). A state marker ("Current", "Default") is a badge, never ink.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
### Button
|
|
2
|
+
|
|
3
|
+
**Use.** One ink primary per region, paper secondary for the rest, stone tertiary for small utilities; danger
|
|
4
|
+
only confirms a destructive action.
|
|
5
|
+
|
|
6
|
+
**Anatomy.** The ring-controls recipe. Small `size.controlSm`, padding 0 `space.12`, `font.size.small`; default
|
|
7
|
+
`size.control`, 0 `space.16`; large `size.controlLg`, 0 `space.24`, `font.size.body`. Optional `size.icon` icon,
|
|
8
|
+
gap `space.8`; icon-only is square with `aria-label`. Full width
|
|
9
|
+
(`.btn--block`): `display:flex; width:100%`, still centered, never `display:block`. Labels 500, verb first, 1 to 3 words. On
|
|
10
|
+
`color.surface.inverse`: primary fill `color.text.inverse`, label `color.surface.inverse`; ghost transparent,
|
|
11
|
+
`color.text.inverse`, 1px `color.border.inverse` ring.
|
|
12
|
+
|
|
13
|
+
**States.** Hover, focus-visible, active: Interaction. Disabled: `color.surface.subtle`, `color.text.disabled`.
|
|
14
|
+
Loading, only while a real request is pending: glyph and gerund replace the label inside the button, width held,
|
|
15
|
+
`aria-busy="true"`. Danger: `color.action.danger`,
|
|
16
|
+
`color.text.onAction`, hover ring in the same color.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
### Card
|
|
2
|
+
|
|
3
|
+
**Anatomy.** `color.surface.raised`, `radius.card`, inset 1px `color.border.default` ring, padding `space.32`
|
|
4
|
+
(`space.24` on product screens and mobile), no resting shadow. Title serif `font.size.h5`, 500; body
|
|
5
|
+
`font.size.ui`, `color.text.secondary`; meta `font.size.caption`, `color.text.tertiary`.
|
|
6
|
+
|
|
7
|
+
**Variants.** Feature or offer: `size.pictoMd` drawing top-left; offer name serif `font.size.plan`; price sans
|
|
8
|
+
`font.size.h3`; full-width primary; checklist with 16px check-circles. Media (every card in a grid of subject items, image field or not; text-only cards are for links, resources and metadata): a 4:3 plate on top (photo or the item's own drawing),
|
|
9
|
+
body padding `space.20`. Stat: label `font.size.small`; value sans `font.size.h3`, `tabular-nums`; change
|
|
10
|
+
`font.size.caption`, colored by meaning, not sign (a falling count of something bad is success), secondary if unknown. Numbered steps (any count): hairline top rule, mono "01", serif title.
|
|
11
|
+
|
|
12
|
+
**States.** Linked hover and focus-visible: Interaction; one stretched title link. Selected: 2px inset
|
|
13
|
+
`color.action.primary` ring. Loading: static `color.surface.subtle` skeleton bars. Error: a `color.status.danger`
|
|
14
|
+
line and a secondary "Retry".
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
### Checkbox and radio
|
|
2
|
+
|
|
3
|
+
**Anatomy.** The native `<input>` with `appearance:none` is the visible control and takes every click:
|
|
4
|
+
`size.iconLg` square, `radius.badge` (radio `radius.full`), `color.surface.raised`, inset 1px `color.border.check`
|
|
5
|
+
ring. The tick is a sibling 12px SVG (1.75px stroke, `color.text.onAction`) over the box with
|
|
6
|
+
`pointer-events:none`; the radio dot is an inset 5px `color.action.primary` ring on a `color.text.onAction` fill.
|
|
7
|
+
Label `font.size.ui` at `space.8`; rows at least `size.touch`; groups in a `<fieldset>`.
|
|
8
|
+
|
|
9
|
+
**States.** Hover: ring `color.text.primary`. Focus-visible: outline. Selected: `color.action.primary` fill,
|
|
10
|
+
`motion.duration.press`. Disabled: `color.surface.subtle`, ring `color.border.default`, label
|
|
11
|
+
`color.text.disabled`. Error: ring `color.status.danger`, message under the group.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
### Dialog
|
|
2
|
+
|
|
3
|
+
**Anatomy.** Native `<dialog>` with `showModal()`. `color.surface.raised`, `radius.stage`, padding `space.32`,
|
|
4
|
+
width `min(var(--size-dialog), 100% - 2 * var(--space-16))`, centered, `shadow.overlay`; backdrop `color.surface.overlay`. Title serif `font.size.h4`, 500, static; body `font.size.ui`,
|
|
5
|
+
`color.text.secondary`; actions right, `space.32` below, gap `space.12`: cancel secondary, confirm primary or
|
|
6
|
+
danger; stacked full width under `breakpoint.md`.
|
|
7
|
+
|
|
8
|
+
**States.** Open and close per Motion. Focus-visible on open: first field, or cancel for destructive confirms.
|
|
9
|
+
Loading: glyph in confirm, others disabled. Error: `color.status.danger` line above actions, `role="alert"`.
|
|
10
|
+
Escape closes; focus returns to the trigger.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
### Empty state
|
|
2
|
+
|
|
3
|
+
**Anatomy.** Centered, max width `size.dialog`, padding `space.64` `space.24`: a `size.pictoLg` drawing
|
|
4
|
+
(`size.pictoMd` in cards and tables) that plays once, `space.24`, serif `font.size.h4` title written in, `space.8`,
|
|
5
|
+
one `color.text.secondary` line, `space.24`, one action. First
|
|
6
|
+
run: on a small stage (next color in the rotation) over a ghosted skeleton (raised cards at 60% opacity, no text).
|
|
7
|
+
|
|
8
|
+
**Variants.** Filtered-empty: the title names the filter, the action clears it. Not found and error: `size.pictoXl`, serif h1, two actions.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"components": [
|
|
3
|
+
{ "name": "button", "category": "action", "status": "specified", "file": "button.md", "states": ["default", "hover", "focus-visible", "active", "disabled", "loading"] },
|
|
4
|
+
{ "name": "text-field", "category": "form", "status": "specified", "file": "text-field.md", "states": ["default", "hover", "focus-visible", "disabled", "loading", "error"] },
|
|
5
|
+
{ "name": "select", "category": "form", "status": "specified", "file": "select.md", "states": ["default", "hover", "focus-visible", "selected", "disabled", "error"] },
|
|
6
|
+
{ "name": "checkbox", "category": "form", "status": "specified", "file": "checkbox.md", "states": ["default", "hover", "focus-visible", "selected", "disabled", "error"] },
|
|
7
|
+
{ "name": "switch", "category": "form", "status": "specified", "file": "switch.md", "states": ["default", "hover", "focus-visible", "selected", "disabled", "loading"] },
|
|
8
|
+
{ "name": "tabs", "category": "navigation", "status": "specified", "file": "tabs.md", "states": ["default", "hover", "focus-visible", "selected", "disabled"] },
|
|
9
|
+
{ "name": "navigation", "category": "navigation", "status": "specified", "file": "navigation.md", "states": ["default", "hover", "focus-visible", "selected"] },
|
|
10
|
+
{ "name": "card", "category": "surface", "status": "specified", "file": "card.md", "states": ["default", "hover", "focus-visible", "selected", "loading", "error"] },
|
|
11
|
+
{ "name": "table", "category": "data-display", "status": "specified", "file": "table.md", "states": ["default", "hover", "focus-visible", "selected", "loading", "error"] },
|
|
12
|
+
{ "name": "badge", "category": "data-display", "status": "specified", "file": "badge.md", "states": ["default"] },
|
|
13
|
+
{ "name": "dialog", "category": "overlay", "status": "specified", "file": "dialog.md", "states": ["default", "focus-visible", "loading", "error"] },
|
|
14
|
+
{ "name": "toast", "category": "feedback", "status": "specified", "file": "toast.md", "states": ["default", "focus-visible", "error"] },
|
|
15
|
+
{ "name": "empty-state", "category": "feedback", "status": "specified", "file": "empty-state.md", "states": ["default", "error"] },
|
|
16
|
+
{ "name": "avatar", "category": "data-display", "status": "specified", "file": "avatar.md", "states": ["default", "focus-visible"] }
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
### Navigation
|
|
2
|
+
|
|
3
|
+
**Header.** `size.header`, sticky, `color.surface.default`, 1px `color.border.default` bottom ring. Product name
|
|
4
|
+
as serif `font.size.h5` text (no invented logo); in a product shell its left edge lines up with the sidebar item
|
|
5
|
+
text (`space.16` + `space.12` from the edge). Links `font.size.ui`, `color.text.secondary`, padded boxes
|
|
6
|
+
`size.controlSm` high, gap `space.16`; current `color.text.primary`, 500, `aria-current="page"`. Right: small
|
|
7
|
+
secondary, then small primary. Below `breakpoint.lg`, more than 3 links collapse into a `size.touch` menu button
|
|
8
|
+
opening a sheet of hairline `size.touch` rows.
|
|
9
|
+
|
|
10
|
+
**Menu** (account, row actions). `color.surface.raised`, `radius.tile`, `shadow.overlay`, padding `space.6`. Every item, link or
|
|
11
|
+
`<button>`, is `size.control` high, full width, `display:flex; align-items:center`, padding 0 `space.12`,
|
|
12
|
+
`font:inherit` at `font.size.ui`, `text-align:start`, `radius.control`. A header line (the email): caption,
|
|
13
|
+
tertiary, not interactive. Sign out and destructive items come last after a hairline, same size and inset.
|
|
14
|
+
|
|
15
|
+
**Sidebar** (from `breakpoint.lg`). `size.sidebar`, right hairline, padding `space.16`; items `size.control`,
|
|
16
|
+
`radius.control`, padding 0 `space.12`, 16px icon; current `color.surface.subtle`, `color.text.primary`, 500; group
|
|
17
|
+
labels `font.size.micro` uppercase `color.text.tertiary`. Below `breakpoint.lg` it collapses into the header's
|
|
18
|
+
`size.touch` menu button and sheet, on every product screen; never a link grid above the content.
|
|
19
|
+
|
|
20
|
+
**Breadcrumb.** `font.size.small`, `color.text.secondary`, "/" in `color.text.tertiary`, `space.16` below.
|
|
21
|
+
|
|
22
|
+
**Footer.** Content sites with two or more link groups: `color.surface.inverse` band, padding `space.96` 0,
|
|
23
|
+
caption link columns in `color.text.inverseMuted`. Otherwise, and in product apps: a hairline, then one caption
|
|
24
|
+
line, padding `space.24` 0.
|
|
25
|
+
|
|
26
|
+
**A11y.** `<nav aria-label>`, skip link, Escape closes menus.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
### Select
|
|
2
|
+
|
|
3
|
+
**Anatomy.** Text field's box, label, hint and error, `appearance:none`, a 16px chevron in
|
|
4
|
+
`color.text.secondary` at `space.12` from the right. Prefer native `<select>`. Custom menu: the Navigation menu's
|
|
5
|
+
surface and items, max height 320px; selected option 500 with a 16px check.
|
|
6
|
+
|
|
7
|
+
**States.** Hover, focus-visible, disabled, error: as Text field. Open: chevron rotates 180°, menu per Motion.
|
|
8
|
+
Option hover and keyboard-active: `color.surface.hover`.
|
|
9
|
+
|
|
10
|
+
**A11y.** Custom menus: `listbox`, `aria-expanded`, arrows, typeahead, Escape returns focus.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
### Switch
|
|
2
|
+
|
|
3
|
+
**Anatomy.** `<input type="checkbox" role="switch">` with `appearance:none` is the track: `size.control` x
|
|
4
|
+
`space.24`, `radius.full`, `color.surface.subtle`, inset 1px `color.border.check` ring. Thumb: sibling span,
|
|
5
|
+
`space.16` circle, `color.surface.raised`, `pointer-events:none`, `space.4` inset. Switch rows: label left,
|
|
6
|
+
`font.size.small` secondary description below, at least `size.touch`, hairline below.
|
|
7
|
+
|
|
8
|
+
**States.** Hover: ring `color.text.primary`. Focus-visible: outline on the track. Selected: track
|
|
9
|
+
`color.action.primary`, thumb `color.text.onAction`, moved `space.16` over `motion.duration.hover`,
|
|
10
|
+
`motion.easing.settle`. Disabled: ring `color.border.default`, label `color.text.disabled`. A switch that applies
|
|
11
|
+
immediately needs no Save; inside a form, it follows the form's submit.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
### Table
|
|
2
|
+
|
|
3
|
+
**Anatomy.** In a clipped card or bare. Head row `size.rowDense`, eyebrow type (Typography). Rows `size.rowDense` (comparison `size.row`), `font.size.dense`, hairlines only, no
|
|
4
|
+
zebra; cells padding 0 `space.16`; first column `color.text.primary`, others secondary; numbers right,
|
|
5
|
+
`tabular-nums`; `table-layout:fixed`. A header cell aligns like its cells (numbers right; text and badges start),
|
|
6
|
+
never at the card edge over a column whose content starts elsewhere. Group rows: serif `font.size.h5`. Booleans: check-circle or thin cross. Status: badge, running ones breathe. Row actions last:
|
|
7
|
+
small secondary buttons or a `size.controlSm` menu button.
|
|
8
|
+
|
|
9
|
+
**Toolbar** (a table in a card). Card head: one row, serif `font.size.h5` title left, count `font.size.caption`
|
|
10
|
+
`color.text.tertiary` right. Toolbar row `space.16` below: filter chips left, search right, both `size.control` high,
|
|
11
|
+
centered; the search label visually hidden, never stacked above the field.
|
|
12
|
+
|
|
13
|
+
**States.** Hover, focus-visible, selected: Interaction. Sortable header: a button, `aria-sort`, sorted column
|
|
14
|
+
`color.text.primary` with a 12px arrow. Loading: 5 static skeleton rows. Empty: the empty state with a
|
|
15
|
+
`size.pictoMd` drawing. Error: danger line and "Retry".
|
|
16
|
+
|
|
17
|
+
**Mobile** (under `breakpoint.md`): tables with status or actions stack and hide the header row; sorting moves to a native "Sort by" select in the toolbar. Others scroll in a
|
|
18
|
+
labelled `role="region"` wrapper, `tabindex="0"`.
|
|
19
|
+
|
|
20
|
+
Stacked: `thead` visually hidden; table, `tbody`, `tr`, `td` `display:block`; rows padded `space.12` `space.16`
|
|
21
|
+
over a hairline; each `td` a grid `minmax(96px, 38%) 1fr`, gap `space.12`, its `data-label` in a `::before` at
|
|
22
|
+
`font.size.caption`, `color.text.tertiary`. Every stacked label and value is start-aligned: reset numeric
|
|
23
|
+
`text-align:right` there.
|
|
24
|
+
|
|
25
|
+
Keep `<table>`, explicit `role`s, `data-label` per cell, `<th scope>`.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
### Tabs
|
|
2
|
+
|
|
3
|
+
**Variants.** Segmented (views of one thing, up to 5): track `color.surface.subtle`, `radius.tile`, padding
|
|
4
|
+
`space.4`; segments `size.controlSm`, padding 0 `space.16`, `radius.control`, `color.text.secondary`; selected: a
|
|
5
|
+
`color.surface.raised` pill with 1px `color.border.default` ring, `color.text.primary`, 500. Underline (page
|
|
6
|
+
sections): tabs `size.control`, gap `space.24`, hairline below; selected `color.text.primary`, 500, 2px
|
|
7
|
+
`color.action.primary` rule.
|
|
8
|
+
|
|
9
|
+
**States.** Hover, focus-visible, selected: Interaction. Disabled: `color.text.disabled`, skipped by arrows.
|
|
10
|
+
Mobile: underline tabs scroll in their own strip; segmented go full width.
|
|
11
|
+
|
|
12
|
+
**A11y.** `tablist`, `tab`, `tabpanel`, `aria-selected`, arrows. Filter chips: `aria-pressed` buttons.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
### Text field
|
|
2
|
+
|
|
3
|
+
**Anatomy.** Label above (`font.size.ui`, 500), `space.8`; control `size.control` high (never shrinks in a flex
|
|
4
|
+
row), `radius.control`, `color.surface.raised`, inset 1px `color.border.strong` ring, padding 0 `space.12`,
|
|
5
|
+
placeholder `color.text.tertiary`; hint `space.6` below, `font.size.small`, `color.text.secondary`. Search: 16px
|
|
6
|
+
icon at `space.12`, text from `space.40`, own clear button (hide `::-webkit-search-cancel-button`). Textarea: min 3 rows, padding `space.12`. Prompt field:
|
|
7
|
+
`radius.tile`, send square at the right.
|
|
8
|
+
|
|
9
|
+
**States.** Hover: ring `color.border.check`. Focus-visible: outline, ring unchanged. Disabled:
|
|
10
|
+
`color.surface.subtle`, `color.text.disabled`. Error: ring `color.status.danger`; the message replaces the hint in
|
|
11
|
+
`color.status.danger`, `aria-invalid`, `aria-describedby`; no red fill. A failed submit adds "2 fields need attention"
|
|
12
|
+
above the actions (`role="alert"`) and focuses the first invalid field. Loading: glyph inside, right.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
### Toast
|
|
2
|
+
|
|
3
|
+
**Anatomy.** Bottom-right at `space.24` (mobile: bottom, full width minus `space.16`). `color.surface.raised`,
|
|
4
|
+
`radius.tile`, inset 1px `color.border.default` ring, `shadow.overlay`, padding `space.12` `space.16`, max width
|
|
5
|
+
`size.dialog`, `font.size.ui`. Leading: the glyph while running, a 16px check-circle on success. Optional action, close button. Error: 2px inset `color.status.danger` left rule.
|
|
6
|
+
|
|
7
|
+
**States.** Enter and leave per Motion; at most 3, gap `space.8`. Success dismisses after 5s, paused on hover or focus;
|
|
8
|
+
errors stay. `role="status"` (errors `alert`); if the screen already has a status region, "Saved" goes there instead.
|