Skip to content

Instantly share code, notes, and snippets.

@brkckr
Last active January 14, 2026 21:49
Show Gist options
  • Select an option

  • Save brkckr/83a0b77a23af187cd6587945c3e8f9c1 to your computer and use it in GitHub Desktop.

Select an option

Save brkckr/83a0b77a23af187cd6587945c3e8f9c1 to your computer and use it in GitHub Desktop.
Bouncing DVD logo animation on Jetpack Compose
@Composable
fun DVDScreen() {
var dvdVideoSize by remember { mutableStateOf(Size.Zero) } // dvd+video size
var isSizeReady by remember { mutableStateOf(false) } // is size ready?
var velocityX by remember { mutableFloatStateOf(5f) }
var velocityY by remember { mutableFloatStateOf(5f) }
var textColor by remember { mutableStateOf(Color.Blue) }
fun randomColor(): Color {
return Color(
red = Random.nextFloat(),
green = Random.nextFloat(),
blue = Random.nextFloat(),
alpha = 1f
)
}
val configuration = LocalConfiguration.current
val screenWidth = with(LocalDensity.current) { configuration.screenWidthDp.dp.toPx() }
val screenHeight = with(LocalDensity.current) { configuration.screenHeightDp.dp.toPx() }
var positionX by remember { mutableFloatStateOf(0f) }
var positionY by remember { mutableFloatStateOf(0f) }
LaunchedEffect(Unit) {
while (true) {
if (isSizeReady) {
positionX += velocityX // update x position
positionY += velocityY // update y position
var colorChanged = false // flag for collision
// check for collision with left edge
if (positionX <= 0f) {
velocityX = -velocityX // reverse x velocity
positionX = 0f // clamp position to left
colorChanged = true // trigger color change
}
// check for collision with right edge
else if (dvdVideoSize != Size.Zero && positionX + dvdVideoSize.width >= screenWidth) {
velocityX = -velocityX
positionX = screenWidth - dvdVideoSize.width
colorChanged = true
}
// check for collision with top edge
if (positionY <= 0f) {
velocityY = -velocityY // reverse y velocity
positionY = 0f
colorChanged = true
}
// check for collision with bottom edge
else if (dvdVideoSize != Size.Zero && positionY + dvdVideoSize.height >= screenHeight) {
velocityY = -velocityY
positionY = screenHeight - dvdVideoSize.height
colorChanged = true
}
// change color if a collision occurred
if (colorChanged) {
textColor = randomColor()
}
delay(16) // wait for 60 fps
}
}
}
Box(
modifier = Modifier
.fillMaxSize()
.background(Color.Black),
contentAlignment = Alignment.TopStart
) {
Column(
modifier = Modifier
.offset(
x = with(LocalDensity.current) { positionX.toDp() },
y = with(LocalDensity.current) { positionY.toDp() }
)
.onGloballyPositioned { layoutCoordinates ->
val size = layoutCoordinates.size
if (size.width > 0 && size.height > 0) {
dvdVideoSize = Size(size.width.toFloat(), size.height.toFloat())
isSizeReady = true
}
},
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(0.dp)
) {
Text(
text = "DVD",
style = TextStyle(
fontSize = 72.sp,
fontStyle = FontStyle.Italic,
fontWeight = FontWeight.Bold,
color = textColor,
letterSpacing = 0.sp
)
)
Text(
text = "VIDEO",
color = Color.Black,
fontSize = 24.sp,
fontWeight = FontWeight.Medium,
textAlign = TextAlign.Center,
letterSpacing = 4.sp,
modifier = Modifier
.width(with(LocalDensity.current) { dvdVideoSize.width.toDp() })
.drawBehind {
drawOval(
color = textColor,
size = Size(dvdVideoSize.width, size.height)
)
}
)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment