DOL Design System - Direction
Scope: Triết lý, core pillars, anti-patterns cross-topic. Compact “why” layer. Technical topic files (same folder):
typography.md,color.md,radius.md,spacing.md,shadow.md. Code reference:../ui-style-guide/CORE.md(Tailwind classes, component recipes).
1. Triết lý tổng
Section titled “1. Triết lý tổng”Guideline này định nghĩa cảm giác chung của mọi surface DOL (trừ KID - có guideline riêng). AI và designer được khuyến khích sáng tạo về layout, animation, visual treatment - miễn là kết quả giữ được bản sắc DOL và không phạm anti-patterns.
Cảm giác mục tiêu
Section titled “Cảm giác mục tiêu”- Professional nhưng ấm - không lạnh lẽo như enterprise dashboard, không rối như trang tin tức.
- Rộng rãi, thoáng đãng - whitespace là feature, không phải lỗi.
- Rõ ràng, dễ quét - hierarchy rõ bằng mắt, không cần đọc kỹ mới hiểu cấu trúc.
- Tinh tế, không phô trương - chi tiết nhỏ tạo chất lượng (radius mềm, transition mượt, màu nhất quán).
2. 4 Core pillars
Section titled “2. 4 Core pillars”Visual direction mặc định của DOL Design System:
- Semantic-first - ưu tiên token semantic trước; không set tay raw values nếu không có lý do rõ.
- Variable-first styling - variable là lớp mặc định; effect style dùng cho elevation/focus; paint style chỉ dùng khi là reusable decorative asset hoặc spec gọi đúng tên.
- Soft-large radius - controls và surfaces mặc định thiên về bo tròn mềm, không phải sharp-corner UI.
- Generous spacing - dùng khoảng trắng để tạo hierarchy rõ, nhóm element liên quan theo proximity trước khi thêm line/divider.
3. Style layer precedence
Section titled “3. Style layer precedence”Áp dụng theo thứ tự này khi styling UI:
- Variable / semantic token = lớp mặc định cho text, fill, surface, border, radius, spacing, sizing.
- Effect style = chỉ dùng cho elevation, colored depth accent, focus ring.
- Paint style = chỉ dùng khi cần reusable decorative/media surface đã được canon đặt tên sẵn.
Quy tắc cứng:
- Không dùng paint style để thay thế semantic text color, border color, background color cơ bản.
- Không dùng effect style như cách bù cho spacing hoặc hierarchy yếu.
- Nếu chưa có lý do rõ ràng, luôn quay về variable trước.
→ Technical detail: shadow.md §Variable-first rule + §Paint style usage.
4. Bản sắc màu DOL
Section titled “4. Bản sắc màu DOL”Mỗi màu mang ý nghĩa cố định. DOL tuân thủ bảng Báo hiệu Hành Vi chung.
Canonical shade = -600 (NOT Tailwind’s default -500). Tất cả intent class dưới đây dùng shade 600 khi solid vivid.
| Intent | Class prefix | Canonical value | Vai trò |
|---|---|---|---|
| Brand | bg-brand-* | #D42525 (custom) | Thương hiệu DOL, accent logo, CTA thương hiệu |
| Danger / Error | bg-red-* | red-600 | Error, xóa, thao tác nguy hiểm |
| Success | bg-green-* | green-600 | Success, positive feedback, tick đúng |
| Warning | bg-amber-* | amber-600 | Warning nhẹ, near deadline, review |
| Info | bg-blue-* | blue-600 | Link, active state, progress, in-progress badge |
| Special | bg-purple-* | purple-600 | Premium, feature đặc biệt, gamification |
| AI | bg-sky-* | sky-600 | AI features, smart actions, chatbot, magic/sparkles |
| Neutral | bg-slate-* | slate-* range | Text/border/surface. Không dùng gray-* / zinc-* / neutral-*. Không text-black. |
Semantic aliases (preferred cho new code): bg-danger-*, bg-success-*, bg-warning-*, bg-info-*, bg-special-* - map xuống underlying Tailwind class.
Rules cứng:
- Brand ≠ Danger.
bg-red-*= danger/error only.bg-brand-*= custom class (NOTbg-red-*). - Canonical shade =
-600(NOT-500). - Text trên colored/inverse bg cần fixed white: dùng
text-on-inverse-primary(--white-w100).text-white=--neutral-n00. - Không dùng
bg-brand-*cho body text dài. - Tối đa 2 semantic accent colors đồng thời per view.
English skill semantic colors
Section titled “English skill semantic colors”Áp dụng cho title, icon, tag/badge/card tint liên quan trực tiếp đến skill đó.
| Skill | Color | Rationale |
|---|---|---|
| Reading | Emerald/Green | Tiếp thu, đọc hiểu |
| Listening | Blue | Luồng âm thanh thông suốt |
| Writing | Amber/Yellow | Sáng tạo, tập trung viết |
| Speaking | Rose (KHÔNG phải Brand Red) | Tự tin, phát âm lớn |
| Full Test / Online Test | Purple | Đa kỹ năng, đánh giá toàn diện |
| AI Features / Smart Actions | Sky/Cyan | Thông minh, gợi ý, magic |
→ Technical detail: color.md §Semantic text colors + §Quick mapping by use case.
5. Critical accessibility - CVD (color blindness)
Section titled “5. Critical accessibility - CVD (color blindness)”Khoảng 8% nam + 0.5% nữ có color vision deficiency.
Confusing pair: blue vs purple (info vs special). Normal ΔE = 21, deuteranopia ΔE = 2 → khoảng 5% users không phân biệt được.
Rule cứng khi blue + purple xuất hiện cùng:
- KHÔNG rely on color alone.
- Pair với icon hình dạng khác nhau + text label rõ ràng.
- Chart/data viz: dùng pattern + label, không chỉ màu.
- Nav/tab: thêm icon prefix bên cạnh label.
Nếu user phải distinguish 2 elements bằng visual only, không dùng blue + purple cùng nhau. Tách ra blue + green hoặc purple + amber.
→ Technical detail: color.md §CVD considerations (có code examples).
6. Typography philosophy
Section titled “6. Typography philosophy”Clear voice, not loud voice - typography phục vụ việc đọc, không decorate cho UI.
- 2 fonts only:
Plus Jakarta Sans(heading/display) +Inter(body/label).Noto Serifdành riêng cho quote. Because DOL là education, text cần feel như textbook chất lượng - không phải marketing page đầy font-experiments. - Handwritten accent font exception (landing only): cho personal/emotional accent ngắn ≤8 từ, 1 lần/page max -
Caveat/Pacifico/Dancing Script. KHÔNG cho body/heading/label. Recipe:ui-style-guide/landing.md §7.8. - Body baseline: 14px (
--text-base). Không dùng <13px. Reading comfort > dense UI - DOL user đọc lâu, không scan nhanh. - Density taxonomy:
fit/compact/standard/extended.standard= default cho đa số. Density là tool của context, không phải stylistic choice. fitchỉ dùng cho text trang trí, 1 dòng duy nhất - không dùng cho content cần đọc. Dùng sai = text crop mid-word, user cảm giác app chưa tinh.
→ Technical detail: typography.md §Text scale + §Rule line-height theo độ dài nội dung.
7. Spacing philosophy
Section titled “7. Spacing philosophy”Breathing room is content - whitespace không phải empty space, là nhịp thở để user tiêu hóa thông tin.
- Generous spacing - khi phân vân giữa 2 gap values, chọn giá trị lớn hơn. Because DOL là learning context, user cần khoảng nghỉ mắt để xử lý - tight spacing đọc như productivity tool (wrong feel).
- Hierarchy-first - tăng spacing giữa nhóm khác nhau trước khi thêm divider. Divider là last resort, spacing là first tool.
- Atomic grouping: atom → molecule → organism → section, mỗi cấp có nhịp spacing riêng. User đọc UI như đọc văn bản có paragraph - cần cấp độ break.
Core laws:
- Proximity - element cùng chức năng gần nhau hơn element khác nhóm.
- Similarity - item cùng loại dùng cùng nhịp spacing/inset.
→ Technical detail: spacing.md §Spacing levels A-D + §Recommended defaults.
8. Radius philosophy
Section titled “8. Radius philosophy”Pillowy confidence - controls cảm giác như pressed foam, không phải laser-cut acrylic.
- Soft-large radius - user cảm thấy UI “mời chạm” thay vì “cấm kỵ”. Because DOL = education (trust + calm), sharp corners đọc như enterprise compliance dashboard - wrong feel cho learning context.
- Radius scales with element height - bigger surface cần bigger curve để optical consistency (h48/r16, h64/r24). Không phải công thức để nhớ, là tỷ lệ để internalize.
- Pill = purposeful commitment - chip/tag/capsule only. “Button muốn bo nhiều” là red flag - nếu nó muốn pill, có lẽ nó nên là chip.
→ Technical detail: radius.md §Control radius by element height + §Default control mapping.
9. Shadow philosophy
Section titled “9. Shadow philosophy”Paper on desk, not neon on stage - shadow tạo depth tinh tế, không drama.
- Neutral shadow = default elevation -
shadow-neutral/to-bot/1..5tùy mức nổi. Shadow như bóng nhẹ của trang giấy đặt trên mặt bàn - đủ để mắt nhận ra depth, không intrude vào reading flow. - Colored shadow (brand/info/success/etc.) chỉ dùng khi:
- Cần accent có chủ đích theo brand/category
- Surface mang tính campaign / special state / themed section
- Không dùng colored shadow làm default elevation cho layout bình thường. Colored shadow là spotlight - dùng sai = sân khấu rực rỡ chứ không phải education UI.
- Không thay focus ring bằng colored shadow level 3/4/5.
- Tối đa 2 elevation levels đồng thời per view. Layer quá nhiều shadow = floating mess, user mất sense of depth order.
→ Technical detail: shadow.md §Default elevation + §Colored shadows.
10. Anti-patterns cross-topic
Section titled “10. Anti-patterns cross-topic”🛑 Match-and-refuse (meta-rule for all §10 sub-tables): nếu code/design bạn sắp commit khớp một row trong bất kỳ sub-table nào dưới, STOP - rewrite approach, không chỉ swap value lẻ. DIRECTION §10 = philosophy + WHY; xem
CORE.md§11 cho quick-ref Tailwind mapping.
Layout
Section titled “Layout”<dol_anti_pattern scope=“direction-10-layout”>
| ID | ❌ Không làm | Vì sao | ✅ Thay vào đó |
|---|---|---|---|
| 01 | Content rộng hơn 1280px không có max-width | Mắt user chạy quá xa giữa các từ; đọc thành marathon, không phải reading flow | max-w-[1120px] đến max-w-[1280px] + mx-auto |
| 02 | Padding page <16px mobile | Không chỉ ugly - feels cheap app, user trust drops instant trên first impression | Min 16px mobile, 24-32px tablet, 32-60px desktop |
| 03 | Section liền nhau không có khoảng cách rõ | UI như list không đoạn; user không biết chuyển context giữa blocks | --section-gap-* (32-80px) hoặc divider nhẹ |
| 04 | Grid quá đều, không focal point | Everything equal priority = nothing has priority; trang như Excel sheet vô hồn | Cho 1-2 element “to hơn” / “nổi hơn” dẫn mắt |
</dol_anti_pattern>
Typography
Section titled “Typography”<dol_anti_pattern scope=“direction-10-typography”>
| ID | ❌ Không làm | Vì sao | ✅ Thay vào đó |
|---|---|---|---|
| 01 | Hơn 3 cấp font-size trong 1 card | Mỗi size = 1 hierarchy layer user phải parse; brain overload → skip card | Tối đa 3 cấp: title → body → label |
| 02 | Body text <13px | A11y fail + DOL có user lớn tuổi; readability > density cho learning context | Body tối thiểu 14px (--text-base) |
| 03 | Heading + body cùng weight | Hierarchy invisible → user không biết đọc từ đâu; visual chaos = skip | Heading nặng hơn body ít nhất 1 bậc |
| 04 | Quá nhiều màu text trong 1 view | Rainbow UI feels unprofessional; DOL là education, không phải children’s game | Stick to semantic: emphasis / primary / secondary / placeholder |
</dol_anti_pattern>
Color & Brand
Section titled “Color & Brand”<dol_anti_pattern scope=“direction-10-color-brand”>
| ID | ❌ Không làm | Vì sao | ✅ Thay vào đó |
|---|---|---|---|
| 01 | bg-red-* cho brand | Brand và danger trộn lẫn → user confuse CTA với cảnh báo; trust-crash instant | Brand chỉ dùng custom class bg-brand-* (mapped #D42525). bg-red-* = danger only |
| 02 | bg-brand-* cho error/danger | Brand feel biến thành “mọi thứ đang hỏng”; signal-noise inverted | Danger = bg-red-* (canonical -600) |
| 03 | Hơn 2 semantic accents đồng thời | Eye không biết nhìn đâu trước; cognitive overload = UI thất bại | 1 brand + 1 status color per context |
| 04 | bg-blue-* cho “mọi thứ nổi bật” | Blue loãng ý nghĩa → mất signal active vs decorated | Blue = progress/info/active/link; nổi bật → bg-brand-* |
| 05 | Shade -500 làm canonical | TW default là -500 nhưng DOL tune shade cho WCAG + aesthetic tại -600 | Luôn dùng -600 cho solid vivid intent |
| 06 | text-white trên vivid bg (shade 500-600) | Dark mode sẽ swap → text biến màu giữa theme; broken contrast | text-on-inverse-primary cố định trắng xuyên theme |
| 07 | gray-* / zinc-* / neutral-* | Neutral family split = inconsistent hover/border across components | Dùng slate-* duy nhất |
| 08 | Background gradient rực rỡ toàn page | DOL = calm classroom, not casino landing - phá cảm giác space to think | Gradient nhẹ (slate-50 → white) hoặc chỉ hero/header, body giữ neutral |
| 09 | Card trắng trên trắng không border/shadow | Border = edge definition; thiếu = card biến mất khi viewport thu nhỏ | Border bắt buộc (border-slate-100 / border-slate-200); shadow bổ trợ |
</dol_anti_pattern>
Spacing & Depth
Section titled “Spacing & Depth”<dol_anti_pattern scope=“direction-10-spacing-depth”>
| ID | ❌ Không làm | Vì sao | ✅ Thay vào đó |
|---|---|---|---|
| 01 | Shadow quá đậm hoặc nhiều levels đồng thời | Mỗi level = noise; UI feels như web 2010, mất modern feel | Tối đa 2 levels per view; ưu tiên neutral-1..3 |
| 02 | Padding nội bộ không đều 4 phía | Feels đối xứng sai → user perceive misalign dù không conscious | Bội số 4px; top/bottom ≥ left/right |
| 03 | Element quá sát (<8px) khi không liên quan | Brain nhóm chúng lại = hiểu sai structure; spacing là ngôn ngữ grouping | Giữ 12-16px+ giữa nhóm không liên quan |
</dol_anti_pattern>
Component & Interaction
Section titled “Component & Interaction”<dol_anti_pattern scope=“direction-10-component-interaction”>
| ID | ❌ Không làm | Vì sao | ✅ Thay vào đó |
|---|---|---|---|
| 01 | Button không có hover/focus | User không biết clickable vs label; trust-gap “có chạm được không?” | Min hover: brightness shift hoặc bg change |
| 02 | Click target <32px | Touch miss rate tăng mobile, user rage-tap; app rating drop | Min 36px height; 44px cho primary actions |
| 03 | Transition đột ngột (instant) | Layout change no motion = feels glitchy, context mất theo frame | 150-300ms ease-out cho UI transitions |
| 04 | Loading state trắng trơn | User giả định app hỏng sau 2s blank; skeleton = reassurance | Skeleton / spinner / text “Đang tải…” |
</dol_anti_pattern>
Responsive
Section titled “Responsive”<dol_anti_pattern scope=“direction-10-responsive”>
| ID | ❌ Không làm | Vì sao |
|---|---|---|
| 01 | Text/layout y hệt desktop trên mobile | Chữ to quá, reading flow gãy; screen real-estate waste |
| 02 | Ẩn nav trên mobile mà không có thay thế | User lạc giữa page, không back được; trap UX |
| 03 | Horizontal scroll trên content chính | Anti-pattern từ 2015; user cảm giác app chưa modern/professional |
</dol_anti_pattern>
AI Slop fingerprints
Section titled “AI Slop fingerprints”These patterns reveal “AI made this” instantly. DOL canonical tokens correct nhưng vẫn produce slop nếu dính các pattern dưới. Match-and-refuse: nếu bạn sắp write một trong các PATTERN này, STOP và rewrite element với structure khác hoàn toàn (đừng chỉ swap value).
Naming convention: Universal patterns có ID
slop-NN(canonical, defined here). Product-surface anti-patterns dùng namespace<product>-<topic>-NN(defined trong respectiveui-style-guide/{landing,practice,data-entry}.md). AI agents có thể cite cả hai layers, e.g., “vi phạm slop-08 + practice-2.6-answer-cards row 1”.
Named pattern exceptions (đặc biệt cho slop-03 nested-cards): trước khi refuse nested composition, check
../pattern-registry.md- Constellation Block + future named patterns dùng nesting INTENTIONALLY với DIFFERENT treatment per tier (outer frame / middle bg / inner cells). slop-03 chỉ cấm CÙNG treatment chồng nhau, KHÔNG cấm intentional 3-tier composition.
<dol_anti_pattern scope=“direction-10-ai-slop-universal”>
| ID | PATTERN | WHY | REWRITE |
|---|---|---|---|
| slop-01 side-stripe | border-left hoặc border-right: ≥2px solid <color> trên card/list/alert | #1 AI tell ở admin/dashboard/medical UIs; never looks intentional | Full border border border-slate-100 HOẶC background tint bg-blue-50 HOẶC leading icon/number. Không chỉ swap sang shadow inset. |
| slop-02 gradient-text | bg-gradient-* + text-transparent + bg-clip-text trên heading/metric | Top-3 AI tell; decorative without meaning | Solid color (text-slate-900) + font weight/size cho emphasis |
| slop-03 nested-cards | Card (bg-white + border + shadow) chứa Card khác cùng treatment | Visual noise, excessive depth, flatten-failure | Flatten: 1 outer card + inner content dùng spacing + typography hierarchy, KHÔNG nested containers |
| slop-04 monotonous-spacing | Cùng 1 gap/padding value (vd gap-4 everywhere) trong whole view | No rhythm = layout monotone, feels templated | Vary: atom=gap-2, molecule=gap-3, organism=gap-4, section=gap-8 (per §7) |
| slop-05 everything-centered | Multiple consecutive text-center trong siblings (section sau section) | Every element centered = nothing stands out; lazy alignment | Left-align body + asymmetric composition. Center reserved cho hero + CTA duy nhất. |
| slop-06 icon-tile-above | Big icon box (rounded + tinted bg) trên mỗi heading trong feature list | Templated, makes site look AI-generated instant | Inline icon bên cạnh heading HOẶC no icon. Icon box reserved cho genuine feature card với purpose, không decoration. |
| slop-07 dark-glow | shadow-[...rgba(brand-color)...] box-shadow với colored glow | ”Cool dark aesthetic” without design decisions | Neutral shadow (shadow-neutral/to-bot/N). Colored glow chỉ cho campaign/special state đã canon. |
| slop-08 bounce-easing | cubic-bezier với negative values (overshoot) hoặc ease-bounce/elastic | Dated 2010s feel, real objects decelerate smoothly | ease-out hoặc cubic-bezier(0.25, 1, 0.5, 1) (ease-out-quart) |
| slop-09 layout-animation | CSS transition / transition-property of layout props (width/height/padding/margin) - NOT Tailwind transition-all when only transform/opacity/color/shadow actually change | Layout-prop transitions force repaint + reflow - performance tanks on slow devices | Don’t animate layout props. Use transition-property: transform, opacity, color, box-shadow (or Tailwind transition-all when CSS only changes these - shorthand is fine since nothing layout-ey animates). Height animation → grid-template-rows technique |
| slop-10 body-typography-loud | Body text với uppercase + tracking-wider HOẶC text-justify | Body text treatment như label/hero = AI tell, hurts readability | Body: normal case + normal tracking + text-left (not justified). Uppercase reserved cho label ≤3 words. |
</dol_anti_pattern>
→ Automation: audit.sh catches slop-01, -02, -07, -08, -09, -10 at static scan. Slop-03, -04, -05, -06 need visual review (no reliable regex).
11. DOL English feature naming (domain-specific)
Section titled “11. DOL English feature naming (domain-specific)”Tên chuẩn trên mọi surface:
| Feature | Tên chuẩn | ❌ Không dùng |
|---|---|---|
| Practice | Kho bài tập | Luyện tập, Practice Hub |
| Vocabulary | Sổ từ vựng | Từ vựng, Vocab |
| Courses | Khóa học | Courses |
| Progress | Tiến độ | Theo dõi tiến độ |
→ Xem thêm Playground: docs/DOL_ENGLISH_STYLE_GUIDE.md.
12. Handoff checklist
Section titled “12. Handoff checklist”Smell tests trước khi coi UI hoàn thành - nếu một câu hỏi trả lời “không chắc” = chưa done.
- Hierarchy rõ? - 2-second test: mắt user có biết đọc gì trước, gì sau, gì là optional?
- Nhất quán? - Same element = same style everywhere? Nếu khác = user sẽ hỏi “cái này khác gì vậy?”
- Token đúng vai trò? - Heading =
emphasis, body =primary, phụ =secondary(không ngược)? - Breathing room? - Mắt có “chỗ nghỉ” giữa các nhóm, hay feel crammed/claustrophobic?
- Interactive feedback? - Rê chuột qua clickable → có phản hồi, hay “dead silent”?
- Mobile? - Thu viewport nhỏ → layout elegant adapt, hay gãy/overflow?
- Edge states? - Empty / loading / error: user nhận message rõ ràng, hay màn hình trắng?
- Semantic-first? - Không hardcode raw values (hex, px) khi đã có token tương ứng?
- Blue + purple a11y? - Nếu CVD user dùng UI này, 2 element cùng màu có distinguishable?
- AI slop test? - Nếu show UI này và nói “AI made this”, user có tin ngay không? Nếu có → review §10 AI Slop fingerprints để tìm pattern đang reveal AI-generated feel.
Navigation
Section titled “Navigation”- Topic files (same folder):
typography.md- font family, text scale, density taxonomy, text group matrixcolor.md- semantic hierarchy, skill colors detail, shade scale math, CVD detailradius.md- control / surface / overlay radius by height mappingspacing.md- atomic levels A-D, wireframe defaultsshadow.md- shadow tier mapping, variable/effect/paint precedence, paint style inventory
- Code reference:
../ui-style-guide/CORE.md(Tailwind classes, component recipes) - Deep reference:
../../docs/tailwind-color-guideline.md(18-family mapping)../../docs/alpha-decomposition-spec.md(shade scale + alpha math)../../docs/color-system-rules.md(34 universal color rules)
- See also:
../kid/Design System Guideline/KID_DS_Basic_Guideline.md(KID-specific) - Hub: README.md