- Implemented complete design system with 40+ CSS custom properties - Created 9 UI primitives (GameCard, SectionHeader, StatRow, ManaBar, ElementBadge, ValueDisplay, ActionButton, SkillRow, TooltipInfo) - Redesigned all tabs: Spire, Skills, Stats, Equipment, Crafting, Attunements, Golemancy, Spells, Loot, Achievements, Lab, Debug - Added toast notification system (GameToast) with success/warning/error/info types - Added confirmation dialogs for destructive actions - Removed all dev artifacts and component name labels - Added empty states to all tabs - Replaced emoji icons with Lucide React icons - Added enchantPower placeholder to StatsTab and EquipmentTab - Mobile audit passed at 375px viewport - Build passes with 0 errors, lint passes with 0 errors Sub-tasks completed: - ST1: Design System Implementation - ST2: Global Layout & Header - ST3: Left Panel (Mana Display & Action Area) - ST4: Skills Tab - ST5: Spire Tab & Spire Mode UI - ST6: Stats Tab - ST7: Equipment & Crafting Tabs - ST8: Attunements Tab - ST9: Remaining Tabs - ST10: Toast System & Confirmation Dialogs Documentation: 15+ files in docs/task4/
12 KiB
Mana Loop - Design System
Version: 1.0
Date: 2024-04-27
1. Visual Identity
Theme: Ancient Arcane Grimoire
The Mana Loop UI should feel like an ancient spellbook infused with crystalline magic - not a generic dark mode SaaS application.
Aesthetic References:
- Path of Exile passive tree (dark, arcane, intricate)
- Slay the Spire card UI (clear, readable, atmospheric)
- Hades menu screens (bold, high-contrast, mythological)
Guiding Principles:
- Every UI region should feel like it belongs in the world
- Restraint over decoration: one strong texture/treatment per region
- The UI must stay fast and readable - this is an idle game
- No generic purple-gradient-on-charcoal
Key Visual Elements:
- Illuminated manuscript styling for headers (gold accents, serif fonts)
- Crystalline magic effects for interactive elements
- Subtle arcane patterns as background texture
- High contrast for readability with muted atmospheric colors
2. Color Tokens
2a. Background Colors (Depth Levels)
--bg-base: #060811; /* Outermost / page - deep void black */
--bg-surface: #0C1020; /* Panels, cards - dark navy */
--bg-elevated: #111628; /* Dropdowns, tooltips, modals - medium dark */
--bg-sunken: #181f35; /* Inset wells, progress track - lighter panel */
2b. Border Colors
--border-subtle: #1e2a45; /* Barely-there separators */
--border-default: #2a3a60; /* Standard card edges */
--border-focus: #5B8FFF; /* Interactive focus rings */
2c. Text Colors
--text-primary: #c8d8f8; /* Main text - light blue-white */
--text-secondary: #7a92c0; /* Secondary text - muted blue-gray */
--text-muted: #4a5f8a; /* Muted text - darker blue-gray */
--text-disabled: #2a3a60; /* Disabled text - very muted */
2d. Mana Element Colors
Each mana type has a distinct, semantic color that reflects its nature:
--mana-fire: #E8734A; /* Ember orange-red */
--mana-water: #3BAFDA; /* Deep teal */
--mana-air: #C8D8F8; /* Silver-white */
--mana-earth: #B8860B; /* Warm ochre */
--mana-light: #D4A843; /* Gold */
--mana-dark: #4B0082; /* Deep indigo */
--mana-death: #8B7D8B; /* Muted violet-grey */
--mana-transfer: #00CED1; /* Cyan - the "tech mana" */
--mana-metal: #708090; /* Cool steel */
--mana-sand: #C2B280; /* Warm tan */
--mana-lightning: #FFD700; /* Electric yellow */
--mana-crystal: #B0E0E6; /* Pale ice blue */
--mana-stellar: #FF8C00; /* Bright amber */
--mana-void: #1A0A2E; /* Deep black-purple */
2e. Semantic UI Colors
--color-success: #27AE60; /* Green */
--color-warning: #F39C12; /* Orange */
--color-danger: #C0392B; /* Red */
--color-info: #3B6FE8; /* Blue */
2f. Interactive Colors
--interactive-primary: #3B6FE8; /* Main CTA - Gather, Study, Climb */
--interactive-primary-hover: #5B8FFF; /* Hover state */
--interactive-secondary: #2a3a60; /* Secondary actions */
--interactive-secondary-hover: #3a4a70; /* Secondary hover */
--interactive-danger: #C0392B; /* Danger actions */
--interactive-danger-hover: #E74C3C; /* Danger hover */
--interactive-disabled: #1e2a45; /* Disabled state */
3. Typography
3a. Font Stack
--font-heading: 'Cinzel', serif; /* Fantasy-adjacent serif for headers */
--font-body: 'Crimson Text', Georgia, serif; /* All body copy */
--font-mono: 'JetBrains Mono', monospace; /* Numbers, values, timers */
3b. Type Scale
| Size | Font Size | Line Height | Letter Spacing | Usage |
|---|---|---|---|---|
| xs | 0.75rem (12px) | 1rem | 0.05em | Captions, labels |
| sm | 0.875rem (14px) | 1.25rem | 0.025em | Secondary text |
| base | 1rem (16px) | 1.5rem | normal | Body text |
| lg | 1.125rem (18px) | 1.75rem | normal | Emphasized text |
| xl | 1.25rem (20px) | 1.75rem | -0.025em | Subheaders |
| 2xl | 1.5rem (24px) | 2rem | -0.05em | Section headers |
| 3xl | 1.875rem (30px) | 2.25rem | -0.05em | Page titles |
Heading Specifics:
- Font:
--font-heading(Cinzel) - Letter spacing: 0.05em to 0.1em
- Text transform: uppercase for game panel titles
- Font weight: 600 or 700
4. Spacing & Layout
4a. Base Unit
- 4px (Tailwind default: 1 unit = 0.25rem)
4b. Border Radius
--radius: 0.5rem; /* 8px - used everywhere for consistency */
4c. Panel Inner Padding
- All tabs/panels:
1.5rem(24px / p-6 in Tailwind) - Card content:
1rem(16px / p-4 in Tailwind) - Tight spacing:
0.75rem(12px / p-3 in Tailwind)
4d. Gaps
- Between cards:
1rem(16px / gap-4) - Between elements:
0.5rem(8px / gap-2) - Tight elements:
0.25rem(4px / gap-1)
5. Component Primitives
5a. GameCard
Purpose: All panel/section wrappers
Variants: default, elevated, sunken, danger
Props: variant, className, children
interface GameCardProps {
variant?: 'default' | 'elevated' | 'sunken' | 'danger';
className?: string;
children: React.ReactNode;
}
Styling:
- default:
--bg-surfacebackground,--border-defaultborder - elevated:
--bg-elevatedbackground, stronger shadow - sunken:
--bg-sunkenbackground, inset appearance - danger: Red-tinted border for warning states
5b. SectionHeader
Purpose: Consistent section titles with optional right-side action slot
Props: title, action, className
interface SectionHeaderProps {
title: string;
action?: React.ReactNode;
className?: string;
}
Styling:
- Font:
--font-heading - Text transform: uppercase
- Letter spacing: 0.1em
- Color:
--text-primary - Optional right-side action slot for buttons/badges
5c. StatRow
Purpose: Label + value pair
Props: label, value, highlight, className
interface StatRowProps {
label: string;
value: string | number;
highlight?: 'default' | 'success' | 'warning' | 'danger' | 'mana-*';
className?: string;
}
Styling:
- Label:
--text-secondary, left-aligned - Value:
--text-primary, right-aligned,--font-mono - Highlight colors change value text color
5d. ManaBar
Purpose: Progress bar skinned per mana type
Props: value, max, manaType, className
interface ManaBarProps {
value: number;
max: number;
manaType?: keyof typeof MANA_COLORS;
className?: string;
}
Styling:
- Height: 8px (h-2)
- Border radius:
--radius - Fill uses appropriate
--mana-*color - Transition: 300ms ease-out
- Background:
--bg-sunken
5e. ElementBadge
Purpose: Pill badge for mana/element type with matching icon + color
Props: element, showIcon, size, className
interface ElementBadgeProps {
element: string;
showIcon?: boolean;
size?: 'sm' | 'md';
className?: string;
}
Styling:
- Pill shape (rounded-full)
- Background:
--mana-{type}at 20% opacity - Border:
--mana-{type}at 60% opacity - Text:
--mana-{type}full color - Icon from Lucide icons matching element
5f. ValueDisplay
Purpose: Animated numeric display for mana, DPS, etc.
Props: value, label, color, className
interface ValueDisplayProps {
value: number;
label?: string;
color?: string;
className?: string;
}
Styling:
- Font:
--font-mono - Font feature:
tabular-numsfor aligned digits - Transition on value change (CSS only)
- Optional label below in
--text-secondary
5g. ActionButton
Purpose: Primary game CTA
Variants: primary, secondary, danger, ghost
Props: variant, size, disabled, children, className
interface ActionButtonProps {
variant?: 'primary' | 'secondary' | 'danger' | 'ghost';
size?: 'sm' | 'md' | 'lg';
disabled?: boolean;
children: React.ReactNode;
className?: string;
}
Styling:
- primary:
--interactive-primarybackground - secondary:
--interactive-secondarybackground - danger:
--interactive-dangerbackground - ghost: Transparent with border
- Hover: 100ms ease transition
- Disabled:
--interactive-disabledwith reduced opacity
5h. SkillRow
Purpose: Standard skill entry row
Props: skill, onStudy, onUpgrade, children, className
interface SkillRowProps {
skill: Skill;
onStudy?: () => void;
onUpgrade?: () => void;
children?: React.ReactNode;
className?: string;
}
Styling:
- Name:
--text-primary,--font-heading - Description:
--text-secondary,--font-body - Cost:
--text-muted,--font-mono - Level dots: Using
--mana-purplefor filled - Study button: ActionButton (secondary variant)
5i. TooltipInfo
Purpose: Consistent tooltip triggered by ? icon
Props: content, children, className
interface TooltipInfoProps {
content: string;
children?: React.ReactNode;
className?: string;
}
Styling:
- Trigger:
?icon in circle,--text-muted - Content:
--bg-elevatedbackground,--text-primarytext - Uses Radix Tooltip under the hood
- Delay: 0ms (instant)
6. Animation Budget
| Category | Rule | Duration | Easing |
|---|---|---|---|
| Mana bar fill | CSS transition | 300ms | ease-out |
| Progress bars (study/cast) | CSS transition | linear | linear |
| Tab switch | CSS transition | 150ms | fade-in |
| Hover states | CSS transition | 100ms | ease |
| Number changes | CSS tabular-nums |
N/A | N/A |
| Idle sparkle / glow | One subtle glow pulse on Gather button ONLY | 2s | ease-in-out, infinite |
| Spire combat | Cast bar animates smoothly | 300ms | ease-out |
Important Notes:
- NO framer-motion for layout shifts - CSS transitions only
- All animations must be performant (idle game runs constantly)
- Respect
prefers-reduced-motionsetting
7. Icon System
Library: Lucide React (already installed)
Usage Guidelines:
- No emoji in UI - use Lucide icons only
- Icons should match mana element colors when applicable
- Standard sizes: 16px (sm), 20px (md), 24px (lg)
- Stroke width: 2 (default)
Common Icons:
- Mana: Zap, Flame, Droplet, Wind, Mountain, Sun, Moon, Skull, etc.
- Actions: Play, Pause, RotateCcw, ChevronRight, etc.
- UI: Settings, Info, AlertTriangle, Check, X, etc.
8. Z-Index Scale
| Layer | Value | Usage |
|---|---|---|
| Base | 0 | Normal content |
| Dropdown | 50 | Select, dropdown menus |
| Sticky | 100 | Sticky headers |
| Overlay | 200 | Modals, dialogs |
| Toast | 300 | Toast notifications |
| Tooltip | 400 | Tooltips |
9. Shadow System
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.4);
--shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.5);
--shadow-glow-gold: 0 0 15px rgba(212, 168, 67, 0.4);
--shadow-glow-purple: 0 0 15px rgba(124, 92, 191, 0.4);
--shadow-glow-accent: 0 0 15px rgba(60, 111, 232, 0.4);
10. Implementation Checklist
- Update
src/app/globals.csswith all CSS custom properties - Create
src/components/ui/game-card.tsx - Create
src/components/ui/section-header.tsx - Create
src/components/ui/stat-row.tsx - Create
src/components/ui/mana-bar.tsx - Create
src/components/ui/element-badge.tsx - Create
src/components/ui/value-display.tsx - Create
src/components/ui/action-button.tsx(or update existing button.tsx) - Create
src/components/ui/skill-row.tsx - Create
src/components/ui/tooltip-info.tsx - Update
src/components/ui/index.tswith all exports - Search and remove component name labels
- Create all sub-task documentation files
- Run final lint verification