Skip to content

Instantly share code, notes, and snippets.

@remziakgoz
Created June 10, 2025 12:33
Show Gist options
  • Save remziakgoz/a5dc14cc73672a8d7802047bb5d31531 to your computer and use it in GitHub Desktop.
Save remziakgoz/a5dc14cc73672a8d7802047bb5d31531 to your computer and use it in GitHub Desktop.
Jetpack Compose Wavy Gradient Ring Visualizer 🎨
/**
* A colorful animated ring built with Jetpack Compose Canvas.
* Uses sine waves and HSV gradient segments for a smooth, reactive visualization.
* Sliders allow you to adjust amplitude and frequency in real time.
*/
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Slider
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.delay
import kotlin.math.PI
import kotlin.math.cos
import kotlin.math.sin
@Composable
fun WavyRingVisualizer() {
var amplitude by remember { mutableStateOf(0.5f) }
var frequency by remember { mutableStateOf(5f) }
var time by remember { mutableStateOf(0f) }
LaunchedEffect(Unit) {
while (true) {
time += 0.03f
delay(16L) // ~60fps
}
}
Column(
modifier = Modifier
.fillMaxSize()
.background(Color.Black),
verticalArrangement = Arrangement.SpaceEvenly,
horizontalAlignment = Alignment.CenterHorizontally
) {
Canvas(modifier = Modifier.size(300.dp)) {
val center = Offset(size.width / 2, size.height / 2)
val radius = size.minDimension / 2.5f
val points = mutableListOf<Offset>()
// Generate exactly 360 points for 0 to 359 degrees
for (i in 0 until 360) {
val angle = (i * 2.0 * PI) / 360.0 // Use 2Ο€ instead of converting degrees
val wave = sin(frequency * angle + time) * amplitude * 20
val r = radius + wave.toFloat()
val x = (r * cos(angle)).toFloat() + center.x
val y = (r * sin(angle)).toFloat() + center.y
points.add(Offset(x, y))
}
// Draw as connected line segments, manually connecting each point to the next
for (i in points.indices) {
val current = points[i]
val next = points[(i + 1) % points.size] // Wrap around to first point
drawLine(
brush = Brush.linearGradient(
colors = listOf(
Color.hsv((i * 360f / points.size) % 360f, 1f, 1f),
Color.hsv(((i + 1) * 360f / points.size) % 360f, 1f, 1f)
),
start = current,
end = next
),
start = current,
end = next,
strokeWidth = 6f,
cap = StrokeCap.Round
)
}
}
Slider(
value = amplitude,
onValueChange = { amplitude = it },
valueRange = 0f..1f,
modifier = Modifier.padding(horizontal = 32.dp)
)
Slider(
value = frequency,
onValueChange = { frequency = it },
valueRange = 1f..15f,
modifier = Modifier.padding(horizontal = 32.dp)
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment