Shader Transitions
AsyncPic V3.0.0 introduces AGSL (Android Graphics Shading Language) cinematic reveal effects. These are GPU-accelerated transitions that play when the image finishes loading.
Shader transitions require Android 13 (API 33 / Tiramisu). On older devices, AsyncPic silently falls back to the standard crossfade — no crash, no extra code needed.
AsyncPicTransition​
sealed class AsyncPicTransition {
object Standard : AsyncPicTransition() // default crossfade
data class ShaderReveal(
val type: RevealType = RevealType.DISSOLVE,
val durationMillis: Int = 1000
) : AsyncPicTransition()
}
RevealType​
Three GPU shader effects are available:
DISSOLVE (default)​
Noise-based particle dissolve. Image materializes from random pixels.
AsyncPic(
source = ImageSource.Url("https://example.com/photo.jpg"),
modifier = Modifier.fillMaxWidth().height(250.dp),
transition = AsyncPicTransition.ShaderReveal(
type = RevealType.DISSOLVE,
durationMillis = 1200
)
)
PIXELATE​
Starts as large pixel blocks that shrink into full resolution.
AsyncPic(
source = ImageSource.Url("https://example.com/photo.jpg"),
modifier = Modifier.fillMaxWidth().height(250.dp),
transition = AsyncPicTransition.ShaderReveal(
type = RevealType.PIXELATE,
durationMillis = 800
)
)
WIPE​
Clean left-to-right wipe reveal.
AsyncPic(
source = ImageSource.Url("https://example.com/photo.jpg"),
modifier = Modifier.fillMaxWidth().height(250.dp),
transition = AsyncPicTransition.ShaderReveal(
type = RevealType.WIPE,
durationMillis = 600
)
)
Standard (No Shader)​
Use the default Coil crossfade with no shader:
AsyncPic(
source = ImageSource.Url("..."),
modifier = Modifier.size(200.dp),
transition = AsyncPicTransition.Standard // default
)
Duration​
Control animation speed via durationMillis (milliseconds):
// Fast: 400ms
transition = AsyncPicTransition.ShaderReveal(durationMillis = 400)
// Slow cinematic: 2000ms
transition = AsyncPicTransition.ShaderReveal(durationMillis = 2000)
How It Works​
AsyncPic uses android.graphics.RuntimeShader and RenderEffect.createRuntimeShaderEffect to apply the AGSL shader to the composable's graphicsLayer. A progress uniform (0.0 → 1.0) is animated via animateFloatAsState and passed into the shader each frame. On API < 33, the shader block is skipped entirely.