Skip to content

Instantly share code, notes, and snippets.

@bitspittle
Last active June 26, 2025 16:50
Show Gist options
  • Select an option

  • Save bitspittle/7e506898549cef62e8c9eb5878a4f218 to your computer and use it in GitHub Desktop.

Select an option

Save bitspittle/7e506898549cef62e8c9eb5878a4f218 to your computer and use it in GitHub Desktop.
Animating in a 4x4 grid of squares in Kobweb (in BFS order)
// Drafted as part of a conversation in https://www.linkedin.com/posts/shubhamsinghshubham777_kotlin-compose-jetpackcompose-activity-7343659024954925059-QS39
// To repro yourself, you can run `kobweb create app/empty` and overwrite `pages/Index.kt` with this code:
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import com.varabyte.kobweb.compose.css.CSSTimeNumericValue
import com.varabyte.kobweb.compose.css.StyleVariable
import com.varabyte.kobweb.compose.foundation.layout.Box
import com.varabyte.kobweb.compose.foundation.layout.Column
import com.varabyte.kobweb.compose.foundation.layout.Row
import com.varabyte.kobweb.compose.ui.Alignment
import com.varabyte.kobweb.compose.ui.Modifier
import com.varabyte.kobweb.compose.ui.graphics.Colors
import com.varabyte.kobweb.compose.ui.modifiers.*
import com.varabyte.kobweb.core.Page
import com.varabyte.kobweb.silk.style.CssStyle
import com.varabyte.kobweb.silk.style.animation.Keyframes
import com.varabyte.kobweb.silk.style.base
import com.varabyte.kobweb.silk.style.toModifier
import org.jetbrains.compose.web.css.AnimationFillMode
import org.jetbrains.compose.web.css.percent
import org.jetbrains.compose.web.css.px
import org.jetbrains.compose.web.css.s
import org.jetbrains.compose.web.dom.Text
val AnimDelay by StyleVariable<CSSTimeNumericValue>()
val GrowInKeyframes = Keyframes {
0.percent { Modifier.scale(0) }
100.percent { Modifier.scale(1) }
}
val SquareStyle = CssStyle.base {
Modifier
.size(100.px)
.fontSize(20.px)
.backgroundColor(Colors.Cyan)
.color(Colors.Black)
.scale(0)
.animation(GrowInKeyframes.toAnimation(duration = 1.s, delay = AnimDelay.value(), fillMode = AnimationFillMode.Forwards))
}
@Composable
fun Square(label: String, delay: CSSTimeNumericValue) {
Box(SquareStyle.toModifier().setVariable(AnimDelay, delay), contentAlignment = Alignment.Center) {
Text(label)
}
}
@Page
@Composable
fun HomePage() {
// We render a 4x4 grid of squares labeled left-to-right, top-to-bottom,
// but we animate them in in a breadth-first manner, starting from the top left.
// The example here is easy enough to just hardcode this order for now.
val animInIndex = remember {
arrayOf(
intArrayOf(0, 2, 5, 9),
intArrayOf(1, 4, 8, 12),
intArrayOf(3, 7, 11, 14),
intArrayOf(6, 10, 13, 15),
)
}
Column {
for (y in 0 until 4) {
Row {
for (x in 0 until 4) {
val orderIndex = y * 4 + x
Square(label = orderIndex.toString(), delay = (animInIndex[y][x] * 0.1).s)
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment