
Declarative Compose-style widget DSL that serializes UI to an AST/JSON and generates native renderers, with shared state, adaptive sizing, interactive actions, and minimal app size overhead.
Widget Abstraction & Rendering Pipeline for Kotlin Multiplatform.
Write home screen widgets once in Kotlin — render natively on Android (Glance) and iOS (WidgetKit + SwiftUI).
https://github.com/user-attachments/assets/50072112-45a3-4bab-bba5-46d696108ec4
⚠️ Alpha Stage: WARP is currently in Alpha. APIs and implementation details may evolve based on community feedback. If you discover any bugs or have feature requests, please open an issue on GitHub Issues.
WARP is a declarative widget engine for Kotlin Multiplatform developers.
It allows you to describe home screen widget UI using familiar Compose syntax (WarpColumn, WarpRow, WarpText, WarpButton), serialize the resulting Abstract Syntax Tree (AST) to JSON, and render it using 100% native platform frameworks on each OS:
Declarative Compose Kotlin UI ──> WarpNode AST ──> JSON ──> Native Platform Renderers
│
Shared State & Action Handlers
commonMain.compose.runtime — does not pull in compose.ui graphics pipelines.SharedPreferences (Android) and UserDefaults App Groups (iOS).Small, Medium, and Large widget sizes.Add WARP and serialization dependencies to your catalog:
[versions]
warp = "0.1.4"
kotlinx-serialization-json = "1.11.0"
compose-multiplatform = "1.11.1"
[libraries]
warp-widget = { group = "io.github.devatrii", name = "warp-widget", version.ref = "warp" }
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization-json" }
compose-runtime = { module = "org.jetbrains.compose.runtime:runtime", version.ref = "compose-multiplatform" }
[plugins]
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
composeCompiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }In your shared KMP module build.gradle.kts:
plugins {
alias(libs.plugins.kotlin.serialization)
alias(libs.plugins.composeCompiler)
}
kotlin {
listOf(iosArm64(), iosSimulatorArm64()).forEach { iosTarget ->
iosTarget.binaries.framework {
export(libs.warp.widget)
}
}
sourceSets {
commonMain.dependencies {
api(libs.warp.widget)
implementation(libs.kotlinx.serialization.json)
implementation(libs.compose.runtime)
}
}
}/** 1. State */
@Serializable
data class CounterState(val count: Int = 0)
/** 2. Type-Safe Actions */
@Serializable
sealed class CounterActions {
@Serializable data object Increment : CounterActions()
@Serializable data object Decrement : CounterActions()
}
/** 3. Widget Definition */
object CounterWarpWidget : WarpWidget<CounterState>(CounterState.serializer()) {
override val id: String = "CounterWidget"
override val iosGroupId: String = "group.com.example.app"
override val stateScope: WarpWidgetStateScope = WarpWidgetStateScope.Shared
override suspend fun defaultState(): CounterState = CounterState()
@Composable
override fun Content(session: WarpWidgetSession, state: CounterState) {
val env = session.environment
WarpTheme(environment = env) {
WarpRow(
modifier = WarpModifier.fillMaxWidth().padding(16.dp),
verticalAlignment = WarpVerticalAlignment.Center
) {
WarpButton("−", CounterActions.Decrement.asClickAction())
WarpText("${state.count}", modifier = WarpModifier.weight())
WarpButton("+", CounterActions.Increment.asClickAction())
}
}
}
override fun clickHandlers(session: WarpWidgetSession): List<WarpActionHandler<*>> =
listOf(CounterActionHandler(session))
}Below is the real-world iOS build size report for the Todo Widget Example App:
| Artifact | Component / Path | Release Size | Note |
|---|---|---|---|
Xcode App Store Archive (.ipa) |
TodoWidget.ipa (App Thinning Export)
|
1.8 MB | Official App Store Download Size |
| Installed App Size (Thinned) | On-Device Installed Footprint | 5.8 MB | Official App Store Install Size |
| Shared KMP Framework | SharedLogic.framework |
18.0 MB | ~73% Release Binary Stripping |
| Widget Extension Bundle | TodoWidgetExtension.appex |
8.50 MB | Uncompressed bundle on-disk |
| Module | Role |
|---|---|
| warp-runtime | Compose compiler DSL, WarpNode AST tree, WarpModifier chain, serializable actions |
| warp-ui | Native platform renderers — Jetpack Glance (Android) & SwiftUI generator (iOS) |
| warp-widget | Shared WarpWidget API, session manager, persistent state store, WarpTheme, WarpAdaptive
|
| warpWidgetKit |
SPM SwiftUI / WidgetKit package (import warpWidgetKit) for Xcode extensions |
| shared | Shared KMP module with Counter widget demo |
| examples/todo-widget | Complete full-featured Todo Widget example application |
WARP is open-source software released under the MIT License. You are free to use, modify, and distribute it in personal or commercial applications.
Widget Abstraction & Rendering Pipeline for Kotlin Multiplatform.
Write home screen widgets once in Kotlin — render natively on Android (Glance) and iOS (WidgetKit + SwiftUI).
https://github.com/user-attachments/assets/50072112-45a3-4bab-bba5-46d696108ec4
⚠️ Alpha Stage: WARP is currently in Alpha. APIs and implementation details may evolve based on community feedback. If you discover any bugs or have feature requests, please open an issue on GitHub Issues.
WARP is a declarative widget engine for Kotlin Multiplatform developers.
It allows you to describe home screen widget UI using familiar Compose syntax (WarpColumn, WarpRow, WarpText, WarpButton), serialize the resulting Abstract Syntax Tree (AST) to JSON, and render it using 100% native platform frameworks on each OS:
Declarative Compose Kotlin UI ──> WarpNode AST ──> JSON ──> Native Platform Renderers
│
Shared State & Action Handlers
commonMain.compose.runtime — does not pull in compose.ui graphics pipelines.SharedPreferences (Android) and UserDefaults App Groups (iOS).Small, Medium, and Large widget sizes.Add WARP and serialization dependencies to your catalog:
[versions]
warp = "0.1.4"
kotlinx-serialization-json = "1.11.0"
compose-multiplatform = "1.11.1"
[libraries]
warp-widget = { group = "io.github.devatrii", name = "warp-widget", version.ref = "warp" }
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization-json" }
compose-runtime = { module = "org.jetbrains.compose.runtime:runtime", version.ref = "compose-multiplatform" }
[plugins]
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
composeCompiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }In your shared KMP module build.gradle.kts:
plugins {
alias(libs.plugins.kotlin.serialization)
alias(libs.plugins.composeCompiler)
}
kotlin {
listOf(iosArm64(), iosSimulatorArm64()).forEach { iosTarget ->
iosTarget.binaries.framework {
export(libs.warp.widget)
}
}
sourceSets {
commonMain.dependencies {
api(libs.warp.widget)
implementation(libs.kotlinx.serialization.json)
implementation(libs.compose.runtime)
}
}
}/** 1. State */
@Serializable
data class CounterState(val count: Int = 0)
/** 2. Type-Safe Actions */
@Serializable
sealed class CounterActions {
@Serializable data object Increment : CounterActions()
@Serializable data object Decrement : CounterActions()
}
/** 3. Widget Definition */
object CounterWarpWidget : WarpWidget<CounterState>(CounterState.serializer()) {
override val id: String = "CounterWidget"
override val iosGroupId: String = "group.com.example.app"
override val stateScope: WarpWidgetStateScope = WarpWidgetStateScope.Shared
override suspend fun defaultState(): CounterState = CounterState()
@Composable
override fun Content(session: WarpWidgetSession, state: CounterState) {
val env = session.environment
WarpTheme(environment = env) {
WarpRow(
modifier = WarpModifier.fillMaxWidth().padding(16.dp),
verticalAlignment = WarpVerticalAlignment.Center
) {
WarpButton("−", CounterActions.Decrement.asClickAction())
WarpText("${state.count}", modifier = WarpModifier.weight())
WarpButton("+", CounterActions.Increment.asClickAction())
}
}
}
override fun clickHandlers(session: WarpWidgetSession): List<WarpActionHandler<*>> =
listOf(CounterActionHandler(session))
}Below is the real-world iOS build size report for the Todo Widget Example App:
| Artifact | Component / Path | Release Size | Note |
|---|---|---|---|
Xcode App Store Archive (.ipa) |
TodoWidget.ipa (App Thinning Export)
|
1.8 MB | Official App Store Download Size |
| Installed App Size (Thinned) | On-Device Installed Footprint | 5.8 MB | Official App Store Install Size |
| Shared KMP Framework | SharedLogic.framework |
18.0 MB | ~73% Release Binary Stripping |
| Widget Extension Bundle | TodoWidgetExtension.appex |
8.50 MB | Uncompressed bundle on-disk |
| Module | Role |
|---|---|
| warp-runtime | Compose compiler DSL, WarpNode AST tree, WarpModifier chain, serializable actions |
| warp-ui | Native platform renderers — Jetpack Glance (Android) & SwiftUI generator (iOS) |
| warp-widget | Shared WarpWidget API, session manager, persistent state store, WarpTheme, WarpAdaptive
|
| warpWidgetKit |
SPM SwiftUI / WidgetKit package (import warpWidgetKit) for Xcode extensions |
| shared | Shared KMP module with Counter widget demo |
| examples/todo-widget | Complete full-featured Todo Widget example application |
WARP is open-source software released under the MIT License. You are free to use, modify, and distribute it in personal or commercial applications.