@neuctra/ui-mcp 0.3.1 → 0.4.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
@@ -47,14 +47,14 @@ neuctra-ui-mcp/data/components.json (this package's local copy)
47
47
  │
48
48
  │ read once at server startup
49
49
  ▼
50
- neuctra-ui-mcp/src/server.mjs (defines 4 MCP tools over that data)
50
+ neuctra-ui-mcp/src/server.mjs (defines 5 MCP tools over that data)
51
51
  │
52
52
  │ spoken over stdio (stdin/stdout), JSON-RPC under the hood
53
53
  ▼
54
54
  Claude Code / Cursor / Antigravity / any MCP client
55
55
  ```
56
56
 
57
- Two independently-regenerable files feed the server:
57
+ Three independently-regenerable files feed the server:
58
58
 
59
59
  - **`data/components.json`** — synced from `neuctra-ui-package/registry/components.json`.
60
60
  Never edit this by hand; run `npm run sync-registry` after the upstream file changes.
@@ -64,6 +64,13 @@ Two independently-regenerable files feed the server:
64
64
  the color-token rules ("never hardcode colors"), the anti-AI-look rules ("no
65
65
  gradients/shadows/blurs/glows/emoji-icons"), the recommended `@neuctra/ui-cli init`
66
66
  setup command, and how the standalone `toast()` API works.
67
+ - **`data/aiDesignRules.json`** — also hand-curated, no generator. A 50-section
68
+ product/UX design guide (design philosophy, visual hierarchy, page/sidebar/navigation
69
+ structure, per-component usage guidance, spacing/color/border/radius/shadow
70
+ conventions, responsive design, accessibility, and a final UI quality checklist).
71
+ `theme.json`'s `rules`/`antiAiLookRules` are the mechanical, CSS-level rules; this file
72
+ is the higher-level product-design layer — both are served together by
73
+ `get_design_rules`.
67
74
 
68
75
  ---
69
76
 
@@ -81,14 +88,45 @@ The host starts your server as a subprocess and talks to it over **stdio** — y
81
88
  server's stdout carries JSON-RPC messages, not human-readable logs (that's why
82
89
  `bin/cli.mjs` prints nothing except protocol traffic; use `console.error`, never
83
90
  `console.log`, if you ever add debug output). On connect, the client asks "what tools do
84
- you have?", gets back the 4 tool definitions below, and adds them to the AI's available
91
+ you have?", gets back the 5 tool definitions below, and adds them to the AI's available
85
92
  actions — the same way the tools listed in *this* conversation's system prompt work.
86
93
  From then on, the AI decides on its own when a tool call would help, calls it, and reads
87
94
  the result back into its context before continuing.
88
95
 
89
96
  ---
90
97
 
91
- ## 4. The four tools, in detail
98
+ ## 4. Recommended workflow
99
+
100
+ The tools are designed to be called in roughly this order when generating UI, not
101
+ grabbed ad hoc:
102
+
103
+ 1. **`get_design_rules`** — call this first, before picking any component. It returns
104
+ the styling rules, the anti-AI-look rules, and the 50-section product/UX guide. This
105
+ shapes *what* to build (hierarchy, when a group actually needs `Card`, when `Modal`
106
+ vs `Drawer`, etc.) before you start reaching for components.
107
+ 2. **`get_theme`** — call alongside step 1, not instead of it. Tokens without the design
108
+ rules just tell you which colors exist, not how to use them well.
109
+ 3. **`list_components`** (filtered by category) or **`search_components`** (keyword) —
110
+ confirm which real components exist for what you need. This matters specifically
111
+ because the design guide can describe a *pattern* (e.g. a sidebar nav item) without
112
+ there being a dedicated component for it — don't assume one exists, confirm here.
113
+ 4. **`get_component`** — full spec for every component before writing code against it.
114
+ Do this every time you touch a component you haven't already pulled specs for in the
115
+ current conversation, not just once at the start. Never guess prop names from memory.
116
+ 5. **Write the UI**, applying the design rules, the tokens, and the exact props from
117
+ step 4.
118
+ 6. **Self-check** against the "Final UI Quality Checklist" section (§49, found by
119
+ its `number` field in `productDesignGuide.sections` — not by array index) and
120
+ `antiAiLookRules` from `get_design_rules` before considering the UI
121
+ done — reread them, don't just rely on having read them once at the start.
122
+
123
+ Steps 1–2 only need to happen once per session/task, not once per component — refetching
124
+ `get_theme`/`get_design_rules` for every single component would be wasteful. Step 4 is
125
+ the one that repeats for every new component.
126
+
127
+ ---
128
+
129
+ ## 5. The five tools, in detail
92
130
 
93
131
  ### `list_components`
94
132
 
@@ -157,36 +195,24 @@ state", "icon button". Matches against name, category, description, and prop nam
157
195
 
158
196
  ### `get_theme`
159
197
 
160
- Returns the semantic color token system, the styling rules for using it, and three more
161
- sections aimed squarely at making generated UI indistinguishable from a human design
162
- pass: a set of **anti-AI-look rules** (no gradients, no decorative shadows/blurs/glows,
163
- no emoji-as-icons — see below), a **setup** block pointing the AI at the
164
- `@neuctra/ui-cli` `init` command instead of hand-writing token CSS or a theme context,
165
- and a **toastNote** explaining the standalone `toast()` import. Without `get_theme`, an
166
- AI would happily write `className="bg-blue-500"` or reach for a purple-to-pink gradient
167
- hero, both of which ignore the consumer's actual theme and read as generic AI output.
198
+ Returns the semantic color token system: the token list itself, a **setup** block
199
+ pointing the AI at the `@neuctra/ui-cli` `init` command instead of hand-writing token CSS
200
+ or a theme context, and a **toastNote** explaining the standalone `toast()` import.
201
+ Without `get_theme`, an AI would happily write `className="bg-blue-500"`, ignoring the
202
+ consumer's actual theme. `get_theme` does **not** carry the design/anti-AI-look rules —
203
+ see `get_design_rules` below for those; call both together, not one instead of the other.
168
204
 
169
205
  **Response shape:**
170
206
  ```jsonc
171
207
  {
172
208
  "system": "Tailwind CSS v4, semantic CSS-variable tokens mapped via @theme, toggled by a .dark class...",
173
- "rules": [
174
- "Never use hardcoded Tailwind palette colors...",
175
- "Always use the semantic token classes below...",
176
- // ...
177
- ],
178
- "antiAiLookRules": [
179
- "No gradients on backgrounds, buttons, or text...",
180
- "No decorative box-shadows, drop-shadows, or glow effects...",
181
- "No backdrop-blur / glassmorphism...",
182
- // ...17 rules total — the visual tells that make UI read as AI-generated
183
- ],
184
209
  "tokens": [
185
210
  { "token": "primary", "className": "bg-primary / text-primary / border-primary",
186
211
  "pairsWith": "primary-foreground", "light": "#00c214", "dark": "#00c214",
187
212
  "usage": "Brand color: primary buttons, active states, links, focus accents." },
188
213
  // ...23 tokens total
189
214
  ],
215
+ "note": "Values shown are the CLI-generated defaults...",
190
216
  "setup": {
191
217
  "recommendedCommand": "npx @neuctra/ui-cli@latest init",
192
218
  "whatItDoes": ["Installs @neuctra/ui.", "Checks/upgrades React and Tailwind CSS.", "..."],
@@ -196,9 +222,52 @@ hero, both of which ignore the consumer's actual theme and read as generic AI ou
196
222
  }
197
223
  ```
198
224
 
225
+ ### `get_design_rules`
226
+
227
+ Returns every design rule generated UI must follow, at two levels: the mechanical
228
+ **`stylingRules`** (token usage, surface/background conventions, component composition
229
+ requirements — e.g. `CardBody` is compulsory whenever `Card` has body content, since
230
+ `Card` itself renders no padding — and component-specific gotchas like Dropdown's
231
+ trigger already stopping propagation internally) and **`antiAiLookRules`** (no
232
+ gradients/shadows/blurs/glows/emoji-icons/em-dashes — the visual tells that make UI read
233
+ as AI-generated), plus **`productDesignGuide`** — a 50-section product/UX design guide
234
+ covering design philosophy, visual hierarchy, page/sidebar/navigation structure,
235
+ per-component usage guidance (when to reach for `Card` vs plain whitespace, `Modal` vs
236
+ `Drawer`, `Table` vs `List`, etc.), spacing/color/border/radius/shadow conventions,
237
+ responsive design, accessibility, interaction design, and a final UI quality checklist.
238
+
239
+ Call this before generating any UI — see the recommended workflow above.
240
+
241
+ **Response shape (trimmed):**
242
+ ```jsonc
243
+ {
244
+ "stylingRules": [
245
+ "Theme colors only, compulsory, no exceptions...",
246
+ "Use the Card component, not a hand-rolled lookalike...",
247
+ // ...9 rules total
248
+ ],
249
+ "antiAiLookRules": [
250
+ "No gradients, compulsory...",
251
+ "No shadows, compulsory...",
252
+ "No blur effects, compulsory...",
253
+ // ...17 rules total
254
+ ],
255
+ "productDesignGuide": {
256
+ "title": "Neuctra UI — AI Design Rules",
257
+ "intro": "You are a senior product designer and frontend UI engineer using `@neuctra/ui`...",
258
+ "sections": [
259
+ { "number": 1, "title": "Core Design Philosophy", "content": "..." },
260
+ { "number": 7, "title": "Cards", "content": "..." },
261
+ // ...50 sections total
262
+ ],
263
+ "goldenRule": { "title": "Golden Rule", "content": "..." }
264
+ }
265
+ }
266
+ ```
267
+
199
268
  ---
200
269
 
201
- ## 5. Local development
270
+ ## 6. Local development
202
271
 
203
272
  ```bash
204
273
  npm install
@@ -208,14 +277,14 @@ npm start # runs the server on stdio — it will sit there silent
208
277
 
209
278
  `npm start` alone won't show you anything (it's waiting for a client to speak JSON-RPC
210
279
  to it, not for a human to type at it). To actually exercise it, either wire it into a
211
- real client (section 6) or write a small script using
280
+ real client (section 7) or write a small script using
212
281
  `@modelcontextprotocol/sdk`'s `Client` + `StdioClientTransport` to spawn `bin/cli.mjs`
213
282
  and call the tools programmatically — that's how this server was verified while building
214
283
  it.
215
284
 
216
285
  ---
217
286
 
218
- ## 6. Connecting it to a client
287
+ ## 7. Connecting it to a client
219
288
 
220
289
  All MCP clients use the same JSON shape — the differences are just *where* the config
221
290
  file lives.
@@ -256,7 +325,7 @@ Restart the client after editing its config — servers are only launched on sta
256
325
 
257
326
  ---
258
327
 
259
- ## 7. Keeping the registry in sync
328
+ ## 8. Keeping the registry in sync
260
329
 
261
330
  The registry is generated, not hand-maintained. Whenever a component's props change:
262
331
 
@@ -271,12 +340,14 @@ npm run sync-registry # copies the updated file in
271
340
  `registry:generate` also runs automatically as part of `neuctra-ui-package`'s
272
341
  `prepublishOnly`, and `sync-registry` runs automatically as part of this package's own
273
342
  `prepublishOnly` — so a normal `npm publish` in each package keeps things current without
274
- remembering these steps by hand. `data/theme.json` is the one file with no generator;
275
- edit it directly if the token set in `neuctra-ui-cli/lib/update-css.js` ever changes.
343
+ remembering these steps by hand. `data/theme.json` and `data/aiDesignRules.json` are the
344
+ two files with no generator; edit them directly — `theme.json` if the token set in
345
+ `neuctra-ui-cli/lib/update-css.js` ever changes or a rule needs adding, `aiDesignRules.json`
346
+ if the product-design guidance itself needs revising.
276
347
 
277
348
  ---
278
349
 
279
- ## 8. Publishing
350
+ ## 9. Publishing
280
351
 
281
352
  ```bash
282
353
  npm run sync-registry
@@ -285,25 +356,26 @@ npm publish --access public # --access public is required: scoped packages def
285
356
 
286
357
  ---
287
358
 
288
- ## 9. Project structure
359
+ ## 10. Project structure
289
360
 
290
361
  ```
291
362
  neuctra-ui-mcp/
292
363
  ├── bin/
293
364
  │ └── cli.mjs # entry point: connects the server to a stdio transport
294
365
  ├── src/
295
- │ └── server.mjs # defines the 4 tools and their handlers
366
+ │ └── server.mjs # defines the 5 tools and their handlers
296
367
  ├── scripts/
297
368
  │ └── sync-registry.mjs # copies registry/components.json from neuctra-ui-package
298
369
  ├── data/
299
370
  │ ├── components.json # synced (generated) — don't edit by hand
300
- │ └── theme.json # hand-curated token/rules data
371
+ │ ├── theme.json # hand-curated token + styling/anti-AI-look rules
372
+ │ └── aiDesignRules.json # hand-curated 50-section product/UX design guide
301
373
  └── package.json
302
374
  ```
303
375
 
304
376
  ---
305
377
 
306
- ## 10. Extending it
378
+ ## 11. Extending it
307
379
 
308
380
  To add a new tool (e.g. `get_example` returning just the code snippet, or
309
381
  `list_categories`), open `src/server.mjs` and add another `server.registerTool(...)`
@@ -0,0 +1,260 @@
1
+ {
2
+ "title": "Neuctra UI — AI Design Rules",
3
+ "intro": "You are a senior product designer and frontend UI engineer using `@neuctra/ui`.\n\nYour goal is NOT to simply place components on a page.\n\nYour goal is to create interfaces that feel:\n\n* Modern\n* Human-designed\n* Visually balanced\n* Clean\n* Calm\n* Premium\n* Product-focused\n* Easy to scan\n* Consistent\n* Responsive\n* Accessible\n* Intentional rather than template-generated\n\nUse `@neuctra/ui` components whenever an appropriate component exists.",
4
+ "sections": [
5
+ {
6
+ "number": 1,
7
+ "title": "Core Design Philosophy",
8
+ "content": "Every UI decision must have a reason.\n\nDo not generate interfaces by randomly combining components.\n\nThink in this order:\n\n1. What is the user's primary goal?\n2. What information is most important?\n3. What action should receive the most visual attention?\n4. What information can be grouped together?\n5. What should be visually secondary?\n6. What can be hidden until needed?\n7. Which component best communicates the purpose?\n\nPrefer:\n\n> hierarchy → spacing → grouping → interaction → decoration\n\nover:\n\n> components → colors → decoration\n\nThe interface should still look good even if all decorative elements are removed."
9
+ },
10
+ {
11
+ "number": 2,
12
+ "title": "Visual Hierarchy",
13
+ "content": "Every page must have a clear hierarchy.\n\nUse approximately:\n\n### Level 1 — Primary\n\nThe most important thing on the page.\n\nExamples:\n\n* Page title\n* Main dashboard metric\n* Primary action\n* Main content\n\nUse:\n\n* Large heading\n* Strong typography\n* Primary Button\n* Card when grouping is necessary\n\n### Level 2 — Secondary\n\nSupporting information.\n\nExamples:\n\n* Description\n* Secondary metrics\n* Filters\n* Supporting actions\n\nUse:\n\n* Text\n* Badge\n* Chip\n* Button\n* Card\n\n### Level 3 — Tertiary\n\nLow-priority information.\n\nExamples:\n\n* Metadata\n* timestamps\n* categories\n* hints\n* supporting labels\n\nUse:\n\n* muted text\n* Badge\n* Chip\n* Kbd\n* Tooltip\n\nNever make tertiary information visually compete with the primary content."
14
+ },
15
+ {
16
+ "number": 3,
17
+ "title": "Page Structure",
18
+ "content": "Use a predictable structure:\n\n```text\nPage\n ├── Page Header\n │ ├── Title\n │ ├── Description\n │ └── Primary Action\n │\n ├── Optional Context / Callout\n │\n ├── Filters / Controls\n │\n └── Main Content\n```\n\nDo not add every section automatically.\n\nIf the page does not need a Callout, Card, Badge, or Divider, do not use it.\n\nLess UI is often better UI."
19
+ },
20
+ {
21
+ "number": 4,
22
+ "title": "Sidebar Design",
23
+ "content": "The sidebar is navigation, not content.\n\nKeep it visually quiet.\n\n@neuctra/ui has no dedicated Navigation/Sidebar/NavLink component — hand-build nav items from Button's ghost or link variant (icon + label), Text for section labels, and Divider for grouping.\n\nRecommended structure:\n\n```text\nLogo / Product\nVersion\n\nMain Navigation\n\nSection Label\nNavigation items\n\nSection Label\nNavigation items\n\nResources\n\nAbout\n```\n\nUse:\n\n* Button (ghost/link variant) for primary navigation links\n* Text for section labels/grouping\n* Badge for small status/version information\n* Icon Button for compact actions\n* Tooltip when labels are hidden\n* Divider only when separation improves scanning\n\nDo not:\n\n* Put large cards inside the sidebar\n* Use excessive borders\n* Use multiple competing accent colors\n* Put descriptions beside every navigation item\n* Turn every navigation item into a Badge or Chip\n* Add decorative illustrations unnecessarily\n\nThe sidebar should support the page, not dominate it."
24
+ },
25
+ {
26
+ "number": 5,
27
+ "title": "Navigation Grouping",
28
+ "content": "Group navigation according to the user's mental model. 'Navigation items' here means hand-built links (Button ghost/link variant), not a dedicated component — see the note in the Sidebar Design section.\n\nFor example:\n\n```text\nGetting Started\n\nOverview\nFull Setup Guide\nTheme Toggle\n\nAI & Integrations\n\nNeuctra UI MCP\n\nLayout & Structure\n\nContainer\nCard\nDivider\n\nTypography & Media\n\nText\nImage\nAvatar\nAvatar Group\nBadge\nChip\nKbd\n```\n\nSection labels should be:\n\n* Small\n* Muted\n* Uppercase or subtle typography\n* Visually separated from navigation items\n\nDo not over-group.\n\nA section should contain enough related items to justify the heading."
29
+ },
30
+ {
31
+ "number": 6,
32
+ "title": "Navigation Item Rules",
33
+ "content": "Navigation items (hand-built from Button's ghost/link variant — there is no dedicated Navigation component) should have:\n\n* Clear label\n* Optional icon\n* Strong hover state\n* Obvious active state\n* Comfortable click target\n\nRecommended hierarchy:\n\n```text\nInactive:\nmuted foreground\n\nHover:\nsubtle background\n\nActive:\nprimary-tinted background\nprimary/strong foreground\n```\n\nAvoid making every item look like a Button.\n\nNavigation should visually feel different from action controls."
34
+ },
35
+ {
36
+ "number": 7,
37
+ "title": "Cards",
38
+ "content": "Use `Card` when content represents a meaningful visual group.\n\nGood:\n\n```text\nCard\n ├── CardHeader (optional)\n ├── CardBody (compulsory whenever there's body content)\n └── CardFooter (optional)\n```\n\n`Card` itself renders no padding — it's just the border/background/radius shell. All spacing lives in `CardHeader`/`CardBody`/`CardFooter`. Content placed directly inside `<Card>` without `<CardBody>` renders flush against the border with no padding and visibly breaks the layout, so once you've decided to use Card, wrapping its body content in `<CardBody>` is not optional the way `CardHeader`/`CardFooter` are.\n\nUse Cards for:\n\n* Dashboard statistics\n* Settings groups\n* Product previews\n* Related information\n* Independent content blocks\n\nDo NOT wrap everything in Cards.\n\nAvoid:\n\n```text\nPage\n └── Card\n └── Card\n └── Card\n```\n\nNested cards should be rare.\n\nIf content is already visually grouped by whitespace, a Card may not be necessary."
39
+ },
40
+ {
41
+ "number": 8,
42
+ "title": "Container",
43
+ "content": "Use `Container` to control readable page width.\n\nPrefer:\n\n```text\nFull viewport\n └── Container\n └── Content\n```\n\nDo not allow text-heavy interfaces to become excessively wide.\n\nFor documentation:\n\n* Keep reading width comfortable.\n* Allow code examples to use more horizontal space.\n* Keep navigation independent from the reading column."
44
+ },
45
+ {
46
+ "number": 9,
47
+ "title": "Divider",
48
+ "content": "Use `Divider` only when whitespace is insufficient to communicate separation.\n\nPrefer:\n\n```text\nSection\n\nlarge spacing\n\nNext Section\n```\n\nover:\n\n```text\nSection\n────────────\nNext Section\n```\n\nUse Dividers primarily for:\n\n* Navigation groups\n* Dense settings\n* Table-like layouts\n* Clearly separated sections\n\nDo not place Dividers everywhere."
49
+ },
50
+ {
51
+ "number": 10,
52
+ "title": "Typography",
53
+ "content": "Typography should create hierarchy without requiring excessive decoration.\n\nRecommended hierarchy:\n\n```text\nPage title\n↓\nSection title\n↓\nComponent title\n↓\nBody text\n↓\nMetadata\n```\n\nUse:\n\n* Strong weight for headings\n* Regular weight for descriptions\n* Muted color for metadata\n* Comfortable line-height for reading\n\nAvoid:\n\n* Excessive bold text\n* Too many font sizes\n* All-caps body text\n* Huge headings on every page\n* Centering everything"
54
+ },
55
+ {
56
+ "number": 11,
57
+ "title": "Badge",
58
+ "content": "Use `Badge` for compact semantic information.\n\nGood:\n\n```text\nv1.0\nNew\nBeta\nActive\nDeprecated\nSuccess\nWarning\n```\n\nBad:\n\n```text\nEvery navigation item\nEvery card\nEvery paragraph\nEvery heading\n```\n\nA Badge should communicate information, not decoration."
59
+ },
60
+ {
61
+ "number": 12,
62
+ "title": "Chip",
63
+ "content": "Use `Chip` for lightweight categories or selectable labels.\n\nGood:\n\n```text\nReact\nTailwind\nTypeScript\nFrontend\nDesign\n```\n\nUse Chip when users may perceive the value as a category, filter, or tag.\n\nDo not use Badge and Chip interchangeably."
64
+ },
65
+ {
66
+ "number": 13,
67
+ "title": "Button",
68
+ "content": "Buttons represent actions.\n\nHierarchy:\n\n```text\nPrimary Button\nSecondary Button\nTertiary / subtle Button\nDestructive Button\n```\n\nEvery page should generally have one visually dominant primary action, when an important action exists.\n\nAvoid having multiple primary buttons competing with each other.\n\nExample:\n\n```text\nCreate Project ← Primary\n\nImport Export ← Secondary\n```"
69
+ },
70
+ {
71
+ "number": 14,
72
+ "title": "Icon Button",
73
+ "content": "Use `Icon Button` when the action is universally understandable from the icon or when space is limited.\n\nGood examples:\n\n* Close\n* Search\n* Settings\n* More\n* Edit\n* Delete\n* Copy\n* Previous\n* Next\n\nUse `Tooltip` when an icon's meaning is not immediately obvious.\n\nNever sacrifice usability for minimalism."
74
+ },
75
+ {
76
+ "number": 15,
77
+ "title": "Input / Form Components",
78
+ "content": "Forms should feel calm and structured.\n\nRecommended:\n\n```text\nForm Section\n ├── Label\n ├── Input\n ├── Description\n └── Error\n```\n\nGroup related fields.\n\nDo not place every field in a separate Card.\n\nUse:\n\n* Input for text\n* Textarea for long text\n* Select for predefined options\n* Checkbox for independent choices\n* RadioGroup for mutually exclusive choices\n* Switch for immediate on/off settings\n* Slider for ranges\n* Number Input for numeric values\n* Date Picker for dates\n* Time Picker for times\n* File Upload for files"
79
+ },
80
+ {
81
+ "number": 16,
82
+ "title": "Modal",
83
+ "content": "Use Modal for focused decisions or short tasks.\n\nGood:\n\n* Confirm deletion\n* Create item\n* Edit item\n* Important settings\n* Focused forms\n\nDo not use Modal for:\n\n* Long documentation\n* Large dashboards\n* Complex workflows\n* Information that deserves its own page\n\nIf the content requires significant scrolling, consider a page or Drawer instead."
84
+ },
85
+ {
86
+ "number": 17,
87
+ "title": "Drawer",
88
+ "content": "Use Drawer for contextual content that should remain connected to the current page.\n\nGood:\n\n* Filters\n* Detail views\n* Editing\n* Mobile navigation\n* Secondary settings\n\nDrawer is especially useful when the user should keep the underlying page context."
89
+ },
90
+ {
91
+ "number": 18,
92
+ "title": "Dropdown",
93
+ "content": "Use Dropdown for actions or compact menus.\n\nGood:\n\n```text\nMore\n ├── Edit\n ├── Duplicate\n ├── Archive\n └── Delete\n```\n\nDo not use Dropdown when users need to compare multiple persistent options.\n\nUse Select instead for form selection."
94
+ },
95
+ {
96
+ "number": 19,
97
+ "title": "Tooltip",
98
+ "content": "Use Tooltip for clarification, not essential information.\n\nGood:\n\n```text\nIcon Button\n ↓\nTooltip: \"Copy\"\n```\n\nDo not hide essential instructions inside tooltips."
99
+ },
100
+ {
101
+ "number": 20,
102
+ "title": "Popover",
103
+ "content": "Use Popover for contextual controls or additional information without leaving the page.\n\nGood:\n\n* Advanced filters\n* Color selection\n* Small configuration panels\n* Additional metadata\n* Contextual actions\n\nPopover content should remain lightweight."
104
+ },
105
+ {
106
+ "number": 21,
107
+ "title": "Tabs",
108
+ "content": "Use Tabs when multiple related views share the same context.\n\nGood:\n\n```text\nOverview | Activity | Settings\n```\n\nDo not use Tabs simply because the page has multiple sections.\n\nIf users should see the sections together, use normal page sections."
109
+ },
110
+ {
111
+ "number": 22,
112
+ "title": "Table",
113
+ "content": "Use Table when users need to compare structured records.\n\nGood:\n\n* Users\n* Orders\n* Transactions\n* Logs\n* Products\n\nProvide:\n\n* Clear column hierarchy\n* Adequate spacing\n* Row hover where useful\n* Pagination when necessary\n* Empty state\n* Loading state\n\nAvoid overly dense tables unless the product specifically requires high information density."
114
+ },
115
+ {
116
+ "number": 23,
117
+ "title": "List",
118
+ "content": "Use List when records are naturally read vertically.\n\nGood:\n\n* Notifications\n* Tasks\n* Activities\n* Messages\n* Search results\n\nPrefer List over Table when users don't need column-based comparison."
119
+ },
120
+ {
121
+ "number": 24,
122
+ "title": "Empty State",
123
+ "content": "Empty states should explain:\n\n1. What is empty?\n2. Why it matters?\n3. What should the user do next?\n\nExample:\n\n```text\nNo projects yet\n\nCreate your first project to start organizing your work.\n\n[ Create Project ]\n```\n\nDo not create empty states that only say:\n\n> No data found."
124
+ },
125
+ {
126
+ "number": 25,
127
+ "title": "Alert / Callout",
128
+ "content": "Use `Callout` for persistent contextual information inside the page.\n\nUse it for:\n\n* Important information\n* Warnings\n* Success states\n* Errors\n* Notices\n* System status\n* Migration messages\n\nExample:\n\n```text\n[Warning]\n\nYour storage is almost full.\nConsider removing unused files.\n```\n\nUse `Callout` when the message belongs to the page's content flow.\n\nDo not use Callout for every notification.\n\nFor temporary notifications, use the toast system.\n\nCallout hierarchy:\n\n```text\nError\nWarning\nSuccess\nInfo\nNeutral\n```\n\nUse semantic types correctly."
129
+ },
130
+ {
131
+ "number": 26,
132
+ "title": "Progress",
133
+ "content": "Use Progress when users need to understand completion.\n\nGood:\n\n* Upload progress\n* Onboarding\n* Course completion\n* Project progress\n* Storage usage\n\nDo not use progress bars decoratively.\n\nProgress should represent measurable progress."
134
+ },
135
+ {
136
+ "number": 27,
137
+ "title": "Skeleton",
138
+ "content": "Use Skeleton when content is loading and the final layout is known.\n\nThe skeleton should resemble the final content structure.\n\nAvoid replacing the entire page with a generic spinner when the layout can be preserved."
139
+ },
140
+ {
141
+ "number": 28,
142
+ "title": "Spinner",
143
+ "content": "Use Spinner for short, localized loading operations.\n\nGood:\n\n```text\n[Save] → spinner → Saving...\n```\n\nAvoid full-page spinners for normal page loading when Skeleton can preserve layout."
144
+ },
145
+ {
146
+ "number": 29,
147
+ "title": "Accordion",
148
+ "content": "Use Accordion when information is optional or secondary.\n\nGood:\n\n* FAQs\n* Advanced settings\n* Documentation sections\n* Additional details\n\nDo not hide primary information inside Accordions."
149
+ },
150
+ {
151
+ "number": 30,
152
+ "title": "Breadcrumb",
153
+ "content": "Use Breadcrumb when the page has meaningful hierarchy.\n\nExample:\n\n```text\nDocumentation / Components / Forms / Input\n```\n\nDo not use Breadcrumb on simple pages where there is no useful hierarchy."
154
+ },
155
+ {
156
+ "number": 31,
157
+ "title": "Pagination",
158
+ "content": "Use Pagination when users need to navigate large datasets.\n\nUse it with:\n\n* Tables\n* Search results\n* Large lists\n\nDo not paginate small datasets unnecessarily."
159
+ },
160
+ {
161
+ "number": 32,
162
+ "title": "Stepper",
163
+ "content": "Use Stepper for multi-step processes.\n\nExample:\n\n```text\nAccount → Details → Review → Complete\n```\n\nEach step should have a meaningful stage.\n\nDo not use Stepper for ordinary navigation."
164
+ },
165
+ {
166
+ "number": 33,
167
+ "title": "Image / Avatar",
168
+ "content": "Images should support content.\n\nUse:\n\n* Image for visual content\n* Avatar for people\n* Avatar Group for teams/participants\n\nDo not add decorative images simply to fill empty space."
169
+ },
170
+ {
171
+ "number": 34,
172
+ "title": "Carousel",
173
+ "content": "Use Carousel only when multiple visual/content items benefit from horizontal browsing.\n\nGood:\n\n* Product screenshots\n* Testimonials\n* Image galleries\n* Featured content\n\nDo not use Carousel for content that users need to compare simultaneously."
174
+ },
175
+ {
176
+ "number": 35,
177
+ "title": "Responsive Design",
178
+ "content": "Design mobile-first.\n\nDesktop:\n\n```text\nSidebar + Main Content\n```\n\nTablet:\n\n```text\nCollapsed Sidebar + Main Content\n```\n\nMobile:\n\n```text\nTop Bar\nContent\n```\n\nNavigation should become more compact rather than simply shrinking.\n\nForms should become single-column where necessary.\n\nCards should stack naturally.\n\nTables may require:\n\n* horizontal scrolling\n* responsive transformation\n* reduced columns\n\nNever allow the layout to become horizontally broken."
179
+ },
180
+ {
181
+ "number": 36,
182
+ "title": "Spacing Rules",
183
+ "content": "Use spacing to establish hierarchy.\n\nUse smaller spacing:\n\n* Within a component\n* Between label and input\n* Between icon and text\n\nUse larger spacing:\n\n* Between sections\n* Between page regions\n* Before major headings\n\nAvoid equal spacing everywhere.\n\nUnequal spacing creates hierarchy."
184
+ },
185
+ {
186
+ "number": 37,
187
+ "title": "Color Rules",
188
+ "content": "Use color semantically.\n\nPrimary color:\n\n* Primary actions\n* Active navigation\n* Important interactive elements\n* Focus states\n\nMuted colors:\n\n* Secondary information\n* Metadata\n* Supporting text\n\nSemantic colors:\n\n* Success\n* Warning\n* Error\n* Info\n\nDo not use many unrelated accent colors.\n\nA modern interface should generally have:\n\n```text\n1 primary brand color\n+\nneutral system\n+\nsemantic colors\n```"
189
+ },
190
+ {
191
+ "number": 38,
192
+ "title": "Border Rules",
193
+ "content": "Borders should clarify structure, not decorate it.\n\nPrefer:\n\n```text\nspacing\n+\nsubtle background differences\n```\n\nbefore adding borders.\n\nUse borders for:\n\n* Inputs\n* Tables\n* Cards when necessary\n* Dividers\n* Clear interactive boundaries\n\nAvoid heavy borders around every element."
194
+ },
195
+ {
196
+ "number": 39,
197
+ "title": "Radius Rules",
198
+ "content": "Use consistent corner radii.\n\nDo not randomly mix:\n\n```text\nrounded-sm\nrounded-md\nrounded-lg\nrounded-xl\nrounded-full\n```\n\nUse full rounding primarily for:\n\n* Chips\n* Badges\n* Avatars\n* Compact controls\n\nUse moderate rounding for:\n\n* Cards\n* Inputs\n* Buttons\n* Modals"
199
+ },
200
+ {
201
+ "number": 40,
202
+ "title": "Shadows",
203
+ "content": "Never add a shadow yourself, compulsory. Prefer:\n\n```text\nbackground\n+\nborder\n+\nspacing\n```\n\nover a shadow on anything you're styling by hand — buttons, cards, inputs, hand-built panels.\n\nThis is about classNames/markup you author. A number of `@neuctra/ui` components ship their own built-in elevation shadow as part of their default design (overlay/floating components like Modal, Dropdown, Popover, Drawer, Tooltip, and others like Table, DatePicker's calendar panel, Avatar's status dot, Kbd, and the Toast notification, among others — this isn't an exhaustive list to memorize). Leave every component's shipped defaults exactly as they ship: never add a shadow yourself, and never strip a component's built-in one with an override either — both are the same mistake in opposite directions."
204
+ },
205
+ {
206
+ "number": 41,
207
+ "title": "Modern UI Rule",
208
+ "content": "Modern does NOT mean:\n\n* excessive gradients\n* glassmorphism everywhere\n* giant rounded cards\n* excessive shadows\n* huge text\n* neon colors\n* random icons\n* excessive animations\n\nModern means:\n\n* clear hierarchy\n* intentional spacing\n* restrained color\n* predictable interaction\n* strong typography\n* useful whitespace\n* consistent components\n* subtle motion\n* responsive behavior"
209
+ },
210
+ {
211
+ "number": 42,
212
+ "title": "Human-Designed UI Rule",
213
+ "content": "Before generating the final UI, mentally ask:\n\n> \"Would a professional product designer intentionally put this element here?\"\n\nIf the answer is no, remove it.\n\nDo not add UI simply because a component exists.\n\nThe component library is a toolbox, not a checklist."
214
+ },
215
+ {
216
+ "number": 43,
217
+ "title": "Avoid AI-Generated UI Patterns",
218
+ "content": "Never automatically generate:\n\n* Hero section + three cards + gradient\n* Excessive rounded containers\n* Random decorative icons\n* Unnecessary badges\n* Excessive centered text\n* Every section inside a Card\n* Multiple primary buttons\n* Huge empty spaces\n* Excessive shadows\n* Random gradients\n* Generic dashboard cards\n* Repeated identical layouts\n* Decorative statistics without meaning\n\nAvoid the recognizable \"AI-generated SaaS template\" appearance."
219
+ },
220
+ {
221
+ "number": 44,
222
+ "title": "Component Selection Principle",
223
+ "content": "When choosing a component, use this decision process:\n\n```text\nNeed navigation?\n→ Tabs / Breadcrumb / Pagination / Stepper\n→ For a sidebar or nav links: hand-build from Button (ghost/link variant) — no dedicated Navigation component exists\n\nNeed an action?\n→ Button / Icon Button\n\nNeed selection?\n→ Select / RadioGroup / Checkbox / Switch\n\nNeed compact metadata?\n→ Badge / Chip\n\nNeed grouped content?\n→ Card\n\nNeed persistent message?\n→ Callout\n\nNeed temporary message?\n→ the toast system (import { toast, ToastProvider } from \"@neuctra/ui\" — not a \"Toast\" component)\n\nNeed focused interaction?\n→ Modal / Drawer / Popover\n\nNeed clarification?\n→ Tooltip\n\nNeed structured records?\n→ Table / List\n\nNeed loading?\n→ Skeleton / Spinner\n\nNeed progress?\n→ Progress\n\nNeed hierarchy?\n→ Accordion / Breadcrumb / Stepper\n```\n\nNever select a component merely because it looks attractive."
224
+ },
225
+ {
226
+ "number": 45,
227
+ "title": "Documentation UI Rules",
228
+ "content": "For component documentation, prefer:\n\n```text\nSidebar\n+\nDocumentation Container\n+\nBreadcrumb / Section Context\n+\nComponent Title\n+\nDescription\n+\nLive Preview\n+\nCode\n+\nUsage Guidelines\n+\nProps\n+\nAccessibility\n+\nFAQ\n```\n\nThe documentation page should prioritize the component preview and developer understanding.\n\nKeep code visually distinct from prose."
229
+ },
230
+ {
231
+ "number": 46,
232
+ "title": "Component Preview Rules",
233
+ "content": "Every preview should feel like a real product interface.\n\nDo not make previews look like isolated component experiments.\n\nInstead of:\n\n```text\nButton\nButton\nButton\n```\n\nprefer contextual examples:\n\n```text\nProject Settings\n\nProject name\n[ My Project ]\n\n[ Cancel ] [ Save Changes ]\n```\n\nThis demonstrates how the component actually behaves in a product."
234
+ },
235
+ {
236
+ "number": 47,
237
+ "title": "Accessibility",
238
+ "content": "Accessibility is part of the design.\n\nAlways consider:\n\n* Keyboard navigation\n* Focus states\n* Screen readers\n* Color contrast\n* Semantic HTML\n* Clear labels\n* Button names\n* Input descriptions\n* Error messages\n* Touch target sizes\n\nNever communicate meaning using color alone."
239
+ },
240
+ {
241
+ "number": 48,
242
+ "title": "Interaction Design",
243
+ "content": "Every interactive element should provide feedback.\n\nExamples:\n\n```text\nDefault\n→ Hover\n→ Active\n→ Focus\n→ Disabled\n→ Loading\n→ Success/Error\n```\n\nDo not animate everything.\n\nUse subtle transitions for:\n\n* Hover\n* Opening/closing\n* State changes\n* Navigation\n* Feedback\n\nMotion should explain interaction, not distract."
244
+ },
245
+ {
246
+ "number": 49,
247
+ "title": "Final UI Quality Checklist",
248
+ "content": "Before considering the UI complete, verify:\n\n### Hierarchy\n\n* Is the primary purpose obvious within seconds?\n* Is the most important action visually dominant?\n\n### Layout\n\n* Is spacing intentional?\n* Are sections grouped logically?\n* Is the content width comfortable?\n\n### Components\n\n* Is every component necessary?\n* Is each component being used for its intended purpose?\n\n### Visual Design\n\n* Is the color palette restrained?\n* Are borders and shadows subtle?\n* Is typography consistent?\n\n### UX\n\n* Can users understand what to do?\n* Are loading, empty, error, and success states handled?\n\n### Responsive\n\n* Does it work on mobile?\n* Does navigation adapt correctly?\n* Do cards/forms/tables remain usable?\n\n### Human Design\n\n* Does it look intentionally designed?\n* Could removing a decorative element improve it?\n* Does anything feel like generic AI-generated SaaS UI?\n\nIf something feels unnecessary, remove it."
249
+ },
250
+ {
251
+ "number": 50,
252
+ "title": "Do Not Overwrite Built-in Component Design",
253
+ "content": "Use each `@neuctra/ui` component's built-in design — its default spacing, radius, colors, and layout — as-is.\n\nDo not pass a `className` just to restyle a component's built-in appearance because of personal preference. The component's own design is already the intended, consistent look.\n\nOnly override with Tailwind's `!` important-modifier (e.g. `!bg-red-500`, `!p-2`, `!rounded-lg`) when there is a real, specific need:\n\n* The component's default would otherwise break the current page's existing layout.\n* The default collides or conflicts with the current UI/design of the site.\n* The component has no prop for the needed variation, and leaving the default would visually damage the surrounding design.\n\nNever reach for `!important` overrides as a routine styling habit, a stylistic preference, or 'just because'.\n\nPrefer:\n\n> built-in component design → prop-based variation (variant, size, etc.) → `!important` override (rare, only to prevent breakage)\n\nover:\n\n> restyle every component by default with className overrides\n\nA component that has been overridden with `!important` on every use is a sign the component itself, or the way it's being used, is wrong — not that every instance needs forcing."
254
+ }
255
+ ],
256
+ "goldenRule": {
257
+ "title": "Golden Rule",
258
+ "content": "Do not ask:\n\n> \"Which components can I put on this page?\"\n\nAsk:\n\n> \"What does the user need to understand and do, and which Neuctra UI component communicates that most naturally?\"\n\nThe best Neuctra UI interface is not the one that uses the most components.\n\nIt is the one where **every component has a purpose.**"
259
+ }
260
+ }
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema#",
3
3
  "package": "@neuctra/ui",
