@revikornmann/muka-ui 0.17.0 → 0.19.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.
Files changed (182) hide show
  1. package/README.md +81 -60
  2. package/cli/bin/muka-ui.js +12 -5
  3. package/cli/commands/brand.js +33 -14
  4. package/cli/commands/init.js +21 -17
  5. package/cli/commands/install-skill.js +84 -26
  6. package/cli/templates/AGENTS.md +128 -0
  7. package/cli/templates/CLAUDE.md +8 -88
  8. package/cli/templates/muka-ui-guidelines.md +50 -14
  9. package/dist/cjs/components/ActionSheet/ActionSheet.js +1 -1
  10. package/dist/cjs/components/Breadcrumb/Breadcrumb.css +11 -3
  11. package/dist/cjs/components/Breadcrumb/Breadcrumb.js +19 -1
  12. package/dist/cjs/components/Breadcrumb/Breadcrumb.js.map +1 -1
  13. package/dist/cjs/components/Combobox/Combobox.css +116 -132
  14. package/dist/cjs/components/Combobox/Combobox.js +175 -52
  15. package/dist/cjs/components/Combobox/Combobox.js.map +1 -1
  16. package/dist/cjs/components/Combobox/index.js.map +1 -1
  17. package/dist/cjs/components/ContextSelect/ContextSelect.css +117 -0
  18. package/dist/cjs/components/ContextSelect/ContextSelect.js +49 -0
  19. package/dist/cjs/components/ContextSelect/ContextSelect.js.map +1 -0
  20. package/dist/cjs/components/ContextSelect/index.js +11 -0
  21. package/dist/cjs/components/ContextSelect/index.js.map +1 -0
  22. package/dist/cjs/components/DropdownSelect/DropdownSelect.css +225 -0
  23. package/dist/cjs/components/DropdownSelect/DropdownSelect.js +106 -0
  24. package/dist/cjs/components/DropdownSelect/DropdownSelect.js.map +1 -0
  25. package/dist/cjs/components/DropdownSelect/index.js +6 -0
  26. package/dist/cjs/components/DropdownSelect/index.js.map +1 -0
  27. package/dist/cjs/components/Icon/custom/ArrowDropUpDownIcon.js +11 -0
  28. package/dist/cjs/components/Icon/custom/ArrowDropUpDownIcon.js.map +1 -0
  29. package/dist/cjs/components/Icon/custom/ArrowReturnIcon.js +11 -0
  30. package/dist/cjs/components/Icon/custom/ArrowReturnIcon.js.map +1 -0
  31. package/dist/cjs/components/Icon/iconRegistry.js +11 -0
  32. package/dist/cjs/components/Icon/iconRegistry.js.map +1 -1
  33. package/dist/cjs/components/Input/Input.css +45 -8
  34. package/dist/cjs/components/Input/Input.js +14 -3
  35. package/dist/cjs/components/Input/Input.js.map +1 -1
  36. package/dist/cjs/components/Menu/Menu.css +213 -17
  37. package/dist/cjs/components/Menu/Menu.js +429 -39
  38. package/dist/cjs/components/Menu/Menu.js.map +1 -1
  39. package/dist/cjs/components/Menu/index.js +5 -1
  40. package/dist/cjs/components/Menu/index.js.map +1 -1
  41. package/dist/cjs/components/ProgressTracker/ProgressTracker.css +273 -22
  42. package/dist/cjs/components/ProgressTracker/ProgressTracker.js +109 -9
  43. package/dist/cjs/components/ProgressTracker/ProgressTracker.js.map +1 -1
  44. package/dist/cjs/components/Scrollbar/Scrollbar.css +124 -0
  45. package/dist/cjs/components/Scrollbar/Scrollbar.js +118 -0
  46. package/dist/cjs/components/Scrollbar/Scrollbar.js.map +1 -0
  47. package/dist/cjs/components/Scrollbar/index.js +11 -0
  48. package/dist/cjs/components/Scrollbar/index.js.map +1 -0
  49. package/dist/cjs/components/index.js +13 -16
  50. package/dist/cjs/components/index.js.map +1 -1
  51. package/dist/esm/components/ActionSheet/ActionSheet.js +1 -1
  52. package/dist/esm/components/Breadcrumb/Breadcrumb.css +11 -3
  53. package/dist/esm/components/Breadcrumb/Breadcrumb.js +19 -1
  54. package/dist/esm/components/Breadcrumb/Breadcrumb.js.map +1 -1
  55. package/dist/esm/components/Combobox/Combobox.css +116 -132
  56. package/dist/esm/components/Combobox/Combobox.js +177 -54
  57. package/dist/esm/components/Combobox/Combobox.js.map +1 -1
  58. package/dist/esm/components/Combobox/index.js +1 -1
  59. package/dist/esm/components/Combobox/index.js.map +1 -1
  60. package/dist/esm/components/ContextSelect/ContextSelect.css +117 -0
  61. package/dist/esm/components/ContextSelect/ContextSelect.js +45 -0
  62. package/dist/esm/components/ContextSelect/ContextSelect.js.map +1 -0
  63. package/dist/esm/components/ContextSelect/index.js +3 -0
  64. package/dist/esm/components/ContextSelect/index.js.map +1 -0
  65. package/dist/esm/components/DropdownSelect/DropdownSelect.css +225 -0
  66. package/dist/esm/components/DropdownSelect/DropdownSelect.js +102 -0
  67. package/dist/esm/components/DropdownSelect/DropdownSelect.js.map +1 -0
  68. package/dist/esm/components/DropdownSelect/index.js +2 -0
  69. package/dist/esm/components/DropdownSelect/index.js.map +1 -0
  70. package/dist/esm/components/Icon/custom/ArrowDropUpDownIcon.js +7 -0
  71. package/dist/esm/components/Icon/custom/ArrowDropUpDownIcon.js.map +1 -0
  72. package/dist/esm/components/Icon/custom/ArrowReturnIcon.js +7 -0
  73. package/dist/esm/components/Icon/custom/ArrowReturnIcon.js.map +1 -0
  74. package/dist/esm/components/Icon/iconRegistry.js +11 -0
  75. package/dist/esm/components/Icon/iconRegistry.js.map +1 -1
  76. package/dist/esm/components/Input/Input.css +45 -8
  77. package/dist/esm/components/Input/Input.js +14 -3
  78. package/dist/esm/components/Input/Input.js.map +1 -1
  79. package/dist/esm/components/Menu/Menu.css +213 -17
  80. package/dist/esm/components/Menu/Menu.js +428 -40
  81. package/dist/esm/components/Menu/Menu.js.map +1 -1
  82. package/dist/esm/components/Menu/index.js +1 -1
  83. package/dist/esm/components/Menu/index.js.map +1 -1
  84. package/dist/esm/components/ProgressTracker/ProgressTracker.css +273 -22
  85. package/dist/esm/components/ProgressTracker/ProgressTracker.js +110 -10
  86. package/dist/esm/components/ProgressTracker/ProgressTracker.js.map +1 -1
  87. package/dist/esm/components/Scrollbar/Scrollbar.css +124 -0
  88. package/dist/esm/components/Scrollbar/Scrollbar.js +114 -0
  89. package/dist/esm/components/Scrollbar/Scrollbar.js.map +1 -0
  90. package/dist/esm/components/Scrollbar/index.js +3 -0
  91. package/dist/esm/components/Scrollbar/index.js.map +1 -0
  92. package/dist/esm/components/index.js +4 -2
  93. package/dist/esm/components/index.js.map +1 -1
  94. package/dist/styles/components/Breadcrumb.css +11 -3
  95. package/dist/styles/components/Combobox.css +116 -132
  96. package/dist/styles/components/ContextSelect.css +117 -0
  97. package/dist/styles/components/DropdownSelect.css +225 -0
  98. package/dist/styles/components/Input.css +45 -8
  99. package/dist/styles/components/Menu.css +213 -17
  100. package/dist/styles/components/ProgressTracker.css +273 -22
  101. package/dist/styles/components/Scrollbar.css +124 -0
  102. package/dist/styles/components/Typography.css +89 -0
  103. package/dist/styles/index.css +1526 -480
  104. package/dist/styles/muka-dark.css +1526 -480
  105. package/dist/styles/muka-light.css +1526 -480
  106. package/dist/styles/tokens-bouwplan-dark.css +9 -6
  107. package/dist/styles/tokens-bouwplan-light.css +9 -6
  108. package/dist/styles/tokens-fscl-dark.css +29 -26
  109. package/dist/styles/tokens-fscl-light.css +29 -26
  110. package/dist/styles/tokens-grip-dark.css +8 -5
  111. package/dist/styles/tokens-grip-light.css +8 -5
  112. package/dist/styles/tokens-muka-dark.css +8 -5
  113. package/dist/styles/tokens-muka-light.css +8 -5
  114. package/dist/styles/tokens-wireframe-dark.css +53 -50
  115. package/dist/styles/tokens-wireframe-light.css +53 -50
  116. package/dist/styles/wireframe-dark.css +1571 -525
  117. package/dist/styles/wireframe-light.css +1571 -525
  118. package/dist/types/components/ActionSheet/ActionSheet.d.ts +1 -1
  119. package/dist/types/components/Breadcrumb/Breadcrumb.d.ts +27 -3
  120. package/dist/types/components/Breadcrumb/Breadcrumb.d.ts.map +1 -1
  121. package/dist/types/components/Combobox/Combobox.d.ts +38 -38
  122. package/dist/types/components/Combobox/Combobox.d.ts.map +1 -1
  123. package/dist/types/components/Combobox/index.d.ts +1 -1
  124. package/dist/types/components/Combobox/index.d.ts.map +1 -1
  125. package/dist/types/components/ContextSelect/ContextSelect.d.ts +62 -0
  126. package/dist/types/components/ContextSelect/ContextSelect.d.ts.map +1 -0
  127. package/dist/types/components/ContextSelect/index.d.ts +3 -0
  128. package/dist/types/components/ContextSelect/index.d.ts.map +1 -0
  129. package/dist/types/components/DataTable/DataTable.d.ts +1 -1
  130. package/dist/types/components/DropdownSelect/DropdownSelect.d.ts +71 -0
  131. package/dist/types/components/DropdownSelect/DropdownSelect.d.ts.map +1 -0
  132. package/dist/types/components/DropdownSelect/index.d.ts +2 -0
  133. package/dist/types/components/DropdownSelect/index.d.ts.map +1 -0
  134. package/dist/types/components/Icon/custom/ArrowDropUpDownIcon.d.ts +9 -0
  135. package/dist/types/components/Icon/custom/ArrowDropUpDownIcon.d.ts.map +1 -0
  136. package/dist/types/components/Icon/custom/ArrowReturnIcon.d.ts +9 -0
  137. package/dist/types/components/Icon/custom/ArrowReturnIcon.d.ts.map +1 -0
  138. package/dist/types/components/Icon/iconRegistry.d.ts.map +1 -1
  139. package/dist/types/components/Input/Input.d.ts +5 -0
  140. package/dist/types/components/Input/Input.d.ts.map +1 -1
  141. package/dist/types/components/Menu/Menu.d.ts +99 -29
  142. package/dist/types/components/Menu/Menu.d.ts.map +1 -1
  143. package/dist/types/components/Menu/index.d.ts +2 -2
  144. package/dist/types/components/Menu/index.d.ts.map +1 -1
  145. package/dist/types/components/ProgressTracker/ProgressTracker.d.ts +29 -8
  146. package/dist/types/components/ProgressTracker/ProgressTracker.d.ts.map +1 -1
  147. package/dist/types/components/Scrollbar/Scrollbar.d.ts +19 -0
  148. package/dist/types/components/Scrollbar/Scrollbar.d.ts.map +1 -0
  149. package/dist/types/components/Scrollbar/index.d.ts +3 -0
  150. package/dist/types/components/Scrollbar/index.d.ts.map +1 -0
  151. package/dist/types/components/index.d.ts +5 -4
  152. package/dist/types/components/index.d.ts.map +1 -1
  153. package/docs/consumers/README.md +116 -37
  154. package/docs/consumers/brand.md +261 -0
  155. package/docs/consumers/figma-console-mcp.md +116 -0
  156. package/docs/consumers/setup-instructions.md +98 -12
  157. package/docs/consumers/skills.md +79 -0
  158. package/package.json +4 -6
  159. package/scripts/postinstall-nudge.js +8 -4
  160. package/skills/add-brand/SKILL.md +204 -0
  161. package/skills/add-brand/reference.md +160 -0
  162. package/skills/figma-to-code/SKILL.md +127 -0
  163. package/skills/pull-from-figma/SKILL.md +123 -0
  164. package/skills/push-to-figma/SKILL.md +172 -0
  165. package/skills/setup-muka/SKILL.md +73 -13
  166. package/tokens/README.md +40 -18
  167. package/tokens/t2-alias/brand/bouwplan/fonts.json +1 -1
  168. package/tokens/t2-alias/brand/fscl/fonts.json +3 -3
  169. package/tokens/t2-alias/brand/wireframe/fonts.json +2 -2
  170. package/tokens/t4-components/menu.json +20 -5
  171. package/dist/cjs/components/ContextMenu/ContextMenu.js +0 -186
  172. package/dist/cjs/components/ContextMenu/ContextMenu.js.map +0 -1
  173. package/dist/cjs/components/ContextMenu/index.js +0 -17
  174. package/dist/cjs/components/ContextMenu/index.js.map +0 -1
  175. package/dist/esm/components/ContextMenu/ContextMenu.js +0 -145
  176. package/dist/esm/components/ContextMenu/ContextMenu.js.map +0 -1
  177. package/dist/esm/components/ContextMenu/index.js +0 -2
  178. package/dist/esm/components/ContextMenu/index.js.map +0 -1
  179. package/dist/types/components/ContextMenu/ContextMenu.d.ts +0 -188
  180. package/dist/types/components/ContextMenu/ContextMenu.d.ts.map +0 -1
  181. package/dist/types/components/ContextMenu/index.d.ts +0 -3
  182. package/dist/types/components/ContextMenu/index.d.ts.map +0 -1
