Skip to content
Development
Skill

/compose-animations

Use when writing or reviewing Jetpack Compose motion: visibility enter/exit, animating one property toward a target, color or size transitions, multiple properties from one state, switching composable content, or choosing between AnimatedVisibility, animate*AsState,

From plugin
chrisbanes-skills
90813 skills
Install
$ npx -y skills add chrisbanes/skills --skill compose-animations --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/compose-animations

Context preview

The summary Claude sees to decide when to auto-load this skill.

Use when writing or reviewing Jetpack Compose motion: visibility enter/exit, animating one property toward a target, color or size transitions, multiple properties from one state, switching composable content, or choosing between AnimatedVisibility, animate*AsState,

SKILL.md

compose-animations.SKILL.md
name: compose-animations
description: "Use when writing or reviewing Jetpack Compose motion: visibility enter/exit, animating one property toward a target, color or size transitions, multiple properties from one state, switching composable content, or choosing between AnimatedVisibility, animate*AsState, rememberTransition, AnimatedContent, and Crossfade."

Compose: animations

Core principle

Pick the **smallest API that matches the problem**: built-in visibility and layout transitions first, then a single animated value, then a shared transition object when several values must move together, then gesture-level or imperative APIs when the framework cannot express the motion.

Review procedure

1. Identify the visual job: show/hide, one value, coordinated values, content swap, size change, or gesture-driven motion. 2. Choose the smallest API from the table below. 3. Check lifecycle semantics: should hidden content leave composition, keep focus/state, or only become transparent? 4. Check identity: for state-holder wrappers, choose `AnimatedContent.contentKey` by visual shape rather than payload churn. 5. Check performance: keep frame-rate animation values as `State` and read them in layout/draw block modifiers when possible. 6. Escalate to `Animatable` or lower-level APIs only when target-state animation cannot express the motion.

Pick the smallest animation API

| Need | API | |---|---| | Show or hide a subtree with enter/exit semantics; content is removed after exit completes | [`AnimatedVisibility`](https://developer.android.com/develop/ui/compose/animation/composables-modifiers#animatedvisibility) | | Animate one property toward a target derived from state | [`animateFloatAsState`](https://developer.android.com/develop/ui/compose/animation/value-based#animate-as-state) / `animateDpAsState` / `animateColorAsState` / `animateOffsetAsState` / … | | Several animated values keyed off one boolean, enum, or sealed state | `rememberTransition` + transition child animations (`animateFloat`, `animateDp`, `animateColor`, `animateValue`, …) | | Smooth size when child layout height/width changes (e.g. text wraps) | `Modifier.animateContentSize()` | | Swap between different composable trees for the same slot | `AnimatedContent` or `Crossfade` | | User-driven motion (drag, fling, interruptible springs) | [`Animatable`](https://developer.android.com/reference/kotlin/androidx/compose/animation/core/Animatable) and related coroutine APIs (see Advanced pointers) |

Appear and disappear

**Prefer `AnimatedVisibility`** when the UI should leave or join the tree with enter/exit transitions.

AnimatedVisibility(visible = expanded) {
    Text("Details…")
}

**`animateFloatAsState` on alpha** only fades; the composable **stays in composition** and continues to participate in layout unless you gate it yourself. Use that tradeoff when you intentionally keep children mounted (state, focus) but visually hidden. For true remove-from-tree behavior, use `AnimatedVisibility` (or conditional composition with `AnimatedVisibility` / `AnimatedContent` patterns from the [quick guide](https://developer.android.com/develop/ui/compose/animation/quick-guide)).

Background color

Use `animateColorAsState` for smooth color targets.

For animated fills behind children, the [quick guide](https://developer.android.com/develop/ui/compose/animation/quick-guide) recommends drawing with **`Modifier.drawBehind`** rather than `Modifier.background()` so the animated color is applied in the draw phase appropriately for performance.

val background = animateColorAsState(
    targetValue = if (selected) selectedColor else idleColor,
    label = "background",
)
Box(
    Modifier.drawBehind { drawRect(background.value) },
) { /* content */ }

Size changes

`Modifier.animateContentSize()` animates layout size changes—common for expanding/collapsing text or dynamic chips—without hand-rolling width/height animations.

Value-based animations (`animate*AsState`)

Compose provides `animate*AsState` for `Float`, `Dp`, `Color`, `Size`, `Offset`, `Rect`, `Int`, `IntOffset`, `IntSize`, and more. You supply the **target**; the API owns the animation state.

  • Pass an [`AnimationSpec`](https://developer.android.com/reference/kotlin/androidx/compose/animation/core/AnimationSpec) via `animationSpec` (e.g. `spring`, `tween`) when defaults are wrong for the UI.
  • Set a distinct **`label`** for debugging and tooling when multiple animations exist in one composable.
  • For completion or sequencing details, see [Value-based animations](https://developer.android.com/develop/ui/compose/animation/value-based).
val width by animateDpAsState(
    targetValue = if (expanded) 200.dp else 56.dp,
    animationSpec = spring(dampingRatio = 0.7f, stiffness = Spring.StiffnessMedium),
    label = "fabWidth",
)

Multiple properties: `rememberTransition`

When one piece of state (e.g. `enum class Phase { A, B, C }`) should drive **several** animated values in lockstep, use `rememberTransition` and define child animations on that transition:

val transition = rememberTransition(targetState = phase, label = "phase")
val alpha by transition.animateFloat(label = "alpha") { target ->
    if (target == Phase.Visible) 1f else 0f
}
val offset by transition.animateDp(label = "offset") { target ->
    if (target == Phase.Visible) 0.dp else 24.dp
}

Avoid multiple independent `animate*AsState` calls that should stay visually synchronized but can drift if specs or targets diverge. Older code may use `updateTransition`; prefer `rememberTransition` for new code.

Choosing between content-level APIs

Use the official [Choose an animation API](https://developer.android.com/develop/ui/compose/animation/choose-api) tree when the table is not enough. Compressed rules:

| Situation | Prefer | |---|---| | Same composable, different **target values** for layout properties | `animate*AsState` or `rememberTr

Read more
Ships withchrisbanes-skills

A set of skills for Kotlin, Jetpack Compose, and Android development.

Get the whole plugin

Other skills on chrisbanes-skills.