ui-ux-master 1.2.1 → 1.5.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 +160 -209
- package/SKILL.md +89 -47
- package/docs/package-publishing.md +5 -3
- package/index.cjs +3 -1
- package/index.d.ts +1 -1
- package/index.mjs +4 -1
- package/package.json +4 -3
- package/references/brand-method-card-based-discovery.md +285 -0
- package/references/brand-method-conversion-simplicity.md +276 -0
- package/references/brand-method-ecosystem-bundling.md +263 -0
- package/references/brand-method-editorial-brand-world.md +265 -0
- package/references/brand-method-enterprise-trust-hub.md +298 -0
- package/references/brand-method-playful-familiarity.md +284 -0
- package/references/brand-method-premium-restraint.md +270 -0
- package/references/brand-method-product-cinema.md +258 -0
- package/references/brand-method-technical-authority.md +290 -0
- package/references/brand-method-utility-command-center.md +278 -0
- package/references/color-psychology-branding.md +286 -0
- package/references/color-scale-system.md +347 -0
- package/references/competitive-landscape.md +32 -6
- package/references/design-discovery-protocol.md +171 -0
- package/references/design-system-schema.md +407 -0
- package/references/industry-reasoning-rules.md +504 -0
- package/references/landing-page-patterns.md +327 -0
- package/references/output-quality-gates.md +246 -0
- package/references/tech-stack-guidelines.md +636 -0
- package/references/ui-styles-catalog.md +552 -0
- package/references/visual-directions.md +362 -0
- package/tests/install-smoke.test.mjs +93 -12
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
# Visual Directions
|
|
2
|
+
|
|
3
|
+
Load this file when a user has no brand and selects "No brand yet" in the discovery question form. Present the 5 direction summaries, wait for the user to select one, then bind the direction's full token spec as the design baseline.
|
|
4
|
+
|
|
5
|
+
Do not improvise a color palette. Do not default to blue + white. Select a direction and apply it precisely.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## How to Use
|
|
10
|
+
|
|
11
|
+
1. Present the 5 direction summaries (the short descriptions below) to the user.
|
|
12
|
+
2. Ask: "Which direction fits your vision? Pick a number or describe a preference."
|
|
13
|
+
3. Once selected, apply the full token block for that direction.
|
|
14
|
+
4. State in the output: "Visual direction: [name]. All tokens are provisional — update when a brand identity is confirmed."
|
|
15
|
+
5. Every render uses that direction's `:root` tokens until the user establishes a brand.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Direction 1 — Neutral Modern
|
|
20
|
+
|
|
21
|
+
**One-line:** Clean, rational, whitespace-led. No personality extremes — works for any B2B SaaS, productivity, or professional tool.
|
|
22
|
+
|
|
23
|
+
**When to use:** The user needs something polished and professional but has no strong opinion about aesthetics. Safe default for B2B, admin, or internal tools.
|
|
24
|
+
|
|
25
|
+
### Token Spec
|
|
26
|
+
|
|
27
|
+
```css
|
|
28
|
+
:root {
|
|
29
|
+
/* Color */
|
|
30
|
+
--color-bg: oklch(99% 0.002 264); /* #FAFAFA near-white */
|
|
31
|
+
--color-surface: oklch(97% 0.003 264); /* #F4F4F6 */
|
|
32
|
+
--color-surface-2: oklch(94% 0.004 264); /* #EDEDF0 */
|
|
33
|
+
--color-border: oklch(88% 0.005 264); /* #DDDDE3 */
|
|
34
|
+
--color-text-primary: oklch(15% 0.010 264); /* #1A1A22 */
|
|
35
|
+
--color-text-secondary: oklch(45% 0.010 264); /* #666677 */
|
|
36
|
+
--color-text-muted: oklch(65% 0.008 264); /* #999AAA */
|
|
37
|
+
--color-accent: oklch(52% 0.18 264); /* #4361EE indigo */
|
|
38
|
+
--color-accent-hover: oklch(45% 0.18 264); /* darker */
|
|
39
|
+
--color-success: oklch(52% 0.16 142); /* #1A7F5A green */
|
|
40
|
+
--color-warning: oklch(72% 0.18 72); /* #D4A017 amber */
|
|
41
|
+
--color-error: oklch(52% 0.22 25); /* #C0392B red */
|
|
42
|
+
|
|
43
|
+
/* Typography */
|
|
44
|
+
--font-display: "Inter", "Helvetica Neue", system-ui, sans-serif;
|
|
45
|
+
--font-body: "Inter", system-ui, sans-serif;
|
|
46
|
+
--font-mono: "JetBrains Mono", "Fira Code", monospace;
|
|
47
|
+
|
|
48
|
+
/* Scale */
|
|
49
|
+
--text-xs: 11px;
|
|
50
|
+
--text-sm: 13px;
|
|
51
|
+
--text-base: 15px;
|
|
52
|
+
--text-lg: 17px;
|
|
53
|
+
--text-xl: 20px;
|
|
54
|
+
--text-2xl: 24px;
|
|
55
|
+
--text-3xl: 32px;
|
|
56
|
+
--text-4xl: 40px;
|
|
57
|
+
|
|
58
|
+
/* Spacing (8px base) */
|
|
59
|
+
--space-1: 4px;
|
|
60
|
+
--space-2: 8px;
|
|
61
|
+
--space-3: 12px;
|
|
62
|
+
--space-4: 16px;
|
|
63
|
+
--space-6: 24px;
|
|
64
|
+
--space-8: 32px;
|
|
65
|
+
--space-12: 48px;
|
|
66
|
+
--space-16: 64px;
|
|
67
|
+
--space-24: 96px;
|
|
68
|
+
|
|
69
|
+
/* Shape */
|
|
70
|
+
--radius-sm: 4px;
|
|
71
|
+
--radius-md: 8px;
|
|
72
|
+
--radius-lg: 12px;
|
|
73
|
+
--radius-xl: 16px;
|
|
74
|
+
--radius-pill: 999px;
|
|
75
|
+
|
|
76
|
+
/* Elevation */
|
|
77
|
+
--shadow-sm: 0 1px 2px oklch(0% 0 0 / 0.06);
|
|
78
|
+
--shadow-md: 0 4px 12px oklch(0% 0 0 / 0.08);
|
|
79
|
+
--shadow-lg: 0 8px 32px oklch(0% 0 0 / 0.10);
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Direction 2 — Dark Technical
|
|
86
|
+
|
|
87
|
+
**One-line:** Near-black surface, high-contrast text, vivid accent. Developer tools, AI products, terminal-adjacent interfaces.
|
|
88
|
+
|
|
89
|
+
**When to use:** Technical audience, developer tool, AI product, performance-focused brand, or any context where dark mode is the primary experience.
|
|
90
|
+
|
|
91
|
+
### Token Spec
|
|
92
|
+
|
|
93
|
+
```css
|
|
94
|
+
:root {
|
|
95
|
+
/* Color */
|
|
96
|
+
--color-bg: oklch(10% 0.005 264); /* #0D0D10 */
|
|
97
|
+
--color-surface: oklch(14% 0.006 264); /* #161619 */
|
|
98
|
+
--color-surface-2: oklch(18% 0.007 264); /* #1E1E22 */
|
|
99
|
+
--color-border: oklch(24% 0.008 264); /* #2A2A30 */
|
|
100
|
+
--color-text-primary: oklch(93% 0.005 264); /* #EBEBF0 */
|
|
101
|
+
--color-text-secondary: oklch(65% 0.008 264); /* #999AAA */
|
|
102
|
+
--color-text-muted: oklch(48% 0.008 264); /* #666677 */
|
|
103
|
+
--color-accent: oklch(72% 0.22 142); /* #3ECF8E green — use for links, active, CTA */
|
|
104
|
+
--color-accent-hover: oklch(78% 0.22 142); /* lighter on hover */
|
|
105
|
+
--color-success: oklch(68% 0.18 142); /* green */
|
|
106
|
+
--color-warning: oklch(78% 0.18 72); /* amber */
|
|
107
|
+
--color-error: oklch(62% 0.22 25); /* red */
|
|
108
|
+
|
|
109
|
+
/* Code syntax */
|
|
110
|
+
--syntax-string: oklch(72% 0.14 42); /* warm orange */
|
|
111
|
+
--syntax-keyword: oklch(68% 0.18 264); /* blue-indigo */
|
|
112
|
+
--syntax-comment: oklch(52% 0.08 142); /* muted green */
|
|
113
|
+
--syntax-number: oklch(78% 0.14 142); /* light green */
|
|
114
|
+
|
|
115
|
+
/* Typography */
|
|
116
|
+
--font-display: "Geist", "Inter", system-ui, sans-serif;
|
|
117
|
+
--font-body: "Geist", "Inter", system-ui, sans-serif;
|
|
118
|
+
--font-mono: "Geist Mono", "JetBrains Mono", monospace;
|
|
119
|
+
|
|
120
|
+
/* Scale — same as Neutral Modern */
|
|
121
|
+
--text-xs: 11px; --text-sm: 13px; --text-base: 15px; --text-lg: 17px;
|
|
122
|
+
--text-xl: 20px; --text-2xl: 24px; --text-3xl: 32px; --text-4xl: 40px;
|
|
123
|
+
|
|
124
|
+
/* Spacing — same as Neutral Modern */
|
|
125
|
+
--space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px;
|
|
126
|
+
--space-6: 24px; --space-8: 32px; --space-12: 48px; --space-16: 64px; --space-24: 96px;
|
|
127
|
+
|
|
128
|
+
/* Shape */
|
|
129
|
+
--radius-sm: 4px; --radius-md: 6px; --radius-lg: 10px; --radius-xl: 14px; --radius-pill: 999px;
|
|
130
|
+
|
|
131
|
+
/* Elevation — glow replaces shadow on dark */
|
|
132
|
+
--shadow-sm: 0 0 0 1px var(--color-border);
|
|
133
|
+
--shadow-md: 0 4px 16px oklch(0% 0 0 / 0.4);
|
|
134
|
+
--shadow-lg: 0 8px 40px oklch(0% 0 0 / 0.6);
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Direction 3 — Warm Editorial
|
|
141
|
+
|
|
142
|
+
**One-line:** Cream backgrounds, serif headings, generous whitespace. Publishing, culture, premium lifestyle, editorial content, high-end brands.
|
|
143
|
+
|
|
144
|
+
**When to use:** Content-led products, editorial sites, premium lifestyle, food/culture/arts, or any brand that values story over speed.
|
|
145
|
+
|
|
146
|
+
### Token Spec
|
|
147
|
+
|
|
148
|
+
```css
|
|
149
|
+
:root {
|
|
150
|
+
/* Color */
|
|
151
|
+
--color-bg: oklch(97% 0.012 72); /* #FAF7F2 warm cream */
|
|
152
|
+
--color-surface: oklch(95% 0.014 72); /* #F4EFE8 */
|
|
153
|
+
--color-surface-2: oklch(92% 0.016 72); /* #EDE5DA */
|
|
154
|
+
--color-border: oklch(85% 0.018 72); /* #D9CEBC */
|
|
155
|
+
--color-text-primary: oklch(18% 0.020 72); /* #2A2118 near-black warm */
|
|
156
|
+
--color-text-secondary: oklch(42% 0.016 72); /* #6B5B48 warm brown */
|
|
157
|
+
--color-text-muted: oklch(62% 0.012 72); /* #9A8B7A */
|
|
158
|
+
--color-accent: oklch(38% 0.16 42); /* #8B3A1A deep terra */
|
|
159
|
+
--color-accent-hover: oklch(32% 0.16 42); /* darker */
|
|
160
|
+
--color-success: oklch(48% 0.14 142); /* forest green */
|
|
161
|
+
--color-warning: oklch(68% 0.18 72); /* warm amber */
|
|
162
|
+
--color-error: oklch(48% 0.20 25); /* deep red */
|
|
163
|
+
|
|
164
|
+
/* Typography */
|
|
165
|
+
--font-display: "Playfair Display", "Cormorant Garamond", Georgia, serif;
|
|
166
|
+
--font-body: "Lato", "Source Sans 3", system-ui, sans-serif;
|
|
167
|
+
--font-mono: "Courier Prime", "Courier New", monospace;
|
|
168
|
+
|
|
169
|
+
/* Scale — editorial uses larger body */
|
|
170
|
+
--text-xs: 12px;
|
|
171
|
+
--text-sm: 14px;
|
|
172
|
+
--text-base: 17px; /* larger for readability */
|
|
173
|
+
--text-lg: 20px;
|
|
174
|
+
--text-xl: 24px;
|
|
175
|
+
--text-2xl: 32px;
|
|
176
|
+
--text-3xl: 44px;
|
|
177
|
+
--text-4xl: 60px;
|
|
178
|
+
|
|
179
|
+
/* Spacing — editorial is generous */
|
|
180
|
+
--space-1: 6px; --space-2: 12px; --space-3: 18px; --space-4: 24px;
|
|
181
|
+
--space-6: 36px; --space-8: 48px; --space-12: 72px; --space-16: 96px; --space-24: 144px;
|
|
182
|
+
|
|
183
|
+
/* Shape — editorial avoids round corners */
|
|
184
|
+
--radius-sm: 2px; --radius-md: 2px; --radius-lg: 4px; --radius-xl: 4px; --radius-pill: 2px;
|
|
185
|
+
|
|
186
|
+
/* Elevation */
|
|
187
|
+
--shadow-sm: 0 1px 3px oklch(18% 0.020 72 / 0.10);
|
|
188
|
+
--shadow-md: 0 4px 12px oklch(18% 0.020 72 / 0.12);
|
|
189
|
+
--shadow-lg: 0 8px 32px oklch(18% 0.020 72 / 0.14);
|
|
190
|
+
|
|
191
|
+
/* Editorial specific */
|
|
192
|
+
--line-height-body: 1.85;
|
|
193
|
+
--line-height-heading: 1.15;
|
|
194
|
+
--letter-spacing-heading: -0.02em;
|
|
195
|
+
--letter-spacing-caption: 0.08em;
|
|
196
|
+
--max-prose-width: 68ch;
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## Direction 4 — Bold Energetic
|
|
203
|
+
|
|
204
|
+
**One-line:** High-contrast, high-energy. Strong typographic statements, minimal decoration. Sports, fitness, food, gaming, consumer apps, campaign sites.
|
|
205
|
+
|
|
206
|
+
**When to use:** Consumer brands targeting young audiences, energy or action-oriented products, brands where personality and boldness are the differentiator.
|
|
207
|
+
|
|
208
|
+
### Token Spec
|
|
209
|
+
|
|
210
|
+
```css
|
|
211
|
+
:root {
|
|
212
|
+
/* Color */
|
|
213
|
+
--color-bg: oklch(99% 0.002 0); /* #FAFAFA pure white */
|
|
214
|
+
--color-surface: oklch(96% 0.004 0); /* #F2F2F2 */
|
|
215
|
+
--color-surface-2: oklch(92% 0.006 0); /* #E8E8E8 */
|
|
216
|
+
--color-border: oklch(84% 0.006 0); /* #D4D4D4 */
|
|
217
|
+
--color-text-primary: oklch(8% 0.005 0); /* #0D0D0D near-black */
|
|
218
|
+
--color-text-secondary: oklch(38% 0.006 0); /* #555555 */
|
|
219
|
+
--color-text-muted: oklch(58% 0.006 0); /* #888888 */
|
|
220
|
+
--color-accent: oklch(52% 0.26 25); /* #D32F2F bold red */
|
|
221
|
+
--color-accent-hover: oklch(44% 0.26 25); /* darker red */
|
|
222
|
+
--color-accent-alt: oklch(8% 0.005 0); /* black — for secondary CTA */
|
|
223
|
+
--color-success: oklch(50% 0.18 142);
|
|
224
|
+
--color-warning: oklch(68% 0.22 72);
|
|
225
|
+
--color-error: oklch(52% 0.22 25);
|
|
226
|
+
|
|
227
|
+
/* Typography — condensed, heavy */
|
|
228
|
+
--font-display: "Barlow Condensed", "Bebas Neue", "Arial Narrow", sans-serif;
|
|
229
|
+
--font-body: "Barlow", "Inter", system-ui, sans-serif;
|
|
230
|
+
--font-mono: "JetBrains Mono", monospace;
|
|
231
|
+
--font-weight-display: 800; /* ExtraBold or Black */
|
|
232
|
+
|
|
233
|
+
/* Scale — headlines go large */
|
|
234
|
+
--text-xs: 11px;
|
|
235
|
+
--text-sm: 13px;
|
|
236
|
+
--text-base: 15px;
|
|
237
|
+
--text-lg: 18px;
|
|
238
|
+
--text-xl: 22px;
|
|
239
|
+
--text-2xl: 28px;
|
|
240
|
+
--text-3xl: 44px;
|
|
241
|
+
--text-4xl: 72px; /* campaign headlines */
|
|
242
|
+
|
|
243
|
+
/* Spacing — tighter than editorial */
|
|
244
|
+
--space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px;
|
|
245
|
+
--space-6: 24px; --space-8: 32px; --space-12: 48px; --space-16: 64px; --space-24: 96px;
|
|
246
|
+
|
|
247
|
+
/* Shape — bold uses sharper or pill */
|
|
248
|
+
--radius-sm: 2px; --radius-md: 4px; --radius-lg: 6px; --radius-xl: 8px; --radius-pill: 999px;
|
|
249
|
+
|
|
250
|
+
/* Elevation */
|
|
251
|
+
--shadow-sm: 0 2px 4px oklch(0% 0 0 / 0.12);
|
|
252
|
+
--shadow-md: 0 4px 16px oklch(0% 0 0 / 0.16);
|
|
253
|
+
--shadow-lg: 0 8px 40px oklch(0% 0 0 / 0.20);
|
|
254
|
+
|
|
255
|
+
/* Bold specific */
|
|
256
|
+
--letter-spacing-display: -0.01em;
|
|
257
|
+
--letter-spacing-label: 0.08em; /* all-caps labels */
|
|
258
|
+
--text-transform-display: uppercase; /* optional, brand-dependent */
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
## Direction 5 — Calm Trust
|
|
265
|
+
|
|
266
|
+
**One-line:** Soft blues, rounded shapes, plenty of air. Healthcare, wellness, finance, education — anywhere trust and calm are the emotional goal.
|
|
267
|
+
|
|
268
|
+
**When to use:** Any product where the user might be anxious, uncertain, or making high-stakes decisions. Medtech, finance, mental health, insurance, legal, education.
|
|
269
|
+
|
|
270
|
+
### Token Spec
|
|
271
|
+
|
|
272
|
+
```css
|
|
273
|
+
:root {
|
|
274
|
+
/* Color */
|
|
275
|
+
--color-bg: oklch(98% 0.006 230); /* #F5F9FD light blue-white */
|
|
276
|
+
--color-surface: oklch(96% 0.008 230); /* #EDF4FB */
|
|
277
|
+
--color-surface-2: oklch(93% 0.010 230); /* #E2EDF7 */
|
|
278
|
+
--color-border: oklch(87% 0.012 230); /* #C8DCF0 */
|
|
279
|
+
--color-text-primary: oklch(18% 0.018 230); /* #1A2B3C deep blue-black */
|
|
280
|
+
--color-text-secondary: oklch(42% 0.016 230); /* #4A6380 */
|
|
281
|
+
--color-text-muted: oklch(62% 0.012 230); /* #7A9AB8 */
|
|
282
|
+
--color-accent: oklch(52% 0.18 230); /* #0072CE calm blue */
|
|
283
|
+
--color-accent-hover: oklch(45% 0.18 230); /* darker */
|
|
284
|
+
--color-accent-soft: oklch(90% 0.06 230); /* #D6EAFB — for tinted surfaces */
|
|
285
|
+
--color-success: oklch(52% 0.16 165); /* #1A7F6A teal-green */
|
|
286
|
+
--color-warning: oklch(68% 0.18 80); /* muted amber */
|
|
287
|
+
--color-error: oklch(52% 0.18 25); /* calm red */
|
|
288
|
+
|
|
289
|
+
/* Typography — humanist, readable */
|
|
290
|
+
--font-display: "DM Sans", "Source Sans 3", "Open Sans", system-ui, sans-serif;
|
|
291
|
+
--font-body: "DM Sans", "Source Sans 3", system-ui, sans-serif;
|
|
292
|
+
--font-mono: "Roboto Mono", monospace;
|
|
293
|
+
|
|
294
|
+
/* Scale */
|
|
295
|
+
--text-xs: 12px;
|
|
296
|
+
--text-sm: 14px;
|
|
297
|
+
--text-base: 16px;
|
|
298
|
+
--text-lg: 18px;
|
|
299
|
+
--text-xl: 22px;
|
|
300
|
+
--text-2xl: 28px;
|
|
301
|
+
--text-3xl: 36px;
|
|
302
|
+
--text-4xl: 48px;
|
|
303
|
+
|
|
304
|
+
/* Spacing — generous, breathes */
|
|
305
|
+
--space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px;
|
|
306
|
+
--space-6: 24px; --space-8: 32px; --space-12: 48px; --space-16: 64px; --space-24: 96px;
|
|
307
|
+
|
|
308
|
+
/* Shape — rounded, soft */
|
|
309
|
+
--radius-sm: 6px;
|
|
310
|
+
--radius-md: 10px;
|
|
311
|
+
--radius-lg: 16px;
|
|
312
|
+
--radius-xl: 24px;
|
|
313
|
+
--radius-pill: 999px;
|
|
314
|
+
|
|
315
|
+
/* Elevation — soft, not dramatic */
|
|
316
|
+
--shadow-sm: 0 1px 4px oklch(18% 0.018 230 / 0.06);
|
|
317
|
+
--shadow-md: 0 4px 16px oklch(18% 0.018 230 / 0.08);
|
|
318
|
+
--shadow-lg: 0 8px 32px oklch(18% 0.018 230 / 0.10);
|
|
319
|
+
|
|
320
|
+
/* Calm Trust specific */
|
|
321
|
+
--line-height-body: 1.7;
|
|
322
|
+
--line-height-heading: 1.3;
|
|
323
|
+
}
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
## Direction Summary (present to user)
|
|
329
|
+
|
|
330
|
+
When presenting options, use this short-form:
|
|
331
|
+
|
|
332
|
+
```
|
|
333
|
+
Pick a visual direction:
|
|
334
|
+
|
|
335
|
+
1. Neutral Modern — Clean, rational, professional. No personality extremes.
|
|
336
|
+
Great for: SaaS, productivity tools, admin, B2B.
|
|
337
|
+
|
|
338
|
+
2. Dark Technical — Near-black surface, vivid accent. Developer-first.
|
|
339
|
+
Great for: Dev tools, AI products, technical platforms.
|
|
340
|
+
|
|
341
|
+
3. Warm Editorial — Cream, serif type, generous whitespace. Story-first.
|
|
342
|
+
Great for: Publishing, food, culture, premium lifestyle.
|
|
343
|
+
|
|
344
|
+
4. Bold Energetic — High-contrast, heavy type, big headlines.
|
|
345
|
+
Great for: Sports, fitness, food brands, consumer apps.
|
|
346
|
+
|
|
347
|
+
5. Calm Trust — Soft blues, rounded shapes, breathes easily.
|
|
348
|
+
Great for: Healthcare, finance, wellness, education.
|
|
349
|
+
|
|
350
|
+
Or describe your preference and I'll match the closest direction.
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
## Applying a Direction
|
|
356
|
+
|
|
357
|
+
Once the user selects a direction:
|
|
358
|
+
|
|
359
|
+
1. Copy the full `:root` token block into the design context.
|
|
360
|
+
2. Declare: "Visual direction: [Direction Name] applied. Using [primary palette description] with [font stack]."
|
|
361
|
+
3. All subsequent design output uses only tokens from this block — no ad-hoc color or spacing values.
|
|
362
|
+
4. If the user later provides real brand assets, run the brand extraction protocol (`references/design-discovery-protocol.md`) and override the direction tokens with the extracted brand values.
|
|
@@ -3,12 +3,18 @@ import fs from 'node:fs';
|
|
|
3
3
|
import os from 'node:os';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { execFileSync, spawnSync } from 'node:child_process';
|
|
6
|
+
import { createRequire } from 'node:module';
|
|
6
7
|
import test from 'node:test';
|
|
8
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
7
9
|
|
|
8
|
-
const
|
|
10
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
11
|
+
const __dirname = path.dirname(__filename);
|
|
12
|
+
const require = createRequire(import.meta.url);
|
|
13
|
+
const root = path.resolve(__dirname, '..');
|
|
9
14
|
const bin = path.join(root, 'bin', 'ui-ux-master.mjs');
|
|
10
15
|
const mcpBin = path.join(root, 'bin', 'ui-ux-master-mcp.mjs');
|
|
11
16
|
const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
|
|
17
|
+
|
|
12
18
|
const templates = [
|
|
13
19
|
'agent-templates/claude/commands/ui-ux-master.md',
|
|
14
20
|
'agent-templates/universal/ui-ux-master-trigger.md',
|
|
@@ -20,29 +26,61 @@ const templates = [
|
|
|
20
26
|
];
|
|
21
27
|
|
|
22
28
|
function run(args, cwd = root) {
|
|
23
|
-
return execFileSync(process.execPath, [bin, ...args], {
|
|
29
|
+
return execFileSync(process.execPath, [bin, ...args], {
|
|
30
|
+
cwd,
|
|
31
|
+
encoding: 'utf8',
|
|
32
|
+
});
|
|
24
33
|
}
|
|
25
34
|
|
|
26
35
|
function runMcp(messages) {
|
|
27
36
|
const input = messages.map(m => JSON.stringify(m)).join('\n') + '\n';
|
|
28
|
-
|
|
37
|
+
|
|
38
|
+
const res = spawnSync(process.execPath, [mcpBin], {
|
|
39
|
+
input,
|
|
40
|
+
encoding: 'utf8',
|
|
41
|
+
cwd: root,
|
|
42
|
+
timeout: 5000,
|
|
43
|
+
});
|
|
44
|
+
|
|
29
45
|
assert.equal(res.status, 0, res.stderr);
|
|
30
|
-
|
|
46
|
+
|
|
47
|
+
return res.stdout
|
|
48
|
+
.trim()
|
|
49
|
+
.split(/\n+/)
|
|
50
|
+
.map(line => JSON.parse(line));
|
|
31
51
|
}
|
|
32
52
|
|
|
33
53
|
test('package exposes cli and mcp bins with Rupak Biswas author', () => {
|
|
34
54
|
assert.equal(pkg.author, 'Rupak Biswas');
|
|
35
55
|
assert.equal(pkg.bin['ui-ux-master'], './bin/ui-ux-master.mjs');
|
|
36
56
|
assert.equal(pkg.bin['ui-ux-master-mcp'], './bin/ui-ux-master-mcp.mjs');
|
|
57
|
+
|
|
37
58
|
assert.ok(fs.existsSync(bin));
|
|
38
59
|
assert.ok(fs.existsSync(mcpBin));
|
|
60
|
+
|
|
39
61
|
assert.ok(fs.readFileSync(bin, 'utf8').startsWith('#!/usr/bin/env node'));
|
|
40
62
|
assert.ok(fs.readFileSync(mcpBin, 'utf8').startsWith('#!/usr/bin/env node'));
|
|
41
63
|
});
|
|
42
64
|
|
|
65
|
+
test('package metadata APIs work from ESM and CommonJS entrypoints', async () => {
|
|
66
|
+
const esm = await import(pathToFileURL(path.join(root, 'index.mjs')).href);
|
|
67
|
+
const cjs = require(path.join(root, 'index.cjs'));
|
|
68
|
+
|
|
69
|
+
for (const api of [esm, cjs]) {
|
|
70
|
+
assert.equal(api.name, 'ui-ux-master');
|
|
71
|
+
assert.equal(api.version, pkg.version);
|
|
72
|
+
assert.equal(api.trigger, '/ui-ux-master');
|
|
73
|
+
assert.equal(api.bins.cli, bin);
|
|
74
|
+
assert.equal(api.bins.mcp, mcpBin);
|
|
75
|
+
assert.equal(api.assetPath('skill'), path.join(root, 'SKILL.md'));
|
|
76
|
+
assert.throws(() => api.assetPath('missing'), /Unknown ui-ux-master asset/);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
43
80
|
test('agent templates include trigger and avoid local absolute paths', () => {
|
|
44
81
|
for (const rel of templates) {
|
|
45
82
|
const text = fs.readFileSync(path.join(root, rel), 'utf8');
|
|
83
|
+
|
|
46
84
|
assert.match(text, /\/ui-ux-master/);
|
|
47
85
|
assert.match(text, /\.ui-ux-master\/SKILL\.md|\.ui-ux-master\/|\.ui-ux-master/);
|
|
48
86
|
assert.match(text, /UI\/UX|ui-ux-master/i);
|
|
@@ -59,26 +97,38 @@ test('discovery assets and system prompts exist', () => {
|
|
|
59
97
|
'system-prompts/ui-ux-master-mcp-add-on.md',
|
|
60
98
|
'docs/mcp-server.md',
|
|
61
99
|
];
|
|
100
|
+
|
|
62
101
|
for (const rel of required) {
|
|
63
102
|
const text = fs.readFileSync(path.join(root, rel), 'utf8');
|
|
64
103
|
assert.match(text, /\/ui-ux-master/);
|
|
65
104
|
}
|
|
66
|
-
|
|
105
|
+
|
|
106
|
+
const manifest = JSON.parse(
|
|
107
|
+
fs.readFileSync(path.join(root, 'ai-discovery/ui-ux-master.manifest.json'), 'utf8')
|
|
108
|
+
);
|
|
109
|
+
|
|
67
110
|
assert.equal(manifest.author, 'Rupak Biswas');
|
|
68
111
|
assert.equal(manifest.activation.trigger, '/ui-ux-master');
|
|
69
112
|
assert.equal(manifest.entrypoints.mcp_server_bin, 'ui-ux-master-mcp');
|
|
70
113
|
});
|
|
71
114
|
|
|
72
115
|
test('cli help doctor and where work', () => {
|
|
73
|
-
|
|
74
|
-
assert.match(
|
|
75
|
-
|
|
116
|
+
const help = run(['--help']);
|
|
117
|
+
assert.match(help, /ui-ux-master/i);
|
|
118
|
+
|
|
119
|
+
const doctor = run(['doctor', '--dry-run']);
|
|
120
|
+
assert.match(doctor, /package root|target root|ok SKILL\.md/i);
|
|
121
|
+
|
|
122
|
+
const where = run(['where']);
|
|
123
|
+
assert.match(where.trim(), /UI[-\s]UX[-\s]Skills|ui-ux-master/i);
|
|
76
124
|
});
|
|
77
125
|
|
|
78
126
|
test('project install dry-run does not write', () => {
|
|
79
127
|
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'ui-ux-master-dry-'));
|
|
80
128
|
fs.writeFileSync(path.join(dir, 'package.json'), '{}');
|
|
129
|
+
|
|
81
130
|
const out = run(['install', '--project', '--dry-run', '--dir', dir]);
|
|
131
|
+
|
|
82
132
|
assert.match(out, /dry-run/);
|
|
83
133
|
assert.equal(fs.existsSync(path.join(dir, 'AGENTS.md')), false);
|
|
84
134
|
});
|
|
@@ -86,8 +136,10 @@ test('project install dry-run does not write', () => {
|
|
|
86
136
|
test('project install writes expected files and is idempotent', () => {
|
|
87
137
|
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'ui-ux-master-install-'));
|
|
88
138
|
fs.writeFileSync(path.join(dir, 'package.json'), '{}');
|
|
139
|
+
|
|
89
140
|
run(['install', '--project', '--dir', dir]);
|
|
90
141
|
run(['install', '--project', '--dir', dir]);
|
|
142
|
+
|
|
91
143
|
assert.ok(fs.existsSync(path.join(dir, '.ui-ux-master', 'SKILL.md')));
|
|
92
144
|
assert.ok(fs.existsSync(path.join(dir, '.ui-ux-master', 'llms.txt')));
|
|
93
145
|
assert.ok(fs.existsSync(path.join(dir, '.ui-ux-master', 'ai-discovery', 'ui-ux-master.manifest.json')));
|
|
@@ -98,7 +150,9 @@ test('project install writes expected files and is idempotent', () => {
|
|
|
98
150
|
assert.ok(fs.existsSync(path.join(dir, 'AGENTS.md')));
|
|
99
151
|
assert.ok(fs.existsSync(path.join(dir, '.windsurf', 'rules', 'ui-ux-master.md')));
|
|
100
152
|
assert.ok(fs.existsSync(path.join(dir, 'GEMINI.md')));
|
|
153
|
+
|
|
101
154
|
const agents = fs.readFileSync(path.join(dir, 'AGENTS.md'), 'utf8');
|
|
155
|
+
|
|
102
156
|
assert.equal((agents.match(/ui-ux-master:start/g) || []).length, 1);
|
|
103
157
|
assert.match(agents, /\.ui-ux-master\/SKILL\.md/);
|
|
104
158
|
assert.match(agents, /\/ui-ux-master/);
|
|
@@ -110,8 +164,19 @@ test('mcp server lists tools resources prompts and can return the skill', () =>
|
|
|
110
164
|
{ jsonrpc: '2.0', id: 2, method: 'tools/list', params: {} },
|
|
111
165
|
{ jsonrpc: '2.0', id: 3, method: 'resources/list', params: {} },
|
|
112
166
|
{ jsonrpc: '2.0', id: 4, method: 'prompts/list', params: {} },
|
|
113
|
-
{
|
|
167
|
+
{
|
|
168
|
+
jsonrpc: '2.0',
|
|
169
|
+
id: 5,
|
|
170
|
+
method: 'tools/call',
|
|
171
|
+
params: {
|
|
172
|
+
name: 'get_asset',
|
|
173
|
+
arguments: {
|
|
174
|
+
name: 'system_prompt',
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
},
|
|
114
178
|
]);
|
|
179
|
+
|
|
115
180
|
assert.equal(responses[0].result.serverInfo.name, 'ui-ux-master');
|
|
116
181
|
assert.ok(responses[1].result.tools.some(t => t.name === 'generate_system_prompt'));
|
|
117
182
|
assert.ok(responses[2].result.resources.some(r => r.uri === 'ui-ux-master://skill'));
|
|
@@ -122,10 +187,26 @@ test('mcp server lists tools resources prompts and can return the skill', () =>
|
|
|
122
187
|
|
|
123
188
|
test('mcp server handles prompt retrieval and unknown methods correctly', () => {
|
|
124
189
|
const responses = runMcp([
|
|
125
|
-
{
|
|
126
|
-
|
|
190
|
+
{
|
|
191
|
+
jsonrpc: '2.0',
|
|
192
|
+
id: 1,
|
|
193
|
+
method: 'prompts/get',
|
|
194
|
+
params: {
|
|
195
|
+
name: 'ui-ux-design-system',
|
|
196
|
+
arguments: {
|
|
197
|
+
scope: 'admin dashboard',
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
jsonrpc: '2.0',
|
|
203
|
+
id: 2,
|
|
204
|
+
method: 'not/a-method',
|
|
205
|
+
params: {},
|
|
206
|
+
},
|
|
127
207
|
]);
|
|
208
|
+
|
|
128
209
|
assert.match(responses[0].result.messages[0].content.text, /\/ui-ux-master/);
|
|
129
210
|
assert.match(responses[0].result.messages[0].content.text, /admin dashboard/);
|
|
130
211
|
assert.equal(responses[1].error.code, -32601);
|
|
131
|
-
});
|
|
212
|
+
});
|