---
name: superdesign-flutter
description: Flutter Design Skill - SuperDesign adapted for Flutter/Dart development. Optimized for Material Design 3 and Flutter widgets.
version: 1.0.0
original: superdesign
adapted_for: Flutter/Dart
---

# Flutter Design Skill

Use this skill when creating Flutter UI components, screens, or any Flutter UI design work.

This is an adapted version of SuperDesign for Flutter, converting web/CSS patterns to Flutter/Dart equivalents.

## Design Workflow

Follow this structured approach for Flutter UI design:

- **Layout Design** — Think through widget structure, create ASCII wireframes
- **Theme Design** — Define colors, text styles, spacing, shadows
- **Animation Design** — Plan micro-interactions and transitions
- **Implementation** — Generate Flutter/Dart code

### 1. Layout Design

Before coding, sketch the widget tree in ASCII format:

```
┌─────────────────────────────────────┐
│      Scaffold / AppBar              │
├─────────────────────────────────────┤
│                                     │
│      Hero Section (Column)          │
│     - Title Text                    │
│     - CTA ElevatedButton            │
│                                     │
├─────────────────────────────────────┤
│  Row (3x Feature Cards)             │
│  ┌─────┐ ┌─────┐ ┌─────┐           │
│  │Card │ │Card │ │Card │           │
│  └─────┘ └─────┘ └─────┘           │
├─────────────────────────────────────┤
│      BottomNavigationBar            │
└─────────────────────────────────────┘
```

### 2. Theme Guidelines

#### Color Rules:

- NEVER use generic blue (Colors.blue) — it looks dated
- Prefer Material Design 3 color system (ColorScheme)
- Use Theme.of(context).colorScheme for semantic colors
- Support both light and dark mode with ColorScheme

#### OKLCH to Flutter Color Conversion:

Convert OKLCH values to Flutter Color using this helper:

```dart
import 'package:flutter/material.dart';

/// Convert OKLCH to Flutter Color
/// Example: oklch(0.205 0 0) → Color
Color oklchToColor(double l, double c, double h) {
  // Simplified conversion - for accurate conversion use a color library
  // This is a placeholder implementation
  final hue = h;
  final chroma = c;
  final lightness = l;
  
  // Convert to HSL then to RGB
  // For production, use package:flutter_color or similar
  return HSLColor.fromAHSL(1.0, hue, chroma, lightness).toColor();
}

// Modern Dark Mode Colors (Vercel/Linear style)
class ModernDarkColors {
  static const background = Color(0xFFFFFFFF);  // oklch(1 0 0)
  static const foreground = Color(0xFF252525);  // oklch(0.145 0 0)
  static const primary = Color(0xFF343434);     // oklch(0.205 0 0)
  static const secondary = Color(0xFFF7F7F7);   // oklch(0.970 0 0)
  static const muted = Color(0xFFF7F7F7);       // oklch(0.970 0 0)
  static const border = Color(0xFFEBEBEB);      // oklch(0.922 0 0)
}
```

#### Flutter Theme Setup:

```dart
MaterialApp(
  theme: ThemeData(
    useMaterial3: true,
    colorScheme: ColorScheme.fromSeed(
      seedColor: Color(0xFF343434),  // Modern neutral
      brightness: Brightness.light,
    ),
    fontFamily: 'Inter',
  ),
  darkTheme: ThemeData(
    useMaterial3: true,
    colorScheme: ColorScheme.fromSeed(
      seedColor: Color(0xFF343434),
      brightness: Brightness.dark,
    ),
    fontFamily: 'Inter',
  ),
);
```

#### Font Selection (Google Fonts):

Use `google_fonts` package:

```yaml
# pubspec.yaml
dependencies:
  google_fonts: ^6.1.0
```

```dart
import 'package:google_fonts/google_fonts.dart';

// Sans-serif fonts
final inter = GoogleFonts.inter();
final roboto = GoogleFonts.roboto();
final poppins = GoogleFonts.poppins();
final montserrat = GoogleFonts.montserrat();
final outfit = GoogleFonts.outfit();
final dmSans = GoogleFonts.dmSans();

// Monospace fonts
final jetBrainsMono = GoogleFonts.jetBrainsMono();
final firaCode = GoogleFonts.firaCode();
final sourceCodePro = GoogleFonts.sourceCodePro();
```

