Install
$ agentstack add skill-iammohdzaki-kmp-skills-material3 ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Material Design 3 — KMP / Compose Multiplatform Skill
This skill guides implementation of Google's Material Design 3 (MD3 / Material You) using Jetpack Compose and Compose Multiplatform for KMP projects (Android + Desktop).
> Attribution: This skill is adapted from and gives credit to > hamen/material-3-skill by Hamen. > The original skill covers web and Flutter targets. This KMP edition strips all web/CSS/Flutter > patterns and replaces them with pure Compose Multiplatform APIs, adds the audit report system, > and extends the reference set for adaptive layout, navigation, and versioning.
> Scope: Compose-only. All examples use androidx.compose.material3 APIs — the same API > surface is available in KMP commonMain via org.jetbrains.compose.material3:material3 > (declared explicitly in libs.versions.toml). No web CSS, no @material/web elements, no Flutter.
MD3 Philosophy
| Principle | What it means in Compose | |---|---| | Personal | Dynamic color from user wallpaper (Android 12+). Static fallback for Desktop. | | Adaptive | WindowSizeClass drives layout changes across compact → expanded screens. | | Expressive | Spring-based motion, shape morphing, emphasized typography. |
Google I/O 2026 Key Updates
- Compose-first on Android: For all new Android work, use
androidx.compose.material3. - Expressive layout scaffold: Design screens to adapt across mobile, desktop, foldables. Use
Material3Adaptivescaffold APIs. - 8dp spacing system: Define spacing as tokens — never scatter raw
Dpliterals. - New expressive components: Lists, menus, search, and search app bars have refreshed expressive guidance; check your Material3 BOM for expressive variants.
Design Token System
All MD3 values come through MaterialTheme. Never hardcode raw values inline.
| Token category | Access in Compose | |---|---| | Color | MaterialTheme.colorScheme.* | | Typography | MaterialTheme.typography.* | | Shape | MaterialTheme.shapes.* | | Spacing | Define a Dimens object (no built-in API) |
Decision Tree
What are you building?
Full app scaffold → AppTheme setup + references/theming-and-dynamic-color.md
Single component → references/component-catalog.md
Custom color theme → references/color-system.md
Typography / fonts → references/typography-and-shape.md
Navigation structure → references/navigation-patterns.md
Adaptive layout → references/layout-and-responsive.md
Color Token Summary
Full details in [references/color-system.md](references/color-system.md).
Key Roles (Compose token → usage)
| Role | Token | Primary Usage | |---|---|---| | Primary | colorScheme.primary | FAB, key buttons, active states | | On Primary | colorScheme.onPrimary | Text/icons on primary | | Primary Container | colorScheme.primaryContainer | Tonal buttons, selected chips | | On Primary Container | colorScheme.onPrimaryContainer | Text on primary container | | Secondary | colorScheme.secondary | Less prominent accents, filters | | Secondary Container | colorScheme.secondaryContainer | Recessive fills | | Tertiary | colorScheme.tertiary | Contrasting accent sections | | Surface | colorScheme.surface | Cards, sheets, menus | | Surface Container | colorScheme.surfaceContainer | Navigation areas | | On Surface | colorScheme.onSurface | Body text, icons | | On Surface Variant | colorScheme.onSurfaceVariant | Placeholder, helper text | | Outline | colorScheme.outline | Input borders, dividers | | Error | colorScheme.error | Error states |
Typography Token Summary
Full details in [references/typography-and-shape.md](references/typography-and-shape.md).
| Category | Styles | Usage | |---|---|---| | Display | L / M / S | Hero text, large numbers | | Headline | L / M / S | Screen/section headers | | Title | L / M / S | Toolbar titles, card headers | | Body | L / M / S | Paragraph text, descriptions | | Label | L / M / S | Buttons, chips, captions |
// ✅ Always via MaterialTheme
Text("Title", style = MaterialTheme.typography.titleLarge)
Text("Body", style = MaterialTheme.typography.bodyMedium)
// ❌ Never inline
Text("Title", fontSize = 22.sp, fontWeight = FontWeight.Normal)
Shape Token Summary
| Token | Corner Radius | Typical Components | |---|---|---| | shapes.extraSmall | 4dp | Chips, snackbars | | shapes.small | 8dp | Text fields, menus | | shapes.medium | 12dp | Cards | | shapes.large | 16dp | FABs, nav drawer | | shapes.extraLarge | 28dp | Dialogs, bottom sheets |
Elevation
MD3 communicates depth through tonal surface color, not drop shadows.
| Level | Compose API | Tonal Offset | Use | |---|---|---|---| | 0 | Elevation.Level0 / 0.dp | None | Flat surfaces at rest | | 1 | Elevation.Level1 / 1.dp | +5% primary | Elevated cards | | 2 | Elevation.Level2 / 3.dp | +8% primary | Menus, nav bar | | 3 | Elevation.Level3 / 6.dp | +11% primary | FAB, dialogs |
// Cards respect tonal elevation automatically via surfaceTonalElevation
ElevatedCard(elevation = CardDefaults.elevatedCardElevation(defaultElevation = 6.dp)) { }
Motion Summary
Full details in [references/typography-and-shape.md](references/typography-and-shape.md) §Motion.
| Easing | Compose | Usage | |---|---|---| | Emphasized | CubicBezierEasing(0.2f, 0f, 0f, 1f) | Elements staying on screen | | Emphasized Decelerate | CubicBezierEasing(0.05f, 0.7f, 0.1f, 1f) | Entering screen | | Emphasized Accelerate | CubicBezierEasing(0.3f, 0f, 0.8f, 0.15f) | Leaving screen | | Standard | FastOutSlowInEasing | Utility animations |
Standard Durations
| Token | Duration | Usage | |---|---|---| | Short | 100–200ms | Icon/color state changes | | Medium | 300–400ms | Component expand/collapse | | Long | 400–500ms | Screen-level transitions |
Component Quick Reference
| Component | Compose API | Category | |---|---|---| | Button (Filled) | Button {} | Actions | | Button (Tonal) | FilledTonalButton {} | Actions | | Button (Outlined) | OutlinedButton {} | Actions | | Button (Text) | TextButton {} | Actions | | FAB | FloatingActionButton {} | Actions | | Extended FAB | ExtendedFloatingActionButton {} | Actions | | Icon Button | IconButton {}, FilledIconButton {} | Actions | | Segmented Button | SegmentedButton {} | Actions | | Card | Card {}, ElevatedCard {}, OutlinedCard {} | Containment | | Dialog | AlertDialog {}, Dialog {} | Containment | | Bottom Sheet | ModalBottomSheet {} | Sheets | | Snackbar | SnackbarHost {} | Communication | | Progress | CircularProgressIndicator(), LinearProgressIndicator() | Communication | | Badge | BadgedBox {} | Communication | | Checkbox | Checkbox() | Input | | RadioButton | RadioButton() | Input | | Switch | Switch() | Input | | Slider | Slider(), RangeSlider() | Input | | TextField | TextField(), OutlinedTextField() | Input | | Chips | FilterChip, AssistChip, InputChip, SuggestionChip | Input | | TopAppBar | TopAppBar, CenterAlignedTopAppBar, LargeTopAppBar | Navigation | | Navigation Bar | NavigationBar {} | Navigation | | Navigation Rail | NavigationRail {} | Navigation | | Navigation Drawer | ModalNavigationDrawer {} | Navigation | | Tabs | TabRow {}, ScrollableTabRow {} | Navigation |
Full Compose API + examples: [references/component-catalog.md](references/component-catalog.md)
AppTheme Setup (Quick Start)
@Composable
fun AppTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
// Dynamic color is Android 12+ only — always falls back to static on Desktop
dynamicColor: Boolean = true,
content: @Composable () -> Unit
) {
val colorScheme = when {
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
val context = LocalContext.current
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
}
darkTheme -> DarkColorScheme
else -> LightColorScheme
}
MaterialTheme(
colorScheme = colorScheme,
typography = AppTypography,
shapes = AppShapes,
content = content
)
}
> For Compose Multiplatform Desktop: Remove Build.VERSION_SDK_INT check and always use > LightColorScheme / DarkColorScheme. Dynamic color has no JVM equivalent.
Full theming guide: [references/theming-and-dynamic-color.md](references/theming-and-dynamic-color.md)
Core Rules
- Never hardcode
Color(0xFF...)in composables — alwaysMaterialTheme.colorScheme.* - Never inline
fontSize,fontFamily,fontWeight— alwaysMaterialTheme.typography.* - Never inline
RoundedCornerShape(12.dp)— alwaysMaterialTheme.shapes.* - Always wrap content in
AppThemeat the root — never in individual screens - Always support dark mode — test every screen with
isSystemInDarkTheme() - Always use
Scaffold— it handlestopBar,bottomBar,FAB,snackbarHost, padding - Minimum touch target: 48×48dp for all interactive elements
- Spacing tokens: always multiples of 4dp — define a
Dimensobject - For Desktop/JVM: always use static color schemes — no dynamic color API on JVM
MD3 Compliance Audit
When the user asks for an audit, a compliance check, or passes code / a screen name with the audit argument, run a full MD3 compliance report using the template below.
How to trigger
audit [screen name or paste code here]
audit HomeScreen
audit
check this screen against material 3
run md3 audit
Audit Process
- Scan the target — read the provided code or ask the user to paste the composable(s) to audit.
- Check each category below in order.
- Output the report using the exact format specified.
- Offer fixes — for every ❌ or ⚠️, provide the corrected Compose code snippet inline.
Audit Report Format
Output the report in this exact structure:
╔══════════════════════════════════════════════════════════╗
║ MD3 COMPLIANCE AUDIT — [Screen/File Name] ║
║ KMP / Compose Multiplatform Edition ║
╚══════════════════════════════════════════════════════════╝
Score: [X / 10] Grade: [A / B / C / D / F]
┌─────────────────────────────────────────────────────────┐
│ CATEGORY RESULTS │
└─────────────────────────────────────────────────────────┘
[✅ / ⚠️ / ❌] COLOR SYSTEM [PASS / WARN / FAIL]
[✅ / ⚠️ / ❌] TYPOGRAPHY [PASS / WARN / FAIL]
[✅ / ⚠️ / ❌] SHAPE [PASS / WARN / FAIL]
[✅ / ⚠️ / ❌] SPACING [PASS / WARN / FAIL]
[✅ / ⚠️ / ❌] ELEVATION [PASS / WARN / FAIL]
[✅ / ⚠️ / ❌] COMPONENTS [PASS / WARN / FAIL]
[✅ / ⚠️ / ❌] LAYOUT & ADAPTIVE [PASS / WARN / FAIL]
[✅ / ⚠️ / ❌] NAVIGATION [PASS / WARN / FAIL]
[✅ / ⚠️ / ❌] MOTION & ANIMATION [PASS / WARN / FAIL]
[✅ / ⚠️ / ❌] DARK MODE [PASS / WARN / FAIL]
[✅ / ⚠️ / ❌] ACCESSIBILITY [PASS / WARN / FAIL]
[✅ / ⚠️ / ❌] THEMING SETUP [PASS / WARN / FAIL]
┌─────────────────────────────────────────────────────────┐
│ FINDINGS │
└─────────────────────────────────────────────────────────┘
[findings listed per category — see check rules below]
┌─────────────────────────────────────────────────────────┐
│ FIXES │
└─────────────────────────────────────────────────────────┘
[corrected code snippets for every ❌ and ⚠️]
Audit Check Rules — Per Category
1. COLOR SYSTEM
| Check | Pass condition | Fail condition | |---|---|---| | No hardcoded colors in composables | MaterialTheme.colorScheme.* used | Color(0xFF…) literal in UI code | | No swapped semantic roles | error used for errors only | error used for success/warning | | Both schemes defined | LightColorScheme + DarkColorScheme exist | Only one scheme present | | Dynamic color has static fallback | if (dynamicColor && SDK >= S) with else branch | Dynamic color used unconditionally | | Extended colors use CompositionLocal | LocalExtendedColors pattern | Raw color passed as parameter | | Desktop: no dynamic color API | jvmMain uses static scheme | dynamicDarkColorScheme() in jvmMain |
2. TYPOGRAPHY
| Check | Pass condition | Fail condition | |---|---|---| | No inline font sizes | MaterialTheme.typography.* used | fontSize = 16.sp inline | | No inline font weights | MaterialTheme.typography.* used | fontWeight = FontWeight.Bold inline | | Custom font loaded via Res.font.* | Font(Res.font.*) for KMP | Hardcoded path or fontFamily literal | | All 15 styles defined if custom typography | Typography(displayLarge = …, labelSmall = …) | Missing styles in custom Typography | | Body text uses bodyLarge/bodyMedium | Correct role applied | displayLarge on body copy |
3. SHAPE
| Check | Pass condition | Fail condition | |---|---|---| | No inline RoundedCornerShape | MaterialTheme.shapes.* used | RoundedCornerShape(12.dp) inline | | Shape token matches component | Cards use shapes.medium, FABs use shapes.extraLarge | FAB with shapes.small | | Custom shapes defined in AppShapes | val AppShapes = Shapes(…) in theme | Shape overrides scattered in UI |
4. SPACING
| Check | Pass condition | Fail condition | |---|---|---| | Spacing uses Dimens object | Dimens.md, Dimens.lg, etc. | Scattered 16.dp, 24.dp literals | | Values are multiples of 4dp | 4, 8, 12, 16, 24, 32, 48dp | 15.dp, 7.dp, 11.dp literals | | Screen margins consistent | Dimens.screenHorizontal used | Mixed margin values per screen |
5. ELEVATION
| Check | Pass condition | Fail condition | |---|---|---| | Tonal elevation used | tonalElevation / CardDefaults.elevatedCardElevation() | Modifier.shadow(8.dp) for depth | | Shadow used only for busy backgrounds | Rare Modifier.shadow with clear reason | Shadows on all cards for styling |
6. COMPONENTS
| Check | Pass condition | Fail condition | |---|---|---| | Only one Button (filled) per section | Single primary action | Multiple filled buttons per section | | FAB in Scaffold.floatingActionButton | Scaffold(floatingActionButton = {…}) | FAB positioned manually with Box | | Scaffold used on every screen | Scaffold {} wraps each screen | No Scaffold, manual layout | | AlertDialog for destructive actions | confirmButton + dismissButton both present | No dismiss option on destructive dialog | | Lists use ListItem | ListItem(headlineContent = …) | Custom Row replacing ListItem | | Buttons use correct emphasis hierarchy | Filled → Tonal → Elevated → Outlined → Text | Multiple filled buttons, no hierarchy |
7. LAYOUT & ADAPTIVE
| Check | Pass condition | Fail condition | |---|---|---| | WindowSizeClass used | calculateWindowSizeClass() or currentWindowAdaptiveInfo() | Fixed-width if (isTablet) hack | | No hardcoded breakpoints | WindowWidthSizeClass.* enum | if (width > 600.dp) check | | Canonical layout pattern used | Feed / List-Detail / Supporting Pane | None of the canonical patterns applied | | Edge-to-edge enabled | enableEdgeToEdge() in Activity | Status bar not handled | | WindowInsets applied | Modifier.statusBarsPadding() or Scaffold | Content hidden behind system bars | | Adaptive API used for list-detail | NavigableListDetailPaneScaffold | Manual Row reimplementing list-detail |
8. NAVIGATION
| Check | Pass condition | Fail condition | |---|---|---| | Nav component matches window size | NavigationBar on compact, NavigationRail on medium, drawer on expanded | Bottom nav on tablet | | Bottom nav has 3–5 items | Dest
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: iammohdzaki
- Source: iammohdzaki/kmp-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.