Coil compose
19 Claude AI skills for Kotlin Multiplatform (KMP) & Compose Multiplatform (CMP): architecture, networking, UI, testing, migration & build tooling for Android and iOS.
npx -y skills add ShinKev/kmp-skill-library --skill coil-composeAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Expert guidance on using Coil 3 for image loading in Compose Multiplatform. Use when asked about loading images from URLs, handling image states, or optimizing image performance in CMP (Android + iOS).
SKILL.md
3.9 KB, as published. Nobody here has run it
Coil 3 for Compose Multiplatform
Instructions
Use Coil 3 (coil3) for image loading in CMP. Coil 3 is fully KMP-compatible — it works in commonMain composables without LocalContext.current.
Migration note: Coil 2.x (
coilpackage) requiredLocalContext.currentinImageRequest.Builder. Coil 3 (coil3package) removes this requirement. If you seeLocalContext.currentin image loading code, update to Coil 3.
Setup (libs.versions.toml)
[versions]
coil = "3.1.0"
[libraries]
coil-compose = { group = "io.coil-kt.coil3", name = "coil-compose", version.ref = "coil" }
coil-network = { group = "io.coil-kt.coil3", name = "coil-network-ktor", version.ref = "coil" }
// shared/build.gradle.kts
commonMain.dependencies {
implementation(libs.coil.compose)
implementation(libs.coil.network) // Uses Ktor under the hood
}
1. Primary Composable: AsyncImage
Use AsyncImage for most cases. No LocalContext needed in commonMain:
// coil3 — works in commonMain
AsyncImage(
model = ImageRequest.Builder()
.data("https://example.com/image.jpg")
.crossfade(true)
.build(),
contentDescription = "Profile picture",
contentScale = ContentScale.Crop,
placeholder = painterResource(Res.drawable.placeholder),
error = painterResource(Res.drawable.error_image),
modifier = Modifier
.size(64.dp)
.clip(CircleShape)
)
2. Low-Level Control: rememberAsyncImagePainter
Use only when you need a Painter (e.g., for Canvas or Icon).
Warning:
rememberAsyncImagePainterdoes not auto-detect the display size and loads the image at its original dimensions by default. Always set an explicit size or preferAsyncImage.
val painter = rememberAsyncImagePainter(
model = ImageRequest.Builder()
.data("https://example.com/image.jpg")
.size(Size.ORIGINAL)
.build()
)
3. Custom State Slots: SubcomposeAsyncImage
Use when you need custom loading/error UI with access to the AsyncImagePainter.State.
Caution: Subcomposition is slower than regular composition. Avoid in
LazyColumnorLazyRow.
SubcomposeAsyncImage(
model = "https://example.com/image.jpg",
contentDescription = null,
loading = { CircularProgressIndicator(modifier = Modifier.size(24.dp)) },
error = { Icon(Icons.Default.BrokenImage, contentDescription = null) }
)
4. Singleton ImageLoader via Koin
Provide a single ImageLoader instance for the whole app to share cache:
// commonMain Koin module
val imageModule = module {
single {
ImageLoader.Builder()
.components { add(KtorNetworkFetcherFactory(get())) } // reuse app HttpClient
.crossfade(true)
.build()
}
}
5. Performance & Best Practices
- Singleton: Always share one
ImageLoader— it owns the disk/memory cache. - Crossfade: Enable
crossfade(true)for smooth placeholder → image transitions. - Sizing: Set
contentScaleappropriately — Coil 3 uses it to avoid loading images larger than needed. - Lists: Prefer
AsyncImageoverSubcomposeAsyncImageinsideLazyColumn/LazyRow. - Transformations: Apply via
ImageRequest.Builder().transformations(CircleCropTransformation()).
6. Checklist
- Using
coil3package (notcoil— that's Coil 2) - No
LocalContext.currentincommonMainimage loading code -
ImageLoaderprovided as a Koin singleton -
AsyncImagepreferred over other variants - Meaningful
contentDescriptionon all images (ornullfor decorative) -
crossfade(true)enabled for better UX -
SubcomposeAsyncImageavoided in lazy lists