Skillquality 0.45

design-system

27 Android skills for AI agents (Claude Code, Codex, Cursor). Fixes Supabase auth, Hilt errors, design inconsistency, kapt→ksp, missing UiState states. Reduced my token bills 5×. FitGenZ AI shipped in 18 days.

Price
free
Protocol
skill
Verified
no

What it does

Design System — Global Level (M3 Expressive)

Material 3 Expressive is Google's most advanced design language — physics-based motion, HCT color science, shape morphing, and a full token architecture. These rules make AI-built apps feel professional, personal, and visually unified across every screen.

Token architecture — single source of truth

// ui/theme/tokens/DesignTokens.kt — define once, reference everywhere

object Spacing {
    val none  = 0.dp
    val xs    = 4.dp    // micro: badges, icon gaps
    val sm    = 8.dp    // tight: list item gaps
    val md    = 16.dp   // standard: screen padding, card padding
    val lg    = 24.dp   // section: gaps between content groups
    val xl    = 32.dp   // large: hero padding
    val xxl   = 48.dp   // extra: section breaks
    val xxxl  = 64.dp   // massive: onboarding, splash
}

object Elevation {
    val none   = 0.dp   // flat — standard cards
    val level1 = 1.dp   // slightly raised
    val level2 = 3.dp   // FAB, raised cards
    val level3 = 6.dp   // dialogs
    val level4 = 8.dp   // navigation drawers
    val level5 = 12.dp  // tooltips
}

// M3 Expressive motion duration tokens (replaces ALL hardcoded ms)
object Duration {
    const val short1      = 50    // micro: icon swap
    const val short2      = 100   // fast: color shift
    const val short3      = 150   // quick: appear short distance
    const val short4      = 200   // standard fade
    const val medium1     = 250   // expand/collapse
    const val medium2     = 300   // default transition
    const val medium3     = 350   // complex motion
    const val medium4     = 400   // enter from edge
    const val long1       = 450   // large surface
    const val long2       = 500   // full-screen takeover
    const val extraLong1  = 700   // emphasis / delight
}

// M3 Expressive easing curves (physics-based)
object AppEasing {
    val Standard        = CubicBezierEasing(0.2f, 0f, 0f, 1f)
    val EmphasizedDecel = CubicBezierEasing(0.05f, 0.7f, 0.1f, 1f)  // new content entering
    val EmphasizedAccel = CubicBezierEasing(0.3f, 0f, 0.8f, 0.15f)  // content leaving
    val Linear          = LinearEasing
}

Theme setup — dynamic color + MotionScheme

// ui/theme/AppTheme.kt
@Composable
fun AppTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    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 -> AppDarkColorScheme
        else      -> AppLightColorScheme
    }

    val view = LocalView.current
    if (!view.isInEditMode) {
        SideEffect {
            val window = (view.context as Activity).window
            WindowCompat.getInsetsController(window, view).apply {
                isAppearanceLightStatusBars = !darkTheme
                isAppearanceLightNavigationBars = !darkTheme
            }
        }
    }

    MaterialTheme(
        colorScheme = colorScheme,
        typography = AppTypography,
        shapes = AppShapes,
        content = content
    )
}

Color system — HCT-generated M3 palette

// ui/theme/AppColorScheme.kt
// Generate yours at: material-foundation.com/tools/theme-builder
// M3 uses HCT (Hue/Chroma/Tone) — perceptually uniform, WCAG contrast by construction