#### Spacing System:

```dart
/// Spacing scale based on 4.0 (instead of 0.25rem)
class Spacing {
  static const double xs = 4.0;
  static const double sm = 8.0;
  static const double md = 16.0;
  static const double lg = 24.0;
  static const double xl = 32.0;
  static const double xxl = 48.0;
}

// Usage
Padding(
  padding: EdgeInsets.all(Spacing.md),  // 16.0
  child: Text('Content'),
)
```

### 3. Theme Patterns

#### Modern Dark Mode (Vercel/Linear style):

```dart
ThemeData(
  useMaterial3: true,
  colorScheme: ColorScheme(
    brightness: Brightness.light,
    background: Color(0xFFFFFFFF),
    onBackground: Color(0xFF252525),
    primary: Color(0xFF343434),
    onPrimary: Color(0xFFFBFBFB),
    secondary: Color(0xFFF7F7F7),
    onSecondary: Color(0xFF252525),
    surface: Color(0xFFFFFFFF),
    onSurface: Color(0xFF252525),
    outline: Color(0xFFEBEBEB),
  ),
  cardTheme: CardTheme(
    elevation: 0,
    shape: RoundedRectangleBorder(
      borderRadius: BorderRadius.circular(10.0),  // 0.625rem
    ),
  ),
);
```

#### Neo-Brutalism (90s revival):

```dart
ThemeData(
  useMaterial3: true,
  colorScheme: ColorScheme(
    brightness: Brightness.light,
    background: Color(0xFFFFFFFF),
    onBackground: Color(0xFF000000),
    primary: Color(0xFFFF6B35),     // Vibrant orange
    secondary: Color(0xFF4ECDC4),   // Teal
    tertiary: Color(0xFF5B5F97),    // Purple
    outline: Color(0xFF000000),
  ),
  cardTheme: CardTheme(
    elevation: 0,
    shape: RoundedRectangleBorder(
      borderRadius: BorderRadius.circular(0),  // No radius
      side: BorderSide(color: Colors.black, width: 2),
    ),
  ),
  elevatedButtonTheme: ElevatedButtonThemeData(
    style: ElevatedButton.styleFrom(
      elevation: 0,
      shadowColor: Colors.transparent,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(0),
      ),
    ),
  ),
);
```

#### Glassmorphism:

```dart
class GlassCard extends StatelessWidget {
  final Widget child;
  
  const GlassCard({required this.child});
  
  @override
  Widget build(BuildContext context) {
    return ClipRRect(
      borderRadius: BorderRadius.circular(16.0),
      child: BackdropFilter(
        filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
        child: Container(
          decoration: BoxDecoration(
            color: Colors.white.withOpacity(0.1),
            border: Border.all(
              color: Colors.white.withOpacity(0.2),
              width: 1,
            ),
            borderRadius: BorderRadius.circular(16.0),
          ),
          child: child,
        ),
      ),
    );
  }
}
```

### 4. Animation Guidelines

#### Flutter Animation Equivalents:

```dart
// Button press animation (150ms)
class AnimatedButton extends StatefulWidget {
  @override
  _AnimatedButtonState createState() => _AnimatedButtonState();
}

class _AnimatedButtonState extends State<AnimatedButton>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _scaleAnimation;
  
  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: Duration(milliseconds: 150),
      vsync: this,
    );
    _scaleAnimation = Tween<double>(begin: 1.0, end: 0.95).animate(
      CurvedAnimation(parent: _controller, curve: Curves.easeInOut),
    );
  }
  
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTapDown: (_) => _controller.forward(),
      onTapUp: (_) => _controller.reverse(),
      onTapCancel: () => _controller.reverse(),
      child: ScaleTransition(
        scale: _scaleAnimation,
        child: ElevatedButton(...),
      ),
    );
  }
}

// Fade in animation (400ms)
class FadeInWidget extends StatefulWidget {
  final Widget child;
  const FadeInWidget({required this.child});
  @override
  _FadeInWidgetState createState() => _FadeInWidgetState();
}

class _FadeInWidgetState extends State<FadeInWidget>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _opacity;
  late Animation<Offset> _slide;
  
  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: Duration(milliseconds: 400),
      vsync: this,
    );
    _opacity = Tween<double>(begin: 0.0, end: 1.0).animate(_controller);
    _slide = Tween<Offset>(begin: Offset(0, 0.05), end: Offset.zero)
        .animate(CurvedAnimation(parent: _controller, curve: Curves.easeOut));
    _controller.forward();
  }
  
  @override
  Widget build(BuildContext context) {
    return SlideTransition(
      position: _slide,
      child: FadeTransition(opacity: _opacity, child: widget.child),
    );
  }
}
```

