Design Tokens
Design tokens are the foundational design decisions that create consistency across the BookWish interface. These values should be used throughout the codebase to maintain visual harmony.
Spacing Scale
BookWish uses an 8-point grid system for spacing. All spacing values should be multiples of 8 to maintain consistent rhythm and alignment.
Base Scale
| Token | Value | Usage |
|---|---|---|
space-1 | 8px | Tight spacing, inline elements |
space-2 | 16px | Default component padding, small gaps |
space-3 | 24px | Section spacing, medium gaps |
space-4 | 32px | Large spacing, page margins |
space-5 | 40px | Extra large spacing |
space-6 | 48px | Section dividers |
space-8 | 64px | Page-level spacing |
Common Spacing Patterns
Vertical Spacing:
// Between form fields
const SizedBox(height: 16) // space-2
// Between sections
const SizedBox(height: 24) // space-3
// Empty state padding
padding: const EdgeInsets.all(32) // space-4
// Bottom navigation bar
bottom: 100 // custom for Browser overlay
Horizontal Spacing:
// Icon and text spacing
const SizedBox(width: 8) // space-1
// Between inline elements
const SizedBox(width: 12) // space-1.5
// Card margins
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8)
Component Padding:
// Button padding (internal)
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16)
// Card content padding
padding: const EdgeInsets.all(16)
// Speech bubble padding
padding: const EdgeInsets.all(16)
// List tile padding
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8)
Responsive Spacing
For web and tablet layouts, consider scaling up spacing:
| Breakpoint | Scale Factor | Example |
|---|---|---|
| Mobile | 1x | 16px → 16px |
| Tablet | 1.25x | 16px → 20px |
| Desktop | 1.5x | 16px → 24px |
Border Radius
Consistent corner rounding creates a cohesive, friendly aesthetic.
Radius Scale
| Token | Value | Usage |
|---|---|---|
radius-xs | 4px | Small chips, badges |
radius-sm | 8px | Small elements, speech bubbles, icons |
radius-md | 12px | Cards, inputs, list tiles, dialogs |
radius-lg | 16px | Large cards, overlays, sheets |
radius-xl | 24px | Buttons, pills |
radius-full | 40-50% | Circular avatars, icon buttons |
Implementation Examples
// Input fields
borderRadius: BorderRadius.circular(12) // radius-md
// Primary buttons
borderRadius: BorderRadius.circular(24) // radius-xl
// Cards
borderRadius: BorderRadius.circular(12) // radius-md
// Browser speech bubble
borderRadius: BorderRadius.circular(16) // radius-lg
// Snackbars
borderRadius: BorderRadius.circular(8) // radius-sm
// Avatar (circular)
borderRadius: BorderRadius.circular(40) // radius-full
// Sheet top corners
borderRadius: const BorderRadius.vertical(
top: Radius.circular(16) // radius-lg
)
When to Use Each Radius
- 4px (xs): Tiny elements, status badges, inline chips
- 8px (sm): Small containers, tags, minor elements
- 12px (md): Standard cards, inputs, list items (most common)
- 16px (lg): Modal sheets, large containers, overlays
- 24px (xl): Buttons, pill-shaped elements
- Circular: Avatars, icon buttons, floating action buttons
Shadows & Elevation
Shadows create depth and hierarchy in the interface. BookWish uses subtle shadows for a clean, modern look.
Elevation Scale
| Level | Elevation | Usage | Shadow |
|---|---|---|---|
| 0 | None | Buttons, inline elements | elevation: 0 |
| 1 | Low | Pressed states | Light shadow |
| 2 | Medium | Cards, tiles | elevation: 2 |
| 4 | High | Dropdowns, dialogs | elevation: 4 |
| 8 | Navigation | Bottom nav, app bar | elevation: 8 |
| 16 | Modal | Sheets, overlays | Custom shadow |
Shadow Implementation
Card Shadow (elevation 2):
CardThemeData(
elevation: 2,
shadowColor: AppColors.inkBlue.withValues(alpha: 0.08),
)
Browser Speech Bubble Shadow:
BoxShadow(
color: Colors.black.withValues(alpha: 0.1),
blurRadius: 8,
offset: const Offset(0, 4),
)
Bottom Navigation Shadow (elevation 8):
BottomNavigationBarThemeData(
elevation: 8,
)
Custom Box Shadow:
// Subtle depth
boxShadow: [
BoxShadow(
color: Colors.black.withValues(alpha: 0.1),
blurRadius: 8,
offset: const Offset(0, 4),
),
]
// More pronounced
boxShadow: [
BoxShadow(
color: Colors.black.withValues(alpha: 0.15),
blurRadius: 16,
offset: const Offset(0, 8),
),
]
Shadow Guidelines
- Use sparingly - too many shadows create visual clutter
- Keep alpha values low (0.05 - 0.15) for subtlety
- Offset shadows downward (positive Y) for realism
- Blur radius typically 2x the offset distance
- Consider removing shadows on mobile for performance
Z-Index Scale
Z-index controls stacking order of elements. While Flutter uses different layering mechanisms, this provides a mental model.
Layer Hierarchy
| Layer | Z-Index | Usage |
|---|---|---|
| Base | 0 | Page content |
| Elevated | 1 | Cards, tiles |
| Dropdown | 10 | Dropdowns, popovers |
| Sticky | 50 | Sticky headers, floating buttons |
| Overlay | 100 | Modals, sheets |
| Browser | 150 | Browser the Cat overlay |
| Toast | 200 | Snackbars, toasts |
| Tooltip | 300 | Tooltips |
Flutter Implementation
Flutter uses widget tree order and Stack for layering:
// Browser overlay appears above main content
Stack(
children: [
// Base content (z: 0)
MainContent(),
// Browser overlay (z: 150)
Positioned(
bottom: 100,
child: BrowserOverlay(),
),
],
)
Breakpoints
Breakpoints define responsive behavior across device sizes.
Screen Size Breakpoints
| Breakpoint | Min Width | Max Width | Usage |
|---|---|---|---|
| Mobile Small | 0 | 374px | Small phones |
| Mobile | 375px | 767px | Standard phones |
| Tablet | 768px | 1023px | Tablets, small laptops |
| Desktop | 1024px | 1439px | Laptops, desktops |
| Wide | 1440px+ | - | Large desktops |
Implementation
// Get screen width
final screenWidth = MediaQuery.of(context).size.width;
// Responsive layout
Widget build(BuildContext context) {
if (screenWidth < 768) {
return MobileLayout();
} else if (screenWidth < 1024) {
return TabletLayout();
} else {
return DesktopLayout();
}
}
// Responsive padding
final horizontalPadding = screenWidth < 768 ? 16.0 : 32.0;
Responsive Patterns
Content Width:
- Mobile: Full width with 16px margins
- Tablet: Max 768px centered
- Desktop: Max 1200px centered
Column Layouts:
- Mobile: Single column
- Tablet: 2 columns for cards
- Desktop: 3-4 columns for cards
Navigation:
- Mobile: Bottom navigation bar
- Tablet: Side navigation rail
- Desktop: Expanded side navigation
Animation Durations
Consistent animation timing creates a cohesive, polished experience.
Duration Scale
| Token | Value | Usage |
|---|---|---|
instant | 0ms | Reduced motion, immediate feedback |
fast | 100-200ms | Micro-interactions, hovers |
normal | 200-300ms | Standard transitions |
slow | 300-500ms | Page transitions, complex animations |
slower | 500ms+ | Dramatic reveals, special effects |
Common Animation Durations
| Animation Type | Duration | Example |
|---|---|---|
| Button press | 200ms | Like button animation |
| Page transition | 300ms | Route changes |
| Dialog open/close | 300ms | Modal appearance |
| Snackbar | 2000ms | Toast message display |
| Browser auto-dismiss | 5000ms | Hint auto-hide |
| Hover effect | 150ms | Button hover state |
| Focus ring | 200ms | Input focus transition |
| Dropdown | 200ms | Menu expansion |
| Search debounce | 500ms | Search input delay |
Implementation Examples
// Button press animation
AnimatedContainer(
duration: const Duration(milliseconds: 200),
curve: Curves.easeInOut,
)
// Page transition
PageRouteBuilder(
transitionDuration: const Duration(milliseconds: 300),
pageBuilder: (context, animation, secondaryAnimation) => NextPage(),
)
// Browser auto-dismiss
autoDismiss: const Duration(seconds: 5)
// Search debounce
Timer(const Duration(milliseconds: 500), () {
_performSearch(query);
})
// Snackbar duration
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Success'),
duration: Duration(seconds: 2),
),
)
Animation Curves
Use appropriate easing curves for natural motion:
// Standard easing
Curves.easeInOut // Most animations
// Entrance
Curves.easeOut // Elements appearing
// Exit
Curves.easeIn // Elements disappearing
// Bouncy/playful
Curves.elasticOut // Special moments (use sparingly)
// Sharp
Curves.fastOutSlowIn // Material design standard
Reduced Motion
Always respect system reduced motion preferences:
final disableAnimations = MediaQuery.of(context).disableAnimations;
final duration = disableAnimations
? Duration.zero
: Duration(milliseconds: 300);
Icon Sizes
Consistent icon sizing improves visual balance and usability.
Size Scale
| Token | Value | Usage |
|---|---|---|
icon-xs | 16px | Inline icons, small chips |
icon-sm | 20px | List item icons, small buttons |
icon-md | 24px | Standard icons, app bar icons |
icon-lg | 32px | Feature icons, empty states |
icon-xl | 48px | Large feature illustrations |
icon-2xl | 64px | Error/success states |
icon-3xl | 100px | Onboarding, major empty states |
Implementation
// Standard icon
Icon(Icons.favorite, size: 24) // icon-md
// App bar icon button
Icon(Icons.menu, size: 24) // icon-md
// List item leading icon
Icon(Icons.book, size: 20) // icon-sm
// Empty state icon
Icon(Icons.inbox, size: 64) // icon-2xl
// Bottom nav icons (selected/unselected)
selectedIconTheme: IconThemeData(size: 28, opacity: 1.0)
unselectedIconTheme: IconThemeData(size: 24, opacity: 0.6)
Icon Guidelines
- Use 24px as default size for most icons
- Ensure icon touch target is at least 48x48dp
- Match icon weight to surrounding text weight
- Use outlined icons for unselected states
- Use filled icons for selected/active states
- Maintain consistent icon family (Cupertino or Material)
Typography Tokens
Typography tokens are defined in /app/lib/config/theme.dart.
Type Scale
| Token | Size | Weight | Line Height | Usage |
|---|---|---|---|---|
headingLarge | 24pt | 600 | 1.25 | Page titles |
heading | 20pt | 600 | 1.3 | Section headers |
bookTitle | 17pt | 600 | 1.3 | Book titles (serif) |
label | 16pt | 500 | 1.0 | UI labels, button text |
body | 16pt | 400 | 1.5 | Body text |
bodySmall | 14pt | 400 | 1.4 | Secondary text |
caption | 12pt | 400 | 1.3 | Metadata, timestamps |
See Typography documentation for full details.
Color Tokens
Color tokens are defined in /app/lib/config/theme.dart.
Primary Palette
| Token | Hex | Usage |
|---|---|---|
inkBlue | #233548 | Primary text, headers |
parchment | #FAF4E8 | Background, surface |
amberStar | #FFC857 | Primary buttons, premium |
tealEdge | #4BB4C8 | Interactive elements, links |
coralSpine | #F37C7C | Warnings, destructive actions |
Semantic Colors
| Token | Hex | Usage |
|---|---|---|
success | #3FA37B | Success messages |
error | #C44545 | Error messages |
border | #E0D7C8 | Borders, dividers |
forestGreen | #2D6A4F | Book covers, accents |
maroonLeather | #7B2D26 | Book covers, accents |
See Color System documentation for full palette and usage.
Usage Guidelines
Consistency
- Always use tokens instead of hard-coded values
- Reference theme values:
AppColors.inkBlue,AppTypography.body - Use token names in comments for clarity
- Document deviations from the token system
Scaling
When creating new components:
- Start with existing tokens
- Use spacing scale (8px multiples)
- Choose appropriate border radius
- Apply consistent shadows
- Use standard animation durations
Responsive Adaptation
Tokens should scale appropriately:
- Spacing: Increase by 25-50% on larger screens
- Typography: Increase by 1-2pt on desktop
- Touch targets: Maintain 48dp minimum on mobile
- Shadows: Can be more pronounced on desktop
Performance
Consider performance implications:
- Shadows impact render performance on mobile
- Animations should respect reduced motion
- Large border radius can impact performance
- Use elevation wisely to minimize overdraw
Future Enhancements
Potential token system improvements:
- CSS custom properties - For web version
- Dark mode tokens - Alternative color palette
- Platform-specific tokens - iOS vs Android differences
- Theming system - User-customizable themes
- Token documentation - Auto-generated from code
- Design token library - Shared with design tools
- Component-specific tokens - Per-component variables
- Semantic spacing - Named spacing (buttonPadding vs space-2)