@revikornmann/muka-ui 0.18.0 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +81 -60
- package/cli/bin/muka-ui.js +12 -5
- package/cli/commands/brand.js +33 -14
- package/cli/commands/init.js +21 -17
- package/cli/commands/install-skill.js +84 -26
- package/cli/templates/AGENTS.md +128 -0
- package/cli/templates/CLAUDE.md +8 -88
- package/cli/templates/muka-ui-guidelines.md +50 -14
- package/dist/cjs/components/ActionSheet/ActionSheet.css +4 -4
- package/dist/cjs/components/BottomBar/BottomBar.css +0 -3
- package/dist/cjs/components/Breadcrumb/Breadcrumb.css +26 -2
- package/dist/cjs/components/Combobox/Combobox.css +116 -132
- package/dist/cjs/components/Combobox/Combobox.js +175 -52
- package/dist/cjs/components/Combobox/Combobox.js.map +1 -1
- package/dist/cjs/components/Combobox/index.js.map +1 -1
- package/dist/cjs/components/ContextSelect/ContextSelect.css +4 -4
- package/dist/cjs/components/DocumentViewer/DocumentViewer.css +2 -2
- package/dist/cjs/components/DropdownSelect/DropdownSelect.css +225 -0
- package/dist/cjs/components/DropdownSelect/DropdownSelect.js +106 -0
- package/dist/cjs/components/DropdownSelect/DropdownSelect.js.map +1 -0
- package/dist/cjs/components/DropdownSelect/index.js +6 -0
- package/dist/cjs/components/DropdownSelect/index.js.map +1 -0
- package/dist/cjs/components/EmptyState/EmptyState.css +8 -8
- package/dist/cjs/components/FAB/FAB.css +1 -1
- package/dist/cjs/components/FileUpload/FileUpload.css +10 -10
- package/dist/cjs/components/Icon/custom/ArrowReturnIcon.js +11 -0
- package/dist/cjs/components/Icon/custom/ArrowReturnIcon.js.map +1 -0
- package/dist/cjs/components/Icon/iconRegistry.js +14 -1
- package/dist/cjs/components/Icon/iconRegistry.js.map +1 -1
- package/dist/cjs/components/Input/Input.css +47 -10
- package/dist/cjs/components/Input/Input.js +14 -3
- package/dist/cjs/components/Input/Input.js.map +1 -1
- package/dist/cjs/components/Label/Label.css +1 -1
- package/dist/cjs/components/LicensePlateInput/LicensePlateInput.css +1 -1
- package/dist/cjs/components/Menu/Menu.css +124 -38
- package/dist/cjs/components/Menu/Menu.js +283 -25
- package/dist/cjs/components/Menu/Menu.js.map +1 -1
- package/dist/cjs/components/Pagination/Pagination.css +15 -15
- package/dist/cjs/components/PhotoUploader/PhotoUploader.css +4 -4
- package/dist/cjs/components/ProgressAccordeon/ProgressAccordeon.css +10 -6
- package/dist/cjs/components/ProgressAccordeon/ProgressAccordeon.js +27 -16
- package/dist/cjs/components/ProgressAccordeon/ProgressAccordeon.js.map +1 -1
- package/dist/cjs/components/ProgressTracker/ProgressTracker.css +273 -22
- package/dist/cjs/components/ProgressTracker/ProgressTracker.js +109 -9
- package/dist/cjs/components/ProgressTracker/ProgressTracker.js.map +1 -1
- package/dist/cjs/components/Scrollbar/Scrollbar.css +7 -6
- package/dist/cjs/components/SearchInput/SearchInput.css +4 -4
- package/dist/cjs/components/Select/Select.css +2 -2
- package/dist/cjs/components/SmsOtpField/SmsOtpField.css +2 -2
- package/dist/cjs/components/SpecList/SpecList.css +8 -8
- package/dist/cjs/components/Spinner/Spinner.css +1 -1
- package/dist/cjs/components/SwipeActions/SwipeActions.css +6 -6
- package/dist/cjs/components/Table/Table.css +3 -3
- package/dist/cjs/components/Table/TablePagination.css +1 -1
- package/dist/cjs/components/Tabs/Tabs.css +6 -6
- package/dist/cjs/components/Textarea/Textarea.css +2 -2
- package/dist/cjs/components/Waveform/Waveform.css +1 -1
- package/dist/cjs/components/index.js +5 -3
- package/dist/cjs/components/index.js.map +1 -1
- package/dist/esm/components/ActionSheet/ActionSheet.css +4 -4
- package/dist/esm/components/BottomBar/BottomBar.css +0 -3
- package/dist/esm/components/Breadcrumb/Breadcrumb.css +26 -2
- package/dist/esm/components/Combobox/Combobox.css +116 -132
- package/dist/esm/components/Combobox/Combobox.js +177 -54
- package/dist/esm/components/Combobox/Combobox.js.map +1 -1
- package/dist/esm/components/Combobox/index.js +1 -1
- package/dist/esm/components/Combobox/index.js.map +1 -1
- package/dist/esm/components/ContextSelect/ContextSelect.css +4 -4
- package/dist/esm/components/DocumentViewer/DocumentViewer.css +2 -2
- package/dist/esm/components/DropdownSelect/DropdownSelect.css +225 -0
- package/dist/esm/components/DropdownSelect/DropdownSelect.js +102 -0
- package/dist/esm/components/DropdownSelect/DropdownSelect.js.map +1 -0
- package/dist/esm/components/DropdownSelect/index.js +2 -0
- package/dist/esm/components/DropdownSelect/index.js.map +1 -0
- package/dist/esm/components/EmptyState/EmptyState.css +8 -8
- package/dist/esm/components/FAB/FAB.css +1 -1
- package/dist/esm/components/FileUpload/FileUpload.css +10 -10
- package/dist/esm/components/Icon/custom/ArrowReturnIcon.js +7 -0
- package/dist/esm/components/Icon/custom/ArrowReturnIcon.js.map +1 -0
- package/dist/esm/components/Icon/iconRegistry.js +14 -1
- package/dist/esm/components/Icon/iconRegistry.js.map +1 -1
- package/dist/esm/components/Input/Input.css +47 -10
- package/dist/esm/components/Input/Input.js +14 -3
- package/dist/esm/components/Input/Input.js.map +1 -1
- package/dist/esm/components/Label/Label.css +1 -1
- package/dist/esm/components/LicensePlateInput/LicensePlateInput.css +1 -1
- package/dist/esm/components/Menu/Menu.css +124 -38
- package/dist/esm/components/Menu/Menu.js +284 -26
- package/dist/esm/components/Menu/Menu.js.map +1 -1
- package/dist/esm/components/Pagination/Pagination.css +15 -15
- package/dist/esm/components/PhotoUploader/PhotoUploader.css +4 -4
- package/dist/esm/components/ProgressAccordeon/ProgressAccordeon.css +10 -6
- package/dist/esm/components/ProgressAccordeon/ProgressAccordeon.js +27 -16
- package/dist/esm/components/ProgressAccordeon/ProgressAccordeon.js.map +1 -1
- package/dist/esm/components/ProgressTracker/ProgressTracker.css +273 -22
- package/dist/esm/components/ProgressTracker/ProgressTracker.js +110 -10
- package/dist/esm/components/ProgressTracker/ProgressTracker.js.map +1 -1
- package/dist/esm/components/Scrollbar/Scrollbar.css +7 -6
- package/dist/esm/components/SearchInput/SearchInput.css +4 -4
- package/dist/esm/components/Select/Select.css +2 -2
- package/dist/esm/components/SmsOtpField/SmsOtpField.css +2 -2
- package/dist/esm/components/SpecList/SpecList.css +8 -8
- package/dist/esm/components/Spinner/Spinner.css +1 -1
- package/dist/esm/components/SwipeActions/SwipeActions.css +6 -6
- package/dist/esm/components/Table/Table.css +3 -3
- package/dist/esm/components/Table/TablePagination.css +1 -1
- package/dist/esm/components/Tabs/Tabs.css +6 -6
- package/dist/esm/components/Textarea/Textarea.css +2 -2
- package/dist/esm/components/Waveform/Waveform.css +1 -1
- package/dist/esm/components/index.js +1 -0
- package/dist/esm/components/index.js.map +1 -1
- package/dist/styles/components/ActionSheet.css +4 -4
- package/dist/styles/components/BottomBar.css +0 -3
- package/dist/styles/components/Breadcrumb.css +26 -2
- package/dist/styles/components/Combobox.css +116 -132
- package/dist/styles/components/ContextSelect.css +4 -4
- package/dist/styles/components/DocumentViewer.css +2 -2
- package/dist/styles/components/DropdownSelect.css +225 -0
- package/dist/styles/components/EmptyState.css +8 -8
- package/dist/styles/components/FAB.css +1 -1
- package/dist/styles/components/FileUpload.css +10 -10
- package/dist/styles/components/Input.css +47 -10
- package/dist/styles/components/Label.css +1 -1
- package/dist/styles/components/LicensePlateInput.css +1 -1
- package/dist/styles/components/Menu.css +124 -38
- package/dist/styles/components/Pagination.css +15 -15
- package/dist/styles/components/PhotoUploader.css +4 -4
- package/dist/styles/components/ProgressAccordeon.css +10 -6
- package/dist/styles/components/ProgressTracker.css +273 -22
- package/dist/styles/components/Scrollbar.css +7 -6
- package/dist/styles/components/SearchInput.css +4 -4
- package/dist/styles/components/Select.css +2 -2
- package/dist/styles/components/SmsOtpField.css +2 -2
- package/dist/styles/components/SpecList.css +8 -8
- package/dist/styles/components/Spinner.css +1 -1
- package/dist/styles/components/SwipeActions.css +6 -6
- package/dist/styles/components/Table.css +3 -3
- package/dist/styles/components/Tabs.css +6 -6
- package/dist/styles/components/Textarea.css +2 -2
- package/dist/styles/components/Typography.css +89 -0
- package/dist/styles/components/Waveform.css +1 -1
- package/dist/styles/index.css +1167 -462
- package/dist/styles/muka-dark.css +1167 -462
- package/dist/styles/muka-light.css +1167 -462
- package/dist/styles/tokens-bouwplan-dark.css +5 -4
- package/dist/styles/tokens-bouwplan-light.css +5 -4
- package/dist/styles/tokens-fscl-dark.css +25 -24
- package/dist/styles/tokens-fscl-light.css +25 -24
- package/dist/styles/tokens-grip-dark.css +4 -3
- package/dist/styles/tokens-grip-light.css +4 -3
- package/dist/styles/tokens-muka-dark.css +4 -3
- package/dist/styles/tokens-muka-light.css +4 -3
- package/dist/styles/tokens-wireframe-dark.css +49 -48
- package/dist/styles/tokens-wireframe-light.css +49 -48
- package/dist/styles/wireframe-dark.css +1212 -507
- package/dist/styles/wireframe-light.css +1212 -507
- package/dist/types/components/Combobox/Combobox.d.ts +38 -38
- package/dist/types/components/Combobox/Combobox.d.ts.map +1 -1
- package/dist/types/components/Combobox/index.d.ts +1 -1
- package/dist/types/components/Combobox/index.d.ts.map +1 -1
- package/dist/types/components/DropdownSelect/DropdownSelect.d.ts +71 -0
- package/dist/types/components/DropdownSelect/DropdownSelect.d.ts.map +1 -0
- package/dist/types/components/DropdownSelect/index.d.ts +2 -0
- package/dist/types/components/DropdownSelect/index.d.ts.map +1 -0
- package/dist/types/components/Icon/custom/ArrowReturnIcon.d.ts +9 -0
- package/dist/types/components/Icon/custom/ArrowReturnIcon.d.ts.map +1 -0
- package/dist/types/components/Icon/iconRegistry.d.ts.map +1 -1
- package/dist/types/components/Input/Input.d.ts +5 -0
- package/dist/types/components/Input/Input.d.ts.map +1 -1
- package/dist/types/components/Menu/Menu.d.ts +42 -2
- package/dist/types/components/Menu/Menu.d.ts.map +1 -1
- package/dist/types/components/ProgressAccordeon/ProgressAccordeon.d.ts +17 -12
- package/dist/types/components/ProgressAccordeon/ProgressAccordeon.d.ts.map +1 -1
- package/dist/types/components/ProgressTracker/ProgressTracker.d.ts +29 -8
- package/dist/types/components/ProgressTracker/ProgressTracker.d.ts.map +1 -1
- package/dist/types/components/index.d.ts +1 -0
- package/dist/types/components/index.d.ts.map +1 -1
- package/docs/consumers/README.md +116 -37
- package/docs/consumers/brand.md +261 -0
- package/docs/consumers/figma-console-mcp.md +116 -0
- package/docs/consumers/setup-instructions.md +98 -12
- package/docs/consumers/skills.md +79 -0
- package/package.json +5 -6
- package/scripts/postinstall-nudge.js +8 -4
- package/skills/add-brand/SKILL.md +204 -0
- package/skills/add-brand/reference.md +160 -0
- package/skills/figma-to-code/SKILL.md +127 -0
- package/skills/pull-from-figma/SKILL.md +123 -0
- package/skills/push-to-figma/SKILL.md +172 -0
- package/skills/setup-muka/SKILL.md +73 -13
- package/tokens/README.md +39 -17
- package/tokens/t2-alias/brand/bouwplan/fonts.json +1 -1
- package/tokens/t2-alias/brand/fscl/fonts.json +3 -3
- package/tokens/t2-alias/brand/wireframe/fonts.json +2 -2
- package/tokens/t4-components/menu.json +8 -3
package/docs/consumers/README.md
CHANGED
|
@@ -1,61 +1,140 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Using Muka UI in your app
|
|
2
2
|
|
|
3
|
-
Muka UI is
|
|
4
|
-
|
|
5
|
-
update workflow driven by GitHub Releases. Installing needs no registry config
|
|
6
|
-
or auth token.
|
|
3
|
+
Muka UI is a multi-brand, multi-theme React design system published as a
|
|
4
|
+
**public package on npm**. Installing it needs no registry config or auth token.
|
|
7
5
|
|
|
8
|
-
|
|
6
|
+
These docs are for building an app **with** Muka. To work **on** Muka itself, see
|
|
7
|
+
[`DEVELOPMENT.md`](../../DEVELOPMENT.md).
|
|
9
8
|
|
|
10
|
-
The
|
|
9
|
+
## The workflow
|
|
10
|
+
|
|
11
|
+
Five steps from an empty repo to a branded, designed, working app. Each one is a
|
|
12
|
+
skill or a single command.
|
|
13
|
+
|
|
14
|
+
```mermaid
|
|
15
|
+
flowchart TD
|
|
16
|
+
repo["1. Create your repo"] --> install["2. Install Muka UI<br/>/setup-muka"]
|
|
17
|
+
install --> brand["3. Add your brand<br/>/add-brand"]
|
|
18
|
+
brand --> design["4. Design in Figma<br/>Muka UI Figma Library"]
|
|
19
|
+
design --> handover["5. Hand the Figma link to your agent<br/>/figma-to-code"]
|
|
20
|
+
handover --> app["A branded app built from<br/>Muka components"]
|
|
21
|
+
brand -.->|"designers need your brand"| push["/push-to-figma"]
|
|
22
|
+
push -.-> design
|
|
23
|
+
design -.->|"designer retunes the brand"| pull["/pull-from-figma"]
|
|
24
|
+
pull -.-> brand
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### 1. Create your repo
|
|
28
|
+
|
|
29
|
+
Any React app with a bundler that can import CSS — Vite, Next.js, Remix,
|
|
30
|
+
webpack. React `>=16.8` is the only peer requirement.
|
|
31
|
+
|
|
32
|
+
### 2. Install Muka UI
|
|
11
33
|
|
|
12
34
|
```bash
|
|
13
|
-
|
|
14
|
-
|
|
35
|
+
npm install @revikornmann/muka-ui@latest
|
|
36
|
+
npx muka-ui install-skill # make the skills discoverable
|
|
37
|
+
# then, in your agent:
|
|
15
38
|
/setup-muka [brand]
|
|
16
39
|
```
|
|
17
40
|
|
|
18
|
-
|
|
19
|
-
|
|
41
|
+
`/setup-muka` installs the package, imports the right stylesheet and fonts, adds
|
|
42
|
+
the release auto-update workflow, and opens the PR that registers your repo as a
|
|
43
|
+
consumer. Doing it by hand instead: [`setup-instructions.md`](setup-instructions.md).
|
|
20
44
|
|
|
21
|
-
|
|
45
|
+
Muka ships five brands — `muka`, `wireframe`, `grip`, `fscl`, `bouwplan` — each
|
|
46
|
+
in light and dark. If one of them fits, you can stop here.
|
|
22
47
|
|
|
23
|
-
|
|
24
|
-
2. Import `@revikornmann/muka-ui/styles` (+ brand token CSS) in your app root.
|
|
25
|
-
3. Copy `templates/update-muka.yml` into `.github/workflows/`.
|
|
26
|
-
4. Add the repo to [`.github/consumers.txt`](../../.github/consumers.txt).
|
|
48
|
+
### 3. Add your brand
|
|
27
49
|
|
|
28
|
-
|
|
50
|
+
```
|
|
51
|
+
/add-brand acme
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
This scaffolds a brand layer **in your repo** that overrides Muka's. You author
|
|
55
|
+
about 78 colour references and four font families; primitives, semantics, and
|
|
56
|
+
every component token keep coming from the package. One file of colour references
|
|
57
|
+
restyles the entire component library, and there is no component code to change.
|
|
58
|
+
|
|
59
|
+
Details and the token map: [`brand.md`](brand.md).
|
|
60
|
+
|
|
61
|
+
### 4. Design in Figma
|
|
62
|
+
|
|
63
|
+
Design against the [Muka UI Figma
|
|
64
|
+
Library](https://www.figma.com/design/RL5IFLUJk4yeAFNXlsX4b5/Muka-UI-Figma-Library),
|
|
65
|
+
so screens are assembled from the same components the code has, bound to the same
|
|
66
|
+
variables the tokens generate.
|
|
67
|
+
|
|
68
|
+
To let designers work in **your** brand, publish it to Figma as variables:
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
/push-to-figma
|
|
72
|
+
```
|
|
29
73
|
|
|
30
|
-
When a
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
74
|
+
When a designer retunes the brand there, bring it back with `/pull-from-figma`.
|
|
75
|
+
Both need [Figma Console MCP](figma-console-mcp.md).
|
|
76
|
+
|
|
77
|
+
### 5. Hand the Figma link to your agent
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
/figma-to-code https://figma.com/design/…?node-id=472-4248
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Because the design is made of Muka components and the code has those same
|
|
84
|
+
components, the agent's job is mapping rather than reinventing: it reads the Code
|
|
85
|
+
Connect mapping, composes the screen from real components, and styles the gaps
|
|
86
|
+
with token custom properties. The result inherits your brand and both themes for
|
|
87
|
+
free.
|
|
88
|
+
|
|
89
|
+
### And voilà
|
|
90
|
+
|
|
91
|
+
A branded app built from a component library you did not have to write, that
|
|
92
|
+
follows brand changes centrally and updates itself on each Muka release.
|
|
93
|
+
|
|
94
|
+
## Reference
|
|
95
|
+
|
|
96
|
+
| Doc | Contents |
|
|
97
|
+
|---|---|
|
|
98
|
+
| [`setup-instructions.md`](setup-instructions.md) | Canonical install, styles, fonts, theming, and auto-update setup |
|
|
99
|
+
| [`brand.md`](brand.md) | Building your own brand on top of Muka's token layers |
|
|
100
|
+
| [`skills.md`](skills.md) | Every shipped skill and what it is for |
|
|
101
|
+
| [`figma-console-mcp.md`](figma-console-mcp.md) | One-time setup for the token-sync skills |
|
|
102
|
+
|
|
103
|
+
Component APIs, live Playgrounds, and token documentation are in the Storybook at
|
|
104
|
+
**<https://muka.kornmann.com>**.
|
|
105
|
+
|
|
106
|
+
## Staying up to date
|
|
107
|
+
|
|
108
|
+
When a maintainer publishes a GitHub Release,
|
|
109
|
+
[`publish.yml`](../../.github/workflows/publish.yml) publishes to npm and fires a
|
|
110
|
+
`muka-released` `repository_dispatch` (carrying the version) to every repo listed
|
|
111
|
+
in [`.github/consumers.txt`](../../.github/consumers.txt). Your
|
|
34
112
|
`update-muka.yml` installs that exact version and commits the lockfile bump.
|
|
35
113
|
|
|
36
114
|
```mermaid
|
|
37
115
|
flowchart LR
|
|
38
116
|
tag["Maintainer tags release"] --> publish["publish.yml builds + npm publish"]
|
|
39
|
-
publish --> pkg["npm registry
|
|
40
|
-
publish --> dispatch["repository_dispatch: muka-released
|
|
41
|
-
dispatch --> update["
|
|
117
|
+
publish --> pkg["npm registry"]
|
|
118
|
+
publish --> dispatch["repository_dispatch: muka-released"]
|
|
119
|
+
dispatch --> update["your update-muka.yml"]
|
|
42
120
|
update --> install["npm install @revikornmann/muka-ui@version"]
|
|
43
121
|
install --> commit["Commit + push lockfile"]
|
|
44
|
-
commit --> deploy["Host redeploys
|
|
122
|
+
commit --> deploy["Host redeploys"]
|
|
45
123
|
```
|
|
46
124
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
- Consumers typically pin a caret range, e.g. `"@revikornmann/muka-ui": "^1.4.0"`.
|
|
50
|
-
- The dispatch installs the **exact** published version, so bumps are predictable.
|
|
125
|
+
- Pin a caret range, e.g. `"@revikornmann/muka-ui": "^0.18.0"`. The dispatch
|
|
126
|
+
installs the **exact** published version, so bumps are predictable.
|
|
51
127
|
- Manual `workflow_dispatch` runs install `@latest`.
|
|
52
|
-
-
|
|
53
|
-
|
|
54
|
-
## Notes
|
|
55
|
-
|
|
56
|
-
- The update only changes `package.json` + `package-lock.json`, so it never
|
|
128
|
+
- The update only touches `package.json` and `package-lock.json`, so it never
|
|
57
129
|
conflicts with app source.
|
|
58
|
-
- `dist/` is built at publish time and shipped
|
|
130
|
+
- `dist/` is built at publish time and shipped in the tarball; it is not
|
|
59
131
|
committed to the Muka repo.
|
|
60
|
-
|
|
61
|
-
|
|
132
|
+
|
|
133
|
+
> **Muka is under active development.** A release can bring breaking changes —
|
|
134
|
+
> visual shifts, changed component APIs, altered token values. Treat the update
|
|
135
|
+
> workflow as a trigger to **re-test your app**, not a guarantee of stability.
|
|
136
|
+
> Keep CI checks and visual review on the bump PR.
|
|
137
|
+
>
|
|
138
|
+
> If you maintain a custom brand, rebuild it after every upgrade: your brand CSS
|
|
139
|
+
> is generated against the package's primitives and component tokens. See
|
|
140
|
+
> [`brand.md`](brand.md#keeping-your-brand-current).
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
# Building your own brand
|
|
2
|
+
|
|
3
|
+
Muka ships five brands. When none of them is yours, you can add your own **in
|
|
4
|
+
your repo** without forking Muka: you author one layer of the token system and
|
|
5
|
+
inherit the rest from the package.
|
|
6
|
+
|
|
7
|
+
The fastest path is the [`/add-brand`](skills.md) skill, which walks an agent
|
|
8
|
+
through everything below:
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
/add-brand acme
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
This document is the reference behind it.
|
|
15
|
+
|
|
16
|
+
## What you own, and what you don't
|
|
17
|
+
|
|
18
|
+
Muka's tokens are four layers deep. A brand is defined entirely by the second
|
|
19
|
+
one:
|
|
20
|
+
|
|
21
|
+
| Layer | Owner | Example |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| **T1 Primitives** | Package | `color.violet.9`, `spacing.4`, `size.md` |
|
|
24
|
+
| **T2 Alias — base** | Package | brand-agnostic defaults |
|
|
25
|
+
| **T2 Alias — brand** | **You** | `alias.color.accent.default` → `{color.violet.9}` |
|
|
26
|
+
| **T3 Semantics** | Package | `color.surface.level1`, `color.action.default` |
|
|
27
|
+
| **T4 Components** | Package | `button.color.primary.background.default` |
|
|
28
|
+
|
|
29
|
+
Components read T3 and T4. Those resolve through T2. So repointing
|
|
30
|
+
`alias.color.accent.default` at a different primitive changes every button, link,
|
|
31
|
+
focus ring, and selection highlight in the library at once — with no component
|
|
32
|
+
code, and no fork to maintain.
|
|
33
|
+
|
|
34
|
+
It also means **you should never edit T3 or T4**. They come from `node_modules`
|
|
35
|
+
and are replaced on every upgrade.
|
|
36
|
+
|
|
37
|
+
## Scaffold it
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npx muka-ui brand init acme
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Brand names are lowercase, start with a letter, and contain only letters,
|
|
44
|
+
numbers, and hyphens. This writes, prompting before overwriting anything:
|
|
45
|
+
|
|
46
|
+
| Path | Contents |
|
|
47
|
+
|---|---|
|
|
48
|
+
| `brand/light.json` | Light-mode colour aliases — 78 tokens |
|
|
49
|
+
| `brand/dark.json` | Dark-mode colour aliases |
|
|
50
|
+
| `brand/fonts.json` | Font families and weights for four roles |
|
|
51
|
+
| `brand/muka.brand.json` | Build manifest: your files plus the package's token globs |
|
|
52
|
+
| `brand/build.js` | Build entry using `TokenBuilder` from the package |
|
|
53
|
+
|
|
54
|
+
It also adds a `build:tokens` script to `package.json` if there isn't one.
|
|
55
|
+
|
|
56
|
+
The files start as copies of Muka's `wireframe` brand, so they are complete and
|
|
57
|
+
buildable rather than empty. Prove the pipeline before editing:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
npm run build:tokens
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Expect `All theme combinations built successfully!` and two new files in
|
|
64
|
+
`styles/`. Debugging is far easier against known-good values.
|
|
65
|
+
|
|
66
|
+
## The token groups
|
|
67
|
+
|
|
68
|
+
All 78 colour tokens live under `alias.color`:
|
|
69
|
+
|
|
70
|
+
| Group | Tokens | Effect |
|
|
71
|
+
|---|---|---|
|
|
72
|
+
| `neutral` | `1`–`12` plus `alphaHued.1`–`12` | Every surface, border, and text colour. The widest-reaching choice in the file. |
|
|
73
|
+
| `accent` | `default`, `hover`, `pressed`, `contrast`, `muted`, and an `inverse.*` set | The interactive colour: buttons, links, focus rings, selection. Change this first. |
|
|
74
|
+
| `brand` | `primary.*`, `secondary.*` | Identity colours for marketing surfaces, distinct from ordinary controls. |
|
|
75
|
+
| `state` | `success`, `warning`, `error`, `info` — each with `contrast`/`default`/`muted` and four `surface` levels | Feedback colours. Keep the hues conventional. |
|
|
76
|
+
| `conversation` | `own`, `peer`, `agent` surfaces and borders, plus `meta` | Chat components. Leave as scaffolded if your app has no chat — they still need to resolve. |
|
|
77
|
+
|
|
78
|
+
## Write references, not colours
|
|
79
|
+
|
|
80
|
+
Every value is a reference to a T1 primitive:
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
"accent": {
|
|
84
|
+
"default": { "$type": "color", "$value": "{color.violet.9}" },
|
|
85
|
+
"hover": { "$type": "color", "$value": "{color.violet.10}" },
|
|
86
|
+
"pressed": { "$type": "color", "$value": "{color.violet.11}" },
|
|
87
|
+
"contrast": { "$type": "color", "$value": "{color.violet.12}" },
|
|
88
|
+
"muted": { "$type": "color", "$value": "{color.violet.8}" }
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
A raw hex works, but opts that token out of the system: it gains no dark-mode
|
|
93
|
+
counterpart and stops tracking the ramp. Use references.
|
|
94
|
+
|
|
95
|
+
### Available palettes
|
|
96
|
+
|
|
97
|
+
12-step ramps. Light mode uses the base name; dark mode appends **camelCase
|
|
98
|
+
`Dark`**, and references are case-sensitive — `{color.violetdark.9}` resolves to
|
|
99
|
+
nothing.
|
|
100
|
+
|
|
101
|
+
- **Neutrals:** `gray`, `mauve`, `slate`, `sage`, `olive`, `sand`
|
|
102
|
+
- **Colours:** `tomato`, `red`, `ruby`, `crimson`, `pink`, `plum`, `purple`,
|
|
103
|
+
`violet`, `iris`, `indigo`, `blue`, `cyan`, `teal`, `jade`, `green`, `grass`,
|
|
104
|
+
`bronze`, `gold`, `brown`, `orange`, `amber`, `yellow`, `lime`, `mint`, `sky`
|
|
105
|
+
- **Absolutes:** `white`, `black`, `black-alpha`, `white-alpha`
|
|
106
|
+
- **Hued neutral alphas:** `mauveA`, `grayA`, `sandA`, `sageA` (and their `Dark`
|
|
107
|
+
variants) back `neutral.alphaHued.*`
|
|
108
|
+
|
|
109
|
+
Full values:
|
|
110
|
+
`node_modules/@revikornmann/muka-ui/tokens/t1-primitives/color.json`.
|
|
111
|
+
|
|
112
|
+
### What the steps mean
|
|
113
|
+
|
|
114
|
+
| Steps | Use |
|
|
115
|
+
|---|---|
|
|
116
|
+
| 1–2 | App and component backgrounds |
|
|
117
|
+
| 3–5 | Subtle backgrounds: hover, selected, muted fills |
|
|
118
|
+
| 6–8 | Borders and separators — 8 is the strongest |
|
|
119
|
+
| 9–10 | Solid fills — 9 is the most saturated, 10 its hover |
|
|
120
|
+
| 11 | Low-contrast text |
|
|
121
|
+
| 12 | High-contrast text and headings |
|
|
122
|
+
|
|
123
|
+
Put `accent.default` at 9, `hover` at 10, `pressed` at 11, `contrast` at 12
|
|
124
|
+
unless you have a reason not to. Every shipped brand follows this.
|
|
125
|
+
|
|
126
|
+
### Mirror it for dark mode
|
|
127
|
+
|
|
128
|
+
`brand/dark.json` repeats the structure using the `Dark` ramps, keeping the
|
|
129
|
+
**same step numbers**:
|
|
130
|
+
|
|
131
|
+
```json
|
|
132
|
+
"accent": {
|
|
133
|
+
"default": { "$type": "color", "$value": "{color.violetDark.9}" }
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
The ramps are built so equal steps read as equal emphasis in either mode, which
|
|
138
|
+
is what makes the mirror work.
|
|
139
|
+
|
|
140
|
+
## Typography
|
|
141
|
+
|
|
142
|
+
`brand/fonts.json` sets four roles:
|
|
143
|
+
|
|
144
|
+
| Role | Used for |
|
|
145
|
+
|---|---|
|
|
146
|
+
| `brand` | Headings, buttons, labels |
|
|
147
|
+
| `plain` | Body copy and UI text |
|
|
148
|
+
| `mono` | Code and numeric tables |
|
|
149
|
+
| `script` | Decorative accents only |
|
|
150
|
+
|
|
151
|
+
`family` values must be the **exact `@font-face` family name** that gets loaded —
|
|
152
|
+
the generated CSS passes the literal through to `font-family`. List only weights
|
|
153
|
+
the font actually provides; naming an absent weight makes the browser synthesise
|
|
154
|
+
it, which looks wrong at display sizes.
|
|
155
|
+
|
|
156
|
+
### Loading the fonts
|
|
157
|
+
|
|
158
|
+
Muka self-hosts its own brands' fonts, but that pipeline does not extend to your
|
|
159
|
+
brand. You have three options:
|
|
160
|
+
|
|
161
|
+
1. **Reuse a font Muka already bundles** — import that brand's fonts file and you
|
|
162
|
+
are done:
|
|
163
|
+
```ts
|
|
164
|
+
import '@revikornmann/muka-ui/styles/fonts-muka.css';
|
|
165
|
+
```
|
|
166
|
+
| Family | Import this brand's fonts file |
|
|
167
|
+
|---|---|
|
|
168
|
+
| `Funnel Display`, `Funnel Sans` | `fonts-muka.css` |
|
|
169
|
+
| `Quicksand` | `fonts-grip.css` |
|
|
170
|
+
| `IBM Plex Sans`, `Lora` | `fonts-fscl.css` |
|
|
171
|
+
| `Red Hat Display`, `Red Hat Text` | `fonts-bouwplan.css` |
|
|
172
|
+
| `Yesteryear` (script role) | `fonts-muka.css`, `fonts-grip.css`, or `fonts-bouwplan.css` |
|
|
173
|
+
|
|
174
|
+
`fonts-wireframe.css` is empty — that brand uses system fonts only.
|
|
175
|
+
2. **Use a system font** — `Helvetica`, `Arial`, `Menlo`, `Georgia`,
|
|
176
|
+
`system-ui`, and friends need no loading.
|
|
177
|
+
3. **Bring your own** — self-host it with your own `@font-face` under the exact
|
|
178
|
+
family name from `fonts.json`. Don't use a Google Fonts `<link>`: it breaks
|
|
179
|
+
offline and air-gapped installs and adds a render-blocking request.
|
|
180
|
+
|
|
181
|
+
## Build and load the CSS
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
npm run build:tokens
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
This writes `styles/tokens-acme-light.css` and `styles/tokens-acme-dark.css` —
|
|
188
|
+
complete stylesheets with every resolved token, around 2,200 custom properties
|
|
189
|
+
each.
|
|
190
|
+
|
|
191
|
+
Import your brand CSS **after** Muka's component and reset layer:
|
|
192
|
+
|
|
193
|
+
```ts
|
|
194
|
+
import '@revikornmann/muka-ui/styles/base.css';
|
|
195
|
+
import './styles/tokens-acme-light.css';
|
|
196
|
+
import '@revikornmann/muka-ui/styles/fonts-muka.css'; // or your own @font-face
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Use `base.css`, **not** `@revikornmann/muka-ui/styles`. The latter is the bundled
|
|
200
|
+
`muka-light` theme: it contains a full token set that will fight your brand
|
|
201
|
+
depending on import order.
|
|
202
|
+
|
|
203
|
+
### Switching brand and theme
|
|
204
|
+
|
|
205
|
+
Every token stylesheet declares its variables on `:root`. There are **no
|
|
206
|
+
`[data-brand]` or `[data-theme]` selectors**, so the active theme is simply
|
|
207
|
+
whichever stylesheet loaded last. Adding `data-brand` / `data-theme` attributes
|
|
208
|
+
does nothing.
|
|
209
|
+
|
|
210
|
+
For a runtime light/dark toggle, swap a `<link>` rather than importing both:
|
|
211
|
+
|
|
212
|
+
```ts
|
|
213
|
+
const link = document.getElementById('muka-theme') as HTMLLinkElement;
|
|
214
|
+
link.href = `/styles/tokens-acme-${mode}.css`;
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Copy the generated CSS into your static/public directory so those hrefs resolve.
|
|
218
|
+
This is exactly how Muka's own Storybook switches between its ten themes.
|
|
219
|
+
|
|
220
|
+
## Keeping your brand current
|
|
221
|
+
|
|
222
|
+
Your brand CSS is generated against the package's primitives, semantics, and
|
|
223
|
+
component tokens, so it goes stale when Muka publishes new ones — a new component
|
|
224
|
+
in a release has tokens your last build never saw.
|
|
225
|
+
|
|
226
|
+
Wire the rebuild into your pipeline so it can't be forgotten:
|
|
227
|
+
|
|
228
|
+
```json
|
|
229
|
+
"scripts": {
|
|
230
|
+
"build": "npm run build:tokens && vite build",
|
|
231
|
+
"postinstall": "npm run build:tokens"
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Commit `brand/**`. Generated `styles/tokens-*.css` can be committed or
|
|
236
|
+
gitignored — commit it if your host has no build step.
|
|
237
|
+
|
|
238
|
+
## Verify
|
|
239
|
+
|
|
240
|
+
- Both CSS files exist and were rebuilt after your last edit.
|
|
241
|
+
- Neither contains `undefined` — that is an unresolved reference, usually a
|
|
242
|
+
typo'd palette or a missing `Dark` suffix.
|
|
243
|
+
- Your accent colour is really there:
|
|
244
|
+
```bash
|
|
245
|
+
grep -- '--alias-color-accent-default' styles/tokens-acme-light.css
|
|
246
|
+
```
|
|
247
|
+
- A primary `<Button>` renders in your accent colour and body text in your
|
|
248
|
+
typeface, in both light and dark.
|
|
249
|
+
- Dark mode changes surfaces without leaving text unreadable.
|
|
250
|
+
|
|
251
|
+
## Troubleshooting
|
|
252
|
+
|
|
253
|
+
| Symptom | Cause |
|
|
254
|
+
|---|---|
|
|
255
|
+
| `undefined` in the generated CSS | Unresolved `{reference}` — typo'd palette name or missing `Dark` suffix |
|
|
256
|
+
| Dark mode looks like light mode | `dark.json` still references light ramps |
|
|
257
|
+
| Colours unchanged after rebuilding | Brand CSS imported before Muka's token bundle. Import `base.css`, then your brand last |
|
|
258
|
+
| Text unreadable on accent fills | `accent.contrast` too close to `accent.default` — move it to step 12 or `white` |
|
|
259
|
+
| Fonts fall back to a system face | No `@font-face` loaded for that family, or the name doesn't match byte-for-byte |
|
|
260
|
+
| `Cannot find module '…/build'` | Regenerate with `npx muka-ui brand init` from a current version; older scaffolds wrote an unscoped package name |
|
|
261
|
+
| New components look unstyled after an upgrade | Brand CSS predates the release. Re-run `npm run build:tokens` |
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# Figma Console MCP — one-time setup
|
|
2
|
+
|
|
3
|
+
The [`/push-to-figma`](../../skills/push-to-figma/SKILL.md) and
|
|
4
|
+
[`/pull-from-figma`](../../skills/pull-from-figma/SKILL.md) skills sync your
|
|
5
|
+
brand's design tokens between your repo and Figma. Both talk to Figma through
|
|
6
|
+
**Figma Console MCP**, which relays commands to a **Desktop Bridge** plugin
|
|
7
|
+
running inside Figma Desktop. This guide gets that pipeline working.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
Your agent ──(MCP: figma-console)──► Desktop Bridge plugin ──► Figma Desktop (variables)
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
> **Credits:** [Figma Console MCP](https://github.com/southleft/figma-console-mcp)
|
|
14
|
+
> is an open-source (MIT) MCP server by **[Southleft](https://southleft.com)**,
|
|
15
|
+
> published on npm as
|
|
16
|
+
> [`figma-console-mcp`](https://www.npmjs.com/package/figma-console-mcp). It is
|
|
17
|
+
> not a Muka project — Muka only ships the skills that drive it. Please raise
|
|
18
|
+
> issues with the server itself
|
|
19
|
+
> [upstream](https://github.com/southleft/figma-console-mcp/issues).
|
|
20
|
+
|
|
21
|
+
This is only needed for the two token-sync skills. `/setup-muka`, `/add-brand`,
|
|
22
|
+
and `/figma-to-code` do not require it — `/figma-to-code` works with Figma's own
|
|
23
|
+
official MCP server, which is a separate thing.
|
|
24
|
+
|
|
25
|
+
## 1. Get a Figma access token
|
|
26
|
+
|
|
27
|
+
Create a personal access token in Figma (**Settings → Security → Personal access
|
|
28
|
+
tokens**) with **Variables** read/write scope. It looks like `figd_…`.
|
|
29
|
+
|
|
30
|
+
**Do not paste it into any file.** Keep it in your shell environment:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
# ~/.zshrc (or ~/.bashrc)
|
|
34
|
+
export FIGMA_ACCESS_TOKEN="figd_your_token_here"
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Open a new shell (or `source` the file) so the variable is set.
|
|
38
|
+
|
|
39
|
+
## 2. Register the server
|
|
40
|
+
|
|
41
|
+
Add a project-scoped `.mcp.json` at your repo root. It uses **env expansion**, so
|
|
42
|
+
no secret lives in the file and it is safe to commit:
|
|
43
|
+
|
|
44
|
+
```json
|
|
45
|
+
{
|
|
46
|
+
"mcpServers": {
|
|
47
|
+
"figma-console": {
|
|
48
|
+
"command": "npx",
|
|
49
|
+
"args": ["-y", "figma-console-mcp@latest"],
|
|
50
|
+
"env": {
|
|
51
|
+
"FIGMA_ACCESS_TOKEN": "${FIGMA_ACCESS_TOKEN}",
|
|
52
|
+
"ENABLE_MCP_APPS": "true"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Because it is project-scoped, **Claude Code asks you to approve the
|
|
60
|
+
`figma-console` server** the first time it reads `.mcp.json` (run `/mcp` to
|
|
61
|
+
review and approve). Approve it, then **restart the session** — `.mcp.json` is
|
|
62
|
+
only read at startup, so adding or editing it mid-session will not surface the
|
|
63
|
+
tools.
|
|
64
|
+
|
|
65
|
+
Need machine-specific overrides? Put them in `.mcp.local.json` and gitignore
|
|
66
|
+
that path. Never inline a `figd_…` token in a committed file.
|
|
67
|
+
|
|
68
|
+
## 3. Install the Desktop Bridge plugin
|
|
69
|
+
|
|
70
|
+
The plugin files are written to `~/.figma-console-mcp/plugin/` the first time the
|
|
71
|
+
server runs. Find the exact path with:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
npx figma-console-mcp@latest --print-path
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
In **Figma Desktop**: `Plugins → Development → Import plugin from manifest…` →
|
|
78
|
+
select `~/.figma-console-mcp/plugin/manifest.json`. Then open the file you want
|
|
79
|
+
to edit and run `Plugins → Development → Figma Desktop Bridge` to connect it.
|
|
80
|
+
|
|
81
|
+
The bridge needs **Figma Desktop**; it does not work in the browser.
|
|
82
|
+
|
|
83
|
+
## 4. Verify
|
|
84
|
+
|
|
85
|
+
From your agent, once the server is loaded:
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
figma_get_status { probe: true }
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
A healthy result reports `setup.valid: true`, `probeResult.success: true`, and
|
|
92
|
+
the connected file name. `figma_list_open_files` shows which file the plugin is
|
|
93
|
+
bridged to.
|
|
94
|
+
|
|
95
|
+
## Which Figma file to connect
|
|
96
|
+
|
|
97
|
+
Point the bridge at **your own copy or branch** of the Muka UI Figma Library, not
|
|
98
|
+
the shared library itself. Your brand is your brand — pushing modes into the
|
|
99
|
+
upstream library affects every other consumer.
|
|
100
|
+
|
|
101
|
+
Duplicate the [Muka UI Figma
|
|
102
|
+
Library](https://www.figma.com/design/RL5IFLUJk4yeAFNXlsX4b5/Muka-UI-Figma-Library)
|
|
103
|
+
into your own team, or work on a branch of it, then connect the bridge there.
|
|
104
|
+
|
|
105
|
+
The skills discover collections and modes **by name**, so a duplicate works
|
|
106
|
+
without any ID configuration.
|
|
107
|
+
|
|
108
|
+
## Troubleshooting
|
|
109
|
+
|
|
110
|
+
| Symptom | Fix |
|
|
111
|
+
|---|---|
|
|
112
|
+
| `figma-console` tools don't appear | The session predates `.mcp.json`. Approve it via `/mcp` and restart the session. |
|
|
113
|
+
| `FIGMA_ACCESS_TOKEN` unset | `${FIGMA_ACCESS_TOKEN}` expanded to empty. Export it and restart the session. |
|
|
114
|
+
| Probe fails / no connected file | Open the target file in Figma Desktop and run the Desktop Bridge plugin, then re-check `figma_get_status { probe: true }`. |
|
|
115
|
+
| Permission error writing variables | The token lacks Variables write scope, or you only have view access to the file. |
|
|
116
|
+
| Pushed values show as raw swatches | They were written as hex instead of variable aliases. See Step 4 and Step 6 of `/push-to-figma`. |
|