#### Common Animation Durations:

```dart
class AnimationDurations {
  static const Duration buttonPress = Duration(milliseconds: 150);
  static const Duration hover = Duration(milliseconds: 200);
  static const Duration fadeIn = Duration(milliseconds: 400);
  static const Duration slideIn = Duration(milliseconds: 350);
  static const Duration bounce = Duration(milliseconds: 600);
  static const Duration pageTransition = Duration(milliseconds: 300);
}
```

### 5. Widget Patterns

#### Responsive Layout:

```dart
class ResponsiveLayout extends StatelessWidget {
  final Widget mobile;
  final Widget? tablet;
  final Widget? desktop;
  
  const ResponsiveLayout({
    required this.mobile,
    this.tablet,
    this.desktop,
  });
  
  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        if (constraints.maxWidth >= 1024) {
          return desktop ?? tablet ?? mobile;
        } else if (constraints.maxWidth >= 768) {
          return tablet ?? mobile;
        } else {
          return mobile;
        }
      },
    );
  }
}

// Usage
ResponsiveLayout(
  mobile: MobileLayout(),
  tablet: TabletLayout(),
  desktop: DesktopLayout(),
)
```

#### Icons:

```dart
// Use Material Icons (built-in)
Icon(Icons.home)
Icon(Icons.settings)

// Or use Cupertino Icons
Icon(CupertinoIcons.house)
Icon(CupertinoIcons.settings)

// For custom icons, use flutter_svg
import 'package:flutter_svg/flutter_svg.dart';
SvgPicture.asset('assets/icons/custom_icon.svg')
```

#### Images:

```dart
// Network images with error handling
Image.network(
  'https://images.unsplash.com/photo-xxx?w=800&h=600',
  errorBuilder: (context, error, stackTrace) {
    return Icon(Icons.error);
  },
  loadingBuilder: (context, child, loadingProgress) {
    if (loadingProgress == null) return child;
    return CircularProgressIndicator();
  },
)

// Asset images
Image.asset('assets/images/placeholder.png')

// Use cached_network_image for better performance
CachedNetworkImage(
  imageUrl: 'https://images.unsplash.com/photo-xxx?w=800&h=600',
  placeholder: (context, url) => CircularProgressIndicator(),
  errorWidget: (context, url, error) => Icon(Icons.error),
)
```

### 6. Accessibility

```dart
// Semantic labels for screen readers
Semantics(
  label: 'Submit button',
  button: true,
  enabled: true,
  child: ElevatedButton(...),
)

// Minimum touch target (44x44)
MaterialButton(
  minWidth: 44,
  height: 44,
  child: Text('Button'),
  onPressed: () {},
)

// Sufficient color contrast (4.5:1 minimum)
// Use tools like https://webaim.org/resources/contrastchecker/
```

### 7. Component Design Tips

#### Cards:

