name: kmp-design-systems description: "Design tokens, component library, and Material Icons strategy for dual-theme KMP apps. Use when: (1) Working with design tokens (spacing, shapes, elevation, motion), (2) Creating or customizing themed components (PokemonCard, TypeBadge, AnimatedStatBar), (3) Implementing Material Icons as Vector Drawable XML, (4) Integrating Material Design 3 vs Compose Unstyled themes, (5) Troubleshooting LaunchedEffect token access in suspend contexts. Keywords: design tokens, CompositionLocal, Material Symbols, WCAG, LaunchedEffect, component tokens"
KMP Design Systems
Mode Detection
| User Request | Reference File | Load When |
|---|---|---|
| "Design token values" | design_tokens.md | MANDATORY |
| "Component styling" | component_library.md | MANDATORY |
| "Material Icons/Symbols" | material_icons_strategy.md | MANDATORY |
| "Troubleshooting themes" | troubleshooting.md | When debugging |
Design system architecture for organizing design tokens, reusable components, and icon strategies in Kotlin Multiplatform.
When to Use This Skill
Use this skill when:
- Working on design tokens (spacing, shapes, elevation, motion)
- Creating or customizing components (PokemonCard, TypeBadge, AnimatedStatBar)
- Implementing icons (Vector Drawable XML, Material Symbols)
- Integrating themes (Material Design 3 vs Compose Unstyled)
Design System Architecture
MANDATORY - READ ENTIRE FILE: Before working with design tokens or component styling, you MUST read:
design_tokens.mdcompletely from start to finish (~154 lines) for foundation tokenscomponent_library.mdcompletely from start to finish (~440 lines) for component patterns
Do NOT load material_icons_strategy.md or troubleshooting.md unless specifically working with icons or debugging.
The design system uses a two-layer token system provided via CompositionLocal:
- Design Tokens (design_tokens.md): Foundation tokens (spacing, shapes, elevation, motion).
- Component Tokens (component_library.md): Component-specific styling via interfaces (
CardTokens,BadgeTokens).
Key Patterns
Token Access Pattern
MaterialTheme.tokens.spacing.medium // Design Token
MaterialTheme.componentTokens.card() // Component Token
LaunchedEffect Token Capture (CRITICAL)
Always capture tokens BEFORE LaunchedEffect since the lambda is a suspend context and cannot access @Composable providers:
// ✅ CORRECT
val motionTokens = MaterialTheme.tokens.motion
LaunchedEffect(Unit) {
animateTo(durationMillis = motionTokens.durationMedium)
}
Component Library
Shared components live in :core:designsystem-core and are theme-agnostic. They accept token interfaces to allow different visual styling.
- PokemonCard: Responsive card with press feedback.
- TypeBadge: Accessible Pokémon type indicators.
- AnimatedStatBar: Smoothly animated progress bars with reduced motion support.
See component_library.md for full specs and usage.
Material Icons Strategy
MANDATORY - READ ENTIRE FILE: Before working with Material Icons or Material Symbols, you MUST read material_icons_strategy.md completely from start to finish (~272 lines).
Do NOT load design_tokens.md, component_library.md, or troubleshooting.md unless specifically needed.
We use Material Symbols Rounded Filled as Vector Drawable XML files.
- Source: fonts.google.com/icons (Android tab).
- Storage:
composeResources/drawable/ic_*.xmlin:core:designsystem-core. - Usage:
painterResource(Res.drawable.ic_*)withtintandcontentDescription.
See material_icons_strategy.md for configuration and inventory.
Related Skills
- @kmp-architecture - Module structure and layer placement
- @kmp-compose-unstyled - Headless component patterns
- @compose-screen - Using design system in screens
- @ui-ux-designer - Visual design guidelines
Decision Framework
Before working with design systems, ask yourself:
Which design system should I modify?
- Material Design 3 tokens →
:core:designsystem-material - Compose Unstyled theme →
:core:designsystem-unstyled - Shared design tokens (spacing, shapes) →
:core:designsystem-core - NEVER duplicate tokens across modules
- Material Design 3 tokens →
What level of customization is needed?
- Theme-wide tokens (colors, typography) → Modify design token objects
- Component-specific styling → Material components or Unstyled overrides
- One-off customization → Modifier chains in screen implementation
How do I test design changes?
- Use
@Previewannotations for all components with theme applied - Test both Material and Unstyled themes if component is shared
- Verify color contrast meets WCAG AA standards (use type colors)
- Use
Essential Workflows
Workflow 1: Creating Design Tokens for a New Theme
- Define design token interfaces in
:core:designsystem-material(e.g.,MaterialDesignTokens). - Implement the interface with specific values for spacing, shapes, elevation, and motion.
- Provide the tokens using a
CompositionLocalProviderin your theme Composable.
// features/<feature>/ui-material/src/commonMain/kotlin/.../CustomTheme.kt
internal class CustomDesignTokens : MaterialDesignTokens {
override val spacing = object : SpacingTokens {
override val medium = 16.dp
// ... other tokens
}
// ... implementations for shapes, elevation, motion
}
@Composable
fun CustomTheme(content: @Composable () -> Unit) {
CompositionLocalProvider(
LocalMaterialTokens provides CustomDesignTokens()
) {
MaterialTheme(content = content)
}
}
Workflow 2: Building a Themed Component with Token Access
- Define a Composable component that accepts a token interface as an optional parameter.
- Default to the theme's tokens using the
MaterialThemeextension property. - Apply tokens to internal Material 3 components to maintain visual consistency.
@Composable
fun PokemonCard(
pokemon: Pokemon,
modifier: Modifier = Modifier,
tokens: CardTokens = MaterialTheme.componentTokens.card(),
onClick: () -> Unit = {}
) {
Card(
modifier = modifier.scale(if (pressed) tokens.pressedScale else 1f),
shape = tokens.shape,
elevation = CardDefaults.cardElevation(defaultElevation = tokens.elevation),
colors = CardDefaults.cardColors(containerColor = tokens.containerColor),
onClick = onClick
) {
// Component content using spacing tokens
Column(modifier = Modifier.padding(MaterialTheme.tokens.spacing.medium)) {
Text(text = pokemon.name)
}
}
}
Workflow 3: Adding Material Icons (Vector Drawable XML)
- Download Material Symbol from fonts.google.com/icons in Android XML format.
- Save to
:core:designsystem-coreundersrc/commonMain/composeResources/drawable/ic_<name>.xml. - Remove platform-specific references (like
@android:color) and use hex values orcurrentColor. - Use in UI with
painterResourceand apply type-safe colors.
Icon(
painter = painterResource(Res.drawable.ic_pokemon_type_fire),
contentDescription = "Fire Type",
tint = PokemonTypeColors.getBackground("fire", isDark = isSystemInDarkTheme())
)
Workflow 4: Implementing LaunchedEffect Token Capture Pattern
- Capture the token object in a local variable outside the
LaunchedEffectlambda. - Access the captured variable inside the suspend context.
@Composable
fun AnimatedStatBar(value: Float) {
// 1. Capture BEFORE LaunchedEffect
val motion = MaterialTheme.tokens.motion
val animValue = remember { Animatable(0f) }
LaunchedEffect(value) {
// 2. Use captured token in suspend context
animValue.animateTo(
targetValue = value,
animationSpec = spring(
dampingRatio = Spring.DampingRatioMediumBouncy,
stiffness = motion.stiffnessMedium
)
)
}
}
Critical Guardrails
- NEVER hardcode dp values → always use
MaterialTheme.tokens.spacingorshapes(reason: ensures consistency across all components and themes). - NEVER skip LaunchedEffect token capture pattern → always capture tokens in a local variable before the lambda (reason:
@Composableproviders cannot be accessed from suspend contexts). - NEVER use @android:color references in icons → use hardcoded hex values or
android:fillColor="currentColor"(reason: platform-specific references break multiplatform compilation). - NEVER forget contentDescription for accessibility → always provide a meaningful description or
nullfor decorative elements (reason: ensures screen reader compatibility). - NEVER use material-icons-extended library → always use Vector Drawable XML files in
composeResources/drawable(reason: minimizes application binary size by including only used icons). - NEVER hardcode colors for Pokémon types → always use the
PokemonTypeColorsutility (reason: ensures WCAG AA accessibility compliance across the 18 types). - NEVER apply hardcoded elevation values → use
MaterialTheme.tokens.elevationlevels (reason: maintains consistent visual hierarchy and depth across themes). - NEVER use platform-specific font names → use the design system's
Typographytokens (reason: ensures cross-platform font consistency).
Quick Reference
| Pattern | Purpose | Example |
|---|---|---|
MaterialTheme.tokens.spacing.* |
Access spacing/padding tokens | padding(MaterialTheme.tokens.spacing.medium) |
MaterialTheme.tokens.shapes.* |
Access corner radius tokens | clip(MaterialTheme.tokens.shapes.large) |
MaterialTheme.tokens.elevation.* |
Access elevation level tokens | elevation = MaterialTheme.tokens.elevation.level2 |
MaterialTheme.tokens.motion.* |
Access motion/duration tokens | animateTo(durationMillis = motion.durationLong) |
MaterialTheme.componentTokens.* |
Access component-specific styles | MaterialTheme.componentTokens.card() |
LaunchedEffect Capture |
Access tokens in suspend context | val motion = MaterialTheme.tokens.motion; LaunchedEffect { ... } |
painterResource |
Load icon from resources | painterResource(Res.drawable.ic_search) |
Troubleshooting Common Design System Issues
MANDATORY - READ ENTIRE FILE: When encountering design system errors or unexpected behavior, you MUST read troubleshooting.md completely from start to finish (~85 lines) for comprehensive solutions.
Do NOT load design_tokens.md, component_library.md, or material_icons_strategy.md unless the troubleshooting guide specifically directs you to them.
"Unresolved reference 'generated'" for Compose Resources
Symptom:
import multiplatformpoc.core.designsystem_core.generated.resources.Res
// Error: Unresolved reference 'generated'
Cause: Library module resources not configured for public access.
Solution (3 steps in library module's build.gradle.kts):
// 1. Add dependency
kotlin {
sourceSets {
commonMain.dependencies {
implementation(libs.compose.components.resources) // CRITICAL!
}
}
}
// 2. Enable public Res class
compose.resources {
publicResClass = true // Default internal won't work!
}
// 3. Android namespace determines package
android {
namespace = "com.minddistrict.multiplatformpoc.core.designsystem.core"
}
Generated package name: Namespace with dots → underscores:
- Input:
com.minddistrict.multiplatformpoc.core.designsystem.core - Output:
multiplatformpoc.core.designsystem_core.generated.resources
Theme[property][token] Not Found
Symptom:
Theme[shapes][shapeLarge]
// Error: Unresolved reference
Cause: Wrong imports from platform theme instead of custom theme.
Solution:
// ❌ WRONG
import com.composeunstyled.platformtheme.shapes
// ✅ CORRECT
import com.minddistrict.multiplatformpoc.core.designsystem.unstyled.theme.shapes
import com.minddistrict.multiplatformpoc.core.designsystem.unstyled.theme.shapeLarge
Supported properties in Unstyled:
Theme[spacing][spacingSm/Md/Lg/Xl/...]Theme[shapes][shapeLarge/Medium/Small]Theme[typography][labelMedium/bodyLarge/...]Theme[colors][primary/onSurface/background/...]Theme[elevation][elevationLevel1/2/3]Theme[motionDuration][durationShort/Medium/Long]Theme[motionEasing][easingStandard]
Key insight: Unstyled theme DOES support full Theme[property][token] syntax despite minimal aesthetic.
PokemonTypeColors API Changes
Symptom:
PokemonTypeColors.getColorForType(type.name)
// Error: Unresolved reference 'getColorForType'
Cause: API method name changed.
Solution:
// ✅ CORRECT
val color = PokemonTypeColors.getBackground(type.name, isDark = false)
Why: Centralized color system with light/dark mode support.
Cross-References
Skills (by Category)
Design & UI
| Skill | Purpose | Link |
|---|---|---|
| @compose-screen | Using design system in screens | SKILL.md |
| @kmp-compose-unstyled | Headless component patterns | SKILL.md |
| @ui-ux-designer | Visual design guidelines | SKILL.md |
| @swiftui-screen | iOS design integration | SKILL.md |
Architecture & Development
| Skill | Purpose | Link |
|---|---|---|
| @kmp-architecture | Module structure and layer placement | SKILL.md |
| @kmp-developer | General development patterns | SKILL.md |
| @kmp-testing-patterns | Component testing patterns | SKILL.md |
| @kmp-critical-patterns | Quick patterns reference | SKILL.md |
Documents
| Document | Purpose | Link |
|---|---|---|
| design_tokens.md | Token system architecture | See @kmp-design-systems skill |
| component_library.md | Component specifications | See @kmp-design-systems skill |
| material_icons_strategy.md | Icon usage guide | material_icons_strategy.md |
| troubleshooting.md | Common design system issues and solutions | troubleshooting.md |
| @kmp-architecture | Master architecture reference | Architecture skill |