@@ -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`. |
@@ -9,6 +9,9 @@ version.
9
9
  Muka UI is a **public npm package** — installing it needs no `.npmrc`, registry
10
10
  configuration, or auth token.
11
11
 
12
+ For the wider picture — brands, Figma, the skills — start at
13
+ [`README.md`](README.md).
14
+
12
15
  ## 1. Install
13
16
 
14
17
  ```bash
@@ -22,29 +25,80 @@ import '@revikornmann/muka-ui/styles'; // default muka-light — muka fonts incl
22
25
  import { Button } from '@revikornmann/muka-ui';
23
26
  ```
24
27
 
25
- The default `/styles` bundle — and the pre-bundled `/styles/muka-dark.css` and
26
- `/styles/wireframe-{light,dark}.css` files — already include that brand's self-hosted
27
- fonts, so on those themes you need no separate fonts import. Other brands are loaded
28
- via their raw `tokens-<brand>-<mode>.css` (below), which carries no fonts, so those
29
- also import `fonts-<brand>.css`.
28
+ ## 2. Pick a brand and theme
29
+
30
+ Muka ships five brands — `muka`, `wireframe`, `grip`, `fscl`, `bouwplan` — each in
31
+ light and dark, for **ten themes**. How you load one depends on the brand.
32
+
33
+ **Pre-bundled (muka and wireframe).** `/styles` is `muka-light`; three
34
+ alternatives are drop-in replacements for it. Each is self-contained: base
35
+ styles, tokens, every component's CSS, and that brand's self-hosted fonts.
36
+
37
+ ```ts
38
+ import '@revikornmann/muka-ui/styles'; // muka-light
39
+ import '@revikornmann/muka-ui/styles/muka-dark.css';
40
+ import '@revikornmann/muka-ui/styles/wireframe-light.css';
41
+ import '@revikornmann/muka-ui/styles/wireframe-dark.css';
42
+ ```
30
43
 
31
- For a brand theme, also load the brand CSS **and the brand's fonts** and set the
32
- data attributes (replace `bouwplan` with your brand):
44
+ **Composed (grip, fscl, bouwplan).** No pre-bundled file, so combine three
45
+ imports — base styles, the brand's raw token CSS, and the brand's fonts. The raw
46
+ token CSS carries no `@font-face`, which is why the fonts import is separate:
33
47
 
34
48
  ```ts