```dart
Card(
  elevation: 2,  // Subtle shadow
  shape: RoundedRectangleBorder(
    borderRadius: BorderRadius.circular(12.0),
  ),
  child: Padding(
    padding: EdgeInsets.all(16.0),  // p-4
    child: Column(...),
  ),
)

// Hover effect (web only)
InkWell(
  onTap: () {},
  hoverColor: Colors.transparent,
  splashColor: Colors.transparent,
  child: MouseRegion(
    cursor: SystemMouseCursors.click,
    child: AnimatedContainer(
      duration: Duration(milliseconds: 200),
      transform: Matrix4.identity()..translate(0.0, _isHovered ? -2.0 : 0.0),
      decoration: BoxDecoration(
        boxShadow: [
          BoxShadow(
            color: Colors.black.withOpacity(_isHovered ? 0.15 : 0.1),
            blurRadius: _isHovered ? 12 : 8,
            offset: Offset(0, _isHovered ? 4 : 2),
          ),
        ],
      ),
      child: Card(...),
    ),
  ),
)
```

#### Buttons:

```dart
// Primary button
ElevatedButton(
  style: ElevatedButton.styleFrom(
    minimumSize: Size(44, 44),  // Touch target
    padding: EdgeInsets.symmetric(horizontal: 24, vertical: 12),
  ),
  onPressed: () {},
  child: Text('Primary'),
)

// Secondary button
OutlinedButton(
  style: OutlinedButton.styleFrom(
    minimumSize: Size(44, 44),
  ),
  onPressed: () {},
  child: Text('Secondary'),
)

// Ghost button
TextButton(
  style: TextButton.styleFrom(
    minimumSize: Size(44, 44),
  ),
  onPressed: () {},
  child: Text('Ghost'),
)
```

#### Forms:

```dart
TextFormField(
  decoration: InputDecoration(
    labelText: 'Email',  // Clear label above input
    border: OutlineInputBorder(),
    focusedBorder: OutlineInputBorder(
      borderSide: BorderSide(color: Theme.of(context).colorScheme.primary, width: 2),
    ),
    errorBorder: OutlineInputBorder(
      borderSide: BorderSide(color: Theme.of(context).colorScheme.error),
    ),
  ),
  validator: (value) {
    if (value == null || value.isEmpty) {
      return 'Please enter email';
    }
    return null;
  },
)

// Spacing between fields
SizedBox(height: 16.0)
```

#### Navigation:

```dart
// Bottom navigation bar
BottomNavigationBar(
  currentIndex: _currentIndex,
  onTap: (index) => setState(() => _currentIndex = index),
  items: [
    BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
    BottomNavigationBarItem(icon: Icon(Icons.settings), label: 'Settings'),
  ],
)

// Navigation Rail (for tablets)
NavigationRail(
  selectedIndex: _selectedIndex,
  onDestinationSelected: (index) => setState(() => _selectedIndex = index),
  destinations: [
    NavigationRailDestination(icon: Icon(Icons.home), label: Text('Home')),
    NavigationRailDestination(icon: Icon(Icons.settings), label: Text('Settings')),
  ],
)
```

### 8. Flutter-Specific Best Practices

#### Performance:

```dart
// Use const constructors when possible
const Text('Static text')
const SizedBox(height: 16)

// Use ListView.builder for long lists
ListView.builder(
  itemCount: items.length,
  itemBuilder: (context, index) {
    return ListTile(title: Text(items[index]));
  },
)

// Avoid rebuilding widgets with const
const MyStaticWidget()
```

#### State Management:

```dart
// Simple state with StatefulWidget
setState(() {
  _counter++;
});

// For complex state, use provider, riverpod, or bloc
// Example with provider:
Consumer<MyModel>(
  builder: (context, model, child) {
    return Text('${model.value}');
  },
)
```

## Quick Reference

| Element | Flutter Recommendation |
|---------|------------------------|
| Primary font | Inter, Outfit, DM Sans (google_fonts) |
| Code font | JetBrains Mono, Fira Code (google_fonts) |
| Border radius | 8.0 - 16.0 (modern), 0 (brutalist) |
| Shadow | BoxShadow with elevation 2-4 |
| Spacing | 4.0 base unit (Spacing class) |
| Animation | 150-400ms, Curves.easeOut |
| Colors | ColorScheme.fromSeed (Material 3) |
| Touch targets | Minimum 44x44 |

---

Based on SuperDesign patterns — https://superdesign.dev  
Adapted for Flutter/Dart — Material Design 3