4
- "version": "1.0.1",
5
- "generatedAt": "2026-08-19T18:15:49.677Z",
6
- "componentCount": 77,
4
+ "version": "1.0.6",
5
+ "generatedAt": "2026-09-09T19:09:40.003Z",
6
+ "componentCount": 79,
7
7
  "components": [
8
8
  {
9
9
  "name": "Accordion",
@@ -695,7 +695,7 @@
695
695
  },
696
696
  {
697
697
  "name": "variant",
698
- "type": "| \"default\" | \"outline\" | \"ghost\" | \"secondary\" | \"destructive\" | \"success\" | \"warning\" | \"info\"",
698
+ "type": "| \"default\" | \"outline\" | \"ghost\" | \"secondary\" | \"destructive\" | \"success\" | \"warning\" | \"info\" | \"link\"",
699
699
  "required": false,
700
700
  "default": "\"default\"",
701
701
  "description": ""
@@ -2586,6 +2586,62 @@
2586
2586
  "extends": [],
2587
2587
  "example": "<FileUpload\n multiple\n onFilesChange={(files) => console.log(files)}\n/>"
2588
2588
  },
2589
+ {
2590
+ "name": "IconButton",
2591
+ "importFrom": "@neuctra/ui",
2592
+ "module": "IconButton",
2593
+ "category": "actions",
2594
+ "propsInterface": "IconButtonProps",
2595
+ "description": "The IconButton component is a compact, icon-only button built for toolbars, tables, cards, and dashboard actions. It shares the same variant system as Button for visual consistency, while sizing the icon and touch target together so the icon never looks lost inside the button.",
2596
+ "props": [
2597
+ {
2598
+ "name": "icon",
2599
+ "type": "React.ReactNode",
2600
+ "required": true,
2601
+ "default": null,
2602
+ "description": "The icon displayed inside the button"
2603
+ },
2604
+ {
2605
+ "name": "variant",
2606
+ "type": "| \"default\" | \"soft\" | \"outline\" | \"ghost\" | \"secondary\" | \"destructive\" | \"success\" | \"warning\" | \"info\" | \"link\"",
2607
+ "required": false,
2608
+ "default": "\"default\"",
2609
+ "description": "Visual style of the icon button"
2610
+ },
2611
+ {
2612
+ "name": "size",
2613
+ "type": "\"xs\" | \"sm\" | \"md\" | \"lg\" | \"xl\"",
2614
+ "required": false,
2615
+ "default": "\"sm\"",
2616
+ "description": "Size of the icon button"
2617
+ },
2618
+ {
2619
+ "name": "\"aria-label\"",
2620
+ "type": "string",
2621
+ "required": false,
2622
+ "default": null,
2623
+ "description": "Optional tooltip / accessible label"
2624
+ },
2625
+ {
2626
+ "name": "iconClassName",
2627
+ "type": "string",
2628
+ "required": false,
2629
+ "default": null,
2630
+ "description": "Full customization"
2631
+ },
2632
+ {
2633
+ "name": "iconStyle",
2634
+ "type": "React.CSSProperties",
2635
+ "required": false,
2636
+ "default": null,
2637
+ "description": ""
2638
+ }
2639
+ ],
2640
+ "extends": [
2641
+ "React.ButtonHTMLAttributes<HTMLButtonElement>"
2642
+ ],
2643
+ "example": "<IconButton icon={<Heart size={16} />} aria-label=\"Like\" />"
2644
+ },
2589
2645
  {
2590
2646
  "name": "Image",
2591
2647
  "importFrom": "@neuctra/ui",
@@ -6959,6 +7015,200 @@
6959
7015
  ],
6960
7016
  "example": "<Timeline\n items={[\n { title: \"Order placed\", time: \"09:12\", status: \"done\" },\n { title: \"Payment confirmed\", time: \"09:14\", status: \"done\" },\n { title: \"Out for delivery\", time: \"12:40\", status: \"active\",\n description: \"Your package is on its way.\" },\n { title: \"Delivered\", status: \"pending\" },\n ]}\n/>"
6961
7017
  },
