Compose Recompose Pulse is a local-installable Compose instrumentation toolkit that highlights recomposition with a lightweight visual pulse.
The current setup supports these Kotlin Multiplatform targets:
androidiosArm64iosSimulatorArm64jswasmJsjvm
The public package base is com.adamglin.recompose.pulse.
The Gradle plugin id is com.adamglin.recompose.pulse.
First, make sure your consumer project can resolve artifacts from mavenLocal().
pluginManagement {
repositories {
mavenLocal()
google()
gradlePluginPortal()
mavenCentral()
}
}
dependencyResolutionManagement {
repositories {
mavenLocal()
google()
mavenCentral()
}
}Then apply the plugin:
plugins {
id("com.adamglin.recompose.pulse") version "version"
}If you only want the runtime APIs, you can depend on the libraries directly:
dependencies {
implementation("com.adamglin.recompose.pulse:runtime:version")
implementation("com.adamglin.recompose.pulse:annotations:version")
}Enable the plugin and scope instrumentation to the packages you want:
recomposePulse {
enabled.set(true)
includePackages.add("com.example.app")
}If includePackages is omitted, instrumentation is not restricted to a specific package list.
Wrap your UI with ProvideRecomposePulse:
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.runtime.Composable
import com.adamglin.recompose.pulse.ProvideRecomposePulse
import com.adamglin.recompose.pulse.RecomposePulseStyle
@Composable
fun App() {
ProvideRecomposePulse(
enabled = true,
style = RecomposePulseStyle(),
) {
MaterialTheme {
Surface {
}
}
}
}Skip instrumentation for a specific composable or class:
import com.adamglin.recompose.pulse.NoRecomposePulse
@NoRecomposePulse
@Composable
fun ExpensiveComposable() {
}Disable the pulse for a subtree:
import androidx.compose.runtime.Composable
import com.adamglin.recompose.pulse.DisableRecomposePulse
@Composable
fun Screen() {
DisableRecomposePulse {
}
}The desktop sample in sample-desktop shows a simple counter screen that demonstrates both enabled and disabled subtrees.
Publish all artifacts to your local Maven repository:
./gradlew --no-daemon publishPulseToMavenLocalThis publishes the main coordinates:
com.adamglin.recompose.pulse:annotations:0.1.1com.adamglin.recompose.pulse:runtime:0.1.1com.adamglin.recompose.pulse:compiler:0.1.1com.adamglin.recompose.pulse:gradle:0.1.1- plugin marker:
com.adamglin.recompose.pulse:com.adamglin.recompose.pulse.gradle.plugin:0.1.1
If you republish the same version, refresh dependencies in the consumer project:
./gradlew --refresh-dependencies compileKotlinPush a tag prefixed with v to trigger the GitHub release workflow:
git tag v1.2.3
git push origin v1.2.3The workflow strips the leading v and publishes the remaining value as the Maven Central version. For example, v1.2.3 publishes 1.2.3, and v1.2.3-beta01 publishes 1.2.3-beta01.
Configure these GitHub Actions repository secrets before releasing:
GPG_KEY_CONTENTSMAVEN_CENTRAL_PASSWORDMAVEN_CENTRAL_USERNAMESIGNING_KEY_IDSIGNING_PASSWORD
The project is split into four focused pieces:
annotations: opt-out markers such as@NoRecomposePulseruntime: Compose APIs and modifier implementation that render the pulse effectcompiler: injects the pulse modifier into eligible composable callsgradle: connects the runtime and compiler plugin to consumer projects
The design goal is to keep the consumer API small while moving the heavy lifting into compile-time instrumentation. In practice, the Gradle plugin adds the runtime and annotations dependencies, the compiler plugin rewrites matching composable call sites, and the runtime renders a short-lived overlay pulse at recomposition time.
This keeps application code simple, makes opt-in usage explicit, and allows selective opt-out for performance-sensitive or noisy UI regions.
This project is licensed under Apache-2.0. See LICENSE and NOTICE for the attribution requirement.