{"id":"136f1eb3-55a1-49a3-b9fa-e56d169e9d76","shortId":"6Fs8k2","kind":"skill","title":"compose-animation","tagline":"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.","description":"# Compose Animation — M3 Expressive Motion System\r\n\r\nM3 Expressive (2025) replaced fixed-duration easing with physics-based springs.\r\nThese rules cover the complete animation toolkit — from micro-interactions to screen transitions.\r\n\r\n## The M3 Expressive motion philosophy\r\n\r\n```kotlin\r\n// M3 Expressive motion tokens — import from design-system skill's DesignTokens.kt\r\n\r\n// Physics-based springs for SPATIAL motion (position, size, scale)\r\n// → Never use tween() for elements that move — spring feels natural\r\nval spatialEnter = spring<Float>(\r\n    dampingRatio = Spring.DampingRatioLowBouncy,   // slight bounce\r\n    stiffness    = Spring.StiffnessMediumLow        // smooth, not jerky\r\n)\r\n\r\n// Tween with M3 easing for EFFECTS (opacity, color, blur)\r\n// → Effects have no mass — tween with easing curve is correct\r\nval effectsIn  = tween<Float>(Duration.medium2, easing = AppEasing.EmphasizedDecel)\r\nval effectsOut = tween<Float>(Duration.short4,  easing = AppEasing.EmphasizedAccel)\r\n\r\n// Rule: if it moves → spring. If it fades/colors → tween with M3 easing.\r\n```\r\n\r\n## Rule 1: AnimatedVisibility — M3 Expressive enter/exit\r\n\r\n```kotlin\r\n// ✅ Standard show/hide with M3 Expressive physics\r\nAnimatedVisibility(\r\n    visible = isVisible,\r\n    enter = slideInVertically(\r\n        initialOffsetY = { -it / 4 },\r\n        animationSpec  = spring(Spring.DampingRatioLowBouncy, Spring.StiffnessMediumLow)\r\n    ) + fadeIn(tween(Duration.medium2, easing = AppEasing.EmphasizedDecel)),\r\n    exit = slideOutVertically(\r\n        targetOffsetY = { -it / 4 },\r\n        animationSpec = tween(Duration.short4, easing = AppEasing.EmphasizedAccel)\r\n    ) + fadeOut(tween(Duration.short4))\r\n) { Content() }\r\n\r\n// ✅ Common patterns\r\n// Slide from bottom (FAB, snackbar, floating panels)\r\nval enterFromBottom = slideInVertically(\r\n    initialOffsetY = { it },\r\n    animationSpec = spring(Spring.DampingRatioMediumBouncy, Spring.StiffnessMedium)\r\n) + fadeIn(tween(Duration.medium2))\r\nval exitToBottom = slideOutVertically(\r\n    targetOffsetY = { it },\r\n    animationSpec = tween(Duration.short4, easing = AppEasing.EmphasizedAccel)\r\n) + fadeOut(tween(Duration.short4))\r\n\r\n// Scale pop (context menus, badges, chips)\r\nval popIn  = scaleIn(initialScale = 0.7f,\r\n    animationSpec = spring(Spring.DampingRatioLowBouncy, Spring.StiffnessHigh)\r\n) + fadeIn(tween(Duration.short4))\r\nval popOut = scaleOut(targetScale = 0.7f,\r\n    animationSpec = tween(Duration.short3, easing = AppEasing.EmphasizedAccel)\r\n) + fadeOut(tween(Duration.short3))\r\n\r\n// Expand/collapse (accordion, show more)\r\nval expandDown = expandVertically(\r\n    expandFrom    = Alignment.Top,\r\n    animationSpec = spring(Spring.DampingRatioNoBouncy, Spring.StiffnessMediumLow)\r\n) + fadeIn(tween(Duration.medium1))\r\nval collapseUp = shrinkVertically(\r\n    shrinkTowards = Alignment.Top,\r\n    animationSpec = tween(Duration.short4, easing = AppEasing.EmphasizedAccel)\r\n) + fadeOut(tween(Duration.short4))\r\n```\r\n\r\n## Rule 2: AnimatedContent — state transitions with correct content key\r\n\r\n```kotlin\r\n// ✅ Animate entire UI state transitions\r\nAnimatedContent(\r\n    targetState = uiState,\r\n    contentKey  = { it::class },    // key by STATE TYPE, not value — prevents wrong composable reuse\r\n    transitionSpec = {\r\n        (slideInVertically(\r\n            initialOffsetY = { it / 4 },\r\n            animationSpec  = spring(Spring.DampingRatioLowBouncy, Spring.StiffnessMediumLow)\r\n        ) + fadeIn(tween(Duration.medium2, easing = AppEasing.EmphasizedDecel)))\r\n            .togetherWith(\r\n                slideOutVertically(\r\n                    targetOffsetY = { -it / 4 },\r\n                    animationSpec = tween(Duration.short4, easing = AppEasing.EmphasizedAccel)\r\n                ) + fadeOut(tween(Duration.short4))\r\n            )\r\n    },\r\n    label = \"uiStateTransition\"\r\n) { state ->\r\n    when (state) {\r\n        is Loading -> AppLoadingScreen()\r\n        is Success -> SuccessContent(state.data)\r\n        is Error   -> AppErrorScreen(state.message)\r\n        is Empty   -> AppEmptyScreen(\"No items\", \"Add your first item\")\r\n    }\r\n}\r\n\r\n// ✅ Counter animation (number changes)\r\nAnimatedContent(\r\n    targetState = count,\r\n    transitionSpec = {\r\n        val dir = if (targetState > initialState) 1 else -1\r\n        (slideInVertically { it * dir } + fadeIn()).togetherWith(\r\n            slideOutVertically { -it * dir } + fadeOut()\r\n        ).using(SizeTransform(clip = false))\r\n    },\r\n    label = \"counter\"\r\n) { n -> Text(\"$n\", style = MaterialTheme.typography.displayMedium) }\r\n```\r\n\r\n## Rule 3: animate*AsState — smooth value transitions\r\n\r\n```kotlin\r\n// ✅ Spatial values → spring\r\nval elevation by animateDpAsState(\r\n    targetValue = if (isDragging) 8.dp else 0.dp,\r\n    animationSpec = spring(Spring.DampingRatioMediumBouncy, Spring.StiffnessMedium),\r\n    label = \"cardElevation\"\r\n)\r\nval offsetX by animateDpAsState(\r\n    targetValue = if (isSwipedRight) 300.dp else 0.dp,\r\n    animationSpec = spring(Spring.DampingRatioLowBouncy, Spring.StiffnessMediumLow),\r\n    label = \"swipeOffset\"\r\n)\r\n\r\n// ✅ Effects → tween with M3 easing\r\nval alpha by animateFloatAsState(\r\n    targetValue   = if (isEnabled) 1f else 0.38f,\r\n    animationSpec = tween(Duration.short4, easing = AppEasing.Standard),\r\n    label = \"alpha\"\r\n)\r\nval backgroundColor by animateColorAsState(\r\n    targetValue   = if (isSelected) MaterialTheme.colorScheme.primaryContainer\r\n                    else MaterialTheme.colorScheme.surface,\r\n    animationSpec = tween(Duration.medium1, easing = AppEasing.Standard),\r\n    label = \"bgColor\"\r\n)\r\n\r\n// ✅ Apply in Modifier\r\nCard(\r\n    modifier = Modifier\r\n        .graphicsLayer { this.alpha = alpha }\r\n        .offset(x = offsetX),\r\n    colors = CardDefaults.cardColors(containerColor = backgroundColor),\r\n    elevation = CardDefaults.cardElevation(defaultElevation = elevation)\r\n) { /* ... */ }\r\n```\r\n\r\n## Rule 4: updateTransition — synchronized multi-value animation\r\n\r\n```kotlin\r\n// ✅ Multiple values in sync — all animate together on state change\r\nenum class ButtonState { Idle, Loading, Success, Error }\r\n\r\n@Composable\r\nfun StatefulButton(state: ButtonState, onClick: () -> Unit) {\r\n    val transition = updateTransition(targetState = state, label = \"buttonState\")\r\n\r\n    val containerColor by transition.animateColor(\r\n        transitionSpec = { tween(Duration.medium2, easing = AppEasing.Standard) },\r\n        label = \"containerColor\"\r\n    ) { s -> when (s) {\r\n        ButtonState.Idle    -> MaterialTheme.colorScheme.primary\r\n        ButtonState.Loading -> MaterialTheme.colorScheme.primaryContainer\r\n        ButtonState.Success -> MaterialTheme.colorScheme.tertiaryContainer\r\n        ButtonState.Error   -> MaterialTheme.colorScheme.errorContainer\r\n    } }\r\n\r\n    val scale by transition.animateFloat(\r\n        transitionSpec = { spring(Spring.DampingRatioMediumBouncy, Spring.StiffnessHigh) },\r\n        label = \"scale\"\r\n    ) { s -> if (s == ButtonState.Success) 1.06f else 1f }\r\n\r\n    val contentAlpha by transition.animateFloat(\r\n        transitionSpec = { tween(Duration.short4) },\r\n        label = \"contentAlpha\"\r\n    ) { s -> if (s == ButtonState.Loading) 0f else 1f }\r\n\r\n    Button(\r\n        onClick = onClick,\r\n        colors = ButtonDefaults.buttonColors(containerColor = containerColor),\r\n        modifier = Modifier.graphicsLayer { scaleX = scale; scaleY = scale }\r\n    ) {\r\n        Box(contentAlignment = Alignment.Center) {\r\n            CircularProgressIndicator(\r\n                Modifier.size(20.dp).alpha(1f - contentAlpha),\r\n                strokeWidth = 2.dp, color = LocalContentColor.current\r\n            )\r\n            Text(\r\n                text = when (state) {\r\n                    ButtonState.Idle    -> \"Submit\"\r\n                    ButtonState.Loading -> \"Loading\"\r\n                    ButtonState.Success -> \"Done!\"\r\n                    ButtonState.Error   -> \"Retry\"\r\n                },\r\n                modifier = Modifier.alpha(contentAlpha)\r\n            )\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n## Rule 5: InfiniteTransition — shimmer and pulse\r\n\r\n```kotlin\r\n// ✅ Shimmer skeleton — matches real content shape\r\n@Composable\r\nfun ShimmerEffect(modifier: Modifier = Modifier) {\r\n    val infiniteTransition = rememberInfiniteTransition(label = \"shimmer\")\r\n    val alpha by infiniteTransition.animateFloat(\r\n        initialValue = 0.25f,\r\n        targetValue  = 0.55f,\r\n        animationSpec = infiniteRepeatable(\r\n            animation  = tween(800, easing = FastOutSlowInEasing),\r\n            repeatMode = RepeatMode.Reverse\r\n        ),\r\n        label = \"shimmerAlpha\"\r\n    )\r\n    Box(modifier.clip(MaterialTheme.shapes.small)\r\n        .background(MaterialTheme.colorScheme.onSurface.copy(alpha = alpha)))\r\n}\r\n\r\n// ✅ Skeleton that mirrors real card layout\r\n@Composable\r\nfun ItemCardSkeleton() {\r\n    AppCard {\r\n        Row(verticalAlignment = Alignment.CenterVertically) {\r\n            ShimmerEffect(Modifier.size(56.dp).clip(MaterialTheme.shapes.small))\r\n            Spacer(Modifier.width(Spacing.md))\r\n            Column(Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(Spacing.xs)) {\r\n                ShimmerEffect(Modifier.fillMaxWidth(0.75f).height(16.dp))\r\n                ShimmerEffect(Modifier.fillMaxWidth(0.5f).height(12.dp))\r\n            }\r\n        }\r\n    }\r\n}\r\n\r\n// ✅ Show skeleton grid during loading\r\nwhen (uiState) {\r\n    is Loading -> LazyVerticalGrid(columns = GridCells.Adaptive(180.dp)) {\r\n        items(6) { ItemCardSkeleton() }   // 6 skeleton placeholders\r\n    }\r\n    is Success -> ItemGrid(uiState.items)\r\n    else -> { /* ... */ }\r\n}\r\n\r\n// ✅ Pulsing online indicator\r\n@Composable\r\nfun OnlineDot(color: Color = MaterialTheme.colorScheme.primary) {\r\n    val inf = rememberInfiniteTransition(label = \"pulse\")\r\n    val scale by inf.animateFloat(\r\n        1f, 1.4f, infiniteRepeatable(tween(700, easing = FastOutSlowInEasing), RepeatMode.Reverse),\r\n        label = \"pulseScale\"\r\n    )\r\n    Box(Modifier.size(10.dp).scale(scale).clip(CircleShape).background(color))\r\n}\r\n```\r\n\r\n## Rule 6: LazyList item animations — animateItem\r\n\r\n```kotlin\r\n// ✅ Automatic add/remove/reorder animations in LazyColumn\r\nLazyColumn {\r\n    items(items, key = { it.id }) { item ->\r\n        SwipeToDeleteCard(\r\n            item = item,\r\n            modifier = Modifier.animateItem(\r\n                fadeInSpec   = tween(Duration.medium2, easing = AppEasing.EmphasizedDecel),\r\n                fadeOutSpec  = tween(Duration.short4,  easing = AppEasing.EmphasizedAccel),\r\n                placementSpec = spring(Spring.DampingRatioMediumBouncy, Spring.StiffnessMediumLow)\r\n            )\r\n        )\r\n    }\r\n}\r\n```\r\n\r\n## Rule 7: Gesture-driven animation — swipe interactions\r\n\r\n```kotlin\r\n// ✅ Swipe to delete with spring snap-back\r\n@Composable\r\nfun SwipeToDeleteCard(item: Item, onDelete: (String) -> Unit) {\r\n    var offsetX by remember { mutableStateOf(0f) }\r\n    val animatedOffset by animateFloatAsState(\r\n        targetValue   = offsetX,\r\n        animationSpec = spring(Spring.DampingRatioMediumBouncy, Spring.StiffnessMedium),\r\n        label = \"swipeOffset\"\r\n    )\r\n    val deleteThreshold = -300f\r\n\r\n    Box(\r\n        Modifier.pointerInput(item.id) {\r\n            detectHorizontalDragGestures(\r\n                onDragEnd = {\r\n                    if (offsetX < deleteThreshold) onDelete(item.id)\r\n                    else offsetX = 0f   // spring back\r\n                },\r\n                onHorizontalDrag = { _, dragAmount ->\r\n                    offsetX = (offsetX + dragAmount).coerceIn(deleteThreshold * 1.2f, 0f)\r\n                }\r\n            )\r\n        }\r\n    ) {\r\n        // Delete background\r\n        Box(Modifier.fillMaxSize()\r\n            .alpha((-animatedOffset / (-deleteThreshold)).coerceIn(0f, 1f))\r\n            .background(MaterialTheme.colorScheme.errorContainer),\r\n            Alignment.CenterEnd) {\r\n            Icon(Icons.Default.Delete, \"Delete\",\r\n                tint = MaterialTheme.colorScheme.onErrorContainer,\r\n                modifier = Modifier.padding(end = Spacing.lg))\r\n        }\r\n        // Card content\r\n        AppCard(modifier = Modifier.offset { IntOffset(animatedOffset.roundToInt(), 0) }) {\r\n            Text(item.title)\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n## Rule 8: Animation specs — choosing the right one\r\n\r\n```kotlin\r\n// SPRING — for spatial motion (position, scale, rotation)\r\n// Natural, physics feel. No fixed duration — ends when velocity reaches zero.\r\nspring(\r\n    dampingRatio = Spring.DampingRatioLowBouncy,   // bouncy — for delightful interactions\r\n    // Spring.DampingRatioMediumBouncy               // subtle bounce — standard\r\n    // Spring.DampingRatioNoBouncy                   // no bounce — for content transitions\r\n    stiffness = Spring.StiffnessMediumLow            // slow and smooth\r\n    // Spring.StiffnessMedium                         // standard\r\n    // Spring.StiffnessHigh                           // fast (icon changes, quick snaps)\r\n)\r\n\r\n// TWEEN — for effects (opacity, color, blur)\r\n// Fixed duration. Use M3 easing curves.\r\ntween(\r\n    durationMillis = Duration.medium2,         // from DesignTokens\r\n    easing = AppEasing.EmphasizedDecel         // entering (from M3 Expressive spec)\r\n    // AppEasing.EmphasizedAccel               // exiting\r\n    // AppEasing.Standard                      // color, opacity changes\r\n)\r\n\r\n// KEYFRAMES — branded animations with precise control\r\nkeyframes {\r\n    durationMillis = Duration.medium3\r\n    0f   at 0                    with FastOutLinearInEasing\r\n    1.15f at Duration.medium2    // overshoot\r\n    1f   at Duration.medium3     with LinearOutSlowInEasing\r\n}\r\n\r\n// SNAP — instant, no animation (low-power mode, reduce motion)\r\nsnap()\r\n```\r\n\r\n## Rule 9: Respect reduced motion\r\n\r\n```kotlin\r\n// ✅ Always check system reduce motion setting\r\n@Composable\r\nfun MotionAwareAnimation(\r\n    visible: Boolean,\r\n    content: @Composable () -> Unit\r\n) {\r\n    // Check system accessibility setting\r\n    val reducedMotion = LocalContext.current.getSystemService<AccessibilityManager>()\r\n        ?.isEnabled == true\r\n\r\n    if (reducedMotion) {\r\n        // Instant transition — no motion\r\n        if (visible) content()\r\n    } else {\r\n        AnimatedVisibility(visible, enter = expandVertically() + fadeIn(), exit = shrinkVertically() + fadeOut()) {\r\n            content()\r\n        }\r\n    }\r\n}\r\n\r\n// ✅ Or via WindowManager accessibility\r\n@Composable\r\nfun rememberReducedMotion(): Boolean {\r\n    val context = LocalContext.current\r\n    return remember {\r\n        val am = context.getSystemService<AccessibilityManager>()\r\n        am?.isEnabled == true && am.isTouchExplorationEnabled\r\n    }\r\n}\r\n```\r\n\r\n## Common Mistakes\r\n\r\n❌ `tween(300)` for spatial motion — use `spring()` for anything that moves\r\n❌ No `label` parameter on animate* — hard to debug in profiler\r\n❌ `AnimatedContent` without `contentKey` — wrong composable reused on state change\r\n❌ Stacking animations without `SizeTransform` on count changes — layout jumps\r\n❌ No reduce motion check — bad experience for accessibility users\r\n❌ Hardcoded `300` ms — always use `Duration.*` tokens\r\n❌ `FastOutSlowInEasing` everywhere — use M3 easing: `AppEasing.EmphasizedDecel` for enter, `AppEasing.EmphasizedAccel` for exit\r\n❌ InfiniteTransition without performance check — pauses when app is backgrounded automatically, but don't add them to every screen","tags":["compose","animation","android","agent","skills","piyushverma0","agent-skills","ai-agent","antigravity","claude-code","codex","cursor"],"capabilities":["skill","source-piyushverma0","skill-compose-animation","topic-agent-skills","topic-ai-agent","topic-android","topic-antigravity","topic-claude-code","topic-codex","topic-cursor","topic-gemini-cli","topic-hilt","topic-jetpack-compose","topic-kotlin","topic-material3"],"categories":["android-agent-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/piyushverma0/android-agent-skills/compose-animation","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add piyushverma0/android-agent-skills","source_repo":"https://github.com/piyushverma0/android-agent-skills","install_from":"skills.sh"}},"qualityScore":"0.454","qualityRationale":"deterministic score 0.45 from registry signals: · indexed on github topic:agent-skills · 8 github stars · SKILL.md body (15,306 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T19:09:09.144Z","embedding":null,"createdAt":"2026-05-18T13:14:48.639Z","updatedAt":"2026-05-18T19:09:09.144Z","lastSeenAt":"2026-05-18T19:09:09.144Z","tsv":"'-1':401 '-300':897 '0':953,1054 '0.25':691 '0.38':479 '0.5':749 '0.55':694 '0.7':251,264 '0.75':743 '0.dp':442,458 '0f':618,882,911,923,932,1052 '1':164,399 '1.06':601 '1.15':1057 '1.2':921 '1.4':796 '10.dp':808 '12.dp':752 '16.dp':746 '18':35 '180.dp':765 '1f':477,604,620,641,737,795,933,1062 '2':304 '2.dp':644 '20.dp':639 '2025':45 '27':4 '3':423 '300':1149,1197 '300.dp':456 '4':183,197,338,352,526 '5':30,663 '56.dp':729 '6':767,769,816 '7':853 '700':800 '8':957 '8.dp':440 '800':700 '9':1079 'access':1100,1129,1194 'accordion':275 'add':382,1227 'add/remove/reorder':823 'agent':9 'ai':8,32 'alignment.center':636 'alignment.centerend':936 'alignment.centervertically':726 'alignment.top':282,294 'alpha':471,487,513,640,687,712,713,928 'alway':1084,1199 'am.istouchexplorationenabled':1145 'android':5 'anim':3,38,61,313,387,424,532,539,698,819,824,857,958,1045,1070,1163,1179 'animatecolorasst':491 'animatedcont':305,318,390,1169 'animatedoffset':884,929 'animatedoffset.roundtoint':952 'animatedpasst':436,452 'animatedvis':165,176,1117 'animatefloatasst':473,886 'animateitem':820 'animationspec':184,198,221,233,253,266,283,295,339,353,443,459,481,498,696,889 'anyth':1156 'app':1220 'appcard':723,948 'appeasing.emphasizedaccel':150,202,237,270,299,357,847,1037,1211 'appeasing.emphasizeddecel':144,192,347,842,1031,1208 'appeasing.standard':485,502,573,1039 'appemptyscreen':379 'apperrorscreen':375 'appli':505 'apploadingscreen':368 'arrangement.spacedby':739 'asstat':425 'auth':16 'automat':822,1223 'back':868,913 'background':710,813,925,934,1222 'backgroundcolor':489,520 'bad':1191 'badg':245 'base':54,90 'bgcolor':504 'bill':29 'blur':128,1018 'boolean':1094,1133 'bottom':211 'bounc':114,992,996 'bounci':986 'box':634,707,806,899,926 'brand':1044 'button':621 'buttondefaults.buttoncolors':625 'buttonst':546,555,564 'buttonstate.error':585,657 'buttonstate.idle':579,651 'buttonstate.loading':581,617,653 'buttonstate.success':583,600,655 'card':508,718,946 'carddefaults.cardcolors':518 'carddefaults.cardelevation':522 'cardelev':448 'chang':389,543,1010,1042,1177,1184 'check':1085,1098,1190,1217 'chip':246 'choos':960 'circleshap':812 'circularprogressind':637 'class':323,545 'claud':10 'clip':413,730,811 'code':11 'codex':12 'coercein':919,931 'collapseup':291 'color':127,517,624,645,783,784,814,1017,1040 'column':735,763 'common':207,1146 'complet':60 'compos':2,37,332,551,675,720,780,869,1090,1096,1130,1173 'compose-anim':1 'containercolor':519,566,575,626,627 'content':206,310,673,947,998,1095,1115,1125 'contentalign':635 'contentalpha':606,613,642,661 'contentkey':321,1171 'context':243,1135 'context.getsystemservice':1141 'control':1048 'correct':138,309 'count':392,1183 'counter':386,416 'cover':58 'cursor':13 'curv':136,1024 'dampingratio':111,984 'day':36 'debug':1166 'defaultelev':523 'delet':863,924,939 'deletethreshold':896,906,920,930 'delight':988 'design':19,83 'design-system':82 'designtoken':1029 'designtokens.kt':87 'detecthorizontaldraggestur':902 'dir':395,404,409 'done':656 'dragamount':915,918 'driven':856 'durat':49,977,1020,1201 'duration.medium1':289,500 'duration.medium2':142,190,227,345,571,840,1027,1060 'duration.medium3':1051,1064 'duration.short3':268,273 'duration.short4':148,200,205,235,240,259,297,302,355,360,483,611,845 'durationmilli':1026,1050 'eas':50,123,135,143,149,162,191,201,236,269,298,346,356,469,484,501,572,701,801,841,846,1023,1030,1207 'effect':125,129,465,1015 'effectsin':140 'effectsout':146 'element':102 'elev':434,521,524 'els':400,441,457,478,496,603,619,776,909,1116 'empti':378 'end':944,978 'enter':179,1032,1119,1210 'enter/exit':168 'enterfrombottom':217 'entir':314 'enum':544 'error':18,374,550 'everi':1230 'everywher':1204 'exit':193,1038,1122,1213 'exittobottom':229 'expand/collapse':274 'expanddown':279 'expandfrom':281 'expandvert':280,1120 'experi':1192 'express':40,44,72,77,167,174,1035 'f':252,265,480,602,692,695,744,750,797,898,922,1058 'fab':212 'fadein':188,225,257,287,343,405,1121 'fadeinspec':838 'fadeout':203,238,271,300,358,410,1124 'fadeoutspec':843 'fades/colors':158 'fals':414 'fast':1008 'fastoutlinearineas':1056 'fastoutslowineas':702,802,1203 'feel':106,974 'first':384 'fitgenz':31 'fix':14,48,976,1019 'fixed-dur':47 'float':214 'fun':552,676,721,781,870,1091,1131 'gestur':855 'gesture-driven':854 'graphicslay':511 'grid':755 'gridcells.adaptive':764 'hard':1164 'hardcod':1196 'height':745,751 'hilt':17 'icon':937,1009 'icons.default.delete':938 'idl':547 'import':80 'inconsist':20 'indic':779 'inf':787 'inf.animatefloat':794 'infiniterepeat':697,798 'infinitetransit':664,682,1214 'infinitetransition.animatefloat':689 'initialoffseti':181,219,336 'initialscal':250 'initialst':398 'initialvalu':690 'instant':1068,1109 'interact':66,859,989 'intoffset':951 'isdrag':439 'isen':476,1105,1143 'isselect':494 'isswipedright':455 'isvis':178 'it.id':831 'item':381,385,766,818,828,829,832,834,835,872,873 'item.id':901,908 'item.title':955 'itemcardskeleton':722,768 'itemgrid':774 'jerki':119 'jump':1186 'kapt':21 'key':311,324,830 'keyfram':1043,1049 'kotlin':75,169,312,429,533,668,821,860,964,1083 'ksp':22 'label':361,415,447,463,486,503,563,574,595,612,684,705,789,804,893,1160 'layout':719,1185 'lazycolumn':826,827 'lazylist':817 'lazyverticalgrid':762 'linearoutslowineas':1066 'load':367,548,654,757,761 'localcontentcolor.current':646 'localcontext.current':1136 'localcontext.current.getsystemservice':1104 'low':1072 'low-pow':1071 'm3':39,43,71,76,122,161,166,173,468,1022,1034,1206 'mass':132 'match':671 'materialtheme.colorscheme.errorcontainer':586,935 'materialtheme.colorscheme.onerrorcontainer':941 'materialtheme.colorscheme.onsurface.copy':711 'materialtheme.colorscheme.primary':580,785 'materialtheme.colorscheme.primarycontainer':495,582 'materialtheme.colorscheme.surface':497 'materialtheme.colorscheme.tertiarycontainer':584 'materialtheme.shapes.small':709,731 'materialtheme.typography.displaymedium':421 'menus':244 'micro':65 'micro-interact':64 'mirror':716 'miss':23 'mistak':1147 'mode':1074 'modifi':507,509,510,628,659,678,679,680,836,942,949 'modifier.alpha':660 'modifier.animateitem':837 'modifier.clip':708 'modifier.fillmaxsize':927 'modifier.fillmaxwidth':742,748 'modifier.graphicslayer':629 'modifier.offset':950 'modifier.padding':943 'modifier.pointerinput':900 'modifier.size':638,728,807 'modifier.weight':736 'modifier.width':733 'motion':41,73,78,94,968,1076,1082,1088,1112,1152,1189 'motionawareanim':1092 'move':104,154,1158 'ms':1198 'multi':530 'multi-valu':529 'multipl':534 'mutablestateof':881 'n':417,419 'natur':107,972 'never':98 'number':388 'offset':514 'offsetx':450,516,878,888,905,910,916,917 'onclick':556,622,623 'ondelet':874,907 'ondragend':903 'one':963 'onhorizontaldrag':914 'onlin':778 'onlinedot':782 'opac':126,1016,1041 'overshoot':1061 'panel':215 'paramet':1161 'pattern':208 'paus':1218 'perform':1216 'philosophi':74 'physic':53,89,175,973 'physics-bas':52,88 'placehold':771 'placementspec':848 'pop':242 'popin':248 'popout':261 'posit':95,969 'power':1073 'precis':1047 'prevent':330 'profil':1168 'puls':667,777,790 'pulsescal':805 'quick':1011 'reach':981 'real':672,717 'reduc':26,1075,1081,1087,1188 'reducedmot':1103,1108 'rememb':880,1138 'rememberinfinitetransit':683,788 'rememberreducedmot':1132 'repeatmod':703 'repeatmode.reverse':704,803 'replac':46 'respect':1080 'retri':658 'return':1137 'reus':333,1174 'right':962 'rotat':971 'row':724 'rule':57,151,163,303,422,525,662,815,852,956,1078 'scale':97,241,588,596,631,633,792,809,810,970 'scalein':249 'scaleout':262 'scalex':630 'scaley':632 'screen':68,1231 'set':1089,1101 'shape':674 'shimmer':665,669,685 'shimmeralpha':706 'shimmereffect':677,727,741,747 'ship':33 'show':276,753 'show/hide':171 'shrinktoward':293 'shrinkvert':292,1123 'size':96 'sizetransform':412,1181 'skeleton':670,714,754,770 'skill':6,85 'skill-compose-animation' 'slide':209 'slideinvert':180,218,335,402 'slideoutvert':194,230,349,407 'slight':113 'slow':1002 'smooth':117,426,1004 'snackbar':213 'snap':867,1012,1067,1077 'snap-back':866 'source-piyushverma0' 'spacer':732 'spacing.lg':945 'spacing.md':734 'spacing.xs':740 'spatial':93,430,967,1151 'spatialent':109 'spec':959,1036 'spring':55,91,105,110,155,185,222,254,284,340,432,444,460,592,849,865,890,912,965,983,1154 'spring.dampingratiolowbouncy':112,186,255,341,461,985 'spring.dampingratiomediumbouncy':223,445,593,850,891,990 'spring.dampingrationobouncy':285,994 'spring.stiffnesshigh':256,594,1007 'spring.stiffnessmedium':224,446,892,1005 'spring.stiffnessmediumlow':116,187,286,342,462,851,1001 'stack':1178 'standard':170,993,1006 'state':25,306,316,326,363,365,542,554,562,650,1176 'state.data':372 'state.message':376 'statefulbutton':553 'stiff':115,1000 'string':875 'strokewidth':643 'style':420 'submit':652 'subtl':991 'success':370,549,773 'successcont':371 'supabas':15 'swipe':858,861 'swipeoffset':464,894 'swipetodeletecard':833,871 'sync':537 'synchron':528 'system':42,84,1086,1099 'targetoffseti':195,231,350 'targetscal':263 'targetst':319,391,397,561 'targetvalu':437,453,474,492,693,887 'text':418,647,648,954 'this.alpha':512 'tint':940 'togeth':540 'togetherwith':348,406 'token':28,79,1202 'toolkit':62 'topic-agent-skills' 'topic-ai-agent' 'topic-android' 'topic-antigravity' 'topic-claude-code' 'topic-codex' 'topic-cursor' 'topic-gemini-cli' 'topic-hilt' 'topic-jetpack-compose' 'topic-kotlin' 'topic-material3' 'transit':69,307,317,428,559,999,1110 'transition.animatecolor':568 'transition.animatefloat':590,608 'transitionspec':334,393,569,591,609 'true':1106,1144 'tween':100,120,133,141,147,159,189,199,204,226,234,239,258,267,272,288,296,301,344,354,359,466,482,499,570,610,699,799,839,844,1013,1025,1148 'type':327 'ui':315 'uistat':24,320,759 'uistate.items':775 'uistatetransit':362 'unit':557,876,1097 'updatetransit':527,560 'use':99,411,1021,1153,1200,1205 'user':1195 'val':108,139,145,216,228,247,260,278,290,394,433,449,470,488,558,565,587,605,681,686,786,791,883,895,1102,1134,1139 'valu':329,427,431,531,535 'var':877 'veloc':980 'verticalalign':725 'verticalarrang':738 'via':1127 'visibl':177,1093,1114,1118 'windowmanag':1128 'without':1170,1180,1215 'wrong':331,1172 'x':515 'zero':982","prices":[{"id":"b439e0de-4335-40ff-9c5d-acbb45b93e74","listingId":"136f1eb3-55a1-49a3-b9fa-e56d169e9d76","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"piyushverma0","category":"android-agent-skills","install_from":"skills.sh"},"createdAt":"2026-05-18T13:14:48.639Z"}],"sources":[{"listingId":"136f1eb3-55a1-49a3-b9fa-e56d169e9d76","source":"github","sourceId":"piyushverma0/android-agent-skills/compose-animation","sourceUrl":"https://github.com/piyushverma0/android-agent-skills/tree/main/skills/compose-animation","isPrimary":false,"firstSeenAt":"2026-05-18T13:14:48.639Z","lastSeenAt":"2026-05-18T19:09:09.144Z"}],"details":{"listingId":"136f1eb3-55a1-49a3-b9fa-e56d169e9d76","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"piyushverma0","slug":"compose-animation","github":{"repo":"piyushverma0/android-agent-skills","stars":8,"topics":["agent-skills","ai-agent","android","antigravity","claude-code","codex","cursor","gemini-cli","hilt","jetpack-compose","kotlin","material3","open-source","skills","supabase"],"license":"mit","html_url":"https://github.com/piyushverma0/android-agent-skills","pushed_at":"2026-04-27T09:15:31Z","description":"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.","skill_md_sha":"d89df3807cb7e1379228c96c889d3e62166b6e4f","skill_md_path":"skills/compose-animation/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/piyushverma0/android-agent-skills/tree/main/skills/compose-animation"},"layout":"multi","source":"github","category":"android-agent-skills","frontmatter":{},"skills_sh_url":"https://skills.sh/piyushverma0/android-agent-skills/compose-animation"},"updatedAt":"2026-05-18T19:09:09.144Z"}}