private val AppLightColorScheme = lightColorScheme(
    primary               = Color(0xFF1A73E8),
    onPrimary             = Color(0xFFFFFFFF),
    primaryContainer      = Color(0xFFD3E3FD),
    onPrimaryContainer    = Color(0xFF041E49),
    secondary             = Color(0xFF5F6368),
    onSecondary           = Color(0xFFFFFFFF),
    secondaryContainer    = Color(0xFFE8EAED),
    onSecondaryContainer  = Color(0xFF202124),
    tertiary              = Color(0xFF006E56),
    onTertiary            = Color(0xFFFFFFFF),
    tertiaryContainer     = Color(0xFF7AF8D3),
    onTertiaryContainer   = Color(0xFF002117),
    error                 = Color(0xFFB3261E),
    onError               = Color(0xFFFFFFFF),
    errorContainer        = Color(0xFFF9DEDC),
    onErrorContainer      = Color(0xFF410E0B),
    background            = Color(0xFFFEFBFF),
    onBackground          = Color(0xFF1C1B1F),
    surface               = Color(0xFFFEFBFF),
    onSurface             = Color(0xFF1C1B1F),
    surfaceVariant        = Color(0xFFE7E0EC),
    onSurfaceVariant      = Color(0xFF49454F),
    outline               = Color(0xFF79747E),
    outlineVariant        = Color(0xFFCAC4D0),
    // Surface container hierarchy — tonal elevation without shadows
    surfaceContainerLowest  = Color(0xFFFFFFFF),
    surfaceContainerLow     = Color(0xFFF7F2FA),
    surfaceContainer        = Color(0xFFF3EDF7),
    surfaceContainerHigh    = Color(0xFFECE6F0),
    surfaceContainerHighest = Color(0xFFE6E0E9),
)

private val AppDarkColorScheme = darkColorScheme(
    primary               = Color(0xFFAECBFA),
    onPrimary             = Color(0xFF0A3775),
    primaryContainer      = Color(0xFF2860C4),
    onPrimaryContainer    = Color(0xFFD3E3FD),
    secondary             = Color(0xFFBCC7DC),
    onSecondary           = Color(0xFF263141),
    surface               = Color(0xFF141218),
    onSurface             = Color(0xFFE6E1E5),
    surfaceVariant        = Color(0xFF49454F),
    onSurfaceVariant      = Color(0xFFCAC4D0),
    surfaceContainerLowest  = Color(0xFF0F0D13),
    surfaceContainerLow     = Color(0xFF1D1B20),
    surfaceContainer        = Color(0xFF211F26),
    surfaceContainerHigh    = Color(0xFF2B2930),
    surfaceContainerHighest = Color(0xFF36343B),
    error                 = Color(0xFFF2B8B5),
    errorContainer        = Color(0xFF8C1D18),
    outline               = Color(0xFF938F99),
    outlineVariant        = Color(0xFF49454F),
)

Typography — M3 Expressive 15-style scale

// ui/theme/AppTypography.kt
private val BrandFont = FontFamily(
    Font(R.font.brand_regular,  FontWeight.Normal),
    Font(R.font.brand_medium,   FontWeight.Medium),
    Font(R.font.brand_semibold, FontWeight.SemiBold),
    Font(R.font.brand_bold,     FontWeight.Bold),
)

val AppTypography = Typography(
    displayLarge  = TextStyle(fontFamily = BrandFont, fontWeight = FontWeight.Normal,  fontSize = 57.sp, lineHeight = 64.sp,  letterSpacing = (-0.25).sp),
    displayMedium = TextStyle(fontFamily = BrandFont, fontWeight = FontWeight.Normal,  fontSize = 45.sp, lineHeight = 52.sp),
    displaySmall  = TextStyle(fontFamily = BrandFont, fontWeight = FontWeight.Normal,  fontSize = 36.sp, lineHeight = 44.sp),
    headlineLarge  = TextStyle(fontFamily = BrandFont, fontWeight = FontWeight.SemiBold, fontSize = 32.sp, lineHeight = 40.sp),
    headlineMedium = TextStyle(fontFamily = BrandFont, fontWeight = FontWeight.SemiBold, fontSize = 28.sp, lineHeight = 36.sp),
    headlineSmall  = TextStyle(fontFamily = BrandFont, fontWeight = FontWeight.SemiBold, fontSize = 24.sp, lineHeight = 32.sp),
    titleLarge  = TextStyle(fontFamily = BrandFont, fontWeight = FontWeight.Medium, fontSize = 22.sp, lineHeight = 28.sp),
    titleMedium = TextStyle(fontFamily = BrandFont, fontWeight = FontWeight.Medium, fontSize = 16.sp, lineHeight = 24.sp, letterSpacing = 0.15.sp),
    titleSmall  = TextStyle(fontFamily = BrandFont, fontWeight = FontWeight.Medium, fontSize = 14.sp, lineHeight = 20.sp, letterSpacing = 0.1.sp),
    bodyLarge  = TextStyle(fontFamily = BrandFont, fontWeight = FontWeight.Normal, fontSize = 16.sp, lineHeight = 24.sp, letterSpacing = 0.5.sp),
    bodyMedium = TextStyle(fontFamily = BrandFont, fontWeight = FontWeight.Normal, fontSize = 14.sp, lineHeight = 20.sp, letterSpacing = 0.25.sp),
    bodySmall  = TextStyle(fontFamily = BrandFont, fontWeight = FontWeight.Normal, fontSize = 12.sp, lineHeight = 16.sp, letterSpacing = 0.4.sp),
    labelLarge  = TextStyle(fontFamily = BrandFont, fontWeight = FontWeight.Medium, fontSize = 14.sp, lineHeight = 20.sp, letterSpacing = 0.1.sp),
    labelMedium = TextStyle(fontFamily = BrandFont, fontWeight = FontWeight.Medium, fontSize = 12.sp, lineHeight = 16.sp, letterSpacing = 0.5.sp),
    labelSmall  = TextStyle(fontFamily = BrandFont, fontWeight = FontWeight.Medium, fontSize = 11.sp, lineHeight = 16.sp, letterSpacing = 0.5.sp),
)

// ✅ Always use theme styles — never hardcode font size
Text("Screen title", style = MaterialTheme.typography.titleLarge)
Text("Body text", style = MaterialTheme.typography.bodyMedium)
Text("Button label", style = MaterialTheme.typography.labelLarge)

// ❌ Never hardcode
Text("Wrong", fontSize = 18.sp, fontWeight = FontWeight.Bold)

Shape system — M3 10-step scale + asymmetric shapes

// ui/theme/AppShapes.kt
val AppShapes = Shapes(
    extraSmall = RoundedCornerShape(4.dp),    // chips, small tags
    small      = RoundedCornerShape(8.dp),    // text fields, tooltips
    medium     = RoundedCornerShape(12.dp),   // cards, menus
    large      = RoundedCornerShape(16.dp),   // bottom sheets
    extraLarge = RoundedCornerShape(28.dp),   // nav drawer, large dialogs
)

// M3 Expressive asymmetric shapes — personality and directional emphasis
object AsymmetricShapes {
    val topRounded    = RoundedCornerShape(topStart = 28.dp, topEnd = 28.dp, bottomStart = 4.dp, bottomEnd = 4.dp)
    val bottomRounded = RoundedCornerShape(topStart = 4.dp, topEnd = 4.dp, bottomStart = 28.dp, bottomEnd = 28.dp)
    val startRounded  = RoundedCornerShape(topStart = 28.dp, bottomStart = 28.dp, topEnd = 4.dp, bottomEnd = 4.dp)
    val full          = RoundedCornerShape(50)  // pills, FABs, avatars
}

Component library — standard across every screen

// ✅ AppButton — 5 variants, consistent 48dp height, loading state
enum class AppButtonVariant { Filled, Tonal, Outlined, Ghost, Destructive }

@Composable
fun AppButton(
    text: String, onClick: () -> Unit,
    modifier: Modifier = Modifier,
    variant: AppButtonVariant = AppButtonVariant.Filled,
    leadingIcon: ImageVector? = null,
    isLoading: Boolean = false,
    enabled: Boolean = true,
) {
    val enabled2 = enabled && !isLoading
    val shape = MaterialTheme.shapes.small
    val content: @Composable RowScope.() -> Unit = {
        AnimatedContent(isLoading, label = "btnContent") { loading ->
            if (loading) CircularProgressIndicator(Modifier.size(20.dp), strokeWidth = 2.dp, color = LocalContentColor.current)
            else Row(verticalAlignment = Alignment.CenterVertically) {
                if (leadingIcon != null) { Icon(leadingIcon, null, Modifier.size(18.dp)); Spacer(Modifier.width(Spacing.xs)) }
                Text(text, style = MaterialTheme.typography.labelLarge)
            }
        }
    }
    val mod = modifier.height(48.dp)
    when (variant) {
        AppButtonVariant.Filled      -> Button(onClick, mod, enabled = enabled2, shape = shape, content = content)
        AppButtonVariant.Tonal       -> FilledTonalButton(onClick, mod, enabled = enabled2, shape = shape, content = content)
        AppButtonVariant.Outlined    -> OutlinedButton(onClick, mod, enabled = enabled2, shape = shape, content = content)
        AppButtonVariant.Ghost       -> TextButton(onClick, mod, enabled = enabled2, content = content)
        AppButtonVariant.Destructive -> Button(onClick, mod, enabled = enabled2, shape = shape,
            colors = ButtonDefaults.buttonColors(containerColor = MaterialTheme.colorScheme.errorContainer,
                contentColor = MaterialTheme.colorScheme.onErrorContainer), content = content)
    }
}

// ✅ AppCard — 3 variants
enum class CardVariant { Filled, Elevated, Outlined }

@Composable
fun AppCard(modifier: Modifier = Modifier, onClick: (() -> Unit)? = null, variant: CardVariant = CardVariant.Filled, content: @Composable ColumnScope.() -> Unit) {
    val inner: @Composable () -> Unit = { Column(Modifier.padding(Spacing.md), content = content) }
    val shape = MaterialTheme.shapes.medium
    if (onClick != null) when (variant) {
        CardVariant.Elevated -> ElevatedCard(onClick, modifier, shape = shape) { inner() }
        CardVariant.Outlined -> OutlinedCard(onClick, modifier, shape = shape) { inner() }
        else -> Card(onClick, modifier, shape = shape, elevation = CardDefaults.cardElevation(0.dp),
            colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceContainerHigh)) { inner() }
    } else Card(modifier = modifier, shape = shape, elevation = CardDefaults.cardElevation(0.dp),
        colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceContainerHigh)) { inner() }
}

// ✅ AppTextField — error state, support text, icons
@Composable
fun AppTextField(
    value: String, onValueChange: (String) -> Unit, label: String,
    modifier: Modifier = Modifier,
    supportingText: String? = null, isError: Boolean = false, errorText: String? = null,
    leadingIcon: ImageVector? = null, trailingIcon: (@Composable () -> Unit)? = null,
    keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
    singleLine: Boolean = true,
    visualTransformation: VisualTransformation = VisualTransformation.None,
) {
    OutlinedTextField(
        value = value, onValueChange = onValueChange, label = { Text(label) },
        isError = isError, singleLine = singleLine,
        visualTransformation = visualTransformation,
        leadingIcon = leadingIcon?.let { { Icon(it, null) } },
        trailingIcon = trailingIcon,
        supportingText = when {
            isError && errorText != null -> { { Text(errorText, color = MaterialTheme.colorScheme.error) } }
            supportingText != null -> { { Text(supportingText) } }
            else -> null
        },
        keyboardOptions = keyboardOptions,
        shape = MaterialTheme.shapes.small,
        modifier = modifier.fillMaxWidth()
    )
}

Motion tokens — physics-based, M3 Expressive

// ui/theme/tokens/MotionTokens.kt
object MotionTokens {
    // Spatial — elements that move or scale (use spring for naturalness)
    fun spatialEnter() = spring<Float>(dampingRatio = Spring.DampingRatioLowBouncy, stiffness = Spring.StiffnessMediumLow)
    fun spatialExit()  = tween<Float>(Duration.short4, easing = AppEasing.EmphasizedAccel)

    // Effects — color, opacity, elevation (use tween)
    fun effectsStandard(duration: Int = Duration.medium2) = tween<Float>(duration, easing = AppEasing.Standard)
    fun effectsDecel(duration: Int = Duration.medium4)    = tween<Float>(duration, easing = AppEasing.EmphasizedDecel)