49
+ import '@revikornmann/muka-ui/styles/base.css';
35
50
  import '@revikornmann/muka-ui/styles/tokens-bouwplan-light.css';
36
51
  import '@revikornmann/muka-ui/styles/fonts-bouwplan.css';
37
52
  ```
38
53
 
54
+ None of the five fitting? Build your own brand — see [`brand.md`](brand.md).
55
+
56
+ ### How theme selection actually works
57
+
58
+ Every token stylesheet declares its variables on `:root`. There are **no
59
+ `[data-brand]` or `[data-theme]` selectors in Muka's CSS**, so you select a theme
60
+ by **choosing which stylesheet loads**, and importing two means the last one
61
+ wins. Setting `data-brand` / `data-theme` attributes has no effect.
62
+
63
+ For a runtime light/dark toggle, swap a `<link>` instead of importing both:
64
+
65
+ ```html
66
+ <link id="muka-theme" rel="stylesheet" href="/styles/tokens-muka-light.css" />
67
+ ```
68
+
69
+ ```ts
70
+ document.getElementById('muka-theme').href =
71
+ `/styles/tokens-${brand}-${mode}.css`;
72
+ ```
73
+
74
+ Copy the token CSS you need into your static/public directory (or let your
75
+ bundler emit it at a stable URL) so those hrefs resolve. Muka's own Storybook
76
+ switches between all ten themes exactly this way — see
77
+ `.storybook/ThemeDecorator.ts` in the repo.
78
+
79
+ ### `data-layout`: the one attribute that does do something
80
+
81
+ Brand and theme are not attributes, but **layout density is**. Section padding
82
+ and container gaps respond to viewport width through `@media` blocks, and
83
+ `data-layout` forces one of those steps regardless of viewport:
84
+
39
85
  ```html
