# Cloudy: blur, backdrop blur and liquid glass for Compose

> Cloudy is a Kotlin Multiplatform surface effects library for Compose that ships four independent effects, self blur, backdrop blur, liquid glass and an open shader effect called Mirage, with GPU-accelerated rendering where available and a CPU fallback elsewhere. It suits a Compose developer who wants a frosted panel or a glass lens without writing a render effect from scratch.

**skydoves/Cloudy** — ☁️ Kotlin Multiplatform blur and liquid glass effect library for Compose, with GPU-accelerated rendering and CPU fallback for older devices.

- Repository: https://github.com/skydoves/Cloudy
- Website: https://skydoves.github.io/Cloudy/
- Stars: 1,292 · Forks: 55
- Language: Kotlin
- License: Apache-2.0
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/skydoves-cloudy

## Four effects, and how they differ

Cloudy is a Kotlin Multiplatform surface effects library for Compose, covering blur, liquid glass and shader-driven looks, with GPU-accelerated rendering and a CPU fallback for older devices. The four effects are independent and mix-and-matchable on any composable, which is the design decision that makes the library more than a single modifier. `Modifier.cloudy(radius = …)` is self blur, blurring a composable's own content. `Modifier.cloudy(sky = …)` is backdrop blur, blurring the content behind a composable, which is the glassmorphism case. `Modifier.liquidGlass(…)` is a realistic glass lens with refraction and chromatic dispersion. And `Modifier.mirage { }` is an open shader effect plan with thin-film and specular presets, or your own. The naming is a bit confusing at first, since self blur and backdrop blur share the `cloudy` modifier and differ by argument, but the distinction matters, because self blur captures a composable's own content while backdrop blur has to read what is behind it.

## The platform floor, and the CPU fallback

The README states the constraint plainly. The `Modifier.cloudy(radius = …)` blur path supports only Android 12 and higher without the deprecated `RenderScript` APIs, and there is a CPU fallback for older devices. The badge says API 23 and newer, so the library itself installs broadly, but the accelerated path is much narrower. The project also says Cloudy started as a backport of the blur effect for Jetpack Compose with cross-platform support, and has grown to cover liquid glass and open shader effects. The primary language is Kotlin, the licence is Apache-2.0, the homepage is skydoves.github.io/Cloudy, the last push was on 2026-09-13, and the releases are 1.0.0-alpha01 on 2026-07-17, 0.7.1 on 2026-07-12 and 0.7.0 on 2026-07-10. The 1.0 line is an alpha, so the 0.7.x releases are the ones with a stable version number.

## Adding the dependency, for Gradle and for KMP

The library is on Maven Central as `com.github.skydoves:cloudy`, and the README gives three ways to add it. With a Version Catalog you add it to `libs.versions.toml`:

```toml
[versions]
#...
cloudy = "1.0.0-alpha01"

[libraries]
#...
compose-cloudy = { module = "com.github.skydoves:cloudy", version.ref = "cloudy" }
```

In a plain Gradle module you add it to the module's `build.gradle.kts`:

```gradle
dependencies {
    implementation("com.github.skydoves:cloudy:1.0.0-alpha01")
    
    // if you're using Version Catalog
    implementation(libs.compose.cloudy)
}
```

And for Kotlin Multiplatform it goes into the common source set:

```gradle
sourceSets {
    commonMain.dependencies {
        implementation("com.github.skydoves:cloudy:$version")
    }
}
```

The commonMain placement is the point for a multiplatform project, since that is what makes the effect available on every target rather than only on Android.

## Using the blur, and what the state object tells you

The basic call attaches the effect to any composable, and the `radius` parameter controls the degree of the blur:

```kotlin
Text(
  modifier = Modifier.cloudy(),
  text = "This text is blurred"
)
```

The more interesting part is the `onStateChanged` parameter, which reports a `CloudyState` and tells you which rendering path was taken. The state types are `Success.Applied` for a GPU blur applied in the rendering pipeline, where no bitmap is available because the blur was rendered directly, `Success.Captured` for a CPU blur completed with a bitmap available at `state.bitmap`, `Success.Scrim` where a scrim overlay is shown instead of a blur, which is the background blur case on Android 30 and below, `Loading` while processing is in progress, `Error` when the operation failed with the throwable in `state.throwable`, and `Nothing` as the initial state. Knowing which path ran matters, because the CPU path is slower and gives you a bitmap while the GPU path does not, and an application that wanted to save the blurred image can only do that on the CPU path.

