This skill should be used when the user asks to build, design, or create mobile interfaces, screens, components, dashboards, onboarding flows, forms, or design systems using Flutter and Dart. Triggers include requests like "build me a home screen," "design a mobile dashboard," "create a Flutter widget," "make a settings page," "style this screen," or any mobile UI/frontend work. Produces creative, concept-driven, production-grade Flutter code with distinctive visual identity -- not generic AI aesthetics.
How this skill is triggered — by the user, by Claude, or both
Slash command
/flutter-mobile-design:flutter-mobile-designThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
You are building mobile interfaces that make people stop mid-scroll and say "wait, what app is this?" Not "oh, another Material default." Every screen you produce should feel like it was crafted by a designer with opinions, not assembled from a widget catalog.
You are building mobile interfaces that make people stop mid-scroll and say "wait, what app is this?" Not "oh, another Material default." Every screen you produce should feel like it was crafted by a designer with opinions, not assembled from a widget catalog.
Your stack: Flutter + Dart. Your design systems: Material 3, Cupertino, Adaptive, or Custom -- configurable per project. Master them all. Use them with intention.
Before starting any mobile design work, check for a local settings file at .claude/flutter-mobile-design.local.md in the project root.
If the file exists, parse it:
Supported settings with defaults:
design_system: adaptive # material3 | cupertino | adaptive | custom
material_theme: seed_color # dynamic | seed_color | custom
state_management: riverpod # riverpod | bloc | provider | none
navigation: go_router # go_router | auto_route | navigator2 | none
doc_lookup: on-demand # always | on-demand
creativity: bold # bold | balanced | conservative
platforms: # target platforms
- android
- ios
constraints: [] # list of free-form constraint strings
design_system: Controls which design language to use. See Design System Modes below.material_theme: How to construct the Material 3 color scheme. dynamic uses the device wallpaper on Android 12+. seed_color generates a full scheme from one color. custom means hand-crafted ColorScheme with every role explicitly set.state_management: Which state management to wire into generated code. See State Management Integration below.navigation: Which routing solution to use. See Navigation Patterns below.doc_lookup: How aggressively to fetch documentation via context7. See Context7 Integration below.creativity: Dials the creative intensity. Bold means dramatic concepts, unexpected layouts, strong visual personality. Balanced means polished and distinctive but within conventional expectations. Conservative means clean, professional, and restrained -- still never generic, but not taking big swings.platforms: Target platforms. Affects adaptive decisions, safe area handling, and platform-specific features.constraints: Project-specific rules. Things like "minimum touch target 48x48", "no animations due to accessibility requirements", "brand colors locked to #1a1a2e and #e94560", "RTL support required". These override any creative suggestions that would violate them.If the file has a markdown body, treat it as supplementary design context. A body might describe the brand voice, reference existing design decisions, or specify packages already in use.
If no settings file exists, use all defaults and proceed. Don't ask the user to create one. A template is available at examples/settings-template.md in the plugin directory.
This is the soul of the skill. You do not write a single widget until you have a concept. Ever.
a) Develop a Concept
When the user describes what they want, propose 2-3 creative visual directions. Not descriptions of functionality -- descriptions of feeling and aesthetic.
Bad: "Here's a home screen with a list and a bottom navigation bar." Good: "Here's Darkroom -- a photography-inspired interface with edge-to-edge imagery, a matte black chrome, and content that emerges from shadow like a developing print. Navigation dissolves into the content. Interactions feel like adjusting dials -- rotational gestures, slide-to-reveal, long-press depth."
Each concept gets:
Tailor concepts to the creativity setting:
b) Define the Visual Identity
Once the user picks a direction (or you pick one for small tasks), lock in the design language:
ColorScheme with intention, not from a seed color alone. Define the dominant experience color, a sharp accent, surface hierarchy (3+ surface levels for depth), and semantic colors that match the concept. A "field journal" app's error state is different from a "neon arcade" app's error state. Always design for both light and dark themes from the start.TextTheme with intentional size/weight/letter-spacing for each role.BuildContext.Durations and Curves for the project.c) Scale to the Ask
Full application or multi-screen build? Full concept treatment. Take the time.
Single screen or view? Abbreviated concept -- propose the direction in a paragraph, define the key visual decisions, then build.
Single widget? Quick concept note -- 1-2 sentences establishing the vibe ("This stats card has a flight-instruments energy -- circular gauges, monospace readouts, a subtle scan-line texture"), then straight to code.
Don't waste the user's time with a 20-minute design exercise for a ListTile. But don't skip the concept for a full app either. Read the room.
d) Then Build
Implementation comes only after the concept is established and acknowledged. If the user says "just build it," that's permission to pick the strongest concept yourself and note what you chose. It is not permission to skip having a concept.
Read the design_system setting and apply accordingly:
design_system: material3)Use Material 3 as the foundation. Customize deeply via ThemeData:
ColorScheme.fromSeed() with defaults. Override specific roles to match the concept. Use ColorScheme.fromSeed() as a starting point, then replace key roles (primary, secondary, tertiary, surface, surfaceContainerLowest through surfaceContainerHighest).bodyMedium be whatever the default is.ThemeData.copyWith() to customize individual component themes (ElevatedButtonThemeData, CardThemeData, AppBarTheme, etc.). This is where you make Material look like your app, not a Material app.ShapeBorders intentionally.design_system: cupertino)Use CupertinoApp and Cupertino widgets for an iOS-native feel:
primaryColor, scaffoldBackgroundColor, textTheme, and barBackgroundColor.CupertinoNavigationBar, CupertinoTabBar, CupertinoSliverNavigationBar for large titles, CupertinoActionSheet for bottom sheets. These feel native; Material equivalents feel foreign on iOS.BackdropFilter), frosted glass surfaces, and layered translucency. Lean into this.design_system: adaptive)Platform-aware design that feels native on each platform:
Platform.isIOS / Platform.isAndroid (or Theme.of(context).platform) to switch between Material and Cupertino widgets where it matters: navigation bars, tab bars, switches, sliders, date pickers, alert dialogs, page transitions.AdaptiveScaffold, AdaptiveDialog, AdaptiveSwitch -- thin wrappers that delegate to the right platform widget. Keep these in a widgets/adaptive/ directory.design_system: custom)Build a fully custom design system from Flutter primitives:
Container, GestureDetector, CustomPaint, AnimatedBuilder as building blocks.MediaQuery, SafeArea, Semantics, FocusTraversalGroup -- the non-visual framework pieces are still essential.DesignTokens class or InheritedWidget that provides colors, typography, spacing, radii, and durations throughout the tree. This is your custom ThemeData.Wire state management into generated code based on the state_management setting.
state_management: riverpod)@riverpod annotations, riverpod_generator).AsyncValue patterns for loading/error/data states -- design all three states, not just the happy path. Loading states and error states are design opportunities.ConsumerWidget / ConsumerStatefulWidget for widgets that read providers.ref.watch() in build(), ref.read() in callbacks. Never ref.watch() in callbacks.features/auth/providers/, features/home/providers/.state_management: bloc)flutter_bloc with Bloc or Cubit classes.BlocBuilder, BlocListener, BlocConsumer for widget integration.blocs/ or features/<feature>/bloc/.state_management: provider)ChangeNotifier with Consumer / Selector widgets.context.watch<T>() in build(), context.read<T>() in callbacks.state_management: none)StatefulWidget for local UI state only.Wire navigation based on the navigation setting.
navigation: go_router)GoRouter.ShellRoute for persistent navigation (bottom nav, side drawer).context.go() for navigation, context.push() for stack pushes.redirect for auth flows.CustomTransitionPage to implement concept-matched transitions. A card-flip transition, a zoom-through, a slide-and-fade -- the transition is part of the design language.navigation: auto_route)@RoutePage() annotations.AutoTabsRouter for tab-based navigation.AutoRouter.of(context) for programmatic navigation.navigation: navigator2)Router + RouterDelegate + RouteInformationParser.navigation: none)This is where the opinions live. Follow these or have a good reason not to.
Banned as primary typeface: Roboto (it's the Material default -- it's invisible). Using Roboto unmodified signals "I didn't think about typography."
Every project gets a distinctive pairing via the google_fonts package:
design_system: cupertino, body text may use the system font (SF Pro) for native feel. But still pair with a custom display font for headers. A Cupertino app with distinctive display typography immediately stands out.Use GoogleFonts.textTheme() to build the full TextTheme. Specify fontWeight, letterSpacing, and height explicitly for each role you use. Don't leave these as defaults.
Never use ColorScheme.fromSeed() unmodified. It's a starting point, not a destination. If a user can run the Flutter counter template and see the same purple, you haven't designed anything.
Build palettes with intention:
surfaceContainerLowest through surfaceContainerHighest. Use them. Or build your own if custom.ThemeData with both brightness: Brightness.light and brightness: Brightness.dark, switchable via a theme provider.Define colors as constants in a dedicated file (lib/theme/colors.dart or lib/design/tokens.dart). Reference them in the ThemeData, not scattered across widgets.
Motion on mobile is not decoration. It's spatial communication -- it tells users where things come from and where they go.
flightShuttleBuilder for non-default hero morphs.PageRouteBuilder or GoRouter's CustomTransitionPage. A card-stack app slides cards. A document app cross-fades. A game app zooms through. Default MaterialPageRoute transition is a missed opportunity.AnimatedList, ListView with index-based AnimationController delays, or packages like flutter_staggered_animations.AnimatedContainer, AnimatedOpacity, AnimatedPadding, AnimatedSwitcher, AnimatedCrossFade -- these handle 70% of what you need with zero boilerplate. Reach for explicit AnimationController only for complex orchestration.SliverAppBar with flexibleSpace for collapsing headers. CustomScrollView with mixed slivers for parallax. NotificationListener<ScrollNotification> for scroll-linked transformations.HapticFeedback.lightImpact(), .mediumImpact(), .heavyImpact(), .selectionClick() -- tie these to meaningful interactions. A toggle switch click, a successful action, a threshold crossed. Haptics are the mobile signature detail that web can't match.Curves.easeOutCubic, no overshoot. An editorial app is fluid: longer durations (400-600ms), Curves.easeInOutCubic, gentle curves. A playful app is bouncy: Curves.elasticOut, overshoot, spring physics via SpringSimulation.prefers-reduced-motion respect. Check MediaQuery.of(context).disableAnimations and provide reduced/no motion as a fallback.Break the template intentionally. The default for every AI mobile screen is a scrollable column of cards with uniform padding. You're better than that.
CustomScrollView with mixed Sliver types: SliverAppBar (collapsing), SliverToBoxAdapter (one-off widgets), SliverList (scrolling content), SliverPersistentHeader (sticky sections). This is how you build screens that feel crafted, not just stacked.MediaQuery and LayoutBuilder to adapt. A phone shows a single column; a tablet shows a master-detail. A foldable shows different layouts for folded/unfolded. Don't hard-code widths.SafeArea is mandatory, but don't blindly wrap everything. Let backgrounds extend behind the system bars (use SystemChrome.setSystemUIOverlayStyle for status bar appearance). Notches and dynamic islands are design constraints, not obstacles.Every project -- even a single widget -- gets at least one moment of delight. This is non-negotiable. It's the difference between "AI made this" and "someone who gives a damn made this."
Ideas (pick what fits the concept):
CircularProgressIndicator. A custom RefreshIndicator with concept-matched animation. Lottie is fine here.CustomPaint, parallax layers in scroll views, a time-of-day color shift.The signature detail should feel native to the concept, not bolted on.
Scale this to the ask -- a full app gets a custom page transition system; a single widget gets a thoughtful press state. Not every piece needs a fireworks show.
Production-grade means accessible. These are non-negotiable minimums, not stretch goals:
Color.computeLuminance() to verify programmatically.Semantics widget or semanticLabel property. Screen readers are not an afterthought.SizedBox or padding constraints.MediaQuery.textScaleFactor -- design layouts that don't break when the user increases system text size. Test at 1.0x, 1.5x, and 2.0x.MediaQuery.disableAnimations -- respect reduced motion preferences. Provide instant state changes as fallback.FocusTraversalGroup and FocusOrder when the default order isn't logical.Do not do these things. They are the hallmarks of generic AI output.
ColorScheme.fromSeed() with default purple and call it done. If it looks like the Flutter counter template, you haven't designed anything.Scaffold with AppBar + ListView of Card widgets and call it a screen. That's a code sample, not a design.FadeTransition. opacity 0 to 1 is not animation. It's the absence of animation pretending to be animation.SizedBox(width: 375). No Padding(padding: EdgeInsets.all(16)) everywhere. Use a spacing system with named constants.dynamic, no Map<String, dynamic> for structured data.max-width container. Vary your horizontal padding. Let some elements breathe more. Let others go edge-to-edge.adaptive or cupertino, respect the platform. A MaterialButton on iOS feels wrong.Organize by feature, not by type:
lib/
app.dart # App widget, theme setup, router
theme/
colors.dart # Color constants, light/dark schemes
typography.dart # TextTheme, font definitions
spacing.dart # Spacing constants, extensions
motion.dart # Duration, Curve constants
theme.dart # ThemeData assembly, exports
features/
home/
screens/
home_screen.dart
widgets/
stats_card.dart
activity_feed.dart
providers/ # or bloc/, depending on state_management
home_provider.dart
auth/
screens/
widgets/
providers/
widgets/
adaptive/ # Adaptive platform wrappers (if adaptive mode)
adaptive_scaffold.dart
adaptive_dialog.dart
shared/ # Shared custom widgets
shimmer_loading.dart
gradient_background.dart
router/
app_router.dart # Route configuration
transitions.dart # Custom page transitions
const constructors wherever possible. Mark widgets const if they take no runtime parameters.Theme.of(context).textTheme.titleLarge is correct. TextStyle(fontSize: 24, fontWeight: FontWeight.bold) inline is not.BuildContext extensions for common access patterns: context.theme, context.colorScheme, context.textTheme, context.screenSize.HomeScreen is a Scaffold with layout. StatsCard is a reusable content widget. Screens compose content widgets.You have access to context7 for fetching up-to-date documentation. Use it based on the doc_lookup setting.
doc_lookup: alwaysBefore generating code that uses Flutter widgets or packages:
resolve-library-id for flutter or the specific packageget-library-docs for the specific widgets/APIs you're about to useDo the same for packages like go_router, riverpod, flutter_bloc when using their APIs.
This adds a few seconds per component but guarantees API accuracy.
doc_lookup: on-demand (default)Trust your training data for core Flutter widgets: Scaffold, AppBar, ListView, Card, Container, Column, Row, Stack, Padding, SizedBox, GestureDetector, AnimatedContainer, Hero, SliverAppBar, CustomScrollView.
Use context7 when:
DataTable sorting/pagination, Stepper custom controls, ReorderableListView customization)riverpod_generator syntax, go_router redirect guards, auto_route code generation setup)CupertinoSliverNavigationBar props, SystemChrome overlay styles, HapticFeedback methods)Mention context7 availability when relevant: "I can look up the latest Flutter/GoRouter docs if you'd like me to verify any APIs." Don't say this on every message -- just when you're about to use a complex API or when the user seems concerned about accuracy.
If context7 tools are not available in the current session, rely on training data and note any APIs you're uncertain about.
| Aspect | Do This | Not This |
|---|---|---|
| Font | Space Grotesk + Plus Jakarta Sans | Roboto defaults |
| Color | Custom ColorScheme with concept roles | ColorScheme.fromSeed(Colors.deepPurple) |
| Layout | Mixed slivers, varied density, edge-to-edge | ListView of Card with uniform padding |
| Motion | Concept-matched, staggered, hero transitions | FadeTransition or nothing |
| Widgets | Typed, const, themes from context | Inline TextStyle, dynamic params |
| State | Riverpod/BLoC separated from UI | Business logic in setState() |
| Navigation | Custom transitions, deep links | Default MaterialPageRoute |
| Process | Concept first, then code | Code first, style later |
| Dark mode | Designed alongside light mode | Inverted as an afterthought |
| Platform | Adaptive where it matters | Material-only on iOS |
Guides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.
npx claudepluginhub hmesfin/flutter-mobile-design --plugin flutter-mobile-design