
Interactive lighting effects for UI components: point‑light shadows, directional highlights, text glyph shadows, glow, draggable/animated light sources, and light-facing borders.
LightSource Compose is a Jetpack Compose and Compose Multiplatform library for adding interactive lighting effects to UI components, including point-light shadows, highlights, text shadows, and glow.
It is currently experimental. APIs are marked with @ExperimentalLightSourceApi and may change before a stable release.
Can be used for Jetpack Compose and Compose Multiplatform.
Add the dependency to the module where you use Compose UI.
Make sure your project resolves dependencies from Maven Central:
repositories {
mavenCentral()
}LightSource Compose dependency:
implementation("io.github.lucas-krug:lightsource-compose:0.1.0")Because the API is experimental, callers must opt in.
@OptIn(ExperimentalLightSourceApi::class)Wrap light-aware content in a LightScene, then use lightShadow or LightText inside it.
@OptIn(ExperimentalLightSourceApi::class)
@Composable
fun Example() {
val lightSource = rememberStaticLightSource(
position = Offset(300f, 300f),
color = Color(0xFFFFF1C2),
intensity = 0.9f,
radius = 500.dp,
shadowLength = 1.25f,
)
LightScene(
lightSource = lightSource,
modifier = Modifier.fillMaxSize(),
drawGlow = true,
drawMarker = false,
) {
Box(
Modifier
.lightShadow(
shape = RoundedCornerShape(20.dp),
elevation = 16.dp,
maxOffset = 64.dp,
)
.background(Color.DarkGray, RoundedCornerShape(20.dp)),
)
LightText(
text = "Directional shadow",
color = Color.White,
fontSize = 24.sp,
fontWeight = FontWeight.Bold,
elevation = 8.dp,
)
}
}LightSource.position uses root-layout pixels. If Modifier.dragLightSource is attached to the same full-size element that hosts LightScene, pointer positions can be assigned directly to the light source.
Use a fixed light when the source should stay in one place:
val lightSource = rememberStaticLightSource(
position = Offset(120f, 160f),
radius = 520.dp,
)Use mutable state for draggable or programmatically controlled lights:
val lightState = rememberLightSourceState(initialPosition = Offset(120f, 160f))
val lightSource = rememberStatefulLightSource(
state = lightState,
radius = 520.dp,
)
LightScene(
lightSource = lightSource,
modifier = Modifier
.fillMaxSize()
.dragLightSource(lightState),
) {
// Light-aware content
}Use an animated light when the source should transition between positions:
val lightSource = rememberAnimatedLightSource(
targetPosition = Offset(120f, 720f),
radius = 520.dp,
)Modifier.lightShadow applies a directional shadow and an optional light-facing border to shaped elements.
Modifier.lightShadow(
shape = RoundedCornerShape(16.dp),
elevation = 12.dp,
maxOffset = 36.dp,
highlight = true,
)Set drawLightBorders = false on LightScene to disable light-facing borders for the whole scene. Set highlight = false on a single lightShadow call to disable the border for one element.
LightText behaves like Material 3 Text outside a LightScene. Inside a LightScene, it replaces the text shadow with a directional glyph shadow based on the current light source.
LightScene can draw a marker for the light source:
LightScene(
lightSource = lightSource,
drawGlow = true,
drawMarker = true,
) {
// Content
}drawMarker is mainly useful for demos, debugging, or draggable light controls, if needed.
Apache License 2.0. See LICENSE.
LightSource Compose is a Jetpack Compose and Compose Multiplatform library for adding interactive lighting effects to UI components, including point-light shadows, highlights, text shadows, and glow.
It is currently experimental. APIs are marked with @ExperimentalLightSourceApi and may change before a stable release.
Can be used for Jetpack Compose and Compose Multiplatform.
Add the dependency to the module where you use Compose UI.
Make sure your project resolves dependencies from Maven Central:
repositories {
mavenCentral()
}LightSource Compose dependency:
implementation("io.github.lucas-krug:lightsource-compose:0.1.0")Because the API is experimental, callers must opt in.
@OptIn(ExperimentalLightSourceApi::class)Wrap light-aware content in a LightScene, then use lightShadow or LightText inside it.
@OptIn(ExperimentalLightSourceApi::class)
@Composable
fun Example() {
val lightSource = rememberStaticLightSource(
position = Offset(300f, 300f),
color = Color(0xFFFFF1C2),
intensity = 0.9f,
radius = 500.dp,
shadowLength = 1.25f,
)
LightScene(
lightSource = lightSource,
modifier = Modifier.fillMaxSize(),
drawGlow = true,
drawMarker = false,
) {
Box(
Modifier
.lightShadow(
shape = RoundedCornerShape(20.dp),
elevation = 16.dp,
maxOffset = 64.dp,
)
.background(Color.DarkGray, RoundedCornerShape(20.dp)),
)
LightText(
text = "Directional shadow",
color = Color.White,
fontSize = 24.sp,
fontWeight = FontWeight.Bold,
elevation = 8.dp,
)
}
}LightSource.position uses root-layout pixels. If Modifier.dragLightSource is attached to the same full-size element that hosts LightScene, pointer positions can be assigned directly to the light source.
Use a fixed light when the source should stay in one place:
val lightSource = rememberStaticLightSource(
position = Offset(120f, 160f),
radius = 520.dp,
)Use mutable state for draggable or programmatically controlled lights:
val lightState = rememberLightSourceState(initialPosition = Offset(120f, 160f))
val lightSource = rememberStatefulLightSource(
state = lightState,
radius = 520.dp,
)
LightScene(
lightSource = lightSource,
modifier = Modifier
.fillMaxSize()
.dragLightSource(lightState),
) {
// Light-aware content
}Use an animated light when the source should transition between positions:
val lightSource = rememberAnimatedLightSource(
targetPosition = Offset(120f, 720f),
radius = 520.dp,
)Modifier.lightShadow applies a directional shadow and an optional light-facing border to shaped elements.
Modifier.lightShadow(
shape = RoundedCornerShape(16.dp),
elevation = 12.dp,
maxOffset = 36.dp,
highlight = true,
)Set drawLightBorders = false on LightScene to disable light-facing borders for the whole scene. Set highlight = false on a single lightShadow call to disable the border for one element.
LightText behaves like Material 3 Text outside a LightScene. Inside a LightScene, it replaces the text shadow with a directional glyph shadow based on the current light source.
LightScene can draw a marker for the light source:
LightScene(
lightSource = lightSource,
drawGlow = true,
drawMarker = true,
) {
// Content
}drawMarker is mainly useful for demos, debugging, or draggable light controls, if needed.
Apache License 2.0. See LICENSE.