Cards
Cardsanimated

Story Ring Avatar

Avatar card wrapped in a rotating gradient story ring indicating unseen updates.

NV
Nova Vex
New story

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
@Composable
fun StoryRingCard() {
    val sweep = rememberInfiniteTransition(label = "ring")
    val angle by sweep.animateFloat(
        0f, 360f,
        infiniteRepeatable(tween(3000, easing = LinearEasing)),
        label = "angle"
    )
    Card(
        modifier = Modifier.width(220.dp),
        shape = RoundedCornerShape(20.dp)
    ) {
        Column(
            Modifier.padding(20.dp).fillMaxWidth(),
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Box(
                Modifier.size(84.dp).drawBehind {
                    rotate(angle) {
                        drawCircle(
                            Brush.sweepGradient(
                                listOf(
                                    Color(0xFFF59E0B),
                                    Color(0xFFEC4899),
                                    Color(0xFF8B5CF6),
                                    Color(0xFFF59E0B)
                                )
                            ),
                            style = Stroke(width = 8f)
                        )
                    }
                },
                contentAlignment = Alignment.Center
            ) {
                Box(
                    Modifier.size(68.dp).clip(CircleShape)
                        .background(
                            MaterialTheme.colorScheme.secondary
                        ),
                    contentAlignment = Alignment.Center
                ) { Text("NV") }
            }
            Spacer(Modifier.height(12.dp))
            Text(
                "Nova Vex",
                style = MaterialTheme.typography.titleSmall
            )
            Text(
                "New story",
                style = MaterialTheme.typography.bodySmall,
                color = MaterialTheme.colorScheme.onSurfaceVariant
            )
        }
    }
}