
Reusable patterned backgrounds and follow-glow visuals for Compose, with immutable styles, runtime states, rich layout and interaction presets, lightweight blur, parallax, and seeded randomness.
luma-compose is a Kotlin Multiplatform multi-module library with reusable visual effects for Jetpack Compose.
The shared API lives in common source sets and currently targets Android, Desktop, iOS, and JS.
Main public composables:
PatternBackground for decorative patterned backgroundsFollowGlow for a soft glow that follows a target pointThe API stays app-agnostic: no product-specific models like compass, tilt, or level are built into the library.
Use the published artifact:
dependencies {
implementation("io.github.nvshink:luma-compose:1.0.0")
}For Kotlin Multiplatform consumers, use the shared coordinate in commonMain:
kotlin {
sourceSets {
commonMain.dependencies {
implementation("io.github.nvshink:luma-compose:1.0.0")
}
}
}Published target-specific artifacts:
io.github.nvshink:luma-compose - KMP root publicationio.github.nvshink:luma-compose-android - Android artifactio.github.nvshink:luma-compose-desktop - Desktop JVM artifactio.github.nvshink:luma-compose-js - JS artifactio.github.nvshink:luma-compose-iosx64 - iOS X64 artifactio.github.nvshink:luma-compose-iosarm64 - iOS Arm64 artifactio.github.nvshink:luma-compose-iossimulatorarm64 - iOS Simulator Arm64 artifactModule layout:
:luma KMP library module with shared public API and presets:android-demo Android demo app with catalog screens and live controls:desktop-demo Compose Desktop demo app for trying the same effects on JVM desktopval patternStyle = PatternDefaults.softDots()
val glowStyle = GlowDefaults.softRadial()
Box(Modifier.fillMaxSize()) {
PatternBackground(
state = PatternState(
interactionPoint = OffsetFraction(0.65f, 0.3f),
isAnimated = true,
),
style = patternStyle,
modifier = Modifier.fillMaxSize(),
)
FollowGlow(
state = GlowState(
center = OffsetFraction(0.65f, 0.3f),
isAnimated = true,
),
style = glowStyle,
modifier = Modifier.fillMaxSize(),
)
}PatternBackground(state, style, modifier) draws a reusable background from dots, shapes, sprites, or custom draw content.
Main settings:
PatternElement controls what is rendered: Dot, Shape, Sprite, Custom
PatternLayout controls placement: Random, Uneven, Grid, Radial, Custom
PatternRotation controls motion: None, Uniform, Async, Distributed, Follow, Directed
PatternInteraction controls point-based response: UniformOffset, DistanceBasedOffset
PatternShadow configures shadow and light directionPatternBlur adds a lightweight soft blur layerPatternDepth adds parallax-like offsetPatternStyle groups all visual parameters into one immutable stylePatternState holds runtime inputs like animation and interaction pointExample:
val style = PatternStyle(
element = PatternElement.Shape(
size = DpSize(18.dp, 18.dp),
shape = RoundedCornerShape(50),
color = Color(0xFF7CF4C9),
),
layout = PatternLayout.Grid(
spacing = 32.dp,
rowOffset = 16.dp,
density = 1.2f,
),
shadow = PatternShadow.Drop(
blurRadius = 18.dp,
useInteractionAsLight = true,
),
blur = PatternBlur.Soft(radius = 10.dp),
rotation = PatternRotation.Distributed(
baseDegreesPerSecond = 12f,
variation = 8f,
seed = 42L,
),
interaction = PatternInteraction.DistanceBasedOffset(
point = OffsetFraction.Center,
maxOffset = 18.dp,
intensity = 0.8f,
radius = 180.dp,
falloff = Falloff.Smooth,
),
elementTint = Color(0xFFB8FFE9),
shadowTint = Color(0xFF1D6B57),
)Ready presets:
val dots = PatternDefaults.softDots()
val stripes = PatternDefaults.ferriteStripes()
val sprites = PatternDefaults.floatingSprites()
val field = PatternDefaults.magneticNorthField()Notes:
PatternDefaults read colors from MaterialTheme.colorScheme
PatternState.isAnimated enables internal time-driven animationPatternState.animationTimeMillis lets you drive animation externallyPatternState.interactionPoint can be mapped to drag, cursor, sensor, or app stateseed for reproducibilityCustom sprite example:
val sprite = PatternElement.Sprite(
size = DpSize(24.dp, 24.dp),
painter = rememberVectorPainter(Icons.Rounded.Star),
tint = Color(0xFFFFD166),
)Custom layout example:
val waveLayout = PatternLayout.Custom(
provider = PatternPositionProvider { scope ->
List(20) { index ->
val x = index / 19f
OffsetFraction(x = x, y = 0.5f)
}
},
)FollowGlow(state, style, modifier) draws a soft light layer tied to a target point.
Main settings:
GlowShape controls silhouette: Circle, Ellipse, RoundedRect, Custom
GlowFalloff controls gradient concentration: Soft, Radial, Focused
GlowTrailing adds a short light trailGlowStyle groups color, alpha, size, blur, shape, and trailGlowState holds runtime inputs like center point, intensity, and follow animationExample:
val glowStyle = GlowStyle(
color = Color(0xFF5B8CFF),
alpha = 0.36f,
blurRadius = 120.dp,
size = DpSize(220.dp, 220.dp),
shape = GlowShape.Circle,
trailing = GlowTrailing(steps = 3, alphaDecay = 0.08f),
)Ready presets:
val softGlow = GlowDefaults.softRadial()
val ellipseGlow = GlowDefaults.strongEllipse()
val blobGlow = GlowDefaults.ambientBlob()Notes:
GlowState.center is the target position in fractional coordinatesGlowState.isAnimated enables follow smoothingGlowState.intensity scales the visual output without rebuilding the styleGlowShape.Custom
drawWithCache
density, blurRadius, and sprite size reasonable on large surfacesPatternBlur.Soft is a lightweight approximation, not a full Gaussian blur pipelineThe :android-demo module is a small catalog app for trying the library in isolation.
To use it, clone this repository and run the Android demo app from the local project.
Screens:
Pattern BackgroundGlowCombined DemoWhat it includes:
Run the Android demo:
./gradlew :android-demo:installDebugThe :desktop-demo module is a Compose Desktop app for previewing the library on desktop with the same visual primitives exposed by the shared KMP module.
Run the desktop demo:
./gradlew :desktop-demo:runluma-compose is a Kotlin Multiplatform multi-module library with reusable visual effects for Jetpack Compose.
The shared API lives in common source sets and currently targets Android, Desktop, iOS, and JS.
Main public composables:
PatternBackground for decorative patterned backgroundsFollowGlow for a soft glow that follows a target pointThe API stays app-agnostic: no product-specific models like compass, tilt, or level are built into the library.
Use the published artifact:
dependencies {
implementation("io.github.nvshink:luma-compose:1.0.0")
}For Kotlin Multiplatform consumers, use the shared coordinate in commonMain:
kotlin {
sourceSets {
commonMain.dependencies {
implementation("io.github.nvshink:luma-compose:1.0.0")
}
}
}Published target-specific artifacts:
io.github.nvshink:luma-compose - KMP root publicationio.github.nvshink:luma-compose-android - Android artifactio.github.nvshink:luma-compose-desktop - Desktop JVM artifactio.github.nvshink:luma-compose-js - JS artifactio.github.nvshink:luma-compose-iosx64 - iOS X64 artifactio.github.nvshink:luma-compose-iosarm64 - iOS Arm64 artifactio.github.nvshink:luma-compose-iossimulatorarm64 - iOS Simulator Arm64 artifactModule layout:
:luma KMP library module with shared public API and presets:android-demo Android demo app with catalog screens and live controls:desktop-demo Compose Desktop demo app for trying the same effects on JVM desktopval patternStyle = PatternDefaults.softDots()
val glowStyle = GlowDefaults.softRadial()
Box(Modifier.fillMaxSize()) {
PatternBackground(
state = PatternState(
interactionPoint = OffsetFraction(0.65f, 0.3f),
isAnimated = true,
),
style = patternStyle,
modifier = Modifier.fillMaxSize(),
)
FollowGlow(
state = GlowState(
center = OffsetFraction(0.65f, 0.3f),
isAnimated = true,
),
style = glowStyle,
modifier = Modifier.fillMaxSize(),
)
}PatternBackground(state, style, modifier) draws a reusable background from dots, shapes, sprites, or custom draw content.
Main settings:
PatternElement controls what is rendered: Dot, Shape, Sprite, Custom
PatternLayout controls placement: Random, Uneven, Grid, Radial, Custom
PatternRotation controls motion: None, Uniform, Async, Distributed, Follow, Directed
PatternInteraction controls point-based response: UniformOffset, DistanceBasedOffset
PatternShadow configures shadow and light directionPatternBlur adds a lightweight soft blur layerPatternDepth adds parallax-like offsetPatternStyle groups all visual parameters into one immutable stylePatternState holds runtime inputs like animation and interaction pointExample:
val style = PatternStyle(
element = PatternElement.Shape(
size = DpSize(18.dp, 18.dp),
shape = RoundedCornerShape(50),
color = Color(0xFF7CF4C9),
),
layout = PatternLayout.Grid(
spacing = 32.dp,
rowOffset = 16.dp,
density = 1.2f,
),
shadow = PatternShadow.Drop(
blurRadius = 18.dp,
useInteractionAsLight = true,
),
blur = PatternBlur.Soft(radius = 10.dp),
rotation = PatternRotation.Distributed(
baseDegreesPerSecond = 12f,
variation = 8f,
seed = 42L,
),
interaction = PatternInteraction.DistanceBasedOffset(
point = OffsetFraction.Center,
maxOffset = 18.dp,
intensity = 0.8f,
radius = 180.dp,
falloff = Falloff.Smooth,
),
elementTint = Color(0xFFB8FFE9),
shadowTint = Color(0xFF1D6B57),
)Ready presets:
val dots = PatternDefaults.softDots()
val stripes = PatternDefaults.ferriteStripes()
val sprites = PatternDefaults.floatingSprites()
val field = PatternDefaults.magneticNorthField()Notes:
PatternDefaults read colors from MaterialTheme.colorScheme
PatternState.isAnimated enables internal time-driven animationPatternState.animationTimeMillis lets you drive animation externallyPatternState.interactionPoint can be mapped to drag, cursor, sensor, or app stateseed for reproducibilityCustom sprite example:
val sprite = PatternElement.Sprite(
size = DpSize(24.dp, 24.dp),
painter = rememberVectorPainter(Icons.Rounded.Star),
tint = Color(0xFFFFD166),
)Custom layout example:
val waveLayout = PatternLayout.Custom(
provider = PatternPositionProvider { scope ->
List(20) { index ->
val x = index / 19f
OffsetFraction(x = x, y = 0.5f)
}
},
)FollowGlow(state, style, modifier) draws a soft light layer tied to a target point.
Main settings:
GlowShape controls silhouette: Circle, Ellipse, RoundedRect, Custom
GlowFalloff controls gradient concentration: Soft, Radial, Focused
GlowTrailing adds a short light trailGlowStyle groups color, alpha, size, blur, shape, and trailGlowState holds runtime inputs like center point, intensity, and follow animationExample:
val glowStyle = GlowStyle(
color = Color(0xFF5B8CFF),
alpha = 0.36f,
blurRadius = 120.dp,
size = DpSize(220.dp, 220.dp),
shape = GlowShape.Circle,
trailing = GlowTrailing(steps = 3, alphaDecay = 0.08f),
)Ready presets:
val softGlow = GlowDefaults.softRadial()
val ellipseGlow = GlowDefaults.strongEllipse()
val blobGlow = GlowDefaults.ambientBlob()Notes:
GlowState.center is the target position in fractional coordinatesGlowState.isAnimated enables follow smoothingGlowState.intensity scales the visual output without rebuilding the styleGlowShape.Custom
drawWithCache
density, blurRadius, and sprite size reasonable on large surfacesPatternBlur.Soft is a lightweight approximation, not a full Gaussian blur pipelineThe :android-demo module is a small catalog app for trying the library in isolation.
To use it, clone this repository and run the Android demo app from the local project.
Screens:
Pattern BackgroundGlowCombined DemoWhat it includes:
Run the Android demo:
./gradlew :android-demo:installDebugThe :desktop-demo module is a Compose Desktop app for previewing the library on desktop with the same visual primitives exposed by the shared KMP module.
Run the desktop demo:
./gradlew :desktop-demo:run