Badges
Badgesanimated

Confetti win

An achievement chip that bursts confetti from behind a trophy on unlock.

Winner

Installation

caveui components are copy-paste Jetpack Compose built entirely on Material 3 — there's no caveui dependency to add. Make sure Material 3 is on your classpath (it ships with the Compose BOM), then copy the Usage snippet below into your project.

kotlin
// build.gradle.kts (module)
dependencies {
    implementation(platform("androidx.compose:compose-bom:2025.06.00"))
    implementation("androidx.compose.material3:material3")
}

Usage

kotlin
var won by remember { mutableStateOf(false) }
LaunchedEffect(Unit) { won = true }
val pieces = remember {
    List(8) {
        Triple(
            (it * 45).toFloat(),
            listOf(
                Color(0xFFF59E0B), Color(0xFFEF4444),
                Color(0xFF3B82F6), Color(0xFF22C55E),
            ).random(),
            (8..16).random().toFloat(),
        )
    }
}
Surface(
    shape = RoundedCornerShape(50),
    color = Color(0xFFFEF3C7),
    contentColor = Color(0xFFB45309),
) {
    Row(
        Modifier.padding(horizontal = 10.dp, vertical = 4.dp),
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = Arrangement.spacedBy(6.dp),
    ) {
        Box(contentAlignment = Alignment.Center) {
            pieces.forEach { (ang, c, dist) ->
                val a = remember { Animatable(0f) }
                LaunchedEffect(won) { if (won) a.animateTo(1f, tween(700)) }
                Box(
                    Modifier
                        .size(4.dp)
                        .graphicsLayer {
                            translationX = (cos(ang * PI / 180) * dist * a.value).toFloat()
                            translationY = (sin(ang * PI / 180) * dist * a.value).toFloat()
                            alpha = 1f - a.value
                            rotationZ = a.value * 180
                        }
                        .background(c),
                )
            }
            Icon(Icons.Filled.EmojiEvents, null, Modifier.size(16.dp))
        }
        Text("Winner", fontSize = 12.sp, fontWeight = FontWeight.SemiBold)
    }
}