@morya-ui/setup 0.3.3 → 0.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +107 -103
  3. package/bin/morya-ui-setup.js +14 -14
  4. package/catalog/skills.json +46 -46
  5. package/package.json +1 -1
  6. package/src/cli.mjs +312 -335
  7. package/src/copy-template.mjs +78 -78
  8. package/src/fs-utils.mjs +24 -24
  9. package/src/install.mjs +134 -63
  10. package/src/mcp.mjs +50 -50
  11. package/src/package-json.mjs +30 -30
  12. package/src/skills.mjs +223 -223
  13. package/src/styles.mjs +119 -119
  14. package/template/.agents/skills/morya-ui-pages/SKILL.md +188 -164
  15. package/template/.agents/skills/morya-ui-pages/evals/evals.json +89 -89
  16. package/template/.agents/skills/morya-ui-pages/references/component-index.md +99 -99
  17. package/template/.agents/skills/morya-ui-pages/references/decision-recipes.md +104 -5
  18. package/template/.agents/skills/morya-ui-pages/references/design-system.md +101 -100
  19. package/template/.agents/skills/morya-ui-pages/references/feedback.md +68 -68
  20. package/template/.agents/skills/morya-ui-pages/references/optional-companions.md +62 -34
  21. package/template/.agents/skills/morya-ui-pages/references/page-layouts.md +133 -119
  22. package/template/.agents/skills/morya-ui-pages/references/review-checklist.md +63 -61
  23. package/template/.agents/skills/morya-ui-pages/references/style-presets.md +45 -0
  24. package/template/.agents/skills/morya-ui-pages/references/surfaces.md +91 -89
  25. package/template/.agents/skills/morya-ui-pages/references/visual-craft.md +129 -196
  26. package/template/.cursor/rules/coding-style.mdc +41 -41
  27. package/template/.cursor/rules/component-usage.mdc +41 -41
  28. package/template/.cursor/rules/design-system.mdc +17 -17
  29. package/template/.cursor/rules/page-layout.mdc +97 -78
  30. package/template/DESIGN.md +59 -59
  31. package/template/scripts/check-raw-colors.mjs +74 -74