40
- <html data-brand="bouwplan" data-theme="light">
86
+ <div data-layout="desktop">…</div>
41
87
  ```
42
88
 
89
+ Accepted values are `tablet`, `desktop`, and `widescreen`; omit the attribute to
90
+ let the media queries decide. Use it when a region should keep desktop spacing
91
+ inside a narrow container (or the reverse) — it only overrides
92
+ `--section-padding-*` and `--container-gap-*`, never colours or type.
93
+
94
+ If your app only ever needs one theme, a plain import is simpler and this does
95
+ not apply.
96
+
43
97
  ### Fonts come from Muka — do not load them yourself
44
98
 
45
99
  Muka self-hosts every brand's fonts and ships them as `@font-face` in
46
- `styles/fonts-<brand>.css` (backed by bundled WOFF2, so they work offline with no
47
- CDN). Importing that one file is all the wiring you need:
100
+ `styles/fonts-<brand>.css`, backed by bundled WOFF2, so they work offline with no
101
+ CDN. Importing that one file is all the wiring you need:
48
102
 
49
103
  - **Do not** load these fonts via `next/font`, a Google Fonts `<link>`, or any
50
104
  other loader — you'd ship the bytes twice and risk a name mismatch.
@@ -52,7 +106,7 @@ CDN). Importing that one file is all the wiring you need:
52
106
  font-family names in Muka's tokens are the exact `@font-face` family names, so
53
107
  overriding them only breaks the resolution.
54
108
 
55
- ## 2. Add the auto-update workflow
109
+ ## 3. Add the auto-update workflow
56
110
 
57
111
  Copy the shipped template into your repo so it stays current with Muka releases:
58
112
 
@@ -77,7 +131,10 @@ The workflow auto-detects your package manager from the lockfile
77
131
  > rejecting a just-published version). Match the value to the pnpm/yarn version
78
132
  > you use locally (e.g. `lockfileVersion: 9.0` → pnpm 9).
79
133
 
80
- ## 3. Register as a consumer
134
+ Muka is under active development, so a bump can change component behaviour or
135
+ appearance. Keep CI checks on the update PR rather than trusting it blindly.
136
+
137
+ ## 4. Register as a consumer
81
138
 
82
139
  Add `owner/repo` to Muka's [`.github/consumers.txt`](../../.github/consumers.txt)
83
140
  so the release pipeline dispatches updates here. The `/setup-muka` skill opens
@@ -85,3 +142,32 @@ this PR automatically; merge it to enable automatic updates.
85
142
 
86
143
  The Muka `CONSUMER_DISPATCH_TOKEN` PAT must have **write** access to this repo
87
144
  for the `repository_dispatch` to succeed.
145
+
146
+ ## 5. Give your agents the house rules
147
+
148
+ ```bash
149
+ npx muka-ui init
150
+ ```
151
+
152
+ Writes `AGENTS.md`, `CLAUDE.md`, and `docs/muka-ui-guidelines.md` into your repo
153
+ (prompting before overwriting any of them), so agents working here compose Muka
154
+ components and use token custom properties instead of inventing markup and
155
+ hardcoding values. It also warns about styling libraries that conflict with Muka.
156
+
157
+ `AGENTS.md` holds the rules, because that filename is the vendor-neutral
158
+ convention most agents read. `CLAUDE.md` is a few lines pointing at it, so Claude
159
+ Code finds them too without a second copy that can drift.
160
+
161
+ ## Verify
162
+
163
+ - `npm ls @revikornmann/muka-ui` shows a semver version resolved from npmjs.
164
+ - The app builds and Muka components render with brand tokens.
165
+ - A component's computed `background-color` resolves to a real colour rather than
166
+ falling back — that is the check that the token CSS actually loaded.
167
+ - `.github/workflows/update-muka.yml` exists and is valid YAML.
168
+
169
+ ## Next
170
+
171
+ - [`brand.md`](brand.md) — build your own brand
172
+ - [`skills.md`](skills.md) — every shipped agent skill
173
+ - <https://muka.kornmann.com> — component APIs, Playgrounds, token docs
@@ -0,0 +1,79 @@
1
+ # Agent skills shipped with Muka UI
2
+
3
+ `@revikornmann/muka-ui` ships agent skills inside the package. They turn the
4
+ multi-step jobs around a design system — installing it, branding it, translating
5
+ a design into code, syncing tokens with Figma — into one command each.
6
+
7
+ ## Installing them
8
+
9
+ Agents discover skills under `.claude/skills/`, never inside `node_modules/`, so
10
+ the package ships them and the CLI copies them in:
11
+
12
+ ```bash
13
+ npx muka-ui install-skill # install all of them
14
+ npx muka-ui install-skill --list # see what's available first
15
+ npx muka-ui install-skill add-brand figma-to-code # install specific ones
16
+ ```
17
+
18
+ Restart your agent afterwards so it picks up the new slash commands. Re-run the
19
+ same command after a Muka upgrade to refresh them; it skips anything already
20
+ identical and prompts before overwriting local edits.
21
+
22
+ ## Which agents can use them
23
+
24
+ The directory name is Claude's, but the contents are not: a skill is a plain
25
+ markdown file with YAML frontmatter, and `.claude/skills/` is scanned by **Claude
26
+ Code and Cursor** alike. For an agent that reads neither, the skills still work
27
+ as documentation — point it at `.claude/skills/<name>/SKILL.md` and it has the
28
+ same instructions, just without a slash command to trigger them.
29
+
30
+ Nothing else Muka ships is agent-specific. The tokens are CSS custom properties,
31
+ the components are React, and these consumer docs are prose — none of that cares
32
+ what is editing your repo. `npx muka-ui init` writes the house rules to
33
+ `AGENTS.md`, the vendor-neutral convention, and leaves a short `CLAUDE.md`
34
+ pointing at it.
35
+
36
+ ## The skills
37
+
38
+ | Skill | What it does | Needs |
39
+ |---|---|---|
40
+ | `/setup-muka` | Installs the package, wires up styles and fonts, adds the release auto-update workflow, and registers your repo as a consumer. Start here. | — |
41
+ | `/add-brand` | Creates a custom brand in **your** repo that overrides Muka's brand layer, so every Muka component takes your colours and typography. Scaffolds the token files, explains the palette choices, and builds the CSS. | `/setup-muka` |
42
+ | `/figma-to-code` | Turns a Figma link into a working screen composed from Muka components and token custom properties — rather than a pixel-matched rebuild that ignores your brand. | A Figma MCP server |
43
+ | `/push-to-figma` | Publishes your brand's tokens into Figma as variables, so designers can design in your brand. Code → Figma. | `/add-brand` + Figma Console MCP |
44
+ | `/pull-from-figma` | Brings brand colour and font changes a designer made in Figma back into your token files. Figma → Code. | `/push-to-figma` + Figma Console MCP |
45
+
46
+ `/setup-muka` and `/add-brand` are the two most people need. The Figma pair
47
+ matters once designers and engineers are both editing the brand.
48
+
49
+ ## The Figma Console MCP dependency
50
+
51
+ `/push-to-figma` and `/pull-from-figma` read and write Figma **variables**, which
52
+ the Figma REST API cannot do for local variables. They therefore drive
53
+ [**Figma Console MCP**](https://github.com/southleft/figma-console-mcp), an
54
+ open-source (MIT) MCP server by **[Southleft](https://southleft.com)** published
55
+ as [`figma-console-mcp`](https://www.npmjs.com/package/figma-console-mcp). It
56
+ relays commands to a Desktop Bridge plugin inside Figma Desktop.
57
+
58
+ It is a third-party project. Muka ships only the skills that drive it; report
59
+ server problems [upstream](https://github.com/southleft/figma-console-mcp/issues).
60
+
61
+ One-time setup — token, `.mcp.json`, Desktop Bridge plugin, verification — is in
62
+ [`figma-console-mcp.md`](figma-console-mcp.md). Without it, those two skills
63
+ cannot run; the other three are unaffected.
64
+
65
+ `/figma-to-code` is different: it reads designs through **Figma's own official
66
+ MCP server**, not Figma Console MCP, and needs no Desktop Bridge.
67
+
68
+ ## Maintainer skills are not shipped
69
+
70
+ The Muka repo has its own skills for working **on** the design system —
71
+ `/component-rules`, `/token-system`, `/new-component`, `/release`, and a
72
+ repo-scoped `/add-brand` that adds a brand to Muka itself for every consumer.
73
+ Those live in
74
+ [`.claude/skills/`](https://github.com/revikornmann/muka/tree/main/.claude/skills)
75
+ and are deliberately excluded from the package, because they edit files that
76
+ exist only in the Muka repo.
77
+
78
+ If you are contributing to Muka rather than consuming it, clone the repo and use
79
+ those directly.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@revikornmann/muka-ui",
3
- "version": "0.17.0",
3
+ "version": "0.19.0",
4
4
  "description": "Muka Design System - Multi-brand design tokens and React components",
5
5
  "main": "dist/cjs/components/index.js",
6
6
  "module": "dist/esm/components/index.js",
@@ -69,8 +69,6 @@
69
69
  "disable:automation": "node scripts/disable-automation.js",
70
70
  "enable:automation": "node scripts/enable-automation.js",
71
71
  "check:automation": "node scripts/check-automation-status.js",
72
- "sync:skills": "node scripts/sync-shipped-skills.js",
73
- "prepack": "node scripts/sync-shipped-skills.js",
74
72
  "prepublishOnly": "npm run build",
75
73
  "postinstall": "node scripts/postinstall-nudge.js",
76
74
  "prepare": "husky || true"
@@ -108,15 +106,14 @@
108
106
  "@fontsource-variable/ibm-plex-sans": "^5.2.8",
109
107
  "@fontsource-variable/lora": "^5.2.8",
110
108
  "@fontsource-variable/quicksand": "^5.2.10",
111
- "@fontsource-variable/red-hat-display": "^5.2.8",
112
- "@fontsource-variable/red-hat-text": "^5.2.8",
109
+ "@fontsource-variable/red-hat-display": "^5.3.0",
110
+ "@fontsource-variable/red-hat-text": "^5.3.0",
113
111
  "@fontsource/yesteryear": "^5.2.8",
114
112
  "@playwright/test": "^1.56.1",
115
113
  "@storybook/addon-a11y": "^10.3.4",
116
114
  "@storybook/addon-designs": "^11.1.3",
117
115
  "@storybook/addon-docs": "^10.3.4",
118
116
  "@storybook/addon-mcp": "^0.5.0",
119
- "@storybook/addon-onboarding": "^10.3.4",
120
117
  "@storybook/addon-vitest": "^10.3.4",
121
118
  "@storybook/react-vite": "^10.3.4",
122
119
  "@testing-library/dom": "^10.4.1",
@@ -139,6 +136,7 @@
139
136
  "playwright": "^1.56.1",
140
137
  "react": "^18.0.0",
141
138
  "react-dom": "^18.0.0",
139
+ "remark-gfm": "^4.0.1",
142
140
  "storybook": "^10.3.4",
143
141
  "typescript": "^5.0.0",
144
142
  "typescript-eslint": "^8.59.2",
@@ -18,9 +18,13 @@ if (!__dirname.includes(`${require('path').sep}node_modules${require('path').sep
18
18
  console.log(`
19
19
  🎨 Muka UI installed.
20
20
 
21
- Finish setup in Claude Code:
22
- 1. npx muka-ui install-skill # makes /setup-muka available
23
- 2. /setup-muka [brand] # installs styles + auto-update workflow
21
+ Finish setup in your agent:
22
+ 1. npx muka-ui install-skill # makes the Muka skills available
23
+ 2. /setup-muka [brand] # styles, fonts, auto-update workflow
24
24
 
25
- Docs: node_modules/@revikornmann/muka-ui/docs/consumers/setup-instructions.md
25
+ Then, when you want your own brand:
26
+ /add-brand <name> # overrides Muka's brand layer in this repo
27
+
28
+ See every shipped skill: npx muka-ui install-skill --list
29
+ Docs: node_modules/@revikornmann/muka-ui/docs/consumers/README.md
26
30
  `);