## Keeping the effect on a responsive composable

There is a stated limitation that matters in practice. The `Modifier.cloudy` captures the bitmap of the composable node under the hood, and a bitmap capture of a scrolling or lazy list is the case where the effect can break. The README's example is a `LazyVerticalGrid` with a remembered `LazyGridState`, which is the shape of the problem: a composable that recycles its children needs the capture to be re-taken, and the state object is the signal that it happened. The rest of the documentation is organised in two parts, with Part I covering the four effects and Part II going further, and the three entries there are the ones that move beyond the basics. There is motion-driven light sources, which is the natural pairing with the liquid glass effect since a glass lens that does not respond to movement looks like a flat image. There is authoring your own Mirage optic, for the shader effect. And there is blur effect with network images, which is the case where the blur has to run on something that is not yet loaded.

## The repository, and the native side

The tree shows a project with a real native component, which is unusual for a Compose library. There is `cloudy/` for the Kotlin library and `cloudy-native/` beside it, which is where the platform-specific rendering lives, and that is what makes the CPU fallback and the GPU path two implementations of the same effect. There is `app/` and `app-android/` for the sample application, an `iosApp/` for the iOS target, a `preview/` directory, a `benchmark/` directory, a `buildSrc/` for the Gradle build logic, a `spotless/` directory for code formatting, and a `kotlin-js-store/` for the Kotlin/JS dependency lock. The rename configuration is `renovate.json`, the CI is under `.github/`, and there is a `.coderabbit.yaml` for automated review. The API badge says API 23 or newer, and the multiplatform target list in the topics covers android, blur, blur-image, jetpack-compose and skydoves.

## Conclusion

Adopt Cloudy if you want a blur, a frosted backdrop or a glass lens in Compose and would rather not write a RenderEffect or a shader yourself. Skip it if your minimum supported Android version is below 12 and the CPU fallback is not acceptable for your use, since the self blur path supports only Android 12 and higher without the deprecated RenderScript APIs. Before you start, note that the current release is an alpha, 1.0.0-alpha01, with 0.7.1 as the last non-alpha version, and that the library needs API 23 or newer.

## FAQ

### What effects does the Cloudy library provide?

Four independent ones: Modifier.cloudy(radius) for self blur, Modifier.cloudy(sky) for backdrop blur, Modifier.liquidGlass() for a glass lens with refraction and chromatic dispersion, and Modifier.mirage { } as an open shader effect with thin-film and specular presets or your own.

### Which Android versions does the Cloudy blur support?

The Modifier.cloudy(radius) path supports only Android 12 and higher without the deprecated RenderScript APIs, with a CPU fallback for older devices. The library itself targets API 23 and newer, and the fallback path is reported through CloudyState.Success.Captured, while the GPU path reports Success.Applied.

### How do I add Cloudy to a Kotlin Multiplatform project?

Add it to the common source set in your module's build.gradle.kts, with `sourceSets { commonMain.dependencies { implementation("com.github.skydoves:cloudy:$version") } }`. For a plain Android module you add `implementation("com.github.skydoves:cloudy:1.0.0-alpha01")` to the dependencies block, or use the Version Catalog form.

### How do I know whether a blur ran on the GPU or the CPU?

Use the onStateChanged parameter and inspect the CloudyState. Success.Applied means a GPU blur was applied in the rendering pipeline with no bitmap available, Success.Captured means the CPU blur completed and the bitmap is at state.bitmap, and Success.Scrim means a scrim overlay was shown instead of a blur.

## Sources

- [License: Apache-2.0](https://github.com/skydoves/Cloudy/blob/main/LICENSE)
- [Project website](https://skydoves.github.io/Cloudy/)
- [README](https://github.com/skydoves/Cloudy/blob/main/README.md)
- [Releases](https://github.com/skydoves/Cloudy/releases)
- [skydoves/Cloudy on GitHub](https://github.com/skydoves/Cloudy)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/skydoves-cloudy