package/src/styles.mjs CHANGED
@@ -1,119 +1,119 @@
1
- import { existsSync, readFileSync, writeFileSync } from 'node:fs'
2
- import { join, resolve } from 'node:path'
3
-
4
- const STYLE_IMPORT = "import 'morya-ui/styles.css'"
5
- const STYLE_MARKER = 'morya-ui/styles.css'
6
-
7
- const CANDIDATES = [
8
- 'src/main.ts',
9
- 'src/main.js',
10
- 'src/main.tsx',
11
- 'src/main.jsx',
12
- 'main.ts',
13
- 'main.js',
14
- 'src/app.ts',
15
- 'src/app.js',
16
- ]
17
-
18
- /**
19
- * @param {string} cwd
20
- * @returns {string | null} absolute path
21
- */
22
- export function findEntryFile(cwd) {
23
- for (const rel of CANDIDATES) {
24
- const full = join(cwd, rel)
25
- if (existsSync(full)) return full
26
- }
27
-
28
- const indexHtml = join(cwd, 'index.html')
29
- if (existsSync(indexHtml)) {
30
- const html = readFileSync(indexHtml, 'utf8')
31
- const match = html.match(/<script[^>]*type=["']module["'][^>]*src=["']([^"']+)["']/i)
32
- || html.match(/<script[^>]*src=["']([^"']+)["'][^>]*type=["']module["']/i)
33
- if (match?.[1]) {
34
- const src = match[1].replace(/^\//, '')
35
- const full = resolve(cwd, src)
36
- if (existsSync(full)) return full
37
- }
38
- }
39
-
40
- return null
41
- }
42
-
43
- /**
44
- * Insert an import after the last leading import, or at top.
45
- * @param {string} source
46
- * @param {string} importLine
47
- * @param {string} marker substring that means "already present"
48
- */
49
- export function injectImportLine(source, importLine, marker) {
50
- if (source.includes(marker)) {
51
- return { source, changed: false, reason: 'already-present' }
52
- }
53
-
54
- const lines = source.split(/\r?\n/)
55
- let lastImportIndex = -1
56
- for (let i = 0; i < lines.length; i++) {
57
- const line = lines[i].trim()
58
- if (!line) {
59
- if (lastImportIndex >= 0) continue
60
- continue
61
- }
62
- if (line.startsWith('//') || line.startsWith('/*') || line.startsWith('*')) {
63
- if (lastImportIndex < 0) continue
64
- break
65
- }
66
- if (/^import\s/.test(line) || /^import["']/.test(line)) {
67
- lastImportIndex = i
68
- continue
69
- }
70
- break
71
- }
72
-
73
- if (lastImportIndex >= 0) {
74
- lines.splice(lastImportIndex + 1, 0, importLine)
75
- }
76
- else {
77
- let insertAt = 0
78
- if (lines[0]?.startsWith('#!')) insertAt = 1
79
- lines.splice(insertAt, 0, importLine, '')
80
- }
81
-
82
- return { source: lines.join('\n'), changed: true }
83
- }
84
-
85
- /**
86
- * @param {string} source
87
- * @deprecated use injectImportLine
88
- */
89
- export function injectStyleImport(source) {
90
- return injectImportLine(source, STYLE_IMPORT, STYLE_MARKER)
91
- }
92
-
93
- /**
94
- * @returns {{
95
- * action: 'injected' | 'skipped' | 'missing-entry',
96
- * path?: string,
97
- * reason?: string,
98
- * dryRun?: boolean
99
- * }}
100
- */
101
- export function ensureStylesImport(cwd, { dryRun = false } = {}) {
102
- const entry = findEntryFile(cwd)
103
- if (!entry) {
104
- return { action: 'missing-entry', reason: 'no-entry-found' }
105
- }
106
-
107
- const original = readFileSync(entry, 'utf8')
108
- const { source, changed, reason } = injectImportLine(original, STYLE_IMPORT, STYLE_MARKER)
109
-
110
- if (!changed) {
111
- return { action: 'skipped', path: entry, reason: reason || 'already-present' }
112
- }
113
-
114
- if (!dryRun) {
115
- writeFileSync(entry, source, 'utf8')
116
- }
117
-
118
- return { action: 'injected', path: entry, dryRun }
119
- }
1
+ import { existsSync, readFileSync, writeFileSync } from 'node:fs'
2
+ import { join, resolve } from 'node:path'
3
+
4
+ const STYLE_IMPORT = "import 'morya-ui/styles.css'"
5
+ const STYLE_MARKER = 'morya-ui/styles.css'
6
+
7
+ const CANDIDATES = [
8
+ 'src/main.ts',
9
+ 'src/main.js',
10
+ 'src/main.tsx',
11
+ 'src/main.jsx',
12
+ 'main.ts',
13
+ 'main.js',
14
+ 'src/app.ts',
15
+ 'src/app.js',
16
+ ]
17
+
18
+ /**
19
+ * @param {string} cwd
20
+ * @returns {string | null} absolute path
21
+ */
22
+ export function findEntryFile(cwd) {
23
+ for (const rel of CANDIDATES) {
24
+ const full = join(cwd, rel)
25
+ if (existsSync(full)) return full
26
+ }
27
+
28
+ const indexHtml = join(cwd, 'index.html')
29
+ if (existsSync(indexHtml)) {
30
+ const html = readFileSync(indexHtml, 'utf8')
31
+ const match = html.match(/<script[^>]*type=["']module["'][^>]*src=["']([^"']+)["']/i)
32
+ || html.match(/<script[^>]*src=["']([^"']+)["'][^>]*type=["']module["']/i)
33
+ if (match?.[1]) {
34
+ const src = match[1].replace(/^\//, '')
35
+ const full = resolve(cwd, src)
36
+ if (existsSync(full)) return full
37
+ }
38
+ }
39
+
40
+ return null
41
+ }
42
+
43
+ /**
44
+ * Insert an import after the last leading import, or at top.
45
+ * @param {string} source
46
+ * @param {string} importLine
47
+ * @param {string} marker substring that means "already present"
48
+ */
49
+ export function injectImportLine(source, importLine, marker) {
50
+ if (source.includes(marker)) {
51
+ return { source, changed: false, reason: 'already-present' }
52
+ }
53
+
54
+ const lines = source.split(/\r?\n/)
55
+ let lastImportIndex = -1
56
+ for (let i = 0; i < lines.length; i++) {
57
+ const line = lines[i].trim()
58
+ if (!line) {
59
+ if (lastImportIndex >= 0) continue
60
+ continue
61
+ }
62
+ if (line.startsWith('//') || line.startsWith('/*') || line.startsWith('*')) {
63
+ if (lastImportIndex < 0) continue
64
+ break
65
+ }
66
+ if (/^import\s/.test(line) || /^import["']/.test(line)) {
67
+ lastImportIndex = i
68
+ continue
69
+ }
70
+ break
71
+ }
72
+
73
+ if (lastImportIndex >= 0) {
74
+ lines.splice(lastImportIndex + 1, 0, importLine)
75
+ }
76
+ else {
77
+ let insertAt = 0
78
+ if (lines[0]?.startsWith('#!')) insertAt = 1
79
+ lines.splice(insertAt, 0, importLine, '')
80
+ }
81
+
82
+ return { source: lines.join('\n'), changed: true }
83
+ }
84
+
85
+ /**
86
+ * @param {string} source
87
+ * @deprecated use injectImportLine
88
+ */
89
+ export function injectStyleImport(source) {
90
+ return injectImportLine(source, STYLE_IMPORT, STYLE_MARKER)
91
+ }
92
+
93
+ /**
94
+ * @returns {{
95
+ * action: 'injected' | 'skipped' | 'missing-entry',
96
+ * path?: string,
97
+ * reason?: string,
98
+ * dryRun?: boolean
99
+ * }}
100
+ */
101
+ export function ensureStylesImport(cwd, { dryRun = false } = {}) {
102
+ const entry = findEntryFile(cwd)
103
+ if (!entry) {
104
+ return { action: 'missing-entry', reason: 'no-entry-found' }
105
+ }
106
+
107
+ const original = readFileSync(entry, 'utf8')
108
+ const { source, changed, reason } = injectImportLine(original, STYLE_IMPORT, STYLE_MARKER)
109
+
110
+ if (!changed) {
111
+ return { action: 'skipped', path: entry, reason: reason || 'already-present' }
112
+ }
113
+
114
+ if (!dryRun) {
115
+ writeFileSync(entry, source, 'utf8')
116
+ }
117
+
118
+ return { action: 'injected', path: entry, dryRun }
119
+ }
@@ -1,164 +1,188 @@
1
- ---
2
- name: morya-ui-pages
3
- description: >
4
- Build, redesign, critique, or polish any Vue 3 UI surface that should use the
5
- morya-ui component library — admin CRUD (list, form, dashboard, detail,
6
- settings), auth and onboarding, empty and error states, wizards, overlays,
7
- marketing/landing and pricing pages, docs chrome, and hybrid product UI.
8
- Trigger on: morya-ui, M* components, --m-* tokens, golden pages, 后台页,
9
- 列表页, 表单页, 仪表盘, 登录页, 注册, 空状态, 向导, 落地页, 官网, landing,
10
- login, dashboard, settings, onboarding, or “用组件库做页面”. Prefer this
11
- skill over generic frontend-design, impeccable, or ui-ux-pro-max when the
12
- implementation stack is morya-ui; those companions may inform taste only.
13
- Do not use for backend-only work or for authoring new components inside the
14
- morya-ui library source itself.
15
- ---
16
-
17
- # Morya UI Pages
18
-
19
- Guide agents that **consume morya-ui** across the full product surface — not only admin CRUD.
20
-
21
- Two layers always apply:
22
-
23
- 1. **Contract** — only `M*` controls, `--m-*` tokens, real APIs (MCP/docs). Never invent props or mix UI kits.
24
- 2. **Craft** — pick the right surface pattern, then apply intentional visual direction (distilled from Frontend Design / Impeccable / UI-UX-Pro-Max ideas). Admin golden pages stay disciplined; expressive surfaces (landing, auth brand moments, empty states) may take a justified aesthetic risk — still on-token and on-component.
25
-
26
- When companions conflict with this skill or project `DESIGN.md`, **this skill wins**.
27
-
28
- ## Surface map (pick one first)
29
-
30
- | Lane | Surfaces | Primary references |
31
- | --- | --- | --- |
32
- | **Ops** | list, form, dashboard, detail, settings, filter drawer, CRUD dialog | [page-layouts.md](references/page-layouts.md), golden pages |
33
- | **Account** | login, register, invite, forgot/reset password, profile | [surfaces.md](references/surfaces.md) § Account |
34
- | **Flow** | onboarding, empty state, wizard/stepper, success/result | [surfaces.md](references/surfaces.md) § Flow |
35
- | **System** | 404 / error, permission denied, maintenance | [surfaces.md](references/surfaces.md) § System |
36
- | **Express** | marketing landing, pricing, feature showcase, docs marketing chrome | [surfaces.md](references/surfaces.md) § Express + [visual-craft.md](references/visual-craft.md) |
37
- | **Overlay** | dialog, drawer, popover, command menu as the main UI | [surfaces.md](references/surfaces.md) § Overlay |
38
-
39
- Unclear brief → ask **one** short question, or default: Ops → closest golden page; public marketing → Express.
40
-
41
- Full taxonomy: [references/surfaces.md](references/surfaces.md).
42
-
43
- ## Prerequisites
44
-
45
- 1. `morya-ui` installed; `morya-ui/styles.css` imported.
46
- 2. Prefer `@morya-ui/mcp` — never invent prop / event / slot names.
47
- 3. Golden pages, component APIs, and feedback rules come from `@morya-ui/mcp`. Without MCP, use this skill's `references/`. Project `DESIGN.md` overrides generic taste when the AI pack is merged.
48
-
49
- ## Workflow
50
-
51
- ### 1. Pin subject, audience, surface, job
52
-
53
- State explicitly (even briefly in thinking):
54
-
55
- - **Subject** — product / domain vernacular (not generic “SaaS”)
56
- - **Audience** — who uses this screen
57
- - **Surface** — from the map above
58
- - **Single job** — what the first viewport must accomplish
59
-
60
- For Express / branded Account moments, also draft a tiny **design plan** (see [visual-craft.md](references/visual-craft.md)): palette roles mapped to `--m-*` (extend only if the project already customizes theme), type roles, layout concept, one signature element. Skip the full plan for routine Ops CRUD unless the user asks for a redesign.
61
-
62
- ### 2. Load the smallest useful references
63
-
64
- | Need | Prefer (MCP) | Else read |
65
- | --- | --- | --- |
66
- | Ops pattern | `recommend_page` → **`get_golden_page`** (mirror; do not invent a parallel scaffold aesthetic) | [page-layouts.md](references/page-layouts.md) |
67
- | Account / Express / empty / result | `recommend_page` → `get_golden_page` (`login-page` / `landing-page` / `empty-state` / `result-page`) | [surfaces.md](references/surfaces.md) |
68
- | Visual direction | — | [visual-craft.md](references/visual-craft.md) (Ops polish / atmosphere / anti-defaults) |
69
- | Components / **API truth** | `search` / **`get_component`** / `get_example` / **`recommend_component`** (includes L2 recipes) | [decision-recipes.md](references/decision-recipes.md) + [component-index.md](references/component-index.md) |
70
- | Tokens / rules | `get_design_rules` | [design-system.md](references/design-system.md) |
71
- | Snippet | `get_page_snippet` | golden / surface excerpt |
72
- | Feedback API | — | [feedback.md](references/feedback.md) |
73
- | **Required checks** | **`validate_usage`** (every `M*` you used) + `validate_page` | [review-checklist.md](references/review-checklist.md) |
74
-
75
- ### 3. Compose
76
-
77
- **Ops:** mirror golden-page block order; prefer `MPage*` over custom chrome.
78
-
79
- **Account / Flow / System:** centered or split shells with `MCard` / `MForm` / `MEmpty` / `MResult` (see surfaces); keep controls as `M*`. Persistent form errors use field `errorMessage` or a token-styled `role="alert"` — `<MMessage>` is the `message` host, not an inline alert.
80
-
81
- **Express:** hero + sections with intentional hierarchy; interactive bits still `MButton` / `MTag` / etc.; atmosphere via layout, motion, and tokens — not a second component library.
82
-
83
- **Overlay:** build the host page lightly; put the real job inside `MDialog` / `MDrawer` / `MCommandMenu`.
84
-
85
- ### 4. Wire real API usage
86
-
87
- - Import from `morya-ui` (or documented subpath + style).
88
- - **Selection + key props:** call MCP **`recommend_component`** (by query or `decision` id) and apply the returned **recipe** (`props` / `slots` / `events`) and **antiPatterns**. Without MCP, read [decision-recipes.md](references/decision-recipes.md). Then confirm full API with `get_component` / `get_example`.
89
- - Forms: `MForm` + fields; `@submit` + `type="submit"` (or documented footer button pattern on `form-in-dialog`).
90
- - Tables: `columns` + `rows` + `row-key`; `#cell-{key}`. There is no `data` prop.
91
- - Enums → `MSelect` / `MTreeSelect`; action menus → `MDropdown`.
92
- - Destructive → `MConfirmDialog` / `MConfirmPopup` (`confirm-choice`).
93
- - Feedback → default **`message`**; `toast` only for summary+detail / async; persistent form errors → `errorMessage` / `role="alert"` (`feedback-choice`). See [feedback.md](references/feedback.md).
94
- - Motion → intensity with `useMotion` (`full` / `reduced` / `none`); overlay enter/exit with `transition` prop or `createMoryaUI({ motion: { transitions } })` — do not invent a second animation stack. Prefer MCP / docs `motion` guide.
95
- - **Before craft:** for each unfamiliar or newly written `M*` usage, call MCP **`get_component` / `get_example`**, then **`validate_usage`**. Fix every `unknown-prop` / `unknown-event` before delivery.
96
- - `recommend_page(includeScaffold: true)` returns the **golden page source** when one exists — remap copy/data only; never treat generated fallback as the visual target.
97
-
98
- ### 5. Craft pass (always — lane-aware)
99
-
100
- Run **before** delivery. Do not stop at a structurally correct shell.
101
-
102
- - **Ops:** apply [visual-craft.md](references/visual-craft.md) § Ops polish (one primary, menu icons, `MStatus` in tables, designed empty, no decorative cards).
103
- - **Account / Flow:** one calm brand or empty-state cue from § Atmosphere recipes; form errors via `errorMessage` / token `role="alert"`.
104
- - **Express:** short design plan + one signature; avoid AI-default looks; optional 1–2 token-only motions; intensity via `useMotion` (`full` / `reduced` / `none`), not the OS `prefers-reduced-motion` setting.
105
- - **All lanes:** responsive, focus visible, domain-real copy (active voice).
106
-
107
- Named polish modes (`quieter` | `bolder` | `clarify` | `audit` | …): use as an **extra** pass when the user asks to improve an existing screen. See [visual-craft.md](references/visual-craft.md) § Polish modes.
108
-
109
- ### 6. Review
110
-
111
- Use [review-checklist.md](references/review-checklist.md) (contract + craft sections).
112
-
113
- **Required when MCP is available:**
114
-
115
- 1. `validate_usage` on the page (or per component) — API accuracy gate
116
- 2. `validate_page` — layout / token / contract advisories
117
-
118
- Do not deliver with unresolved `unknown-prop` / `unknown-event`.
119
-
120
- ## Hard boundaries
121
-
122
- - No second UI kit on the same surface.
123
- - No hand-rolled table/modal when `MTable` / `MDialog` / `MDrawer` fit.
124
- - No invented props / events / slots.
125
- - No defaulting every success to `toast`.
126
- - No substituting a generated scaffold for `get_golden_page` when a golden sample exists.
127
- - Ops surfaces follow golden layouts first — do not replace them with marketing heroes.
128
- - Express surfaces still use `M*` for controls and `--m-*` for color/space; do not introduce shadcn/Element/etc. stacks suggested by generic design skills.
129
- - Soft-load companions only; never require Impeccable / UI-UX-Pro-Max / Frontend Design to be installed.
130
-
131
- ## Soft companions
132
-
133
- If already installed in the consumer project:
134
-
135
- | Companion | After contract is fixed, may help with |
136
- | --- | --- |
137
- | `frontend-design` | Distinctive Express / brand moments |
138
- | `impeccable` | Named polish / audit passes |
139
- | `ui-ux-pro-max` | Mood / industry keywords for Express only |
140
-
141
- Details: [optional-companions.md](references/optional-companions.md). Distilled craft lives in [visual-craft.md](references/visual-craft.md) so this skill works **standalone**.
142
-
143
- ## Output expectations
144
-
145
- - Vue 3 `<script setup lang="ts">`.
146
- - PascalCase `M*` in templates.
147
- - Domain-real copy and data shapes (not placeholder “示例 / Name / No data” when the brief names a product).
148
- - Scoped CSS minimal; tokens only (`color-mix` / gradients from `--m-*` OK; control widths may be inline).
149
- - Craft pass completed for the lane (see step 5).
150
- - For multi-file asks: sensible `views/` / `components/` split; otherwise one SFC is fine.
151
-
152
- ## Bundled references
153
-
154
- | File | Read when |
155
- | --- | --- |
156
- | [surfaces.md](references/surfaces.md) | Choosing / composing non-Ops (and hybrid) surfaces |
157
- | [page-layouts.md](references/page-layouts.md) | Ops golden layouts |
158
- | [visual-craft.md](references/visual-craft.md) | Ops polish, atmosphere recipes, anti-defaults, polish modes |
159
- | [design-system.md](references/design-system.md) | Principles, tokens, bans |
160
- | [component-index.md](references/component-index.md) | Catalog + decision-id index |
161
- | [decision-recipes.md](references/decision-recipes.md) | Scenario → component → key props (generated; offline MCP mirror) |
162
- | [feedback.md](references/feedback.md) | message / toast / MMessage |
163
- | [review-checklist.md](references/review-checklist.md) | Pre-delivery checks |
164
- | [optional-companions.md](references/optional-companions.md) | Combining with external design skills |
1
+ ---
2
+ name: morya-ui-pages
3
+ description: >
4
+ Build, redesign, critique, or polish any Vue 3 UI surface that should use the
5
+ morya-ui component library — admin CRUD (list, form, dashboard, detail,
6
+ settings), auth and onboarding, empty and error states, wizards, overlays,
7
+ marketing/landing and pricing pages, docs chrome, and hybrid product UI.
8
+ Trigger on: morya-ui, M* components, --m-* tokens, golden pages, page snippets,
9
+ 后台页, 列表页, 表单页, 仪表盘, 登录页, 注册, 空状态, 向导, 落地页, 官网,
10
+ landing, login, dashboard, settings, onboarding, or “用组件库做页面”. Prefer
11
+ this skill over generic frontend-design, impeccable, or ui-ux-pro-max when the
12
+ implementation stack is morya-ui; those companions may deepen taste and polish
13
+ after structure/contract are fixed (see references/optional-companions.md).
14
+ Do not use for backend-only work or for authoring new components inside the
15
+ morya-ui library source itself.
16
+ ---
17
+
18
+ # Morya UI Pages
19
+
20
+ Guide agents that **consume morya-ui** across the full product surface — not only admin CRUD.
21
+
22
+ Two layers always apply:
23
+
24
+ 1. **Contract** — only `M*` controls, `--m-*` tokens, real APIs (MCP/docs). Never invent props or mix UI kits.
25
+ 2. **Craft** — pick the right surface pattern, then apply intentional visual direction (distilled from Frontend Design / Impeccable / UI-UX-Pro-Max ideas). Ops stays disciplined; expressive surfaces (landing, auth brand moments, empty states) may take a justified aesthetic risk — still on-token and on-component.
26
+
27
+ **Default build path (composition-first):** pin surface → L2 decisions + page snippets → craft → validate. Golden pages are an **optional** whole-page block-order check — not the default clone target.
28
+
29
+ When companions conflict with this skill or project `DESIGN.md`, **this skill wins**.
30
+
31
+ ## Surface map (pick one first)
32
+
33
+ | Lane | Surfaces | Primary references |
34
+ | --- | --- | --- |
35
+ | **Ops** | list, form, dashboard, detail, settings, filter drawer, CRUD dialog | [page-layouts.md](references/page-layouts.md) block order + snippets |
36
+ | **Account** | login, register, invite, forgot/reset password, profile | [surfaces.md](references/surfaces.md) § Account + `auth-split-shell` |
37
+ | **Flow** | onboarding, empty state, wizard/stepper, success/result | [surfaces.md](references/surfaces.md) § Flow + empty/result/wizard snippets |
38
+ | **System** | 404 / error, permission denied, maintenance | [surfaces.md](references/surfaces.md) § System |
39
+ | **Express** | marketing landing, pricing, feature showcase, docs marketing chrome | [surfaces.md](references/surfaces.md) § Express + [visual-craft.md](references/visual-craft.md) |
40
+ | **Overlay** | dialog, drawer, popover, command menu as the main UI | [surfaces.md](references/surfaces.md) § Overlay + form-in-dialog/drawer snippets |
41
+
42
+ Unclear brief → ask **one** short question, or default: Ops → closest page-layout checklist + snippets; public marketing → Express.
43
+
44
+ Full taxonomy: [references/surfaces.md](references/surfaces.md).
45
+
46
+ ## Prerequisites
47
+
48
+ 1. `morya-ui` installed; `morya-ui/styles.css` imported.
49
+ 2. Prefer `@morya-ui/mcp` — never invent prop / event / slot names.
50
+ 3. Component APIs, decision recipes, page snippets, and feedback rules come from `@morya-ui/mcp`. Golden pages are optional assembly demos. Without MCP, use this skill's `references/`. Project `DESIGN.md` overrides generic taste when the AI pack is merged.
51
+
52
+ ## Workflow
53
+
54
+ ### 1. Pin subject, audience, surface, job, **style**
55
+
56
+ State explicitly (even briefly in thinking):
57
+
58
+ - **Subject** — product / domain vernacular (not generic “SaaS”)
59
+ - **Audience** — who uses this screen
60
+ - **Surface** — from the map above
61
+ - **Single job** — what the first viewport must accomplish
62
+ - **Style direction** — resolve in this order (see [style-presets.md](references/style-presets.md); **no preset catalog**):
63
+ 1. User **reference** or **explicit description** → **must follow** (map to `--m-*` + `M*`; never substitute another face)
64
+ 2. No description, but **clear prompt cues** → infer and **state your reading** in one sentence
65
+ 3. **Uncertain** → **ask once** for a description or reference; do not invent the full look first
66
+ 4. User says “直接写 / 你看着办” with still no cues → quiet flat on-token admin face, **say so**; never default glass/neon/aurora
67
+
68
+ Golden pages (when used) lock **block order**, not aesthetics. Blindly cloning golden visuals makes pages feel stiff — prefer composing snippets.
69
+
70
+ For Express / branded Account moments, also draft a tiny **design plan** (see [visual-craft.md](references/visual-craft.md)): palette roles mapped to `--m-*` (extend only if the project already customizes theme), type roles, layout concept, one signature element. For Ops, Ops polish + the resolved direction is enough unless the user asks for a redesign.
71
+
72
+ ### 2. Load the smallest useful references
73
+
74
+ | Need | Prefer (MCP) | Else read |
75
+ | --- | --- | --- |
76
+ | Ops pattern + snippets | `recommend_page` → **`suggestedSnippets`** / **`get_page_snippet`** + **`recommend_component`** | [page-layouts.md](references/page-layouts.md) + [decision-recipes.md](references/decision-recipes.md) |
77
+ | Style direction | `recommend_page({ style })` / **`get_style_direction`** | [style-presets.md](references/style-presets.md) |
78
+ | Account / Express / empty / result | snippets (`auth-split-shell`, `empty-block`, `result-block`, …) + `recommend_page` | [surfaces.md](references/surfaces.md) |
79
+ | Optional whole-page block order | `get_golden_page` only when unsure of section order or user asks to mirror a golden sample | [page-layouts.md](references/page-layouts.md) |
80
+ | Visual direction | — | [visual-craft.md](references/visual-craft.md) + [style-presets.md](references/style-presets.md) |
81
+ | Components / **API truth** | `search` / **`get_component`** / `get_example` / **`recommend_component`** (L2 recipes + `relatedSnippets`) | [decision-recipes.md](references/decision-recipes.md) + [component-index.md](references/component-index.md) |
82
+ | Tokens / rules | `get_design_rules` | [design-system.md](references/design-system.md) |
83
+ | Feedback API | — | [feedback.md](references/feedback.md) |
84
+ | **Required checks** | **`validate_usage`** (every `M*` you used) + `validate_page` | [review-checklist.md](references/review-checklist.md) |
85
+
86
+ ### 3. Compose
87
+
88
+ **Ops:** follow [page-layouts.md](references/page-layouts.md) **block-order checklist**; fill each block with **`get_page_snippet`** / `suggestedSnippets` (filters, table, header actions, form-in-dialog, confirm-delete, …). Apply the resolved **style direction** for density/chrome/copy; prefer `MPage*` over custom chrome. Do not freeze every Ops page into identical chrome. List density/sider cues (`dense` / `rail`) inform craft — do not invent new golden-page variants.
89
+
90
+ **Account / Flow / System:** centered or split shells with `MCard` / `MForm` / `MEmpty` / `MResult` (see surfaces + snippets); keep controls as `M*`. Persistent form errors use field `errorMessage` or a token-styled `role="alert"` — `<MMessage>` is the `message` host, not an inline alert.
91
+
92
+ **Express:** hero + sections with intentional hierarchy; interactive bits still `MButton` / `MTag` / etc.; atmosphere via layout, motion, and tokens — not a second component library.
93
+
94
+ **Overlay:** build the host page lightly; put the real job inside `MDialog` / `MDrawer` / `MCommandMenu` (use `form-in-dialog` / `form-in-drawer` snippets).
95
+
96
+ ### 4. Wire real API usage
97
+
98
+ - Import from `morya-ui` (or documented subpath + style).
99
+ - **Selection + key props:** call MCP **`recommend_component`** (by query or `decision` id) and apply the returned **recipe** (`props` / `slots` / `events`), **antiPatterns**, and **`relatedSnippets`**. Without MCP, read [decision-recipes.md](references/decision-recipes.md). Then confirm full API with `get_component` / `get_example`.
100
+ - Forms: `MForm` + fields; `@submit` + `type="submit"` (or documented footer button pattern on `form-in-dialog` snippet).
101
+ - Tables: `columns` + `rows` + `row-key`; `#cell-{key}`. There is no `data` prop. For full-viewport admin lists whose main job is one table, consider `MPageContent fill` + `MTable fill paginator`; skip `fill` for embedded/short/whole-page-scroll cases (see [page-layouts.md](references/page-layouts.md)).
102
+ - Enums → `MSelect` / `MTreeSelect`; action menus → `MDropdown`.
103
+ - Destructive → `MConfirmDialog` / `MConfirmPopup` (`confirm-choice` + `confirm-delete` snippet).
104
+ - Feedback → default **`message`**; `toast` only for summary+detail / async; persistent form errors → `errorMessage` / `role="alert"` (`feedback-choice`). See [feedback.md](references/feedback.md).
105
+ - Motion → intensity with `useMotion` (`full` / `reduced` / `none`); overlay enter/exit with `transition` prop or `createMoryaUI({ motion: { transitions } })` — do not invent a second animation stack. Prefer MCP / docs `motion` guide.
106
+ - **Before craft:** for each unfamiliar or newly written `M*` usage, call MCP **`get_component` / `get_example`**, then **`validate_usage`**. Fix every `unknown-prop` / `unknown-event` before delivery.
107
+ - `recommend_page(includeScaffold: true)` may return golden source as a **structure reference** — remap copy/data only; default path does **not** require cloning the whole page. Never treat generated fallback as the visual target.
108
+
109
+ ### 5. Craft pass (always — lane-aware + companions)
110
+
111
+ Run **before** delivery. Do not stop at a structurally correct shell.
112
+
113
+ 1. Resolve **style direction** ([style-presets.md](references/style-presets.md)) — reference/description first; else prompt cues; else **ask**; never silent AI face. **No preset catalog.**
114
+ 2. Apply lane craft from [visual-craft.md](references/visual-craft.md):
115
+ - **Ops / Operate:** resolved direction + § Ops polish (one primary, menu icons, `MStatus`, designed empty, no decorative cards).
116
+ - **Account / Flow:** one calm brand or empty-state cue from § Shell recipes; form errors via `errorMessage` / token `role="alert"`.
117
+ - **Express / Persuade:** short design plan + one signature; avoid AI-default looks; optional 1–2 token-only motions via `useMotion`. Signature ≠ unearned gradient/glass/neon.
118
+ 3. **If companions are already installed** (see [optional-companions.md](references/optional-companions.md)):
119
+ - Express / brand → may load **`frontend-design`** for POV after contract **and style direction** are fixed
120
+ - User asks 更大胆/更克制/polish/audit → may load **`impeccable`** command (`bolder` / `quieter` / `polish` / …) **inside** the resolved direction
121
+ - Mood/industry keywords only → optional **`ui-ux-pro-max`** search, then map to `--m-*` (not a preset id)
122
+ - a11y pass → optional **`fixing-accessibility`** after visual
123
+ - Max **one** visual companion per task; always remediate with `M*` + `--m-*`; strip companion-added AI atmosphere the user did not ask for
124
+ 4. If companions are **absent**, use distilled visual-craft / style-direction — do **not** block or ask to install mid-task.
125
+ 5. **All lanes:** responsive, focus visible, domain-real copy. User **reference** overrides companion taste within the morya contract.
126
+
127
+ Named polish modes (`quieter` | `bolder` | `clarify` | `audit` | …): extra pass when the user asks to improve an existing screen.
128
+
129
+ ### 6. Review
130
+
131
+ Use [review-checklist.md](references/review-checklist.md) (contract + craft sections).
132
+
133
+ **Required when MCP is available:**
134
+
135
+ 1. `validate_usage` on the page (or per component) — API accuracy gate
136
+ 2. `validate_page` — layout / token / contract advisories
137
+
138
+ Do not deliver with unresolved `unknown-prop` / `unknown-event`.
139
+
140
+ ## Hard boundaries
141
+
142
+ - No second UI kit on the same surface.
143
+ - No hand-rolled table/modal when `MTable` / `MDialog` / `MDrawer` fit.
144
+ - No invented props / events / slots.
145
+ - No defaulting every success to `toast`.
146
+ - No substituting a generated scaffold for a real golden sample when the user asked to mirror one — but default path composes snippets, not full-page clones.
147
+ - Ops surfaces follow page-layout **block order** — do not replace them with marketing heroes.
148
+ - Express surfaces still use `M*` for controls and `--m-*` for color/space; do not introduce shadcn/Element/etc. stacks suggested by generic design skills.
149
+ - Soft-load companions only; never require Impeccable / UI-UX-Pro-Max / Frontend Design to be installed.
150
+ - Do **not** invent decorative glass / neon / aurora / neumorph / full-page gradients unless the **user reference or description** clearly asks for them.
151
+ - Do **not** add new golden-page craft variants (`list-page-*`); express density/sider via style direction + polish.
152
+
153
+ ## Soft companions
154
+
155
+ If already installed in the consumer project, **combine** them after structure + contract (do not replace this skill):
156
+
157
+ | Companion | Load when | Role |
158
+ | --- | --- | --- |
159
+ | `frontend-design` | Express / branded Account moments | Distinctive design plan + signature (taste) |
160
+ | `impeccable` | Polish / bolder / quieter / audit / delight asks | Named Operate/Persuade craft passes |
161
+ | `ui-ux-pro-max` | Mood / industry keyword search for Express | Keywords → map to `--m-*` (no preset ids) |
162
+ | `fixing-accessibility` | a11y audit after visual | Names, keyboard, focus on top of `M*` |
163
+
164
+ Routing, conflict rules, and load budget: [optional-companions.md](references/optional-companions.md). Distilled craft in [visual-craft.md](references/visual-craft.md) + [style-presets.md](references/style-presets.md) keeps this skill **standalone**.
165
+
166
+ ## Output expectations
167
+
168
+ - Vue 3 `<script setup lang="ts">`.
169
+ - PascalCase `M*` in templates.
170
+ - Domain-real copy and data shapes (not placeholder “示例 / Name / No data” when the brief names a product).
171
+ - Scoped CSS minimal; tokens only (`color-mix` OK). Prefer **flat** surfaces; gradients / glass / glow **only** when the user/reference asks (control widths may be inline).
172
+ - Craft pass completed for the lane (see step 5).
173
+ - For multi-file asks: sensible `views/` / `components/` split; otherwise one SFC is fine.
174
+
175
+ ## Bundled references
176
+
177
+ | File | Read when |
178
+ | --- | --- |
179
+ | [surfaces.md](references/surfaces.md) | Choosing / composing non-Ops (and hybrid) surfaces |
180
+ | [page-layouts.md](references/page-layouts.md) | Ops block-order checklists (fill with snippets) |
181
+ | [style-presets.md](references/style-presets.md) | Style resolution (no preset catalog) |
182
+ | [visual-craft.md](references/visual-craft.md) | Ops polish, shell recipes, anti-defaults, polish modes |
183
+ | [design-system.md](references/design-system.md) | Principles, tokens, bans |
184
+ | [component-index.md](references/component-index.md) | Catalog + decision-id index |
185
+ | [decision-recipes.md](references/decision-recipes.md) | Scenario → component → key props (generated; offline MCP mirror) |
186
+ | [feedback.md](references/feedback.md) | message / toast / MMessage |
187
+ | [review-checklist.md](references/review-checklist.md) | Pre-delivery checks |
188
+ | [optional-companions.md](references/optional-companions.md) | Combining with external design skills |