    // Container — screen-level transitions
    fun containerEnter() = tween<IntOffset>(Duration.medium4, easing = AppEasing.EmphasizedDecel)
    fun containerExit()  = tween<IntOffset>(Duration.short4,  easing = AppEasing.EmphasizedAccel)
}

// ✅ Usage — always MotionTokens, never tween(300)
val alpha by animateFloatAsState(
    targetValue = if (isVisible) 1f else 0f,
    animationSpec = MotionTokens.effectsStandard(),
    label = "alpha"
)

Screen states — global, use on every screen

@Composable
fun AppLoadingScreen(modifier: Modifier = Modifier) =
    Box(modifier.fillMaxSize(), Alignment.Center) { CircularProgressIndicator() }

@Composable
fun AppEmptyScreen(title: String, body: String, modifier: Modifier = Modifier,
    illustration: (@Composable () -> Unit)? = null, action: Pair<String, () -> Unit>? = null) {
    Column(modifier.fillMaxSize().padding(Spacing.xl), Alignment.CenterHorizontally, Arrangement.Center) {
        illustration?.invoke()
        Spacer(Modifier.height(Spacing.lg))
        Text(title, style = MaterialTheme.typography.headlineSmall, textAlign = TextAlign.Center)
        Spacer(Modifier.height(Spacing.sm))
        Text(body, style = MaterialTheme.typography.bodyMedium, textAlign = TextAlign.Center,
            color = MaterialTheme.colorScheme.onSurfaceVariant)
        if (action != null) { Spacer(Modifier.height(Spacing.lg)); AppButton(action.first, action.second) }
    }
}

@Composable
fun AppErrorScreen(message: String, onRetry: (() -> Unit)? = null, modifier: Modifier = Modifier) {
    Column(modifier.fillMaxSize().padding(Spacing.xl), Alignment.CenterHorizontally, Arrangement.Center) {
        Icon(Icons.Rounded.ErrorOutline, null, Modifier.size(64.dp), tint = MaterialTheme.colorScheme.error)
        Spacer(Modifier.height(Spacing.md))
        Text("Something went wrong", style = MaterialTheme.typography.titleLarge)
        Spacer(Modifier.height(Spacing.sm))
        Text(message, style = MaterialTheme.typography.bodyMedium, textAlign = TextAlign.Center,
            color = MaterialTheme.colorScheme.onSurfaceVariant)
        if (onRetry != null) { Spacer(Modifier.height(Spacing.lg)); AppButton("Try again", onRetry, variant = AppButtonVariant.Tonal) }
    }
}

Common Mistakes

❌ Spacing not on 4dp grid — padding(13.dp) use Spacing.sm or Spacing.md ❌ fontSize = 20.sp hardcoded — MaterialTheme.typography.titleLargeColor(0xFF333333) hardcoded — MaterialTheme.colorScheme.onSurfacecornerRadius = 12.dp inline — MaterialTheme.shapes.mediumtween(300) hardcoded — MotionTokens.effectsStandard() ❌ Different button heights per screen — always 48.dp ❌ No dark mode testing — check every component with darkTheme = true ❌ Dynamic color disabled — enable for Android 12+, fallback palette for older ❌ Color.White in dark mode — MaterialTheme.colorScheme.surfaceCard(elevation = 4.dp) — use tonal containers, not shadows: surfaceContainerHigh

Capabilities

skillsource-piyushverma0skill-design-systemtopic-agent-skillstopic-ai-agenttopic-androidtopic-antigravitytopic-claude-codetopic-codextopic-cursortopic-gemini-clitopic-hilttopic-jetpack-composetopic-kotlintopic-material3

Install

Installnpx skills add piyushverma0/android-agent-skills
Transportskills-sh
Protocolskill

Quality

0.45/ 1.00

deterministic score 0.45 from registry signals: · indexed on github topic:agent-skills · 8 github stars · SKILL.md body (18,024 chars)

Provenance

Indexed fromgithub
Enriched2026-05-18 19:09:09Z · deterministic:skill-github:v1 · v1
First seen2026-05-18
Last seen2026-05-18

Agent access