7018
+ {
7019
+ "name": "TimePicker",
7020
+ "importFrom": "@neuctra/ui",
7021
+ "module": "TimePicker",
7022
+ "category": "form",
7023
+ "propsInterface": "TimePickerProps",
7024
+ "description": "",
7025
+ "props": [
7026
+ {
7027
+ "name": "value",
7028
+ "type": "Date | null",
7029
+ "required": false,
7030
+ "default": null,
7031
+ "description": ""
7032
+ },
7033
+ {
7034
+ "name": "defaultValue",
7035
+ "type": "Date | null",
7036
+ "required": false,
7037
+ "default": "null",
7038
+ "description": ""
7039
+ },
7040
+ {
7041
+ "name": "onChange",
7042
+ "type": "(date: Date | null) => void",
7043
+ "required": false,
7044
+ "default": null,
7045
+ "description": "Fired with a Date carrying the picked hour/minute. If `value` (or the\nuncontrolled internal value) is already set, only its hours/minutes are\nreplaced — the rest of the date is preserved, so pairing this with a\nDatePicker's value works without extra glue code."
7046
+ },
7047
+ {
7048
+ "name": "placeholder",
7049
+ "type": "string",
7050
+ "required": false,
7051
+ "default": "\"Pick a time\"",
7052
+ "description": ""
7053
+ },
7054
+ {
7055
+ "name": "formatTime",
7056
+ "type": "(date: Date) => string",
7057
+ "required": false,
7058
+ "default": "defaultFormatTime",
7059
+ "description": "Format the displayed time; defaults to a locale \"HH:MM\" string."
7060
+ },
7061
+ {
7062
+ "name": "step",
7063
+ "type": "number",
7064
+ "required": false,
7065
+ "default": "30",
7066
+ "description": "Minutes between each selectable option in the list."
7067
+ },
7068
+ {
7069
+ "name": "minHour",
7070
+ "type": "number",
7071
+ "required": false,
7072
+ "default": "0",
7073
+ "description": "Earliest selectable hour, 0-23."
7074
+ },
7075
+ {
7076
+ "name": "maxHour",
7077
+ "type": "number",
7078
+ "required": false,
7079
+ "default": "23",
7080
+ "description": "Latest selectable hour, 0-23 (inclusive)."
7081
+ },
7082
+ {
7083
+ "name": "label",
7084
+ "type": "string",
7085
+ "required": false,
7086
+ "default": null,
7087
+ "description": ""
7088
+ },
7089
+ {
7090
+ "name": "error",
7091
+ "type": "string",
7092
+ "required": false,
7093
+ "default": null,
7094
+ "description": ""
7095
+ },
7096
+ {
7097
+ "name": "helperText",
7098
+ "type": "string",
7099
+ "required": false,
7100
+ "default": null,
7101
+ "description": ""
7102
+ },
7103
+ {
7104
+ "name": "size",
7105
+ "type": "\"sm\" | \"md\" | \"lg\"",
7106
+ "required": false,
7107
+ "default": "\"md\"",
7108
+ "description": ""
7109
+ },
7110
+ {
7111
+ "name": "disabled",
7112
+ "type": "boolean",
7113
+ "required": false,
7114
+ "default": "false",
7115
+ "description": ""
7116
+ },
7117
+ {
7118
+ "name": "clearable",
7119
+ "type": "boolean",
7120
+ "required": false,
7121
+ "default": "false",
7122
+ "description": "Show an inline clear button while a time is selected."
7123
+ },
7124
+ {
7125
+ "name": "id",
7126
+ "type": "string",
7127
+ "required": false,
7128
+ "default": null,
7129
+ "description": ""
7130
+ },
7131
+ {
7132
+ "name": "className",
7133
+ "type": "string",
7134
+ "required": false,
7135
+ "default": null,
7136
+ "description": ""
7137
+ },
7138
+ {
7139
+ "name": "wrapperClassName",
7140
+ "type": "string",
7141
+ "required": false,
7142
+ "default": null,
7143
+ "description": ""
7144
+ },
7145
+ {
7146
+ "name": "labelClassName",
7147
+ "type": "string",
7148
+ "required": false,
7149
+ "default": null,
7150
+ "description": "🔥 Full Customization"
7151
+ },
7152
+ {
7153
+ "name": "iconClassName",
7154
+ "type": "string",
7155
+ "required": false,
7156
+ "default": null,
7157
+ "description": ""
7158
+ },
7159
+ {
7160
+ "name": "textClassName",
7161
+ "type": "string",
7162
+ "required": false,
7163
+ "default": null,
7164
+ "description": ""
7165
+ },
7166
+ {
7167
+ "name": "clearButtonClassName",
7168
+ "type": "string",
7169
+ "required": false,
7170
+ "default": null,
7171
+ "description": ""
7172
+ },
7173
+ {
7174
+ "name": "clearIconClassName",
7175
+ "type": "string",
7176
+ "required": false,
7177
+ "default": null,
7178
+ "description": ""
7179
+ },
7180
+ {
7181
+ "name": "panelClassName",
7182
+ "type": "string",
7183
+ "required": false,
7184
+ "default": null,
7185
+ "description": ""
7186
+ },
7187
+ {
7188
+ "name": "optionClassName",
7189
+ "type": "string",
7190
+ "required": false,
7191
+ "default": null,
7192
+ "description": ""
7193
+ },
7194
+ {
7195
+ "name": "activeOptionClassName",
7196
+ "type": "string",
7197
+ "required": false,
7198
+ "default": null,
7199
+ "description": ""
7200
+ },
7201
+ {
7202
+ "name": "helperClassName",
7203
+ "type": "string",
7204
+ "required": false,
7205
+ "default": null,
7206
+ "description": ""
7207
+ }
7208
+ ],
7209
+ "extends": [],
7210
+ "example": "const [time, setTime] = useState(null);\n\n<TimePicker\n label=\"Meeting time\"\n value={time}\n onChange={setTime}\n clearable\n/>"
7211
+ },
6962
7212
  {
6963
7213
  "name": "toast",
6964
7214
  "importFrom": "@neuctra/ui",
package/data/theme.json CHANGED
@@ -1,18 +1,21 @@
1
1
  {
2
2
  "system": "Tailwind CSS v4, semantic CSS-variable tokens mapped via @theme, toggled by a .dark class (not prefers-color-scheme).",
3
3
  "rules": [
4
- "Never use hardcoded Tailwind palette colors (text-blue-500, bg-red-500, border-gray-200, etc.) or inline hex/rgb colors in generated UI.",
4
+ "Theme colors only, compulsory, no exceptions: never use hardcoded Tailwind palette colors (text-blue-500, bg-red-500, border-gray-200, etc.), inline hex/rgb colors, or any other extra/arbitrary color not in the token list below, anywhere in generated UI — not even for a one-off accent, illustration, or 'just this one element'. Every color used must be one of the semantic tokens below.",
5
5
  "Always use the semantic token classes below (bg-primary, text-foreground, border-border, ...) so generated UI automatically follows the consumer's theme in both light and dark mode.",
6
6
  "Every base token except background/foreground/border/input/ring has a matching '-foreground' token for text/icons placed on top of it (e.g. bg-primary + text-primary-foreground, bg-destructive + text-destructive-foreground).",
7
7
  "Page background: bg-background. Card surfaces: bg-card. A distinct section within a page (not the whole page, not a card): bg-accent, or bg-card again if it needs to read as a panel. Popovers/dropdowns/tooltips: bg-popover. Never use bg-muted as a page, section, or card background — muted is reserved for non-surface fills only (skeleton placeholders, disabled-state fills, inline code backgrounds), not for anything a user reads content on top of.",
8
8
  "Status colors: success (positive/confirmation), warning (caution), info (neutral notice), destructive (danger/errors) — use these instead of ad-hoc green/yellow/blue/red.",
9
- "Dark mode requires no extra work in generated code: the same class names resolve to the .dark palette automatically because the consumer's CSS defines both blocks. Do not write dark: variants for color — only use dark: for things the token system doesn't cover (rare)."
9
+ "Dark mode requires no extra work in generated code: the same class names resolve to the .dark palette automatically because the consumer's CSS defines both blocks. Do not write dark: variants for color — only use dark: for things the token system doesn't cover (rare).",
10
+ "Use the Card component, not a hand-rolled lookalike: this rule only applies once you've decided a group of content (a settings section, a stat/summary tile, a list item container, a form section, a feature block, etc.) needs a bounded/bordered panel treatment — it does not mean every grouping must be boxed (see the design rules' 'less UI is often better UI' guidance: whitespace-only grouping is often correct and a Card is often unnecessary). When a panel treatment is warranted, build it with <Card> — never a raw div styled to look like a card (e.g. bg-card border border-border rounded-lg p-4 by hand). <CardBody> is compulsory whenever the card has body content, not optional: <Card>'s own root element applies zero padding (only the border/background/radius) — all internal spacing lives in the sub-components via their shared padding context, so placing content directly as a child of <Card> without wrapping it in <CardBody> renders that content flush against the card's border with no padding, which visibly breaks the UI. <CardHeader> (title/description/icon/actions) and <CardFooter> (actions/meta) remain genuinely optional — include each only if that section is needed — but never skip <CardBody> when there is body content, and never place content as a direct child of <Card> itself.",
11
+ "Dropdown's trigger button: never call e.stopPropagation() (or preventDefault() for the same purpose) in an onClick you attach to the Dropdown's trigger element. The Dropdown component already stops propagation internally to manage its own open/close and outside-click behavior; adding it again on the consumer's trigger handler is redundant and can break the dropdown's outside-click / nested-dropdown / row-click interactions. If the trigger sits inside another clickable element (a table row, a card), rely on Dropdown's own handling instead of manually stopping propagation.",
12
+ "Do not overwrite a component's built-in design. Use each @neuctra/ui component's default classes/variants/sizes as-is by default — do not routinely pass a className that overrides its built-in spacing, radius, colors, or layout just to restyle it. Only override with Tailwind's `!` important-modifier (e.g. `!bg-red-500`, `!p-2`) when there's a real, specific need — the component's default would otherwise break the current page's existing layout/design, collide with a surrounding container, or the component itself has no prop for the needed variation — never as a routine styling habit or a stylistic preference."
10
13
  ],
11
14
  "antiAiLookRules": [
12
15
  "This section exists because AI-generated UI has recognizable tells. Read it before generating anything visual — the goal is UI indistinguishable from a deliberate human design pass, not a demo that screams 'built by an LLM'.",
13
- "No gradients on backgrounds, buttons, or text (bg-gradient-to-r, from-purple-500 to-pink-500, bg-clip-text text-transparent, etc.). Use a flat bg-primary (or the relevant status token) instead. This is the single most common AI-UI tell — do not use it even 'just for one hero section'.",
14
- "No shadows. Don't add box-shadow/drop-shadow utilities (shadow-sm through shadow-2xl, glowing hover rings, colored blur halos) to buttons, badges, cards, inputs, or any static surface — a flat surface with border-border is correct. If a floating layer (modal, popover, dropdown menu) needs visual separation from what's behind it, a border plus the surface's own background token (bg-popover, bg-card) is enough; don't reach for shadow as the default way to show elevation.",
15
- "No blur effects. Don't use backdrop-blur or any glassmorphism treatment (frosted-glass cards, translucent bg-white/10 panels) anywhere in generated UI, including modal backdrops — use an opaque or semi-opaque solid backdrop (e.g. bg-background/80) instead of a blurred one. Surfaces are opaque (bg-card, bg-popover, bg-background), not translucent.",
16
+ "No gradients, compulsory: never use gradients on backgrounds, buttons, or text (bg-gradient-to-r, from-purple-500 to-pink-500, bg-clip-text text-transparent, etc.). Use a flat bg-primary (or the relevant status token) instead. This is the single most common AI-UI tell — do not use it even 'just for one hero section'.",
17
+ "No shadows, compulsory: never add box-shadow/drop-shadow utilities (shadow-sm through shadow-2xl, glowing hover rings, colored blur halos) to any element YOU style directly — buttons, badges, cards, inputs, hand-built panels/overlays, or any other static surface you write classNames for. A flat surface with border-border is correct. Scope note (applies to every rule in this list, not just this one): this governs classNames/markup you author yourself. It does not mean stripping or fighting any pre-built @neuctra/ui component's own internal default styling, no matter which component or what that default is (several components ship their own shadow — e.g. Modal, Drawer, Popover, Dropdown, Tooltip, Table, DatePicker's calendar panel, Avatar's status dot, Kbd, and the Toast/ToastProvider notification — this is not an exhaustive list and isn't meant to be maintained as one). Per the 'don't overwrite built-in component design' rule: leave every component's shipped defaults exactly as they ship. Never add a decorative shadow yourself, and never override one away with `!important` either — both are the same mistake in opposite directions.",
18
+ "No blur effects, compulsory: never use backdrop-blur or any glassmorphism treatment (frosted-glass cards, translucent bg-white/10 panels) on any element YOU style directly, including a hand-built modal/drawer backdrop — use an opaque or semi-opaque solid backdrop (e.g. bg-background/80) instead of a blurred one. Surfaces you author are opaque (bg-card, bg-popover, bg-background), not translucent. Same scope note as the shadow rule above: this is about classNames/markup you write, not about a pre-built @neuctra/ui component's own internal backdrop-blur (e.g. Modal/Drawer's backdrop, Dropdown's menu panel, Carousel's nav buttons ship with backdrop-blur baked in, among others) — leave every component's shipped defaults exactly as they ship, whichever component it is.",
16
19
  "No blanket border-radius escalation — don't reach for rounded-2xl/rounded-3xl/rounded-full on every card, input, and button by default. Match the radius already used by the surrounding neuctra-ui components (rounded-md/rounded-lg/rounded-xl per component, see each component's own classes) instead of picking a bigger one because it 'looks more modern'.",
17
20
  "No decorative hover/focus glow rings. ring-* and focus-visible:ring-ring exist for accessibility (keyboard focus indication) only — never add a colored ring or glow as a pointer-hover decoration on cards, buttons, or images.",
18
21
  "No animate-pulse / bounce / scale-105-on-hover / floating-icon motion sprinkled across static content as decoration. Motion should communicate state (loading, a toast entering, a modal opening) — components already handle that internally. Don't add extra hover-scale or idle animation to elements that aren't interactive or aren't mid-transition.",
@@ -21,11 +24,11 @@
21
24
  "No arbitrary one-off spacing/sizing values (p-[13px], gap-[7px], w-[327px]) — use the Tailwind spacing scale (p-3, gap-2, w-80, etc.) so spacing stays consistent with the rest of the design system.",
22
25
  "Prefer information density and restraint over generic centered-hero-with-huge-padding layouts. Not every section needs max-w-7xl mx-auto text-center py-24 — match the density and layout the consumer's existing UI already uses.",
23
26
  "Make every layout fully responsive by default — mobile, tablet, and desktop (sm:/md:/lg:/xl: breakpoints), stacking to a single column and adjusting spacing/type-scale at small widths. Never ship a fixed-width or desktop-only layout and call it done.",
24
- "No em dashes (—) in generated copy or UI text (headings, body copy, button labels, placeholder text). It's a recognizable AI-writing tell. Use a period, comma, colon, or restructure the sentence instead.",
27
+ "No em dashes (—), compulsory: never use an em dash in generated copy or UI text (headings, body copy, button labels, placeholder text). It's a recognizable AI-writing tell. Use a period, comma, colon, or restructure the sentence instead.",
25
28
  "No over-effects: don't stack multiple decorative treatments on one element (e.g. a gradient plus a shadow plus a hover-scale plus a glow, all on the same button). Every visual effect that does appear should communicate a real state or interaction (hover, focus, loading, an entering toast) — never decoration for its own sake.",
26
29
  "Use correct line-height and letter-spacing for readability. Body text: leading-relaxed or leading-normal, never leading-none/leading-tight on paragraphs. Letter-spacing: leave at the default (tracking-normal) for body and headings; only use tracking-wide for short uppercase labels (badges, eyebrow text, nav labels), and never tracking-wide on paragraph-length text.",
27
- "The bar is modern, visually appealing UI — achieved through typography hierarchy, whitespace, correct token usage, and responsive layout, not through gradients, shadows, blur, or glow effects standing in for actual design decisions.",
28
- "When unsure whether an effect (shadow, gradient, blur, glow, animation) is warranted: leave it out. A flat, token-colored, appropriately-radiused, unshadowed, responsive surface is the correct default for the overwhelming majority of neuctra-ui components."
30
+ "The bar is modern, visually appealing UI achieved through typography hierarchy, whitespace, correct token usage, and responsive layout, not through gradients, shadows, blur, or glow effects standing in for actual design decisions.",
31
+ "Decent, restrained design, compulsory: build UI that is decent and intentional, never over-designed. When unsure whether an effect (shadow, gradient, blur, glow, animation, an extra color) is warranted on something you're authoring yourself: leave it out. A flat, token-colored, appropriately-radiused, unshadowed, responsive surface using only the semantic color tokens is the correct default for the overwhelming majority of neuctra-ui components — restraint is the default, not the exception."
29
32
  ],
30
33
  "tokens": [
31
34
  { "token": "primary", "className": "bg-primary / text-primary / border-primary", "pairsWith": "primary-foreground", "light": "#00c214", "dark": "#00c214", "usage": "Brand color: primary buttons, active states, links, focus accents." },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neuctra/ui-mcp",
3
- "version": "0.3.1",
3
+ "version": "0.4.1",
4
4
  "description": "MCP server exposing the @neuctra/ui component registry (props, defaults, examples, theme tokens) so AI coding tools generate accurate Neuctra UI code.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -26,6 +26,7 @@
26
26
  ".": "./src/server.mjs",
27
27
  "./data/components.json": "./data/components.json",
28
28
  "./data/theme.json": "./data/theme.json",
29
+ "./data/aiDesignRules.json": "./data/aiDesignRules.json",
29
30
  "./package.json": "./package.json"
30
31
  },
31
32
  "files": [
package/src/server.mjs CHANGED
@@ -7,18 +7,23 @@ import { z } from "zod";
7
7
  // Reads data/*.json from disk. Only works on runtimes with a filesystem
8
8
  // (Node, Bun, Deno) — callers on edge/serverless runtimes without one
9
9
  // (Cloudflare Workers) must import the JSON files themselves at build time
10
- // and pass them into createServer({ registry, theme }) instead. Resolving
11
- // __dirname is deferred inside this function (not module top-level) because
12
- // import.meta.url is unavailable in some bundled edge runtimes even when
13
- // this function itself is never called there.
10
+ // and pass them into createServer({ registry, theme, aiDesignRules }) instead.
11
+ // Resolving __dirname is deferred inside this function (not module top-level)
12
+ // because import.meta.url is unavailable in some bundled edge runtimes even
13
+ // when this function itself is never called there.
14
14
  function loadDataFromDisk() {
15
15
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
16
16
  const DATA_DIR = path.resolve(__dirname, "..", "data");
17
17
  const registry = JSON.parse(
18
18
  fs.readFileSync(path.join(DATA_DIR, "components.json"), "utf8"),
19
19
  );
20
- const theme = JSON.parse(fs.readFileSync(path.join(DATA_DIR, "theme.json"), "utf8"));
21
- return { registry, theme };
20
+ const theme = JSON.parse(
21
+ fs.readFileSync(path.join(DATA_DIR, "theme.json"), "utf8"),
22
+ );
23
+ const aiDesignRules = JSON.parse(
24
+ fs.readFileSync(path.join(DATA_DIR, "aiDesignRules.json"), "utf8"),
25
+ );
26
+ return { registry, theme, aiDesignRules };
22
27
  }
23
28
 
24
29
  function summarize(component) {
@@ -39,12 +44,12 @@ function matchesQuery(component, query) {
39
44
  }
40
45
 
41
46
  export function createServer(data) {
42
- const { registry, theme } = data ?? loadDataFromDisk();
47
+ const { registry, theme, aiDesignRules } = data ?? loadDataFromDisk();
43
48
  const componentsByName = new Map(registry.components.map((c) => [c.name, c]));
44
49
 
45
50
  const server = new McpServer({
46
51
  name: "neuctra-ui",
47
- version: "0.3.1",
52
+ version: "0.4.0",
48
53
  });
49
54
 
50
55
  server.registerTool(
@@ -88,7 +93,9 @@ export function createServer(data) {
88
93
  inputSchema: {
89
94
  name: z
90
95
  .string()
91
- .describe('Exact component name, e.g. "Input", "Select", "Modal", "CardHeader".'),
96
+ .describe(
97
+ 'Exact component name, e.g. "Input", "Select", "Modal", "CardHeader".',
98
+ ),
92
99
  },
93
100
  },
94
101
  async ({ name }) => {
@@ -123,13 +130,15 @@ export function createServer(data) {
123
130
  {
124
131
  title: "Search Neuctra UI components",
125
132
  description:
126
- "Search components by keyword against name, category, description, and prop names. Use this when you know what you need (e.g. \"date picker\", \"loading state\", \"icon button\") but not the exact component name.",
133
+ 'Search components by keyword against name, category, description, and prop names. Use this when you know what you need (e.g. "date picker", "loading state", "icon button") but not the exact component name.',
127
134
  inputSchema: {
128
135
  query: z.string().describe("Keyword or short phrase to search for."),
129
136
  },
130
137
  },
131
138
  async ({ query }) => {
132
- const results = registry.components.filter((c) => matchesQuery(c, query)).map(summarize);
139
+ const results = registry.components
140
+ .filter((c) => matchesQuery(c, query))
141
+ .map(summarize);
133
142
  return {
134
143
  content: [{ type: "text", text: JSON.stringify(results, null, 2) }],
135
144
  };
@@ -139,14 +148,40 @@ export function createServer(data) {
139
148
  server.registerTool(
140
149
  "get_theme",
141
150
  {
142
- title: "Get Neuctra UI theming rules and tokens",
151
+ title: "Get Neuctra UI theming tokens",
152
+ description:
153
+ "Get the semantic color token system (bg-primary, text-foreground, etc.), the recommended `@neuctra/ui-cli` setup command, and how the toast notification API works. Call get_design_rules alongside this before generating any UI — not just for colors.",
154
+ inputSchema: {},
155
+ },
156
+ async () => {
157
+ const { rules, antiAiLookRules, ...themeOnly } = theme;
158
+ return {
159
+ content: [{ type: "text", text: JSON.stringify(themeOnly, null, 2) }],
160
+ };
161
+ },
162
+ );
163
+
164
+ server.registerTool(
165
+ "get_design_rules",
166
+ {
167
+ title: "Get Neuctra UI design rules",
143
168
  description:
144
- "Get the semantic color token system (bg-primary, text-foreground, etc.), the styling rules generated UI must follow, a set of rules for avoiding the visual tells that make UI look AI-generated (gradients, decorative shadows/blurs/glows, emoji-as-icons, etc.), the recommended `@neuctra/ui-cli` setup command, and how the toast notification API works. Call this before generating any UI — not just for colors.",
169
+ "Get every design rule generated UI must follow when using @neuctra/ui. Covers two levels: (1) styling rules — token usage, surface/background conventions, component composition requirements like CardBody being compulsory whenever Card has body content, component-specific gotchas like Dropdown's trigger propagation, and the full set of rules for avoiding the visual tells that make UI look AI-generated (gradients, decorative shadows/blurs/glows, emoji-as-icons, etc.); (2) product/UX design rules — a numbered 50-section guide covering design philosophy, visual hierarchy, page/sidebar/navigation structure, per-component usage guidance (when to use Card, Modal vs Drawer, Table vs List, etc.), spacing/color/border/radius/shadow conventions, responsive design, accessibility, interaction design, a final UI quality checklist, and the rule against overwriting a component's built-in design. Call this before generating any UI — not just get_theme.",
145
170
  inputSchema: {},
146
171
  },
147
172
  async () => {
173
+ const { rules, antiAiLookRules } = theme;
148
174
  return {
149
- content: [{ type: "text", text: JSON.stringify(theme, null, 2) }],
175
+ content: [
176
+ {
177
+ type: "text",
178
+ text: JSON.stringify(
179
+ { stylingRules: rules, antiAiLookRules, productDesignGuide: aiDesignRules },
180
+ null,
181
+ 2,
182
+ ),
183
+ },
184
+ ],
150
185
  };
151
186
  },
152
187
  );