Skip to content

Instantly share code, notes, and snippets.

@iprashantpanwar
Created September 24, 2025 20:16
Show Gist options
  • Select an option

  • Save iprashantpanwar/c4770640e88c7130afcb54251c353c39 to your computer and use it in GitHub Desktop.

Select an option

Save iprashantpanwar/c4770640e88c7130afcb54251c353c39 to your computer and use it in GitHub Desktop.
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.*
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.ComposeViewport
import kotlinx.coroutines.delay
import kotlin.random.Random
@OptIn(ExperimentalComposeUiApi::class)
fun main() {
ComposeViewport { App() }
}
@Composable
fun App() {
var darkTheme by remember { mutableStateOf(false) }
var greetingText by remember { mutableStateOf("Hello World!") }
var showPlugin by remember { mutableStateOf(false) }
var counter by remember { mutableStateOf(0) }
var name by remember { mutableStateOf("") }
var selectedPlugin by remember { mutableStateOf(PluginType.HeartBeat) }
var progress by remember { mutableStateOf(0.3f) }
var snackbarVisible by remember { mutableStateOf(false) }
val scaffoldState = rememberScaffoldState()
PlaygroundTheme(darkTheme) {
Scaffold(
scaffoldState = scaffoldState,
topBar = {
TopAppBar(
title = { Text("Compose WASM Playground") },
backgroundColor = MaterialTheme.colors.primary,
contentColor = MaterialTheme.colors.onPrimary
)
},
bottomBar = {
BottomNavigation(backgroundColor = MaterialTheme.colors.primary) {
for (p in PluginType.values()) {
BottomNavigationItem(
selected = selectedPlugin == p,
onClick = { selectedPlugin = p },
label = { Text(p.label, color = MaterialTheme.colors.onPrimary) },
icon = {}
)
}
}
},
floatingActionButton = {
FloatingActionButton(onClick = { snackbarVisible = true }) {
Text("+", color = MaterialTheme.colors.onPrimary)
}
}
) { paddingValues ->
Column(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.padding(paddingValues),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
// Theme switch
Row(verticalAlignment = Alignment.CenterVertically) {
Text(if (darkTheme) "Dark" else "Light")
Switch(checked = darkTheme, onCheckedChange = { darkTheme = it })
}
// Greeting
Card(elevation = 4.dp, modifier = Modifier.fillMaxWidth()) {
Column(
modifier = Modifier.padding(12.dp),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
Text("Interactive Greeting", style = MaterialTheme.typography.subtitle1)
TextField(
value = name,
onValueChange = { name = it },
label = { Text("Your name") },
modifier = Modifier.fillMaxWidth()
)
Row(verticalAlignment = Alignment.CenterVertically) {
Button(onClick = {
counter++
greetingText =
if (name.isBlank()) "Hello, Compose!" else "Hello, ${name.trim()}!"
progress = Random.nextFloat()
}) {
Text(greetingText)
}
Spacer(modifier = Modifier.width(8.dp))
Text("Presses: $counter")
}
// Progress indicators
LinearProgressIndicator(modifier = Modifier.fillMaxWidth())
Spacer(modifier = Modifier.height(4.dp))
CircularProgressIndicator()
}
}
// Plugin selector
Card(elevation = 4.dp, modifier = Modifier.fillMaxWidth()) {
Column(modifier = Modifier.padding(12.dp)) {
Text("Plugin Host — pick a mini plugin")
Spacer(modifier = Modifier.height(4.dp))
Row {
for (p in PluginType.values()) {
Button(onClick = { selectedPlugin = p }) {
Text(p.label)
}
Spacer(modifier = Modifier.width(8.dp))
}
}
Spacer(modifier = Modifier.height(8.dp))
Row(verticalAlignment = Alignment.CenterVertically) {
Button(onClick = { showPlugin = !showPlugin }) {
Text(if (showPlugin) "Hide Plugin" else "Show Plugin")
}
Spacer(modifier = Modifier.width(8.dp))
Text("Active: ${selectedPlugin.label}")
}
}
}
// Plugin area
AnimatedVisibility(visible = showPlugin) {
Card(elevation = 4.dp, modifier = Modifier.fillMaxWidth()) {
Box(
modifier = Modifier
.fillMaxWidth()
.padding(12.dp),
contentAlignment = Alignment.Center
) {
PluginHost(selectedPlugin)
}
}
}
// Platform info
Text(
"Platform: ${getPlatform().name}",
style = MaterialTheme.typography.caption,
color = MaterialTheme.colors.onSurface.copy(alpha = 0.6f)
)
// Snackbar
if (snackbarVisible) {
LaunchedEffect(Unit) {
delay(1500)
snackbarVisible = false
}
Snackbar { Text("FAB Clicked!") }
}
}
}
}
}
// ---- Theme Setup ----
private val LightColors = lightColors(
primary = Color(0xFF0066CC),
primaryVariant = Color(0xFF004A99),
secondary = Color(0xFFFFA000),
background = Color(0xFFF2F2F2),
surface = Color.White,
onPrimary = Color.White,
onSecondary = Color.Black,
onBackground = Color.Black,
onSurface = Color.Black
)
private val DarkColors = darkColors(
primary = Color(0xFF66B2FF),
primaryVariant = Color(0xFF004A99),
secondary = Color(0xFFFFB300),
background = Color(0xFF121212),
surface = Color(0xFF1E1E1E),
onPrimary = Color.Black,
onSecondary = Color.Black,
onBackground = Color.White,
onSurface = Color.White
)
@Composable
fun PlaygroundTheme(darkTheme: Boolean, content: @Composable () -> Unit) {
MaterialTheme(
colors = if (darkTheme) DarkColors else LightColors,
typography = Typography(),
shapes = Shapes(),
content = content
)
}
// ---- Plugin Host and Types ----
enum class PluginType(val label: String) {
HeartBeat("Beat"),
ColorPulse("Pulse"),
CounterTicker("Ticker"),
BouncingBall("Ball"),
RotatingSquare("Square"),
ColorGrid("Grid")
}
@Composable
fun PluginHost(type: PluginType) {
when (type) {
PluginType.HeartBeat -> HeartBeatPlugin()
PluginType.ColorPulse -> ColorPulsePlugin()
PluginType.CounterTicker -> CounterTickerPlugin()
PluginType.BouncingBall -> BouncingBallPlugin()
PluginType.RotatingSquare -> RotatingSquarePlugin()
PluginType.ColorGrid -> ColorGridPlugin()
}
}
// ---- Plugins ----
// HeartBeatPlugin, ColorPulsePlugin, CounterTickerPlugin, BouncingBallPlugin, RotatingSquarePlugin, ColorGridPlugin
// Keep your previous plugin implementations here (unchanged)
// ---- Plugins ----
@Composable
fun HeartBeatPlugin() {
val transition = rememberInfiniteTransition()
val scale by transition.animateFloat(
initialValue = 0.85f,
targetValue = 1.15f,
animationSpec = infiniteRepeatable(
animation = tween(700, easing = FastOutSlowInEasing),
repeatMode = RepeatMode.Reverse
)
)
Box(
modifier = Modifier
.size(120.dp)
.graphicsLayer(
scaleX = scale,
scaleY = scale
),
contentAlignment = Alignment.Center
) {
// Using Box as heart placeholder
Box(
modifier = Modifier
.size(80.dp)
.background(MaterialTheme.colors.error, shape = CircleShape)
)
}
}
@Composable
fun ColorPulsePlugin() {
val transition = rememberInfiniteTransition()
val fraction by transition.animateFloat(
initialValue = 0f,
targetValue = 1f,
animationSpec = infiniteRepeatable(
animation = tween(1600, easing = FastOutSlowInEasing),
repeatMode = RepeatMode.Reverse
)
)
val color = Color(
red = 0.3f + 0.7f * fraction,
green = 0.6f - 0.4f * fraction,
blue = 0.9f - 0.5f * fraction
)
Box(
modifier = Modifier
.size(120.dp)
.background(color, CircleShape),
contentAlignment = Alignment.Center
) {
Text("Pulsing Box")
}
}
@Composable
fun CounterTickerPlugin() {
var tick by remember { mutableStateOf(0) }
LaunchedEffect(Unit) {
while (true) {
delay(700)
tick++
}
}
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text("Ticker")
Spacer(Modifier.height(8.dp))
Text("Tick: $tick")
Spacer(Modifier.height(8.dp))
Button(onClick = { tick = 0 }) {
Text("Reset")
}
}
}
@Composable
fun BouncingBallPlugin() {
val transition = rememberInfiniteTransition()
val offsetX by transition.animateFloat(
initialValue = -100f,
targetValue = 100f,
animationSpec = infiniteRepeatable(
animation = tween(1200, easing = FastOutSlowInEasing),
repeatMode = RepeatMode.Reverse
)
)
Box(
modifier = Modifier.size(200.dp),
contentAlignment = Alignment.Center
) {
Box(
modifier = Modifier
.offset(x = offsetX.dp)
.size(50.dp)
.background(MaterialTheme.colors.secondary, CircleShape)
)
}
}
@Composable
fun RotatingSquarePlugin() {
val transition = rememberInfiniteTransition()
val angle by transition.animateFloat(
initialValue = 0f,
targetValue = 360f,
animationSpec = infiniteRepeatable(
animation = tween(2000, easing = LinearEasing),
repeatMode = RepeatMode.Restart
)
)
Box(
modifier = Modifier
.size(120.dp)
.background(MaterialTheme.colors.primary, RoundedCornerShape(12.dp))
.graphicsLayer(rotationZ = angle),
contentAlignment = Alignment.Center
) {
Text("Rotating", color = MaterialTheme.colors.onPrimary)
}
}
@Composable
fun ColorGridPlugin() {
var colors by remember { mutableStateOf(List(9) { randomColor() }) }
LaunchedEffect(Unit) {
while (true) {
delay(1000)
colors = List(9) { randomColor() }
}
}
Column {
repeat(3) { row ->
Row {
repeat(3) { col ->
Box(
modifier = Modifier
.size(60.dp)
.background(colors[row * 3 + col])
)
}
}
}
}
}
fun randomColor(): Color =
Color(Random.nextFloat(), Random.nextFloat(), Random.nextFloat())
// ---- platform greeting ----
private val platform = object : Platform {
override val name: String = "Web with Kotlin/Wasm"
}
fun getPlatform(): Platform = platform
interface Platform { val name: String }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment