pigment-mcp 0.6.0 → 0.8.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 +6 -2
- package/content/registry.json +18 -0
- package/content/shots.json +28 -0
- package/content/templates/night-cartridge/1.0.0/CHANGELOG.md +98 -0
- package/content/templates/night-cartridge/1.0.0/agent/instructions.md +40 -0
- package/content/templates/night-cartridge/1.0.0/components/badge.md +5 -0
- package/content/templates/night-cartridge/1.0.0/components/button.md +13 -0
- package/content/templates/night-cartridge/1.0.0/components/card.md +7 -0
- package/content/templates/night-cartridge/1.0.0/components/checkbox.md +7 -0
- package/content/templates/night-cartridge/1.0.0/components/dialog.md +7 -0
- package/content/templates/night-cartridge/1.0.0/components/empty-state.md +5 -0
- package/content/templates/night-cartridge/1.0.0/components/index.json +17 -0
- package/content/templates/night-cartridge/1.0.0/components/navigation.md +18 -0
- package/content/templates/night-cartridge/1.0.0/components/select.md +7 -0
- package/content/templates/night-cartridge/1.0.0/components/switch.md +7 -0
- package/content/templates/night-cartridge/1.0.0/components/table.md +7 -0
- package/content/templates/night-cartridge/1.0.0/components/tabs.md +7 -0
- package/content/templates/night-cartridge/1.0.0/components/text-field.md +7 -0
- package/content/templates/night-cartridge/1.0.0/components/toast.md +7 -0
- package/content/templates/night-cartridge/1.0.0/dist/agent.md +747 -0
- package/content/templates/night-cartridge/1.0.0/dist/tokens.css +363 -0
- package/content/templates/night-cartridge/1.0.0/dist/tokens.json +532 -0
- package/content/templates/night-cartridge/1.0.0/manifest.json +101 -0
- package/content/templates/night-cartridge/1.0.0/principles/visual-language.md +343 -0
- package/content/templates/night-cartridge/1.0.0/tokens/primitives.json +650 -0
- package/content/templates/night-cartridge/1.0.0/tokens/semantic.dark.json +224 -0
- package/content/templates/night-cartridge/1.0.0/tokens/semantic.light.json +224 -0
- package/content/templates/night-cartridge/1.1.0/CHANGELOG.md +149 -0
- package/content/templates/night-cartridge/1.1.0/agent/instructions.md +40 -0
- package/content/templates/night-cartridge/1.1.0/components/badge.md +5 -0
- package/content/templates/night-cartridge/1.1.0/components/button.md +13 -0
- package/content/templates/night-cartridge/1.1.0/components/card.md +7 -0
- package/content/templates/night-cartridge/1.1.0/components/checkbox.md +7 -0
- package/content/templates/night-cartridge/1.1.0/components/dialog.md +7 -0
- package/content/templates/night-cartridge/1.1.0/components/empty-state.md +5 -0
- package/content/templates/night-cartridge/1.1.0/components/index.json +17 -0
- package/content/templates/night-cartridge/1.1.0/components/navigation.md +18 -0
- package/content/templates/night-cartridge/1.1.0/components/select.md +7 -0
- package/content/templates/night-cartridge/1.1.0/components/switch.md +7 -0
- package/content/templates/night-cartridge/1.1.0/components/table.md +7 -0
- package/content/templates/night-cartridge/1.1.0/components/tabs.md +7 -0
- package/content/templates/night-cartridge/1.1.0/components/text-field.md +7 -0
- package/content/templates/night-cartridge/1.1.0/components/toast.md +7 -0
- package/content/templates/night-cartridge/1.1.0/dist/agent.md +682 -0
- package/content/templates/night-cartridge/1.1.0/dist/tokens.css +195 -0
- package/content/templates/night-cartridge/1.1.0/dist/tokens.json +225 -0
- package/content/templates/night-cartridge/1.1.0/manifest.json +99 -0
- package/content/templates/night-cartridge/1.1.0/principles/visual-language.md +343 -0
- package/content/templates/night-cartridge/1.1.0/tokens/primitives.json +516 -0
- package/content/templates/night-cartridge/1.1.0/tokens/semantic.dark.json +220 -0
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -34934,6 +34934,7 @@ function buildPrompt(id2, mode2, delivery) {
|
|
|
34934
34934
|
`Set up design system ${id2} in this codebase.`,
|
|
34935
34935
|
spec,
|
|
34936
34936
|
"First inspect the framework, styling approach and component structure, then propose an installation plan and wait for my approval.",
|
|
34937
|
+
APPEARANCE,
|
|
34937
34938
|
"Don't add libraries that don't fit the existing stack. Leave an AGENTS.md / CLAUDE.md pointer so future screens reuse the system.",
|
|
34938
34939
|
"Report build results, visual checks and anything left unimplemented."
|
|
34939
34940
|
].join("\n");
|
|
@@ -34944,6 +34945,7 @@ function buildPrompt(id2, mode2, delivery) {
|
|
|
34944
34945
|
spec,
|
|
34945
34946
|
"Preserve features, routes, business logic, API contracts, tests and accessibility.",
|
|
34946
34947
|
"Audit styles and components first, then propose a migration plan and wait for my approval. Restyle one screen as a sample and wait again.",
|
|
34948
|
+
APPEARANCE,
|
|
34947
34949
|
"Report build results, visual checks and anything left unimplemented."
|
|
34948
34950
|
].join("\n");
|
|
34949
34951
|
}
|
|
@@ -34953,12 +34955,13 @@ function buildPrompt(id2, mode2, delivery) {
|
|
|
34953
34955
|
"If the spec doesn't cover something, ask me with options before deciding."
|
|
34954
34956
|
].join("\n");
|
|
34955
34957
|
}
|
|
34956
|
-
var SITE_URL, MCP_URL;
|
|
34958
|
+
var SITE_URL, MCP_URL, APPEARANCE;
|
|
34957
34959
|
var init_prompts = __esm({
|
|
34958
34960
|
"../content/src/prompts.ts"() {
|
|
34959
34961
|
"use strict";
|
|
34960
34962
|
SITE_URL = process.env.NEXT_PUBLIC_SITE_URL ?? "https://pigmentui.com";
|
|
34961
34963
|
MCP_URL = process.env.NEXT_PUBLIC_MCP_URL ?? `${SITE_URL}/mcp`;
|
|
34964
|
+
APPEARANCE = "If the system offers both light and dark, ask which my product supports (light only, dark only, or both) as part of the plan: with one, fix that mode; with both, follow the system setting and connect an existing theme switch, adding one only if I ask.";
|
|
34962
34965
|
}
|
|
34963
34966
|
});
|
|
34964
34967
|
|
|
@@ -34968,7 +34971,7 @@ var init_package = __esm({
|
|
|
34968
34971
|
"package.json"() {
|
|
34969
34972
|
package_default = {
|
|
34970
34973
|
name: "@pigment/mcp",
|
|
34971
|
-
version: "0.
|
|
34974
|
+
version: "0.8.0",
|
|
34972
34975
|
private: true,
|
|
34973
34976
|
type: "module",
|
|
34974
34977
|
description: "MCP server for Pigment design systems: tokens, rules, component specs and installation guides for your coding agent.",
|
|
@@ -35162,6 +35165,7 @@ var init_server = __esm({
|
|
|
35162
35165
|
INSTRUCTIONS = [
|
|
35163
35166
|
"Pigment serves design systems for coding agents. Every tool returns the current system; there is nothing to choose or pin.",
|
|
35164
35167
|
"Applying a system copies it into the project's design-system/ folder (tokens, component notes and a VERSION file naming the system and its update date).",
|
|
35168
|
+
"If the system offers both light and dark, ask the user which their product supports (light only, dark only, or both) before applying it: with one, fix that mode; with both, follow the system setting and connect an existing theme switch, adding one only if asked.",
|
|
35165
35169
|
"From then on design-system/ is the project's source of truth: build new screens from it and don't re-fetch tokens unless the user asks to update.",
|
|
35166
35170
|
"To update, call get_changelog, apply only the entries dated after the date in design-system/VERSION, and then write the new date."
|
|
35167
35171
|
].join("\n");
|
package/content/registry.json
CHANGED
|
@@ -29,6 +29,24 @@
|
|
|
29
29
|
"sha256": "950225ff2a2540952b0acbdd499d07d8f78576262299a979d5d831145f51174b"
|
|
30
30
|
}
|
|
31
31
|
]
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"id": "night-cartridge",
|
|
35
|
+
"latest": "1.1.0",
|
|
36
|
+
"versions": [
|
|
37
|
+
{
|
|
38
|
+
"version": "1.0.0",
|
|
39
|
+
"status": "published",
|
|
40
|
+
"publishedAt": "2026-10-15T02:21:28.148Z",
|
|
41
|
+
"sha256": "16fa69d9fef53a8a64e8caef4d7c528e3dfe1c23eb7cbbee0f76e5e9e77ec775"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"version": "1.1.0",
|
|
45
|
+
"status": "published",
|
|
46
|
+
"publishedAt": "2026-10-15T04:49:09.540Z",
|
|
47
|
+
"sha256": "a4e943cb722c1506dac7af6ab80341f3c28bbe1aef3184038d4a9cb863a06e30"
|
|
48
|
+
}
|
|
49
|
+
]
|
|
32
50
|
}
|
|
33
51
|
]
|
|
34
52
|
}
|
package/content/shots.json
CHANGED
|
@@ -52,5 +52,33 @@
|
|
|
52
52
|
"settings.desktopDark": "/showcase/inkleaf/1.0.0/settings/settings-profile-desktop-dark.png",
|
|
53
53
|
"settings.mobileLight": "/showcase/inkleaf/1.0.0/settings/settings-profile-mobile-light.png",
|
|
54
54
|
"settings.mobileDark": "/showcase/inkleaf/1.0.0/settings/settings-profile-mobile-dark.png"
|
|
55
|
+
},
|
|
56
|
+
"night-cartridge@1.0.0": {
|
|
57
|
+
"blog.desktopLight": "/showcase/night-cartridge/1.0.0/blog/home-desktop-light.png",
|
|
58
|
+
"blog.desktopDark": "/showcase/night-cartridge/1.0.0/blog/home-desktop-dark.png",
|
|
59
|
+
"blog.mobileLight": "/showcase/night-cartridge/1.0.0/blog/home-mobile-light.png",
|
|
60
|
+
"blog.mobileDark": "/showcase/night-cartridge/1.0.0/blog/home-mobile-dark.png",
|
|
61
|
+
"commerce.desktopLight": "/showcase/night-cartridge/1.0.0/commerce/home-desktop-light.png",
|
|
62
|
+
"commerce.desktopDark": "/showcase/night-cartridge/1.0.0/commerce/home-desktop-dark.png",
|
|
63
|
+
"commerce.mobileLight": "/showcase/night-cartridge/1.0.0/commerce/home-mobile-light.png",
|
|
64
|
+
"commerce.mobileDark": "/showcase/night-cartridge/1.0.0/commerce/home-mobile-dark.png",
|
|
65
|
+
"dashboard.desktopLight": "/showcase/night-cartridge/1.0.0/dashboard/home-desktop-light.png",
|
|
66
|
+
"dashboard.desktopDark": "/showcase/night-cartridge/1.0.0/dashboard/home-desktop-dark.png",
|
|
67
|
+
"dashboard.mobileLight": "/showcase/night-cartridge/1.0.0/dashboard/home-mobile-light.png",
|
|
68
|
+
"dashboard.mobileDark": "/showcase/night-cartridge/1.0.0/dashboard/home-mobile-dark.png",
|
|
69
|
+
"settings.desktopLight": "/showcase/night-cartridge/1.0.0/settings/settings-profile-desktop-light.png",
|
|
70
|
+
"settings.desktopDark": "/showcase/night-cartridge/1.0.0/settings/settings-profile-desktop-dark.png",
|
|
71
|
+
"settings.mobileLight": "/showcase/night-cartridge/1.0.0/settings/settings-profile-mobile-light.png",
|
|
72
|
+
"settings.mobileDark": "/showcase/night-cartridge/1.0.0/settings/settings-profile-mobile-dark.png"
|
|
73
|
+
},
|
|
74
|
+
"night-cartridge@1.1.0": {
|
|
75
|
+
"blog.desktopDark": "/showcase/night-cartridge/1.1.0/blog/home-desktop-dark.png",
|
|
76
|
+
"blog.mobileDark": "/showcase/night-cartridge/1.1.0/blog/home-mobile-dark.png",
|
|
77
|
+
"commerce.desktopDark": "/showcase/night-cartridge/1.1.0/commerce/home-desktop-dark.png",
|
|
78
|
+
"commerce.mobileDark": "/showcase/night-cartridge/1.1.0/commerce/home-mobile-dark.png",
|
|
79
|
+
"dashboard.desktopDark": "/showcase/night-cartridge/1.1.0/dashboard/home-desktop-dark.png",
|
|
80
|
+
"dashboard.mobileDark": "/showcase/night-cartridge/1.1.0/dashboard/home-mobile-dark.png",
|
|
81
|
+
"settings.desktopDark": "/showcase/night-cartridge/1.1.0/settings/settings-profile-desktop-dark.png",
|
|
82
|
+
"settings.mobileDark": "/showcase/night-cartridge/1.1.0/settings/settings-profile-mobile-dark.png"
|
|
55
83
|
}
|
|
56
84
|
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 1.0.0
|
|
4
|
+
|
|
5
|
+
First release of Night Cartridge: a 16-bit console booted as a product. A night-blue ground, cream pixel type
|
|
6
|
+
that sets Hangul and Latin on one bitmap grid, hard-edged game windows, an RPG menu marker, and small living
|
|
7
|
+
pixel scenes that move only in stepped frames. A derived parchment "day" theme comes with it.
|
|
8
|
+
|
|
9
|
+
- Ten defining rules and a Never list: everything on the pixel grid (radius 0, 2px and 4px borders, hard
|
|
10
|
+
shadows), quantized colors, one pixel typeface at weight 400, and gold reserved for the one primary action,
|
|
11
|
+
the marker and the focus ring.
|
|
12
|
+
- Pixel scenes built by recipe: layered sky, haze and ridges, a focal group with clustered props, a
|
|
13
|
+
hand-placed detail pass (lit windows, signs, textures, stars, small life) and a review at twice the size
|
|
14
|
+
before they ship. Heroes, banners, strips, figures and empty-state vignettes each have their own sizes.
|
|
15
|
+
- Stepped motion only: loops live in the art and status lights, controls respond instantly and press down 2
|
|
16
|
+
to 4px, and reduced motion or the animation switch freezes every scene on its first frame.
|
|
17
|
+
- Game-window chrome: framed windows, dithered heading rules, dotted separators and block meters for real
|
|
18
|
+
counts and limits.
|
|
19
|
+
- Pixel type with Hangul rules (no breaks inside words, 28px prose leading) and a switch to a readable body
|
|
20
|
+
face, all openly licensed.
|
|
21
|
+
- 13 specified components with designed states, and layout rules for dashboards, stores, articles and
|
|
22
|
+
settings.
|
|
23
|
+
|
|
24
|
+
## 0.1.0-rc.6
|
|
25
|
+
|
|
26
|
+
Scene subjects are bigger and gather in clusters with open ground between them. The hero stands on a hill with a path and grass. A scene never shows the same prop twice.
|
|
27
|
+
|
|
28
|
+
- Pixel stage step 4: the focal group's lead sprite goes from 28 to 40 units to 48 to 64 units tall (38 to 50% of the height; hero 40 to 52; strip unchanged at 20 to 26) and stands 4+ units taller than any other prop. Supporting props go from 12 to 24 to 20 to 36 units (strip unchanged at 12 to 18). In a hero or banner, 2+ of them are tall verticals (a tree, tower or mast, at most 8 units wide and up to 44 tall) that top the far ridge by 4+ units.
|
|
29
|
+
- Pixel stage step 4 spacing: "gaps 4 to 60 units, 40+ beside the focal group" is now clusters. The focal group plus 1 or 2 clusters of 2 to 4 supporting props, 2 to 10 units apart inside a cluster, clusters 60 to 160 units apart with only details between them, and no three consecutive gaps within 4 units of each other.
|
|
30
|
+
- Hero: the near ground is a landform. A rise 8 to 16 units high under the focal group (new `rise()` helper), a path of 2-unit steps up to the group, and 25+ hand-placed tufts and stones, counted in the 120 detail entries. Under `breakpoint.lg` the stage shows y 48 to 128, so walls and figures stay below y 48.
|
|
31
|
+
- Pixel stage step 8: in place, a banner lead is at least 96px; props sitting only in the bottom third get scaled up; outside the hero Window, every quarter of the width has a prop, pole or fence; a strip at 1x in dark shows every prop's outline and a lit point.
|
|
32
|
+
- Never: evenly spaced props and two identical props in one scene.
|
|
33
|
+
- Verification: each scene reports the lead's height, the gaps between props left to right, the tall verticals and the hero's rise and path. It also includes a required variant table (`variant | x positions | what differs`); a scene that repeats a variant without the table fails.
|
|
34
|
+
- Shorter wording to make room. Button and Card states point to Interaction. The marker's Where list and the Applying rows for dashboard, store and empty state drop their repeated details. The meter `dl` example shows only the `dd`. Verification drops lines that repeat Spacing and the ground-strip paragraph. Fewer code comments.
|
|
35
|
+
|
|
36
|
+
## 0.1.0-rc.5
|
|
37
|
+
|
|
38
|
+
Scenes are composed instead of listed: one focal group leads, smaller props step down around it, the background stacks graded ridges, and walls darken at night so only lights glow. Empty-state art becomes a small scene, and product detail columns stay balanced.
|
|
39
|
+
|
|
40
|
+
- Pixel stage composition: a `row()` of 6 to 12 evenly strung props → props placed by hand with a new `put()`: a focal group of 2 to 4 sprites, 28 to 40 units tall (strip 20 to 26), in front and 60 to 100 units off the scene centre; 4 to 8 supporting props 12 to 24 units tall (strip 3 to 6, 12 to 18), at least 4 units shorter than the focal group, in three or more heights, with a 40-unit gap on each side of the focal group; at most 12 props (strip 5 to 9).
|
|
41
|
+
- Pixel stage layers: one far ridge → a haze ridge (new `.haze`, `color.art.far` mixed 50% into `color.art.sky6`, tops y 36 to 46), a far ridge (tops y 66 to 76) and the near ground (tops y 100 to 106, was 108 to 112); no flat tone over 25% of a scene's height; new `at()` helper reads the ground height under a prop.
|
|
42
|
+
- Night tone: prop walls in the dark theme mix `--base` 55% into `color.art.sky1` (new `--wall` in the scene CSS; `.hi` and `.shade` follow the toned wall); lights, signs, stars and the moon stay full; the light theme keeps full hues.
|
|
43
|
+
- Hero: only sky, ridges and ground under the text Window; props start 16 units right of its edge.
|
|
44
|
+
- Strip props: benches, stalls and counters stand upright with an awning, sign, shelf or person above; at most twice as wide as tall.
|
|
45
|
+
- Vignette and Empty state: one object and a light → a small scene with sky, ridge, ground, a focal pair spanning half the width and 2 or 3 details.
|
|
46
|
+
- Store: on product detail the picture window is sticky or as tall as the purchase column, or Details spans both columns; no column ends more than 160px above its neighbour.
|
|
47
|
+
- Review step: squint at the render; props of one height or even spacing are recomposed.
|
|
48
|
+
- Verification: per-scene report of prop count, focal lead, duplicate variants and their differences, strip prop proportions and the tallest flat tone; the tallest ground-strip sprite measured at 20 to 24 units with poles and lamps excluded; no prop under the hero Window; toned walls at night.
|
|
49
|
+
- Shorter wording in rules 2, 3, 4, 6, 7 and 9, the Never list (the chip, panel-title and placeholder line moved to Verification and component specs), the Applying table, Navigation, Button, Badge and Verification.
|
|
50
|
+
|
|
51
|
+
## 0.1.0-rc.4
|
|
52
|
+
|
|
53
|
+
Skylines are irregular and always meet the sky, buildings carry facade detail, moons are round, and gold stays out of the header. Meters only show real maxima and sit in valid list markup, dashboards keep their section titles, and menus open with an option highlighted.
|
|
54
|
+
|
|
55
|
+
- Pixel stage: `sky()` takes a bottom edge (the far ridge's largest top y + 2) instead of a band height, so no background shows between sky and ridge; far tops y 40 to 52 → 28 to 36% of the height (y 36 to 46 at 128 units; strip 14 to 20 → 14 to 18); new `rng()`, `tops()` (runs 4 to 16, steps 2 to 8, a new seed per scene), `edge()` (checkered top 2 units on the far ridge and the near ground), `disc()` and `moon()` (an optional round stepped moon with craters and a checkered ring halo; square moons are in Never).
|
|
56
|
+
- Pixel stage objects: walls wider than 12 units carry window grids, doors, signs, siding or trim; shopfronts have a door, a lit window and an awning or sign; strip props 10 to 20 → 12 to 20 units tall, at most twice as wide as tall, half of them taller than wide; new Figure placement (inline prose scenes fill their frame).
|
|
57
|
+
- Ground strip sprites: 12 to 24 units each → one 20 to 24 units tall, the others 14 to 24.
|
|
58
|
+
- Rule 4 and Button: gold is the page content's main commit; the header, search and navigation never use gold, and a screen without a content commit has none.
|
|
59
|
+
- Block meter: only against a real limit, target or count; inside `dd`, `td` or `li` (as `span` where only phrasing content is allowed), never directly in a `dl` group.
|
|
60
|
+
- Dashboard and Card: every group of panels gets a 32/40 h2 on the dither rule outside the panels; KPI tiles show a meter only with a real maximum.
|
|
61
|
+
- Navigation and Select: menus open with the current or first option focused and highlighted (marker, `color.surface.hover`).
|
|
62
|
+
- Verification: axe scan with no list violations, sky-to-ridge gap, ridge reuse, facade detail, gold placement, dashboard titles and open-menu checks.
|
|
63
|
+
- Pixel type: the Galmuri alternative sentence removed; NeoDunggeunmo stays the only pixel face named.
|
|
64
|
+
- Pixel stage: new step 6, a hand-placed detail pass drawn with a new `dot()` helper (1-unit pixels or 2 to 6-unit runs, never generated): at least 120 entries in a hero, 60 in a banner, 30 in a strip or figure, 15 in a vignette, with stars at three brightness levels (new `.star-dim`), lit window pixels and sign glyphs, texture runs, edge highlights and shades, and 1 to 3 bits of small life; every prop gets 3 or more, repeated variants differ by 4 or more units.
|
|
65
|
+
- Pixel stage: the fill check becomes step 7, a review by eye: each scene rendered alone at 2× or more, three differences from the recipe listed and fixed, at least two rounds, then checked in place at 1440px and 390px; Verification asks for each scene's detail count.
|
|
66
|
+
- Typography roles as prose instead of a table; Button use folded into its variants; component keyboard sections titled Accessibility.
|
|
67
|
+
|
|
68
|
+
## 0.1.0-rc.3
|
|
69
|
+
|
|
70
|
+
Scenes on product screens read full instead of mostly sky, lights are big enough to see, the ground strip spreads its sprites, and a few layout and marker gaps are closed.
|
|
71
|
+
|
|
72
|
+
- Pixel stage: sky bands at most 40% of a banner or strip; middle-row props at least 4 units wide and 16 to 32 units tall in a banner (10 to 20 in a strip); focal group 24 to 40 units; poles and cables no longer count as props; demo sprite is now a 10×16 kiosk on 8-unit sky bands.
|
|
73
|
+
- Lights: single units → at least 2×2 units (4×4px at `size.unit`, 8×8px at the hero), drawn with a new `light()` helper; stars no longer count toward the 3 to 8.
|
|
74
|
+
- Ground strip: sprites at least 6 units wide and spread one per quarter, 120 units apart; `.ground` clips its own overflow, and `html, body{overflow-x:clip}` is removed from the root setup (now in Never).
|
|
75
|
+
- Rule 9: n-of-m progress is a block meter; bare "2 of 6 complete" is unfinished.
|
|
76
|
+
- Navigation: the contents list marks its first heading on load; the Animation and Pixel body switches share one transparent `.tool` rule (Button tool variant no longer tint-filled).
|
|
77
|
+
- Layout: side-by-side panels match height by sizing content, never by stretching an empty window; shell sidebars run to the ground strip; an h2 after a window sits `space.48` to `space.64` below it.
|
|
78
|
+
- Component Do / Don't lines removed where they repeated the rules.
|
|
79
|
+
|
|
80
|
+
## 0.1.0-rc.2
|
|
81
|
+
|
|
82
|
+
Chunkier type, fuller scenes and a ground strip that reads at full width; tighter rules for cards, dashboards and menus.
|
|
83
|
+
|
|
84
|
+
- `font.family.pixel`: Galmuri11 → NeoDunggeunmo (16px grid); `font.family.pixelMono`: GalmuriMono11 → NeoDunggeunmo Code; Galmuri is now the alternative; font smoothing off on the root.
|
|
85
|
+
- Rules 1, 3 and 8: every drawn object has an outline, a top-left highlight and a bottom-right shade; the pixel face is a 16px-grid face; every stage has 3 depth layers, 6 to 12 varied props and 3 to 8 lights.
|
|
86
|
+
- Pixel stage recipe: three-layer construction, a `row()` helper for uneven prop rows, `.base`, `.hi` and `.shade` classes for object shading, lights on props, a fill check; focal subject never one lone building.
|
|
87
|
+
- Ground strip: `color.art.groundHi` raised one step lighter and laid over the whole band, new `color.art.edgeHi` dotted edge row, new `size.groundSprite` (48px) layer with sprites 24 to 48px tall.
|
|
88
|
+
- Card: the marker hangs in the left padding; titles stay flush with icon and meta. Dashboard panels: titles outside, bullet captions inside, equal heights; n-of-m progress as a block meter.
|
|
89
|
+
- Navigation: dropdowns are marker menus; search placeholders never clip. Badge: the selected chip's marker replaces its bullet.
|
|
90
|
+
- Game-window limits: inline figures and the newsletter use 2px frames. Never: a single centred building in the hero; marker plus bullet; a 32px title inside a panel. Verification: stem, scene, light, ground-strip and frame counts.
|
|
91
|
+
|
|
92
|
+
## 0.1.0-rc.1
|
|
93
|
+
|
|
94
|
+
First candidate of the night-console pixel system: night ground and parchment day appearance, one pixel typeface for Hangul and Latin, game-window chrome, the RPG marker, and pixel scenes that move in stepped frames.
|
|
95
|
+
|
|
96
|
+
- Tokens: night and day semantic colours, 12-bit scene colours (`color.art.*`), eight identity hues (`color.hue.*`), the 12/16/32/48 type scale at weight 400, 2px and 4px borders, `radius.none`, `shadow.hard`, stepped motion durations and easings.
|
|
97
|
+
- Signature elements: pixel stage, stepped motion, RPG marker with instant physical response, game-window chrome, pixel type with a readable-body switch.
|
|
98
|
+
- Components: button, text field, select, checkbox and radio, switch, tabs, navigation, card, table, badge, dialog, toast, empty state.
|
|
@@ -0,0 +1,40 @@
|
|
|
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`); never retype values. Night follows `prefers-color-scheme` unless `[data-theme]` overrides it; design night first.
|
|
5
|
+
3. Load the fonts (Pixel type links) and set up the root: the motion and shape block from Signature elements, the type base, global `:focus-visible`, the `.dither` rule under the header.
|
|
6
|
+
4. Build the signature elements first, as reusable pieces: `PixelScene` (the helpers, art classes, placements and per-scene detail lists), `GroundStrip`, `Marker`, `Window`, `DitherRule`, `BlockMeter`, `Callout`, the stepped keyframes and both header switches. Pick the app's world; draw 3+ prop variants, focal and ground sprites and icons before any screen.
|
|
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 update date), the tokens, and `components.md`: the app's world, scenes by screen, the hue of each category.
|
|
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 colour becomes `color.action.primary`; remove radius, soft shadows and transition utilities as you restyle.
|
|
15
|
+
3. Build the signature elements, then restyle one screen as a sample (header with dither and marker, scene window, ground strip, a marker list) and wait for review.
|
|
16
|
+
4. Continue screen by screen, one commit each. No fake loading states or extra `role="status"` regions.
|
|
17
|
+
5. Preserve routes, logic, API contracts, form fields, validation, test ids, text used by tests and accessibility attributes. Keep native inputs (visually replaced).
|
|
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 follows Applying the concept; new scenes stay in the app's world with a new crop, prop and skyline seed.
|
|
24
|
+
- Uncovered needs: compose from tokens and note it in `components.md`; for conflicting requests (rounding, gradients, bold, smooth motion) present options.
|
|
25
|
+
|
|
26
|
+
## Verification
|
|
27
|
+
|
|
28
|
+
- Build and tests pass; no raw colours, sizes or radii outside the token files. An axe scan of every screen: no violations, no `definition-list`, `list` or `listitem` errors.
|
|
29
|
+
- Reduced motion: scenes, meters and labels complete on frame 1, nothing runs; with motion, lights blink out of sync and travel jumps 4px per step. Never change app code or config to pass a check.
|
|
30
|
+
- Each screen at 1440px and 390px, light and dark: no sideways scroll; focal group visible at 390px; crisp edges; 16px and 48px type with solid 2px stems. Tab through: the gold ring always visible; one marker per list.
|
|
31
|
+
- Scenes passed two step 8 rounds or more. Report per scene, against the Pixel stage numbers: detail entries by kind (hero tufts and stones); prop count; the lead's height and margin over the next prop; the gaps between props left to right; tall verticals over the far ridge; the hero's rise and path; strip props' width ÷ height; the tallest flat-tone run; the fixes made. Required: a variant table `variant | x positions | what differs (4+ units)`; a scene repeating a variant without it fails.
|
|
32
|
+
- Still frames at 1440px: three graded layers, no gap under the sky, new ridges, detailed walls, a round moon if any; nothing under the hero Window; dark walls toned; vignettes and figures full small scenes; the tallest ground-strip sprite 20–24 units.
|
|
33
|
+
- Per screen: one gold button at most, in the content; at most 3 four-sided 4px frames; card titles flush with their icon; a chip has marker or bullet, not both; every "n of m" has a real-maximum meter; the contents list marked on load; panels in a row end level; the sidebar reaches the ground strip; no placeholder clipped at 390px.
|
|
34
|
+
- Dashboard panel groups each have a 32/40 h2 on the dither rule outside them. Dropdowns and custom selects open with the current or first option highlighted, before any key.
|
|
35
|
+
- Walk the ten rules and the Never list. Report files changed, what you could not apply, and your decisions.
|
|
36
|
+
|
|
37
|
+
## Rollback
|
|
38
|
+
|
|
39
|
+
- Each screen is its own commit and can be reverted alone.
|
|
40
|
+
- Tokens, fonts, root setup and signature pieces are separate commits, reverted last.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
### Badge
|
|
2
|
+
|
|
3
|
+
**Anatomy.** Status or category chip: `size.bullet` square in the hue or status colour + label 16/24 (12/18 when dense) in `color.text.primary`, padding 0 `space.8`, no fill. Count badge: 20px-high box, `color.surface.hover`, 12px `color.text.strong`, padding 0 `space.4`. Filter chip: the chip as a toggle button, 2px `color.border.default` frame, `size.control` high. Tag: plain `#tag` in `color.text.secondary`.
|
|
4
|
+
|
|
5
|
+
**States.** Filter chip hover `color.surface.hover`; selected (`aria-pressed="true"`) adds `color.text.strong` and the marker in the bullet's slot (never both); focus ring.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
### Button
|
|
2
|
+
|
|
3
|
+
**Anatomy.** Label 16/24 pixel; optional 24px pixel icon before it (gap `space.8`); forward actions end with a trailing ▶ (`.cur`, no bevel, `currentColor`). Heights: `size.controlLg` (hero, gold), `size.control` (default), `size.controlSm` (copy, row actions, padding `space.8`). Padding `space.20` (gold), `space.12` (others). Icon-only: square.
|
|
4
|
+
|
|
5
|
+
**Variants.**
|
|
6
|
+
- Gold, the page content's one main commit (rule 4): `color.action.primary` fill, `color.text.onAction`, 2px `color.action.primaryEdge` border, `shadow.hard`.
|
|
7
|
+
- Framed, every other action: transparent, 2px `color.border.control`, `color.text.primary`; optional kbd chip (2px `color.border.default`, 12px).
|
|
8
|
+
- Tool, header switches and icon actions: `.tool` in Navigation; label + state word ("Animation on").
|
|
9
|
+
- Danger, destructive actions confirmed in a dialog: transparent, 2px `color.status.danger` border and text.
|
|
10
|
+
|
|
11
|
+
**States.** Hover, active and focus-visible per Interaction (gold unchanged on hover, 4px press into its shadow). Disabled: `color.surface.hover`, `color.text.disabled`, `color.border.default`, no shadow or press. Loading (real request only): gerund + `.ellipsis`, width held, `aria-busy`.
|
|
12
|
+
|
|
13
|
+
**Accessibility.** Native `<button>`; icons and markers `aria-hidden`; icon-only buttons `aria-label`; toggles `aria-pressed`.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
### Card
|
|
2
|
+
|
|
3
|
+
**Anatomy.** `color.surface.subtle`, no side or bottom border, a 4px `color.hue.*` top bar for its category or entity kind (neutral cards: a 2px `color.border.default` top rule), padding `space.16` `space.20`. Order: 24px pixel icon in the hue, title (16/24; 32/40 in feature grids) flush with icon and meta, its marker in the left padding (`.card-title`), one-line description `color.text.secondary`, meta 12/18. Panel: a `size.bullet` + 12/18 caption, never a 32px title (the group's 32/40 h2 sits outside, on the dither rule). KPI tile: label row (`size.bullet` + 12px label), 48px numeral `color.text.strong`, delta 12px in a status colour with an up/down marker, a block meter only against a real maximum. Product card: framed image area (photo or sprite), name, price 16/24 `color.text.strong`.
|
|
4
|
+
|
|
5
|
+
**States.** Hover (linked): `color.surface.hover`, marker beside the title. Focus and press per Interaction. Selected (plan, option): marker visible, 2px `color.text.accent` frame. Loading: static `color.surface.hover` blocks. Error: a callout with a 4px `color.status.danger` bar inside.
|
|
6
|
+
|
|
7
|
+
**Accessibility.** The whole card is one link (the title link stretched); secondary actions are separate buttons.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
### Checkbox and radio
|
|
2
|
+
|
|
3
|
+
**Anatomy.** Checkbox: 16px square, 2px `color.border.control` frame, `color.surface.raised` fill; checked shows a pixel check drawn with `sprite()` (6×5 units at `size.unit`: rows `.....x`, `....xx`, `x..xx.`, `xxxx..`, `.xx...`) in `color.text.accent`. Indeterminate: an 8×4px bar in `color.text.accent`. Radio: the same square; selected shows an 8px square in `color.text.accent`, never a circle. Label 16/24 at `space.8`.
|
|
4
|
+
|
|
5
|
+
**States.** Hover: frame `color.border.strong`. Focus-visible: ring around the box, offset 3px. Checked: mark appears in one frame. Disabled: `color.border.default`, mark and label `color.text.disabled`. Error: frame `color.status.danger`, message under the group.
|
|
6
|
+
|
|
7
|
+
**Accessibility.** Native inputs, visually replaced; `<fieldset>` + `<legend>` for groups.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
### Dialog
|
|
2
|
+
|
|
3
|
+
**Anatomy.** Native `<dialog>` or `role="dialog"`. A Window: 4px `color.border.strong` frame, `color.surface.raised`, `shadow.hard`, width min(`size.dialog`, 100% − `space.32`). Title bar `size.titleBar` with the title 16/24 `color.text.strong` and a framed close button (12px pixel ×). Body padding `space.20`, 16/28. Actions right, gap `space.12`: framed Cancel, then the gold confirm (the screen's gold moves into the dialog); destructive confirms use the danger button. Scrim `color.surface.overlay`, no blur.
|
|
4
|
+
|
|
5
|
+
**States.** Opens and closes in one frame. Focus moves to the first field or the confirm; focus-visible ring. Loading: confirm shows the gerund + `.ellipsis`, `aria-busy`. Error: a danger callout above the actions.
|
|
6
|
+
|
|
7
|
+
**Accessibility.** `aria-labelledby` the title; Escape closes; focus stays inside and returns to the opener.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
### Empty state
|
|
2
|
+
|
|
3
|
+
**Anatomy.** Centred in the region it replaces, max 400px: a Vignette (Pixel stage; one blinking light), `space.16`, one sentence 16/28 `color.text.secondary`, `space.16`, one framed button with the marker before its label. A first-run empty state may use the gold button when it is the screen's only action.
|
|
4
|
+
|
|
5
|
+
**States.** Error variant: lights off, one `color.art.beacon` light blinking `motion.duration.beacon`, the sentence names the problem, gold "Retry". Reduced motion: still.
|
|
@@ -0,0 +1,17 @@
|
|
|
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", "active", "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", "hover", "focus-visible", "selected"] },
|
|
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
|
+
]
|
|
17
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
### Navigation
|
|
2
|
+
|
|
3
|
+
**Header.** Sticky, `size.header` on `color.surface.default`, a 4px `.dither` rule below. Left: a 24px original pixel mark + product name 16/24 `color.text.strong`; then 3 to 5 nav items (`.item`, marker before the current one, `aria-current="page"`). Right: search as a framed button with a kbd hint (never gold), then the Animation and Pixel body switches as `.tool` text buttons (no fill or frame):
|
|
4
|
+
|
|
5
|
+
```css
|
|
6
|
+
.tool{display:inline-flex;align-items:center;gap:var(--space-8);height:var(--size-control);padding-inline:var(--space-8);background:transparent;border:0;color:var(--color-text-secondary)}
|
|
7
|
+
.tool:hover{background:var(--color-surface-hover);color:var(--color-text-primary)}
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
Dropdowns (user menu, sort) are marker menus: a Window under the trigger, options as `.item`. On open, in the same frame, focus moves to the current (or first) option, highlighted (marker, `color.surface.hover`, `color.text.strong`); arrows move it; Escape closes and refocuses the trigger. Search placeholders fit: one word ("Search") or the icon only under `breakpoint.sm`. Under `breakpoint.lg`: mark, search icon, menu button opening a marker-menu Window.
|
|
11
|
+
|
|
12
|
+
**Sidebar.** `size.sidebar`, `color.surface.subtle`, 2px `color.border.default` right edge. Group titles 12/18 `color.text.secondary`; `.item` rows: 24px hue icon or `size.bullet`, label, count right in `color.text.secondary`; `.sep-dots` between; current item `color.surface.hover` + marker.
|
|
13
|
+
|
|
14
|
+
**Contents list.** 2px `color.border.default` left rule, items 16/24, nested items indented `space.16`, marker on the current heading. One item is always current: on load the first heading (`aria-current="location"`), then the heading under the header as the reader scrolls.
|
|
15
|
+
|
|
16
|
+
**Breadcrumbs, prev/next, pagination.** Breadcrumbs `color.text.secondary` with " / ", hover `color.text.strong` underlined. Prev/next: two columns, 2px `color.border.strong` top rule, ◀/▶ + 12px label, title 16/24. Pagination: ◀ 1 2 3 ▶ `size.control` squares, current page framed 2px `color.border.strong`, `aria-current`.
|
|
17
|
+
|
|
18
|
+
**Accessibility.** `<nav aria-label>`; the menu button has `aria-expanded`; the mobile menu traps focus until closed.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
### Select
|
|
2
|
+
|
|
3
|
+
**Anatomy.** The text field's box, label, helper and error; `appearance:none`; a down marker (`.cur--d`, `color.text.secondary`) at `space.12` from the right. Prefer native `<select>`. A custom list opens as a Window directly below (2px `color.border.strong` frame, `color.surface.raised`, no shadow), options as marker items (`size.row`), 8 visible, then scroll.
|
|
4
|
+
|
|
5
|
+
**States.** Hover: frame `color.border.strong`. Focus-visible: ring. Open: down marker swaps to up; the list appears in one frame with the selected option (or the first) already highlighted. Highlighted option: `color.surface.hover` + marker. Selected option: `color.text.strong`, `aria-selected`. Disabled and error: as text field.
|
|
6
|
+
|
|
7
|
+
**Accessibility.** Custom: `role="combobox"` + `listbox`/`option`, `aria-activedescendant`; arrows move the marker, Enter selects, Escape closes.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
### Switch
|
|
2
|
+
|
|
3
|
+
**Anatomy.** Track 32×16px, 2px `color.border.control` frame, `color.surface.raised`; an 8×8px square thumb, `color.text.secondary` at the left when off, at the right in `color.text.accent` on a `color.surface.hover` track when on; a 12px state word follows. The whole row is the target, at least `size.touch`.
|
|
4
|
+
|
|
5
|
+
**States.** Hover: frame `color.border.strong`. Focus-visible: ring around the track. Selected: one-frame jump, no slide. Disabled: `color.border.default`, thumb `color.text.disabled`. Loading (saved remotely): the state word becomes `.ellipsis`.
|
|
6
|
+
|
|
7
|
+
**Accessibility.** `<button role="switch" aria-checked>` or a checkbox with `role="switch"`; the label names the setting.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
### Table
|
|
2
|
+
|
|
3
|
+
**Anatomy.** Head row on `color.surface.subtle`, 16/24 `color.text.strong`, 2px `color.border.strong` rule under it; body rows `size.row`, 2px `color.border.default` rules, no zebra, no vertical rules; cell padding 0 `space.12`; a 16px leading gutter for the marker. Numbers right-aligned in pixel numerals. Status cells: `size.bullet` in the status colour + word. Row actions: `size.controlSm` framed buttons, right. Under `breakpoint.sm` it scrolls in its wrapper or rows stack as label/value cards. A meter goes inside its `td`.
|
|
4
|
+
|
|
5
|
+
**States.** Hover: row `color.surface.hover`. Focus-visible (interactive rows): ring, offset −4px. Selected: marker in the gutter, `color.text.strong`, `aria-selected`. Sorted header: up/down marker after the label, `aria-sort`. Loading: 5 rows of flat static `color.surface.hover` blocks. Error: a danger callout above with Retry. Empty: the empty state replaces the body.
|
|
6
|
+
|
|
7
|
+
**Accessibility.** Real `<table>`, `<th scope>`, sort buttons inside headers.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
### Tabs
|
|
2
|
+
|
|
3
|
+
**Anatomy.** A row of tabs on a 2px `color.border.strong` baseline that joins the panel. Tab: `size.control` high, padding 0 `space.12`, 16/24, marker slot before the label. Selected: 2px `color.border.strong` frame on top and sides, panel-coloured bottom covering the baseline, `color.text.strong`, marker visible. Unselected: `color.text.secondary`.
|
|
4
|
+
|
|
5
|
+
**States.** Hover: `color.surface.hover`, `color.text.primary`. Focus-visible: ring, offset −4px. Selected: as above; the panel swaps in one frame. Disabled: `color.text.disabled`, no hover.
|
|
6
|
+
|
|
7
|
+
**Accessibility.** `role="tablist"`/`tab`/`tabpanel`, roving tabindex, arrows, Home/End, `aria-selected`.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
### Text field
|
|
2
|
+
|
|
3
|
+
**Anatomy.** Label above (16/24, `color.text.strong`), `space.8`; control `size.control` high, `color.surface.raised` fill, 2px `color.border.control` frame, padding 0 `space.12`, 16px pixel text, placeholder `color.text.secondary`; helper 12/18 `color.text.secondary`, `space.4` below. Textarea: min 4 rows, padding `space.12`. Search: 24px pixel magnifier inside at `space.8`, text from `space.40`, kbd hint at the right (hidden under `breakpoint.sm`).
|
|
4
|
+
|
|
5
|
+
**States.** Hover: frame `color.border.strong`. Focus: the ring, frame unchanged. Disabled: `color.surface.subtle` fill, `color.border.default` frame, `color.text.disabled`. Read-only: `color.surface.subtle`. Error: frame `color.status.danger`, `.nudge` once on submit; the message (12px pixel warning icon + text in `color.status.danger`) replaces the helper, `aria-invalid`, `aria-describedby`; a failed submit focuses the first invalid field. Loading (async check): `.ellipsis` at the right.
|
|
6
|
+
|
|
7
|
+
**Accessibility.** Visible `<label for>`; "required" in words, not only a symbol.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
### Toast
|
|
2
|
+
|
|
3
|
+
**Anatomy.** Bottom-right stack, `space.16` from the edges (full width under `breakpoint.sm`). 2px `color.border.strong` frame, `color.surface.raised`, padding `space.12` `space.16`, max 400px; 12px pixel status icon or `size.bullet` in the status colour, message 16/24, optional framed action and a 12px × close.
|
|
4
|
+
|
|
5
|
+
**States.** Appears and disappears in one frame; auto-hides after 5000ms unless it has an action or is hovered; errors stay until dismissed.
|
|
6
|
+
|
|
7
|
+
**Accessibility.** Announced through the screen's one `role="status"` region (errors `role="alert"`); never steals focus.
|