UI Design System — Umaguide
The source of truth for Umaguide's interface. Read this before changing shared styles, adding components, or building a new page.
One identity, stated once: Umaguide is a fast, readable reference tool with a single game-flavored showcase — the homepage. Utility comes first everywhere; the "game UI" is a deliberate accent, never the default.
1. Governing principle — usability first
Every decision answers one question before any other: does this help someone find an answer faster? Decoration is welcome only after that's true.
This resolves the tension the app was stuck in. The site briefly leaned into a "gamified" chrome everywhere (glossy panels, ribbon headers, beveled buttons on ordinary content). Feedback was clear: people came for a tool and the chrome got in the way. We are not reverting to a plain wiki, and we are not keeping chrome everywhere. We commit to a single rule that makes both camps right:
One system, two registers
| Register | Where | Feels like | Built from |
|---|---|---|---|
| A — Utility (default) | Everything except the homepage: lists, detail pages, tools, guides, the nav shell | A clean, fast document / control panel | VitePress --vp-c-* surfaces, plain typography, page-local section markup |
| B — Showcase (exception) | The homepage board, and only the homepage | A tasteful game-UI "portal board" | The ui/ game-kit: UPanel, USectionHeader, UNavTile, glossy --uma-* chrome |
If you are unsure which register a surface belongs to, it is Register A. Register B is an allow-list of one page.
2. The 10% brand-color rule
This is the most important operational rule in the document. Brand color (green) should occupy roughly 10% of any given screen. It is a spotlight, not a wash.
Spend brand color on:
- the active/current nav item indicator
- primary CTA buttons (one per view, usually)
- links and focus rings
- small status badges and counts (e.g. "142 / 312")
- the homepage showcase chrome (Register B is the budgeted exception)
Never spend brand color on:
- full section-header bands on content pages
- card borders, card backgrounds, or thumbnail placeholders
- large fills behind text
- hover backgrounds for ordinary rows (use a neutral tint)
When a page feels "heavy" or "loud," it is almost always over budget on brand color. The fix is to demote fills to neutral surfaces and let typography and spacing carry the hierarchy.
3. Foundations
Two CSS-variable namespaces, kept strictly separate. All tokens live in custom.css.
--vp-c-*— VitePress core: page surfaces, text, dividers. Neutral cool-white / dark. This is the substrate for Register A and the shell.--uma-*— game-UI chrome: glossy gradients, panel headers, beveled buttons. Register B and a few accents only.
Keeping the substrate neutral is what makes the 10% rule achievable. Do not pipe --uma-* greens into page backgrounds or content surfaces.
3.1 Surfaces & text (the neutral substrate)
| Token | Light | Dark | Use |
|---|---|---|---|
--vp-c-bg | #f2f3f7 | #1b1b1f | Page background |
--vp-c-bg-soft | #eef0f6 | #202127 | Filter bars, soft rows, subtle fills |
--vp-c-bg-elv | #ffffff | #202127 | Elevated cards, dropdown panels |
--vp-c-text-1 | #2b2f38 | rgba(255,255,245,.86) | Primary text |
--vp-c-text-2 | #5b6472 | rgba(235,235,245,.6) | Secondary text |
--vp-c-text-3 | #8a93a3 | rgba(235,235,245,.38) | Muted labels, placeholders |
--vp-c-divider | #d6dae3 | rgba(82,82,89,.32) | Hairlines between sections/rows |
--vp-c-border | #c8cdd8 | rgba(82,82,89,.68) | Stronger outlines |
--shadow-color / --shadow-color-lg | green-cast soft | black soft | Card / popover elevation |
3.2 Brand & accent
| Token | Light | Dark | Role |
|---|---|---|---|
--vp-c-brand-1 | #3f8a00 | #6a9e3a | Links, active text, primary accent (AA on white) |
--uma-green | #65ba00 | #6a9e3a | Chrome fills, focus glow, active indicators |
--uma-green-light | #90d300 | #7aba40 | Hover borders, badges |
--uma-green-deep | #3f8a00 | #8dd050 | Brand text on white (e.g. wordmark) |
Secondary accents — use sparingly, with meaning, mostly inside Register B and small badges:
- Pink
--uma-pink #ff3376— events / community / "gold"-tier highlights. - Blue
--uma-blue #6b79e9— database / tools.
These three (green / pink / blue) propagate through game-kit components via a color prop. On content pages, prefer green-or-neutral and reserve pink/blue for genuine category meaning, not decoration.
3.3 Semantic, rarity, skill & training colors
Domain palettes are stable and theme-aware (each has a dark + colorblind variant). Do not hard-code these hex values in components — reference the tokens.
- Status:
--color-success,--color-danger,--color-warning,--color-info - Rarity:
--color-rarity-{ssr,sr,r}-{bg,text} - Skill types:
--skill-type-{name}+--skill-type-{name}-bgfordebuff · overtake · style · distance · recovery · special · passive · vision - Training stats:
--training-{speed,stamina,power,guts,wit}+-bg
3.4 Themes
Six themes, set by toggling classes on <html> (managed in UmaTopNav.vue). Legacy is the default identity; the gamified green is the opt-in "Uma" theme.
| Stored value key (stable) | Menu label | Notes |
|---|---|---|
legacy-light | Legacy Light | ✅ default when system = light |
legacy-dark | Legacy Dark | ✅ default when system = dark |
light | Uma Light | opt-in green |
dark | Uma Dark | opt-in green |
cb-light | Colorblind Light | Okabe-Ito |
cb-dark | Colorblind Dark | Okabe-Ito |
- Default: a first-time visitor with no stored
uma-themelands in Legacy, matchingprefers-color-scheme(light →legacy-light, dark →legacy-dark). The menu is ordered default-first: Legacy → Uma → Colorblind. - Stored keys never change — only the labels did — so every previously saved preference (
light/dark/legacy-*/cb-*) still loads. .darkoverrides surface/text/shadow + every--uma-*chrome token. Every new surface variable must have a dark value..legacyswaps the brand to the site's original reddish-brown (#c16a5f) without touching surfaces — it layers on top of light or dark. This is the default brand..colorblindswaps to an Okabe-Ito palette (brand → blue, red↔green pairs remapped). New status/category colors must stay legible here too.
Rule: never hard-code brand hex. Go through tokens so all six themes follow.
3.5 Typography
| Token | Stack |
|---|---|
--uma-font-display | Inter → Noto Sans JP → Hiragino Kaku Gothic ProN → system-ui |
--uma-font-rounded | same stack — bold UI labels, badges, buttons |
--uma-font-body | same stack — prose, vp-doc |
- Hierarchy comes from size and weight, not color bands. Section titles on content pages are plain
<h2>/<h3>,--vp-c-text-1, optionally with a bottom hairline — never a gradient header. - Display weight 700 for UI; reserve 800 for the homepage showcase and the wordmark. Nav categories sit at 600 (700 when active) — see §4.
- Body prose: 17px / 1.75 line-height (
vp-doc). letter-spacing: 0.01–0.02emon headers; avoid wide tracking on small UI.
3.6 Spacing, radius & elevation scale
Keep these consistent so the two registers still feel like one app.
| Utility (A) | Showcase (B) | |
|---|---|---|
| Corner radius | 6–8px controls, 12px cards/popovers | 9px headers, 11px rows, 18px panels |
| Border | 1px var(--vp-c-divider) | 1px var(--uma-panel-border) + inset gloss |
| Elevation | flat or 0 4px 12px var(--shadow-color) on hover | --uma-panel-shadow (layered) |
| Gap rhythm | 0.25 / 0.5 / 0.75 / 1rem | 8 / 12 / 16px |
Register A leans flat: hairlines and soft hover shadows do the work. Register B is allowed real elevation and gloss.
4. The shell — top nav & search
Files: UmaTopNav.vue (two-tier bar + mobile drawer) and ui/UNavMenu.vue (each desktop category).
The shell is Register A — it must be quiet and functional. It frames every page, so any noise here is noise everywhere.
Structure
- Tier 1 — utility row (52px): wordmark · search · region tabs · external icons · theme menu. Mobile collapses this to wordmark · search · hamburger.
- Tier 2 — category strip (42px, desktop only): the
UNavMenuitems. - Mobile drawer: the categories + utilities stacked, scroll-locked.
Spec (implemented)
The category strip was once a glossy green ribbon, then half-flattened into a "limbo" — two muddy greys, a white-chiclet hover, 800-weight type, no active indicator, and dead ribbon scaffolding. It is now a quiet header:
- One coherent header surface. Both tiers share
--vp-c-bg; the util row's hairline separates the two, and the strip's bottom hairline divides the whole header from the page. No second competing grey block, no glossy ribbon. - Quiet categories:
--uma-font-displayat 600 (700 when active), ~0.9rem,--vp-c-text-2resting,--vp-c-text-1on hover. No background swap on hover — a low-contrast--vp-c-dividerunderline instead of the white chiclet. - Clear active state: a persistent 2px brand-color bottom indicator under the current category, plus slightly stronger (700) text weight. A budgeted brand use, kept to a thin line.
- Dropdown panels (UNavMenu): neutral —
--vp-c-bg-elvcard,12pxradius,1px --vp-c-dividerborder, pointer notch. Item hover is a neutral--vp-c-bg-softtint with brand text, never a brand fill. The optionaldescline stays--vp-c-text-3. - Behavior: opens on hover for pointer devices, toggles on click/tap, closes on outside-click, Escape, and route change.
Search
The search field (SearchDropdown) is canonical Register A and a good north star for the whole shell: pill input on --vp-c-bg-soft, 1px --vp-c-divider, and brand spent only on the focus ring (box-shadow: 0 0 0 3px rgba(101,186,0,.16)). Copy this restraint.
5. Register A — Utility (content & tools)
The default language for all non-homepage pages: lists/grids, character and support-card detail, skills, guides, and every tool. The canonical references are the original, well-liked grids:
Page anatomy
- Heading row — plain
<h2>(+ optional count / filter metadata). No colored band, no panel header. - Filter / toolbar — a
--vp-c-bg-softbar,8pxradius,1pxdivider border. Search box, chip toggles, segmented buttons. Active filter = brand fill on that chip only (small, budgeted). - Content grid —
repeat(auto-fill, minmax(…)). Items are clean cards or tiles: neutral surface, hairline or shadow, hover = subtletranslateY(-4 to -8px)lift + soft shadow. No brand border-color on hover. - Sections within a detail page — semantic
<section>with a plain heading and, at most, a bottom hairline. Inner repeated items may stay card-like where scanning/comparison benefits; the outer wrapper is borderless.
Hard rules for Register A
- Do not import or use
UPanel,USectionHeader, or other game-kit chrome. Replace any panel wrapper with page-local<section>+ heading markup. - Headings carry hierarchy; colored bands do not.
- Callouts (e.g. a unique effect) use a left-border accent, not a full saturated box.
- Stay under the 10% brand budget. Counts, active filters, links, and focus rings are where brand lives.
- Every surface and hover has a working dark + colorblind appearance.
6. Register B — Showcase (homepage only)
File: HomeLayout.vue.
The homepage is the one place the game-UI board lives. It earns the richer treatment because it's the front door, not a working surface — and a front door is meant to draw the eye and route people into the best content. Restraint still applies (a tidy portal board, not a carnival), but here a prominent focal point is correct, not a distraction.
What we learned
- Lead with a featured hero — people liked it. A large featured hero (banner cards / video embed with thumbnail, title, tag, and CTA) is the page's deliberate focal point. It was once demoted to a compact side-panel list — a regression — and is now restored as a showcase "Featured Content" section sitting just below the Browse row, fed by HeroContent.ts (
heroItems+sidebarItem) and built fromHeroSlot+HeroBanner/HeroVideo, styled to match the board (--uma-panel-*chrome + a green accent strip). - A hero is both showcase and utility. It's eye-candy and the fastest path to the guides most people came for — so it does not violate usability-first.
- The focal point belongs to the homepage only. This is exactly the attention-grabbing treatment that must not spread onto content pages (Register A). Concentrating it on the front door is what keeps the rest calm.
- Hierarchy: hero → Banner Reviews → Current Events. The hero leads; Banner Reviews is the wide primary column (the one saturated green band); Current Events is demoted into the neutral reference rail.
Structure
home-layout
├── home-bg (fixed atmospheric academy background; light/dark)
└── content-wrapper
├── div-sidebar (rail ad, only > 1640px AND landscape)
├── board-shell (max-width 1300px)
│ ├── portal-section USectionHeader "Browse" + UNavTile grid
│ ├── feature-section Featured hero — USectionHeader "Featured Content"
│ │ + HeroSlot (HeroBanner/HeroVideo, 3 equal cards)
│ ├── board-cols primary + rail (~3:2), stack < 920px
│ │ ├── board-main HomeBannerReviews (showcase green band)
│ │ └── board-side Current Events (neutral) · Timers · Promo · Esports
│ │ · Community · Birthdays
│ └── bottom-ad
└── div-sidebar (right rail ad)The hero sits below Browse (not above) and is the page's single focal point; board-cols is a weighted primary + reference rail, not two equal columns.
Portal (nav tile) grid
| Viewport | Columns | Gap |
|---|---|---|
| > 1275px | repeat(10, 1fr) — single row, tiles compress | 12px |
| 721–1275px | repeat(5, 1fr) | 12px |
| 481–720px | repeat(5, 1fr) | 8px |
| ≤ 480px | repeat(5, 1fr) | 5px |
justify-items: center keeps tiles centered at every width.
Register B rules
- Game-kit chrome (
UPanel,USectionHeader,UNavTile, glossy buttons) is allowed here and only here, or in widgets rendered exclusively byHomeLayout(HomeBannerReviews,UCurrentEvents,UResetTimers,UBirthdays, and the heroHeroSlot/HeroBanner/HeroVideo). - Keep it calm: one accent per panel via the
colorprop, generous spacing, no competing animations. - Emphasis tiers via
UPaneltone:tone="showcase"(default — glossy saturated band) marks the lead/primary surfaces;tone="neutral"(neutral--vp-c-bg-elvheader + a thin colored accent rule, hue still set bycolor) is for the reference-rail widgets that should recede. Aim for only ~1–2 saturated bands on the whole board (here: the Browse header + Banner Reviews). - Brand budget still applies in spirit — the board is colorful because it's the showcase, but individual panels shouldn't all shout at once.
7. Component reference
Game-kit components live in components/ui/. Each is tagged with the register it belongs to. B = homepage showcase only; A/B = usable in both; A = utility-safe.
| Component | Register | Purpose |
|---|---|---|
UPanel | B | Glossy header card. Homepage board boxes. Do not wrap content-page sections. |
USectionHeader | B | Ribbon header (pennant / banner). Homepage section titles. |
UNavTile | B | Illustrated square portal tile. Homepage Browse grid. |
UBannerItem | B | Framed event/scout banner with status footer. Current Events. |
UPromoBanner | B | Dark promo banner with logo + CTA. Homepage side column. |
UPortraitCard | A/B | Framed character portrait + name plate. |
UCard | A/B | General content tile (row / tile). Prefer neutral framing on content pages. |
UButton | A/B | Beveled glossy button (green/pink/blue/ghost). On content pages, reserve for the primary CTA; use ghost for secondary. |
UBadge | A/B | Pill badge with white outline (green/pink/blue/gold/gray, outline). |
UGradeBadge | A/B | Race-grade swallowtail flag (G1 blue · G2 pink · G3 green · OP/EX orange · Listed purple). |
UTabs | A/B | Pill tab selector (v-model). Glossy track; fine on tools. |
USelect | A/B | Themed dropdown select (v-model). |
UNavMenu | A | Top-nav category / dropdown. See §4 for target spec. |
When a content page needs "a box," reach for page-local <section> markup first, then UCard/UBadge with neutral framing — not UPanel.
8. Interaction patterns
| Pattern | Implementation |
|---|---|
| Card / tile hover (A) | translateY(-4 to -8px) + soft neutral shadow. No brand border. |
| Row hover (A) | --vp-c-bg-soft background tint, optional translateY(-1px). |
| Panel hover (B) | translateY(-1 to -2px) + stronger --shadow-color. |
| Button press | translateY(3px), bevel shadow collapses to 1px. |
| Focus ring | box-shadow: 0 0 0 3px rgba(101,186,0,.16) (brand glow) — the one consistent brand touch on every focusable control. |
| Dropdown open | opacity + translateY(-4px), ~130ms. |
| Tab switch | Instant; no transition. |
| Active nav | Persistent 2px brand bottom-indicator (§4). |
Keep transitions short (110–180ms) and purposeful. Animation should confirm an action, never decorate idle state.
9. Responsive breakpoints
| px | Change |
|---|---|
| 2048+ | Root font scales to 20px (proportional UI on 2K+) |
| 1640 | Homepage rail ads appear (also requires landscape) |
| 1275 | Homepage portal grid → repeat(5,1fr) |
| 920 | Homepage board columns stack |
| 820 | Shell collapses to mobile: category strip hides, hamburger drawer; --vp-nav-height → 52px |
| 768 | Grid filter toolbars wrap; grids tighten |
| 720 | board-shell padding reduces |
| 640 | UPromoBanner hides description, shrinks logo |
| 480 | Grids drop to smallest minmax; portal gap → 5px |
The two-tier desktop nav exists only above 820px; below that everything is the drawer. Account for both nav heights (98px desktop / 52px mobile) when positioning sticky elements.
10. Do / Don't
Do
- Default to Register A. Treat Register B as a one-page allow-list.
- Spend brand color like money — ~10%, on active states, CTAs, links, focus.
- Let size, weight, spacing, and hairlines build hierarchy.
- Give every new color a dark + colorblind value, via tokens.
- Make the primary action obvious; make everything else quiet.
- Lead the homepage with a prominent featured hero — that focal-point energy belongs there, and only there.
Don't
- Wrap content-page sections in
UPanelor any glossy header band. - Tint page/card backgrounds or hover rows with brand color.
- Use 800-weight or wide tracking on utility text.
- Let a homepage-style hero or focal banner leak onto content / tool pages.
- Solve a structural problem (panel chrome) with a global CSS override — fix it in the consuming component.
11. Migration status
This document describes the shipped state. The "chrome-everywhere" rework has been walked back to usability-first across all five plan phases; the execution log is UIUnificationAndOptimizationPlan.md (and the earlier structural tracker, UIFeedbackRework.md).
Closed seams:
- ✅ Homepage featured hero — restored below the Browse row as a showcase "Featured Content" section (3 equal cards from
heroItems/sidebarItem), with the hierarchy hero → Banner Reviews → demoted Current Events. - ✅ Nav strip — implemented the §4 spec: one unified header surface, quiet 600-weight categories, low-contrast hover underline + 2px brand active indicator, and the dead
::beforegloss +--uma-nav-strip-*indirection removed. - ✅
UPanelon content pages — game chrome is now homepage-only;UPanel/USectionHeaderno longer appear on detail/guide pages. - ✅ Vestigial reddish-brown shadows in
CharacterGrid→--shadow-color/--shadow-color-lgtokens (they now follow the active theme). - ✅ Theme default — Legacy is now the first-time default (matching system light/dark); menu reads Legacy → Uma → Colorblind; stored keys unchanged.
- ✅ Component gallery — ui-preview.md labels each component with its register (§7).
Remaining (out of the plan's named scope, optional sweeps):
- Hard-coded
rgba(193,106,95,…)still inRosterViewer,SkillList,SearchPage/SearchDropdown,UnifiedTopBar(the plan tokenized only the reference grids). - Phase 3 refinements: featured guide-card = badge not accent border; unique- effect callouts → left-border accent.
Last updated: 2026-06-14.