🎯 New Showcase Workflow
Quy trình tạo 1 showcase app mới dùng Prisma Design System.
Quick navigation:
Pre-read (BẮT BUỘC)
.agent/skills/style-scaling/SKILL.md— §1 Design Intent Extraction (3-axis).agent/skills/ux-research/SKILL.md— §6 Typography (T1 font ≥14px), §7 A11y (ARIA, focus), §5 Component (states, keyboard)- CSS Naming Rules bên dưới
design-system/components md/ATOMIC-MAPPING.md— Component → token mapping (4-tier: page/section/group/comp)knowledge/stacking-design-methodology.md— §2 Padding Nesting (page > section > group > comp), §8 Slot Anatomy (--_slot-paddingbridge)knowledge/container-padding-rules.md— §3 Gap Model, §4 Rules P1-P6 (uniform padding, slot ownership)knowledge/divider-separator-rules.md— §7 Rules D1-D9 (spacing > divider > border)knowledge/research/density-formula.md— Tier-base multipliers, density presets, showcase config integration
Steps
// turbo-all
1. Design Intent Extraction
Chạy §1 Design Intent Extraction từ style-scaling skill:
DESIGN INTENT EXTRACTION:
- Client/Project : _______________
- Brand color : #XXXXXX → palette candidate: {color-name}
- Secondary color: #XXXXXX | reuse {existing} | none
- Neutral base : zinc | slate | stone | gray | warm
- Density axis : comfortable | compact | default | custom
- Visual axis : default | glass/liquid | minimal | custom(___)
- Font candidate : Inter | Roboto | system | custom(___)
- Tone : conservative | playful | enterprise | consumer | fintech
- Brand exists? : YES (dùng themes/{existing}) | NO (tạo mới)
- Style-mode? : [tên preset] | cần tạo mới
→ Output này quyết định mọi thứ phía sau.
2. Tạo thư mục + pipeline config
mkdir showcase\{name}
Thêm entry vào design-system/scripts/config/showcase-config.json → xem format tại Pipeline Config
Density config — chọn preset hoặc custom:
"density": "comfortable" // preset: compact | comfortable | spacious | mobile | mobile-compact
// hoặc custom:
"density": { "spacing": "3px", "profile": "web", "tier-bases": { "group": 3 } }
→ Xem chi tiết presets tại knowledge/research/density-formula.md §Showcase Config Integration
3. Generate variables.css
node design-system/scripts/pipeline/sync-tokens.js {name}
→ Output: showcase/{name}/variables.css (563+ tokens, ~58KB)
4. Elevation Map — GÁN LAYER CHO MỌI COMPONENT
📖 ĐỌC CSS Naming Rules TRƯỚC.
Output bắt buộc — liệt kê MỌI component, gán layer + density tier, lock tokens:
ELEVATION MAP: {Tên showcase}
┌────────────────────┬───────────┬──────────┬──────────────────────────────────────┐
│ Component │ Layer │ Tier │ Tokens (locked) │
├────────────────────┼───────────┼──────────┼──────────────────────────────────────┤
│ ground-header │ Ground │ page │ bg: --background, fg: --foreground │
│ ground-hero │ Ground │ page │ bg: --background, fg: --foreground │
│ card-account │ Card │ section │ bg: --card, fg: --card-foreground │
│ card-{feature} │ Card │ group │ bg: --card, fg: --card-foreground │
│ item-{name} │ Item │ comp │ (inherits from parent layer) │
│ btn--primary │ Item │ comp │ bg: --primary, fg: --primary-fg │
│ surface-nav │ Surface │ section │ bg: --surface, fg: --surface-fg │
│ surface-toast │ Surface │ comp │ bg: --surface, fg: --surface-fg │
└────────────────────┴───────────┴──────────┴──────────────────────────────────────┘
TIER ASSIGNMENT RULES:
Card ON page → section tier (--section-*)
Card INSIDE section → group tier (--group-*)
Inline item → comp tier (--comp-*)
⚠️ DỪNG LẠI — User phải approve Elevation Map này TRƯỚC KHI viết CSS.
Sau khi approve:
- Mỗi
ground-*class → BẮT BUỘCbackground: var(--background)hoặcvar(--canvas) - Mỗi
card-*class → BẮT BUỘCbackground: var(--card) - Mỗi
surface-*class → BẮT BUỘCbackground: var(--surface) - KHÔNG hardcode
rgba(...),#hexcho bg/fg/border backdrop-filter, decorative gradients → OK hardcode
5. Tạo HTML
BẮT BUỘC có:
<link rel="stylesheet" href="variables.css">
<link rel="stylesheet" href="{app}.css">
HTML class names PHẢI theo elevation map từ Step 4.
6. Tạo CSS + JS
PRE-CODE CHECKLIST (verify trước khi viết CSS):
| ☐ | Rule | Check |
|---|---|---|
| ☐ | STACK | page.padding > section.padding > group.padding > comp.padding? |
| ☐ | GAP | Card dùng Gap Model (container gap, slots không overlap padding)? |
| ☐ | SLOT | Slots dùng --_slot-padding bridge (không hardcode --group-padding-default)? |
| ☐ | PLCHLD | Placeholder margin: 0 (slot owns padding, placeholder không thêm margin)? |
| ☐ | P2 | padding-inline = padding-block (uniform)? |
| ☐ | D1 | Dùng spacing (gap/margin) thay vì border divider? |
| ☐ | D6 | Không divider giữa các cards? |
| ☐ | D9/S8 | Không border-top/bottom bên trong card/dialog/drawer? |
| ☐ | D5 | Divider margin >= var(--spacing-4)? |
| ☐ | S9 | Content trong slot-body KHÔNG thêm padding inline? |
| ☐ | NAMING | Class names có elevation prefix (ground-/card-/surface-)? |
| ☐ | Token | Mọi bg/fg/spacing/radius dùng var(--token)? |
| ☐ | TIER | Spacing/padding/radius tokens match tier assignment (page/section/group/comp)? |
| ☐ | SLOT-MAP | Structural components dùng data-slot attributes? (ENF-6) |
| ☐ | SLOT-NAME | Slot names lấy từ slot-manifest.json, KHÔNG tự tạo? (ENF-6) |
- Dùng template recipe → xem CSS Authoring Guide
- Không có template → dùng DS tokens trực tiếp, KHÔNG hardcode
- CSS class names → PHẢI theo CSS Naming Rules
7. Validate → chạy /post-change
8. Visual test
http://localhost:3000/showcase/{name}/
Quy tắc
- variables.css luôn từ pipeline — KHÔNG copy từ docs/ hay showcase/ khác
- HTML link local —
href="variables.css"(không../../docs/assets/...) - Mọi CSS value dùng tokens — trừ decorative animations (aurora, orbs, shimmers)
- 1 showcase = 1 entry trong
design-system/scripts/config/showcase-config.json - CSS class names theo elevation —
ground-/card-/surface-prefix bắt buộc - Không đặt tên theo business data — tên = vai trò UI
- Component mapping từ ATOMIC-MAPPING.md — đọc trước khi dùng token
- Sau mọi thay đổi → chạy
/post-change→ ghi/dev-journal - Density tier tokens = 4 cấp —
page > section > group > comp(KHÔNG dùng block/module/item)
📎 Appendix A — Pipeline Config
Showcase Config Entry
Thêm entry vào design-system/scripts/config/showcase-config.json → showcases object:
"{name}": {
"description": "{mô tả}",
"tokensDir": "../../design-system/tokens",
"outputDir": "showcase/{name}",
"defaultBrand": "{brand từ Design Intent}",
"density": "comfortable",
"styleFallbacks": {
"light": {
"--transition-fast": "0.15s ease-in-out",
"--transition-normal": "0.25s ease-in-out",
"--shadow-sm": "...",
"--shadow-md": "...",
"--shadow-lg": "...",
"--gradient-primary": "..."
},
"dark": {}
}
}
Reference Showcases
Existing showcases in showcase-config.json làm tham khảo:
nab-open-banking— NAB SME dark theme, comfortable densitybanking-liquid-style— Premium banking, mobile density
CSS Authoring Guide
Dùng DS tokens trực tiếp (default style):
- Colors:
var(--primary),var(--foreground),var(--muted-foreground) - Spacing:
var(--{tier}-padding-{size}),var(--{tier}-stack-gap-{size}) - Radius:
var(--comp-radius),var(--section-radius-default),var(--group-radius-default) - Components:
var(--card),var(--card-border),var(--surface) - KHÔNG hardcode giá trị — luôn dùng
var(--token-name)
Density tier token pattern:
/* Page-level (outermost) */
padding: var(--page-padding-default);
gap: var(--page-stack-gap-default);
/* Section (content region) */
padding: var(--section-padding-default);
gap: var(--section-stack-gap-default);
border-radius: var(--section-radius-default);
/* Group (card/panel) */
padding: var(--group-padding-default);
gap: var(--group-stack-gap-default);
border-radius: var(--group-radius-default);
/* Comp (button/input/item) */
padding: var(--comp-padding-default);
gap: var(--comp-stack-gap-default);
border-radius: var(--comp-radius);
Icons — SVG Only (IC-1/IC-2/IC-3)
- ALL icons MUST be SVG — use
<svg><use href="#ic-name"/></svg>from the icon sprite - NEVER use text characters as icons: ✕ × ▼ ▾ → ← ↑ ↓ ‹ › + are FORBIDDEN
- Close buttons:
<svg class="icon--sm" aria-hidden="true"><use href="#ic-x"/></svg> - Chevrons: Use SVG chevron icons or CSS
transform: rotate()on SVG - Decorative icons: add
aria-hidden="true" - Icon-only buttons: require
aria-labelfor accessibility
Utility Classes
- Do NOT create ad-hoc utility classes like
.gap-xs,.gap-sm - Use tokens directly in component CSS:
gap: var(--comp-stack-gap-small) - If utility classes are needed, name must reflect tier + axis:
.gap-comp-stack-sm
Validation Pipeline
node design-system/scripts/pipeline/sync-tokens.js --all
node design-system/scripts/docs/build-docs.js
node design-system/scripts/pipeline/lint-css.js --all
node design-system/scripts/pipeline/verify-output.js
→ Phải đạt 0 errors
📎 Appendix B — CSS Class Naming (Elevation-Based Convention)
Quy chuẩn đặt tên CSS class cho mọi showcase. Tên class phải phản ánh UI Layer (elevation).
Referenced by:
new-showcase.md(this file),post-change.md(step 7b)
Cú pháp
.[layer]-[component]__[element]--[modifier]
| Phần | Bắt buộc | Mô tả |
|---|---|---|
layer |
Có* | ground-, card-, surface- (bỏ nếu item-level) |
component |
Có | Vai trò UI, KHÔNG phải business data |
__element |
Tuỳ | BEM child element |
--modifier |
Tuỳ | Variant / state |
⚡ Elevation Token Contract (BẮT BUỘC)
Nguyên tắc gốc: Mỗi component phải được gán layer TRƯỚC khi viết CSS. Layer quyết định token → token quyết định giá trị → đổi value = scale toàn bộ.
3 Layers — Mỗi layer lock 4 thuộc tính
| Layer | Prefix | background |
color |
border-color |
box-shadow |
|---|---|---|---|---|---|
| Ground | ground- |
var(--background) hoặc var(--canvas) |
var(--foreground) |
var(--border) |
none |
| Card | card- |
var(--card) |
var(--card-foreground) |
var(--border) |
var(--shadow-sm) hoặc none |
| Surface | surface- |
var(--surface) |
var(--surface-foreground) |
var(--border) |
var(--shadow-lg) trở lên |
Item-level (no prefix) — inherit từ parent layer
.btn, .badge, .avatar, .icon, .tab, .divider
Items không set bg/fg riêng (trừ variant colors như --primary). Chúng kế thừa từ container.
Liquid Glass — Ngoại lệ có kiểm soát
backdrop-filter và decorative animations (shimmer, orbs) được phép hardcode.
Nhưng background, color, border-color PHẢI dùng token.
/* ✅ Liquid glass đúng cách */
.card-account__glass {
background: var(--card); /* ← token */
backdrop-filter: blur(40px) saturate(160%);
border: 1px solid var(--border); /* ← token */
}
🆕 New Value Escalation — Khi palette không đủ
KHÔNG sửa DS gốc. Có 4 tầng xử lý — chọn tầng thấp nhất phù hợp.
Tầng 1 (Ưu tiên) Dùng token có sẵn trong palette
↓ không có
Tầng 2 --local-* trong showcase CSS
↓ nhiều showcase cùng cần
Tầng 3 styles/*.json (style token)
↓ MỌI showcase cần
Tầng 4 Gap Report → primitives/shared (cần User approve)
Tầng 2: Local variable — --local-*
Token CHỈ dùng trong 1 showcase → khai báo ngay trong file CSS:
:root {
/* ─── Local tokens (scope: showcase only) ─── */
--local-nab-gold: #f5c400;
--local-nab-gradient-hero: linear-gradient(135deg,
rgba(40, 140, 60, .18), rgba(220, 195, 50, .14));
}
Naming rule: --local-{showcase}-{name}
Tầng 3 → 4: Escalation
- Tầng 3 (
styles/*.json): ≥2 showcases cùng cần → promote. PHẢI ref primitives. - Tầng 4 (Gap Report): ≥3 showcases + tất cả styles cần → đề xuất. Cần User approve.
Bảo toàn DS gốc
| Hành vi | ✅ Cho phép | ❌ TUYỆT ĐỐI KHÔNG |
|---|---|---|
Thêm --local-* trong showcase CSS |
✅ | |
Thêm effect vào styles/*.json |
✅ (nếu đủ tiêu chí) | |
Sửa primitives/, modes/, shared/, themes/ |
❌ Không có User approve | |
| Hardcode rgba() cho bg/fg/border | ❌ | |
| Hardcode rgba() cho animation | ✅ shimmer, orb, glow |
Elevation Map — Deliverable bắt buộc
TRƯỚC khi viết CSS, agent phải output bảng Elevation Map (xem Step 4) → User phải approve TRƯỚC KHI code.
6 Rules
R1. Class prefix PHẢI phản ánh UI Layer
/* ✅ */ .card-account { background: var(--card); }
/* ✅ */ .surface-nav { background: var(--surface); }
/* ❌ */ .balance-card { background: rgba(15, 15, 15, .7); }
R2. KHÔNG đặt tên theo business data
Tên = vai trò UI, không phải nội dung nghiệp vụ:
| ❌ Sai | ✅ Đúng | Lý do |
|---|---|---|
.balance-card |
.card-account |
"balance" là data |
.approval-card |
.card-task |
"approval" là domain |
.vip-badge |
.badge--vip |
VIP là modifier |
Ngoại lệ: Feature-specific names OK:
.card-cashflow✅,.card-services✅
R3. KHÔNG viết tắt (trừ .btn)
R4. BEM cho children
.card-account /* Block */
.card-account__glass /* Element */
.card-account--elevated /* Modifier */
R5. Variant dùng modifier, KHÔNG tạo class mới
R6. State suffix chuẩn: --active, --disabled, --done, --visible, --loading, --open
Decision Tree
Component nào?
│
├─ Floating (z-index > 0, overlay)? → surface-
├─ Panel / Card (elevated, border)? → card-
├─ Page-level / Fixed bar? → ground-
└─ Small inline element? → no prefix (btn, badge, avatar)
Token Palette per Layer — Quick Ref
Chi tiết đầy đủ: Xem
token-reviewerSKILL.md §1 + ATOMIC-MAPPING.md
| Layer | bg | fg | border | shadow | density tier |
|---|---|---|---|---|---|
| Ground | --background, --canvas |
--foreground |
--border |
none | --page-* |
| Card (on page) | --card, --card-subtle |
--card-foreground |
--card-border |
--shadow-sm |
--section-* |
| Card (nested) | --card, --card-subtle |
--card-foreground |
--card-border |
--shadow-sm |
--group-* |
| Surface | --surface |
--surface-foreground |
--border |
--shadow-lg+ |
--section-* |
| Item | --primary, --secondary… |
…-foreground |
— | — | --comp-* |
Tier assignment rule: Card directly on page →
sectiontier. Card inside section →grouptier. Seeknowledge/research/density-formula.md§Usage Rule for details.
Checklist — Code Review
☐ 1. Class prefix đúng layer?
☐ 2. Tên theo vai trò UI, KHÔNG theo business data?
☐ 3. Không viết tắt?
☐ 4. Children dùng BEM?
☐ 5. CSS body dùng đúng token cho layer?
☐ 6. State dùng suffix chuẩn?
☐ 7. Density tier tokens match nesting context (page/section/group/comp)?