noslopui 0.2.0 → 0.3.1

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 CHANGED
@@ -59,9 +59,9 @@ Anything else that speaks MCP over HTTP can be connected by hand — add `https:
59
59
 
60
60
  | | |
61
61
  |---|---|
62
- | `npx noslopui search <query>` | Search components and blocks (`--tag style:editorial`, `--framework`, `--limit`) |
62
+ | `npx noslopui search <query>` | Search UI blocks and Motion Lab effects (`--section ui-blocks\|motion-lab`, `--tag style:editorial`, `--limit`) |
63
63
  | `npx noslopui get <id>` | Print a component's code, or `--write src/Hero.tsx` (`--format tsx\|html\|vue`) |
64
- | `npx noslopui prompt <id>` | Print a component's AI-prompt version |
64
+ | `npx noslopui prompt <id>` | Print a ready-to-paste prompt with a component's code |
65
65
  | `npx noslopui design-systems [query]` | Search design systems (`--tag theme:dark`) |
66
66
  | `npx noslopui design-system <id>` | Print a DESIGN.md, or `--write DESIGN.md` |
67
67
  | `npx noslopui collections` | Your saved collections |
package/SKILL.md CHANGED
@@ -3,243 +3,317 @@ name: noslopui
3
3
  description: Build a stunning, non-generic UI using noslopUI's hand-crafted catalog over MCP — either from a collection the user curated themselves, or by choosing one Design System and applying it consistently across every component. Use when asked to build a landing page, dashboard, marketing site, or any new page/section from scratch, when the user mentions a noslopUI collection, or when a UI you're building looks like "AI slop" (gradient text, purple-on-purple, bounce easing, everything centered) and needs a real design system instead.
4
4
  ---
5
5
 
6
- # noslopUI
7
-
8
- You have access to the **noslopUI MCP server** — a catalog of hand-crafted (not
9
- AI-generated) UI components, full page examples, and portable Design Systems.
10
-
6
+ # noslopUI
7
+
8
+ You have access to the **noslopUI MCP server** — a catalog of hand-crafted (not
9
+ AI-generated) UI components, full page examples, and portable Design Systems.
10
+
11
11
  ## The rules
12
12
 
13
13
  1. **Choose one design system before fetching any component, then restyle every component to it** — colours, type scale, spacing, radius, motion. One system applied everywhere is what stops a multi-page build reading as a collage.
14
- 2. **Search the whole catalog on fit.** A design system is a set of rules, not an inventory of parts: any component can be built in any system, so nothing is off-limits once one is chosen.
14
+ 2. **Search the catalog before hand-building a section, not instead of hand-building it.** Check `search_components` for every required section first — having the design system's tokens and prose isn't a reason to skip that, and any component can be built in any system, so nothing is off-limits once one is chosen. Only build a section yourself if nothing in the catalog fits it, and tell the user that's what happened.
15
15
  3. **Never substitute a catalog component for one the user explicitly saved** in a collection. Their pick was a decision, not an oversight.
16
16
  4. **Ask about their brand before building** — logo, brand colours, typeface, real photography. Put their values into the system's tokens (their colour replaces `accent`) and keep the system's rules.
17
- 5. **Check for a collection first:** call `list_collections`. If one fits the request, build from it. If none fits, don't guess a collection — shortlist two or three design systems with `search_design_systems` and let the user pick.
17
+ 5. **A collection existing is not the same as the user asking for it.** `list_collections` is free to call, but only build from what it returns when the user asked for their saved items by name or in substance, or confirmed it when you asked. The default "Favorites" list is just where the save button drops a single item with zero setup — a lone design system sitting in it is not a decision to build the whole thing around. One collection with content and no explicit ask → surface it as a question, don't assume either answer. Nothing confirmed → shortlist two or three design systems with `search_design_systems` and let the user pick.
18
18
  6. **If a gated tool says the trial has ended or the fair-use limit is reached, tell the user and stop** — don't retry, and don't swap in something generated from scratch.
19
-
20
- Setup, if the noslopUI tools aren't available: the user runs
21
- `npx noslopui@latest init`, or adds `https://noslopui.com/api/mcp` in their
22
- agent and signs in when it asks (steps for each agent: `noslopui.com/mcp`).
23
- Every call runs as the user's account. Search, metadata and collections are
24
- free on every account. Code, prompts and DESIGN.md files need a paid plan or
25
- the account's free 3-day trial, which the first such call starts.
26
-
27
- ---
28
-
29
- ## Step 0 — Which path?
30
-
31
- **Call `list_collections` first.** It's free on every account.
32
-
33
- - A relevant collection exists → **Path A**. The user already did the choosing.
34
- - No collection, or nothing relevant → **Path B**.
35
-
36
- Several collections and no obvious match → ask. Don't guess between two curated
37
- sets.
38
-
39
- ---
40
-
41
- ## Step 1 — Requirements, including brand
42
-
43
- Do this on both paths, before choosing a system. Two groups of things.
44
-
45
- **The build:**
46
-
47
- 1. **Purpose** — what is this for? (SaaS product, local service business,
48
- portfolio, storefront, internal dashboard, docs site, …)
49
- 2. **Audience** — who is it for?
50
- 3. **Tone** — 2-3 words ("calm and minimal", "bold and playful", "editorial and
51
- serif-driven", "warm and local"). This is what Step 2 matches against.
52
- 4. **Required sections** — the concrete list of what must exist.
53
-
54
- **Their brand** — skip this and you ship a beautiful page that isn't theirs:
55
-
56
- 5. **Logo or wordmark** — do they have one, and in what format?
57
- 6. **Brand colours** — hex values if they have them, and whether they are fixed
58
- (a franchise or a rebrand-in-progress changes the answer).
59
- 7. **Existing typeface** — anything already in use they need to stay with?
60
- 8. **Photography or illustration** — real assets to work from, or
61
- placeholder-and-replace-later?
62
- 9. **An existing site or profile** to stay consistent with.
63
-
64
- No brand at all → say so plainly and use the design system's own palette. Don't
65
- invent a logo.
66
-
67
- If the user already stated all this, don't re-ask — restate it in one line and
68
- move on.
69
-
70
- ---
71
-
72
- ## Path A — the user curated a collection
73
-
74
- `get_collection({ listId })` (or `name`). Every item carries a `kind` —
75
- `design_systems` or `ui_blocks` — plus a top-level `designSystems` array and a
76
- `guidance` line.
77
-
78
- 1. **The collection's design system wins.** One in it → that is the system, no
79
- searching; `get_design_system_file` for its DESIGN.md. More than one → ask
80
- which; they saved both deliberately. None → say so, choose one as in Path B,
81
- and tell them which and why.
82
- 2. **Cover each required section from the collection first.** If the user saved
83
- something that covers a section, use it. Always. **Never substitute a
84
- catalog component for one they explicitly saved**, even if you found
85
- something you think is better — that was their call, not an oversight.
86
- 3. **Fill the gaps with `search_components`**, searching the whole catalog on
87
- fit, and restyle what you find to the collection's design system.
88
- 4. **Report what you filled in.** "Hero, pricing and footer from your
89
- collection; you had no testimonial section saved, so I pulled one from the
90
- catalog and restyled it." They should never have to diff the result to find
91
- out what they didn't choose.
92
-
93
- Continue to Step 3.
94
-
95
- ---
96
-
97
- ## Path B — you choose
98
-
99
- ### B1. Shortlist design systems, then ask
100
-
101
- Design systems are classified by **tag**, not by category — there is no tree to
102
- walk. Call `search_design_systems` with no arguments first if you don't know
103
- what exists: it returns every system plus `availableTags`, the full filterable
104
- vocabulary (`theme:`, `style:`, `industry:` and so on).
105
-
106
- Then filter with `tags` (ANDed) and/or a free-text `query` built from the tone
107
- words plus purpose:
108
-
109
- ```
110
- search_design_systems({ tags: ["theme:light", "industry:local-business"] })
111
- search_design_systems({ query: "calm minimal saas", tags: ["theme:light"] })
112
- ```
113
-
114
- A system can carry several `industry:` tags — a developer-tools system is
115
- often a SaaS system too — so don't treat one tag as excluding the others.
116
-
117
- Every result comes back with its tags, its token summary (colours, fonts,
118
- radius) and a `previewUrl`. **Present the 2-3 best matches to the user with
119
- their names, one-line descriptions, palettes and preview URLs, and ask which
120
- they want.** Don't pick silently. This single choice shapes every screen, it
121
- costs one question, and the user has taste you cannot infer from "a roofing
122
- business".
123
-
124
- Then `get_design_system` on their pick for the ungated token summary, and
125
- `get_design_system_file` for the full DESIGN.md.
126
-
127
- If nothing matches well, say so and ask whether to go with the closest or with
128
- a system they describe by hand — don't quietly fall back to stock Tailwind
129
- defaults, which is the "AI slop" this workflow exists to avoid.
130
-
131
- **Read the whole DESIGN.md before fetching any component.** It's short by
132
- design — tokens plus a page or two of intent prose, meant to be held in context
133
- for the entire build. Its **Do's and Don'ts** section is the part doing the real
134
- work.
135
-
136
- ### B2. Find components on fit
137
-
138
- For each required section, call `search_components` — `section`, `framework`
139
- and `tags` filters as needed, with `tags` ANDed the same way
140
- (`["style:editorial"]`, `["animation:carousel"]`). Pick the best
141
- **structural** match: the thing that actually does what the section needs.
142
- Largely ignore how it currently looks; you are restyling it regardless.
143
-
144
- Then `get_component_code` for the ones you'll use.
145
-
146
- ---
147
-
148
- ## Step 3 — Apply the system, and fit the brand into it
149
-
150
- Two moves, in this order.
151
-
152
- **A. Restyle everything to the design system.** Same colour variables, same type
153
- scale, same radius, same spacing scale, same motion durations and easing, across
154
- every component. Where a fetched component's own defaults conflict with the
155
- system, the system wins — adapt the component, and never leave both looks in
156
- play at once.
157
-
158
- **B. Substitute the brand into the system's tokens.** This is what makes the
159
- result *theirs* rather than a nice demo:
160
-
161
- - Their primary colour replaces the system's `accent` token. A secondary, if
162
- they have one, replaces a supporting token — not a second accent.
163
- - Their wordmark typeface replaces the `display` face if it suits headlines.
164
- Body text stays the system's text face unless they insist.
165
- - Their photography replaces placeholder imagery at the same crops and ratios.
166
-
167
- **Substitute values, keep the rules.** The system's spacing scale, radius
168
- discipline, contrast requirements and "one accent moment per screen" all still
169
- apply after the swap — that is the point of a system: it survives a brand
170
- change. A roofing company's green goes where the indigo was, and the restraint
171
- around it is unchanged.
172
-
173
- **Check contrast after substituting.** A brand colour that fails the system's
174
- stated contrast pairs is a real problem: tell the user, propose a darker or
175
- lighter variant of their colour for text, and keep the original for large
176
- fills. Don't silently ship unreadable text because it was their hex.
177
-
178
- DESIGN.md files follow the open [DESIGN.md
179
- format](https://github.com/google-labs-code/design.md): YAML front matter with
180
- machine-readable tokens (`colors`, `typography`, `rounded`, `spacing`,
181
- `components`, with `{colors.accent}` references already resolved), then prose
182
- sections. Take concrete values from the front matter and the rules from the
183
- prose.
184
-
185
- ## Step 4 — Polish pass (before calling anything done)
186
-
187
- Run this against the assembled result. These are the "AI slop" tells noslopUI
188
- exists to avoid — catch them here rather than shipping them:
189
-
190
- - **Typography** — one display face used sparingly (headlines only, not buttons
191
- or body), one text face for everything else. Nothing outside the DESIGN.md's
192
- stated scale.
193
- - **Color/contrast** — one accent moment per screen, not accent bleeding into
194
- every icon, border and badge. Real contrast on text over any background,
195
- checked against the DESIGN.md's own stated pairs.
196
- - **Spacing** — compose from the DESIGN.md's spacing scale; don't invent
197
- in-between values. Prefer more whitespace over a denser grid.
198
- - **Motion** — only where it communicates a real state change; the DESIGN.md's
199
- durations and easing, never a default bounce or spring.
200
- - **Named slop-tells to actively reject**: gradient text, purple-on-purple
201
- palettes, bounce/spring easing on everything, every layout centered with no
202
- asymmetry, decorative-only animation.
203
-
204
- ## Step 5 — Point back to the catalog for variations
205
-
206
- If the result doesn't land, don't re-prompt the same component blind. Point the
207
- user at `noslopui.com/explore` (cross-catalog search across UI Blocks and
208
- Design Systems in one grid) to browse real alternatives, and at the
209
- Collections tab on `noslopui.com/account` to save the ones they like — which
210
- turns the next build into Path A. Then repeat from Step 3 with whatever they
211
- pick.
212
-
213
- ---
214
-
215
- ## Quick reference — tool call shape
216
-
217
- ```
218
- list_collections({}) -> { collections: [{ id, name, itemCount }] }
219
- get_collection({ listId?, name? }) -> { collection, designSystems: [{id,name}], items: [{ id, name, kind, ... }], guidance }
220
-
221
- search_design_systems({ query?, tags?, tag?, limit? }) -> { results: [{ id, name, description, tags, tokens, previewUrl, url }], availableTags }
222
- get_design_system({ id }) -> { id, name, tokens, previewUrl, detailUrl }
223
- get_design_system_file({ id }) -> { id, name, designMd } [gated: paid or trial]
224
-
225
- search_components({ query?, section?, framework?, tags?, tag?, limit? }) -> { results: [{ id, name, kind, tags, url }] }
226
- get_component({ id }) -> { id, name, dependencies, builtWithDesignSystem, previewUrl, detailUrl }
227
- get_component_code({ id }) -> { id, name, snippets: [{ language, code }] } [gated: paid or trial]
228
- get_component_prompt({ id }) -> { id, name, promptText } [gated: paid or trial]
229
- ```
230
-
231
- The account rides on the connection (a key or a sign-in, sent as the
232
- `Authorization` header), so no tool takes a credential argument. Every search, metadata and collection tool is free on
233
- every account; `get_design_system_file`, `get_component_code` and
234
- `get_component_prompt` need the account on a paid plan or inside its free
235
- 3-day trial.
236
-
237
- - If a gated call's result carries a `trial` field, that call just started the
238
- user's trial — tell them, with the end date it gives.
239
- - A trial covers up to 30 different items per 24 hours, far more than one site
240
- needs. Fetch what the build uses, not the catalog speculatively; re-fetching
241
- an item you already opened never counts again.
242
- - If a gated call says the trial has ended (or the fair-use limit is reached),
243
- stop and tell the user plainly — don't retry, and don't quietly swap in
244
- something generated from scratch in its place. Search and collections keep
19
+ 7. **A Motion Lab effect is a signature moment, not a section.** Reach for one (`search_components` with `section: "motion_lab"`) when the user asks for an effect, motion, 3D or a showpiece, or the brief clearly calls for one — then use one per page unless they ask for more. Recolour it through its `colorVars` to the design system's tokens, follow its `usage`, and keep its reduced-motion fallback.
20
+
21
+ Setup, if the noslopUI tools aren't available: the user runs
22
+ `npx noslopui@latest init`, or adds `https://noslopui.com/api/mcp` in their
23
+ agent and signs in when it asks (steps for each agent: `noslopui.com/mcp`).
24
+ Every call runs as the user's account. Search, metadata and collections are
25
+ free on every account. Code, prompts and DESIGN.md files need a paid plan or
26
+ the account's free 3-day trial, which the first such call starts.
27
+
28
+ ---
29
+
30
+ ## Step 0 — Which path?
31
+
32
+ **Call `list_collections` first.** It's free on every account. But a
33
+ collection existing is not the same as the user asking you to build from it —
34
+ the default "Favorites" list is just where the save button puts a single item
35
+ with zero setup, so a design system sitting there alone is very often a saved
36
+ reference, not a decision. Don't let its mere presence override what the user
37
+ actually asked for.
38
+
39
+ - The user already said to use their saved items ("build from my collection",
40
+ "use what I've saved", names a list by name) → **Path A**, no need to ask.
41
+ - Nothing was said either way, but exactly one collection has content that
42
+ looks relevant → **ask**: name what's in it and let them choose Path A or
43
+ Path B. Don't assume silently in either direction.
44
+ - No collection, or nothing in any of them fits → **Path B**.
45
+ - Several collections and no obvious match → ask which one. Don't guess
46
+ between two curated sets.
47
+
48
+ ---
49
+
50
+ ## Step 1 — Requirements, including brand
51
+
52
+ Do this on both paths, before choosing a system. Two groups of things.
53
+
54
+ **The build:**
55
+
56
+ 1. **Purpose** — what is this for? (SaaS product, local service business,
57
+ portfolio, storefront, internal dashboard, docs site, …)
58
+ 2. **Audience** — who is it for?
59
+ 3. **Tone** — 2-3 words ("calm and minimal", "bold and playful", "editorial and
60
+ serif-driven", "warm and local"). This is what Step 2 matches against.
61
+ 4. **Required sections** — the concrete list of what must exist.
62
+
63
+ **Their brand** — skip this and you ship a beautiful page that isn't theirs:
64
+
65
+ 5. **Logo or wordmark** — do they have one, and in what format?
66
+ 6. **Brand colours** — hex values if they have them, and whether they are fixed
67
+ (a franchise or a rebrand-in-progress changes the answer).
68
+ 7. **Existing typeface** — anything already in use they need to stay with?
69
+ 8. **Photography or illustration** — real assets to work from, or
70
+ placeholder-and-replace-later?
71
+ 9. **An existing site or profile** to stay consistent with.
72
+
73
+ No brand at all → say so plainly and use the design system's own palette. Don't
74
+ invent a logo.
75
+
76
+ No real photography → don't ship a grey box. Use a seeded placeholder from
77
+ [Picsum](https://picsum.photos) — `https://picsum.photos/seed/<brand-slug>-<slot-name>/<w>/<h>`
78
+ — so the same build gets the same photo on every regenerate instead of a new
79
+ random one. Mark every one with `<!-- TODO: Replace with real photo, target
80
+ size <w>x<h> -->` immediately above it, and write alt text for the *intended*
81
+ subject ("Hand-poured ceramic mug, studio lighting"), not the placeholder
82
+ ("Picsum image"), so it's already correct once they swap it in. Skip
83
+ photography altogether where the chosen design system's own register is
84
+ photo-free (type-led, editorial, most SaaS) rather than forcing a stock photo
85
+ in where the system doesn't call for one.
86
+
87
+ If the user already stated all this, don't re-ask — restate it in one line and
88
+ move on.
89
+
90
+ ---
91
+
92
+ ## Path A — the user curated a collection
93
+
94
+ `get_collection({ listId })` (or `name`). Every item carries a `kind` —
95
+ `design_systems`, `ui_blocks` or `motion_lab` (an effect) — plus a top-level
96
+ `designSystems` array and a `guidance` line. A saved effect is a pick like any
97
+ other: use it where it fits, restyled as in Step 3.
98
+
99
+ 1. **The collection's design system wins.** One in it → that is the system, no
100
+ searching; `get_design_system_file` for its DESIGN.md. More than one → ask
101
+ which; they saved both deliberately. None → say so, choose one as in Path B,
102
+ and tell them which and why.
103
+ 2. **Cover each required section from the collection first.** If the user saved
104
+ something that covers a section, use it. Always. **Never substitute a
105
+ catalog component for one they explicitly saved**, even if you found
106
+ something you think is better — that was their call, not an oversight.
107
+ 3. **Fill the gaps with `search_components`, checked before you hand-build
108
+ anything.** Search the whole catalog on fit, and restyle what you find to
109
+ the collection's design system. Only build a gap section yourself if
110
+ nothing in the catalog fits it, and say so in step 4's report.
111
+ 4. **Report what you filled in.** "Hero, pricing and footer from your
112
+ collection; you had no testimonial section saved, so I pulled one from the
113
+ catalog and restyled it." They should never have to diff the result to find
114
+ out what they didn't choose.
115
+
116
+ Continue to Step 3.
117
+
118
+ ---
119
+
120
+ ## Path B — you choose
121
+
122
+ ### B1. Shortlist design systems, then ask
123
+
124
+ Design systems are classified by **tag**, not by category — there is no tree to
125
+ walk. Call `search_design_systems` with no arguments first if you don't know
126
+ what exists: it returns every system plus `availableTags`, the full filterable
127
+ vocabulary (`theme:`, `style:`, `industry:` and so on).
128
+
129
+ Then filter with `tags` (ANDed) and/or a free-text `query` built from the tone
130
+ words plus purpose:
131
+
132
+ ```
133
+ search_design_systems({ tags: ["industry:hair-beauty"] })
134
+ search_design_systems({ tags: ["industry:dentist", "theme:light"] })
135
+ search_design_systems({ query: "calm minimal", tags: ["industry:saas"] })
136
+ ```
137
+
138
+ `industry:` is a two-level tree, shaped like a template marketplace's: a
139
+ **field** (`food-drink`, `medical`, `home-services`, `technology`…) and, under
140
+ it, **niches** (`restaurant`, `dentist`, `roofing`, `saas`…). Every system
141
+ tagged with a niche is also tagged with its field, so start with the niche if
142
+ the brief names one and widen to the field when that returns fewer than three.
143
+
144
+ **"Local business" is not an industry — name the trade.** A plumber is
145
+ `home-services`, a barber `hair-beauty`, a café `food-drink`, a physio
146
+ `medical`, a yoga studio `wellness`, an accountant `professional-services`.
147
+ Each of those looks and reads differently, and filtering on the specific field
148
+ is what keeps two local businesses from getting the same site.
149
+
150
+ A system can carry several fields — a warm serif system serves a restaurant, a
151
+ wedding planner and a spa alike — so don't treat one tag as excluding the
152
+ others, and don't pick the same system for every brief in a field: read the
153
+ descriptions and match the tone the user described.
154
+
155
+ Every result comes back with its tags, its token summary (colours, fonts,
156
+ radius) and a `previewUrl`. **Present the 2-3 best matches to the user with
157
+ their names, one-line descriptions, palettes and preview URLs, and ask which
158
+ they want.** Don't pick silently. This single choice shapes every screen, it
159
+ costs one question, and the user has taste you cannot infer from "a roofing
160
+ business".
161
+
162
+ Then `get_design_system` on their pick for the ungated token summary, and
163
+ `get_design_system_file` for the full DESIGN.md.
164
+
165
+ If nothing matches well, say so and ask whether to go with the closest or with
166
+ a system they describe by hand — don't quietly fall back to stock Tailwind
167
+ defaults, which is the "AI slop" this workflow exists to avoid.
168
+
169
+ **Read the whole DESIGN.md before fetching any component.** It's short by
170
+ design — tokens plus a page or two of intent prose, meant to be held in context
171
+ for the entire build. Its **Do's and Don'ts** section is the part doing the real
172
+ work.
173
+
174
+ ### B2. Find components on fit
175
+
176
+ **Never write a section's markup from scratch before checking the catalog.**
177
+ Having the DESIGN.md in hand is not the same as being done searching — for
178
+ *every* required section, call `search_components` first — `section` and
179
+ `tags` filters as needed, with `tags` ANDed the same way (`["style:editorial"]`,
180
+ `["animation:carousel"]`). Pick the best **structural** match: the thing that
181
+ actually does what the section needs. Largely ignore how it currently looks;
182
+ you are restyling it regardless. Only once nothing in the catalog fits a
183
+ section is hand-building it acceptable — and say so, don't pass it off as a
184
+ catalog pick.
185
+
186
+ Every result is published as React/TSX with Tailwind classes, whatever stack
187
+ the build target is. That's not a limitation — the markup and styling aren't
188
+ React-specific, so converting a result to plain HTML, Vue, or anything else is
189
+ a mechanical step (`className` to `class`, drop event-handler props, etc.),
190
+ not a rebuild. Never skip a structurally-right component, or conclude the
191
+ catalog has nothing for a non-React project, over its source format.
192
+
193
+ **Effects are a separate kind.** `section: "motion_lab"` searches Motion Lab:
194
+ shader backgrounds, 3D, liquid glass, text, cursor and scroll effects. An
195
+ effect isn't a section of the page — it's the one moment people remember the
196
+ page for. Use one where the brief asks for it (an effect, motion, 3D, "make it
197
+ pop") or clearly calls for a showpiece, and one per page unless the user asks
198
+ for more. `get_component` tells you how: `usage` says where it earns its
199
+ place, `props` are its knobs, `colorVars` are the CSS custom properties its
200
+ colours come from, and `libraries` are the exact npm packages and versions to
201
+ install.
202
+
203
+ Then `get_component_code` for the ones you'll use.
204
+
205
+ ---
206
+
207
+ ## Step 3 — Apply the system, and fit the brand into it
208
+
209
+ Two moves, in this order.
210
+
211
+ **A. Restyle everything to the design system.** Same colour variables, same type
212
+ scale, same radius, same spacing scale, same motion durations and easing, across
213
+ every component. Where a fetched component's own defaults conflict with the
214
+ system, the system wins — adapt the component, and never leave both looks in
215
+ play at once.
216
+
217
+ **B. Substitute the brand into the system's tokens.** This is what makes the
218
+ result *theirs* rather than a nice demo:
219
+
220
+ - Their primary colour replaces the system's `accent` token. A secondary, if
221
+ they have one, replaces a supporting token — not a second accent.
222
+ - Their wordmark typeface replaces the `display` face if it suits headlines.
223
+ Body text stays the system's text face unless they insist.
224
+ - Their photography replaces placeholder imagery at the same crops and ratios.
225
+
226
+ **C. Effects take the system's colours through their variables.** A Motion
227
+ Lab effect exposes each colour as a CSS custom property (`colorVars`, e.g.
228
+ `--ml-accent`) and as a prop. Set those from the system's tokens — the brand
229
+ accent, the darkest surface — and tune its `props` toward the system's motion
230
+ rules (slower if the system is calm). Never recolour inside a shader or
231
+ script, and never remove its reduced-motion fallback.
232
+
233
+ **Substitute values, keep the rules.** The system's spacing scale, radius
234
+ discipline, contrast requirements and "one accent moment per screen" all still
235
+ apply after the swap — that is the point of a system: it survives a brand
236
+ change. A roofing company's green goes where the indigo was, and the restraint
237
+ around it is unchanged.
238
+
239
+ **Check contrast after substituting.** A brand colour that fails the system's
240
+ stated contrast pairs is a real problem: tell the user, propose a darker or
241
+ lighter variant of their colour for text, and keep the original for large
242
+ fills. Don't silently ship unreadable text because it was their hex.
243
+
244
+ DESIGN.md files follow the open [DESIGN.md
245
+ format](https://github.com/google-labs-code/design.md): YAML front matter with
246
+ machine-readable tokens (`colors`, `typography`, `rounded`, `spacing`,
247
+ `components`, with `{colors.accent}` references already resolved), then prose
248
+ sections. Take concrete values from the front matter and the rules from the
249
+ prose.
250
+
251
+ ## Step 4 — Polish pass (before calling anything done)
252
+
253
+ Run this against the assembled result. These are the "AI slop" tells noslopUI
254
+ exists to avoid — catch them here rather than shipping them:
255
+
256
+ - **Typography** — one display face used sparingly (headlines only, not buttons
257
+ or body), one text face for everything else. Nothing outside the DESIGN.md's
258
+ stated scale.
259
+ - **Color/contrast** — one accent moment per screen, not accent bleeding into
260
+ every icon, border and badge. Real contrast on text over any background,
261
+ checked against the DESIGN.md's own stated pairs.
262
+ - **Spacing** — compose from the DESIGN.md's spacing scale; don't invent
263
+ in-between values. Prefer more whitespace over a denser grid.
264
+ - **Motion** — only where it communicates a real state change; the DESIGN.md's
265
+ durations and easing, never a default bounce or spring. The one exception is
266
+ a Motion Lab effect placed where its `usage` says it earns its place — one
267
+ per page, recoloured to the system.
268
+ - **Named slop-tells to actively reject**: gradient text, purple-on-purple
269
+ palettes, bounce/spring easing on everything, every layout centered with no
270
+ asymmetry, decorative-only animation.
271
+
272
+ ## Step 5 — Point back to the catalog for variations
273
+
274
+ If the result doesn't land, don't re-prompt the same component blind. Point the
275
+ user at `noslopui.com/explore` (every UI block in one grid, with Motion Lab and
276
+ design-system shelves) to browse real alternatives, and at the
277
+ Collections tab on `noslopui.com/account` to save the ones they like — which
278
+ turns the next build into Path A. Then repeat from Step 3 with whatever they
279
+ pick.
280
+
281
+ ---
282
+
283
+ ## Quick reference — tool call shape
284
+
285
+ ```
286
+ list_collections({}) -> { collections: [{ id, name, itemCount }] }
287
+ get_collection({ listId?, name? }) -> { collection, designSystems: [{id,name}], items: [{ id, name, kind, ... }], guidance }
288
+
289
+ search_design_systems({ query?, tags?, tag?, limit? }) -> { results: [{ id, name, description, tags, tokens, previewUrl, url }], availableTags, industryTree }
290
+ get_design_system({ id }) -> { id, name, tokens, previewUrl, detailUrl }
291
+ get_design_system_file({ id }) -> { id, name, designMd } [gated: paid or trial]
292
+
293
+ search_components({ query?, section?, tags?, tag?, limit? }) -> { results: [{ id, name, kind, tags, url }] }
294
+ get_component({ id }) -> { id, name, dependencies, builtWithDesignSystem, previewUrl, detailUrl }
295
+ motion_lab items add { usage, props, colorVars, libraries }
296
+ get_component_code({ id }) -> { id, name, snippets: [{ language, code }] } [gated: paid or trial]
297
+ get_component_prompt({ id }) -> { id, name, promptText } [gated: paid or trial]
298
+ ```
299
+
300
+ `promptText` is the component's full code wrapped in integration
301
+ instructions (stack, file path, pinned dependencies, fonts, the design system it
302
+ was built with). You don't need it to build — `get_component_code` is enough.
303
+ It's for handing one component to a different agent or tool.
304
+
305
+ The account rides on the connection (a key or a sign-in, sent as the
306
+ `Authorization` header), so no tool takes a credential argument. Every search, metadata and collection tool is free on
307
+ every account; `get_design_system_file`, `get_component_code` and
308
+ `get_component_prompt` need the account on a paid plan or inside its free
309
+ 3-day trial.
310
+
311
+ - If a gated call's result carries a `trial` field, that call just started the
312
+ user's trial — tell them, with the end date it gives.
313
+ - A trial covers up to 30 different items per 24 hours, far more than one site
314
+ needs. Fetch what the build uses, not the catalog speculatively; re-fetching
315
+ an item you already opened never counts again.
316
+ - If a gated call says the trial has ended (or the fair-use limit is reached),
317
+ stop and tell the user plainly — don't retry, and don't quietly swap in
318
+ something generated from scratch in its place. Search and collections keep
245
319
  working, so the plan itself can still be finished.
@@ -13,6 +13,32 @@ import { dirname, resolve } from 'node:path';
13
13
  import { callTool } from '../lib/api.js';
14
14
  import { readSession } from '../lib/session.js';
15
15
  import { color } from '../lib/ui.js';
16
+ // The catalog's two component sections, as search_components names them.
17
+ // Hyphens are accepted too, since that's how they read in URLs.
18
+ const SECTIONS = {
19
+ ui_blocks: 'ui_blocks',
20
+ 'ui-blocks': 'ui_blocks',
21
+ blocks: 'ui_blocks',
22
+ motion_lab: 'motion_lab',
23
+ 'motion-lab': 'motion_lab',
24
+ effects: 'motion_lab',
25
+ };
26
+ /** search_components arguments for these options; throws on a section it doesn't know. */
27
+ export function searchArguments(options) {
28
+ let section;
29
+ if (options.section !== undefined) {
30
+ section = SECTIONS[options.section.toLowerCase()];
31
+ if (!section)
32
+ throw new Error(`--section takes ui-blocks or motion-lab, not "${options.section}".`);
33
+ }
34
+ return {
35
+ ...(options.args.length ? { query: options.args.join(' ') } : {}),
36
+ ...(section ? { section } : {}),
37
+ ...(options.tags.length ? { tags: options.tags } : {}),
38
+ ...(options.framework ? { framework: options.framework } : {}),
39
+ ...(options.limit ? { limit: options.limit } : {}),
40
+ };
41
+ }
16
42
  const out = (s = '') => process.stdout.write(`${s}\n`);
17
43
  const note = (s = '') => process.stderr.write(`${s}\n`);
18
44
  function requireKey() {
@@ -48,13 +74,9 @@ function writeOut(path, text, force) {
48
74
  }
49
75
  const truncate = (s, n) => (s && s.length > n ? `${s.slice(0, n - 1)}…` : s ?? '');
50
76
  export async function search(options) {
77
+ const args = searchArguments(options);
51
78
  const key = requireKey();
52
- const r = check(await callTool(key, 'search_components', {
53
- ...(options.args.length ? { query: options.args.join(' ') } : {}),
54
- ...(options.tags.length ? { tags: options.tags } : {}),
55
- ...(options.framework ? { framework: options.framework } : {}),
56
- ...(options.limit ? { limit: options.limit } : {}),
57
- }));
79
+ const r = check(await callTool(key, 'search_components', args));
58
80
  if (options.json)
59
81
  return out(JSON.stringify(r.data, null, 2)), 0;
60
82
  const results = r.data?.results ?? [];
@@ -63,7 +85,8 @@ export async function search(options) {
63
85
  return 1;
64
86
  }
65
87
  for (const item of results) {
66
- out(`${color.bold(item.name)} ${color.dim(item.id)}`);
88
+ const kind = item.kind === 'motion_lab' ? ` ${color.cyan('Motion Lab')}` : '';
89
+ out(`${color.bold(item.name)} ${color.dim(item.id)}${kind}`);
67
90
  if (item.description)
68
91
  out(` ${truncate(item.description, 110)}`);
69
92
  out(` ${color.cyan(item.url)}`);
package/dist/index.js CHANGED
@@ -37,9 +37,9 @@ ${color.bold('Account')}
37
37
  logout Forget this CLI's sign-in
38
38
 
39
39
  ${color.bold('Catalog')}
40
- search <query> Search components and blocks --tag <facet:value>, --framework, --limit
40
+ search <query> Search blocks and effects --section ui-blocks|motion-lab, --tag <facet:value>, --limit
41
41
  get <id> Print a component's code --format tsx|html|vue, --write <file>
42
- prompt <id> Print a component's AI-prompt version
42
+ prompt <id> Print a ready-to-paste prompt with a component's code
43
43
  design-systems [query] Search design systems --tag theme:dark …
44
44
  design-system <id> Print a design system's DESIGN.md --write DESIGN.md
45
45
  collections List your saved collections
@@ -98,6 +98,8 @@ function parse(argv) {
98
98
  parsed.format = take();
99
99
  else if (flag === '--framework')
100
100
  parsed.framework = take();
101
+ else if (flag === '--section')
102
+ parsed.section = take();
101
103
  else if (flag === '--write' || flag === '-o')
102
104
  parsed.write = take();
103
105
  else if (flag === '--limit') {
@@ -136,6 +138,7 @@ async function main() {
136
138
  ...(args.limit ? { limit: args.limit } : {}),
137
139
  ...(args.format ? { format: args.format } : {}),
138
140
  ...(args.framework ? { framework: args.framework } : {}),
141
+ ...(args.section ? { section: args.section } : {}),
139
142
  ...(args.write ? { write: args.write } : {}),
140
143
  };
141
144
  switch (args.command) {
@@ -1,3 +1,3 @@
1
1
  // One place for the version, so package.json, --version and the User-Agent
2
2
  // can't disagree. Checked against package.json by a test.
3
- export const CLI_VERSION = '0.2.0';
3
+ export const CLI_VERSION = '0.3.1';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "noslopui",
3
- "version": "0.2.0",
4
- "description": "Connect your coding agent to noslopUI \u2014 hand-crafted UI components and portable design systems, over MCP.",
3
+ "version": "0.3.1",
4
+ "description": "Connect your coding agent to noslopUI — hand-crafted UI components and portable design systems, over MCP.",
5
5
  "keywords": [
6
6
  "mcp",
7
7
  "claude-code",