# Sketch ships 36 modules and one Proguard rule that still names the old group id

> A Kotlin image loading library for Compose Multiplatform and Android View, split into 36 published modules, with a keep rule whose package does not match the coordinates it protects and install snippets that stop mid-word. Apache-2.0, last commit 2026-09-27.

**panpf/sketch** — Image loading library designed for Compose Multiplatform and Android View. Supports loading Image, GIF, SVG, Video thumbnails from the network, local, resources, and photo albums.

- Repository: https://github.com/panpf/sketch
- Website: https://panpf.github.io/sketch/
- Stars: 2,411 · Forks: 328
- Language: Kotlin
- License: Apache-2.0
- Published: 2026-09-28 · Updated: 2026-09-28 · Language: en
- Canonical page: https://hysenlabs.com/projects/panpf-sketch

## The one obfuscation rule matches a package the artifacts do not use

Sketch ships exactly one Proguard rule, and it is required only on JVM platforms:

```proguard
# -------------------------- Sketch Privider ---------------------------- #
-keep class * implements com.github.panpf.sketch.util.ComponentProvider { *; }
```

The package is the interesting part. Every coordinate on the install page starts with `io.github.panpf.sketch4:`, with a 4 on the end, and the module names follow from that prefix. The keep rule matches `com.github.panpf.sketch.util.ComponentProvider`, a group with no digit in it and a `com.github` prefix where the artifacts use `io.github`. The comment above it also spells Provider as Privider, which is the signature of a block copied in and lightly edited rather than maintained where it lives.

Android, iOS and web builds need no obfuscation rules at all, so this only bites the JVM target. The reason it exists at all sits in the registration mechanism, which differs by platform.

## Component discovery is ServiceLoader on the JVM and an annotation everywhere else

Sketch registers its Fetchers and Decoders automatically, and it uses two different mechanisms to do it. On the JVM platform the components are found through ServiceLoader. On non-JVM platforms they are found through the `@EagerInitialization` annotation. Android, iOS, web and the native targets therefore never read a service descriptor, which is exactly why they need no obfuscation configuration and the JVM does.

`ComponentProvider` is the class the rule protects, so it is the seam a custom Fetcher or Decoder implements. Anything that plugs into the pipeline has to survive shrinking intact on the JVM, and the `{ *; }` keeps members as well as the class. Turning automatic registration off is a documented option, after which registration is manual and this rule matters less.

Two manual steps sit in the same part of the page: the component registration guide, and a request to copy `compose_compiler_config.conf` out of the `sketch-core` module into your own project and configure it against the Compose stability documentation. Neither is something a build plugin does for you.

## Eight HTTP modules in the tree, two clients named in the guide

Network loading arrives through a single artifact, `sketch-http`, and behind it sits a larger set than the install page mentions. The repository root holds eight HTTP modules: `sketch-http`, `sketch-http-core`, `sketch-http-hurl`, `sketch-http-okhttp`, `sketch-http-ktor2`, `sketch-http-ktor2-core`, `sketch-http-ktor3` and `sketch-http-ktor3-core`.

The callout in the optional modules section names two of them. `sketch-http` depends on `sketch-http-hurl` on jvm platforms and on `sketch-http-ktor3` on non-jvm platforms. That leaves the ktor2 pair and the okhttp module sitting in the tree with no stated role, and okhttp is separately named as one of the third-party libraries whose own indirect dependencies may need obfuscation configuration.

Three client generations side by side, each split into a public module and a `-core` module, is a maintenance surface the guide does not discuss. Anyone deciding which HTTP stack to pin has to read the directory listing rather than the install instructions.

## The optional modules block stops one word into its last comment

The optional modules block lists animated-image artifacts and stops mid-sentence:

```kotlin
// Use Android or Skia's built-in decoder to decode webp animatio
```

No coordinate follows that comment and the block ends there. The module it was about to introduce is in the repository: the root contains `sketch-animated-webp/`, next to `sketch-animated-gif/`, `sketch-animated-gif-koral/`, `sketch-animated-heif/` and `sketch-animated-core/`. The tree has five animated entries while the install block shows three dependency lines.

Those three are annotated about where they run. `sketch-animated-gif` uses the decoder built into Android or Skia, `sketch-animated-gif-koral` is marked Android only and delegates to the GifDrawable class from the android-gif-drawable library, and `sketch-animated-heif` is marked Android only as well. A reader copying the block gets GIF and HEIF, then has to reconstruct the WebP coordinate from a directory name, and the version placeholder has to be filled in by hand there too.

## The quick start samples carry a transposed parameter and unfinished calls

The Compose sample opens with three commented alternatives for the URI, a local path, a compose resource and a network URL, then shows three AsyncImage calls. The third stops mid-argument:

```kotlin
AsyncImage(
    rqeuest = Compos
```

Two faults in three lines. The parameter name is spelled `rqeuest`, with the first and fourth letters transposed, so the call is not valid Kotlin and will not compile as printed. The line also ends inside the name of a composable function.

The Android View sample ends the same way, on a line that starts `context.sk` and stops. Everything above it is sound: `imageView.loadImage(imageUri)` for the bare case, the same call with a trailing block for placeholder, error and crossfade, and an ImageRequest built from the context and URI with a target attached. These are illustrations rather than copy-paste targets, but they are the only usage code on the front page, and a reader who starts there hits a compiler error before reaching anything about images.

## Every dependency line ends in a placeholder you supply by hand

The install snippets use a literal `${LAST_VERSION}` where the version belongs, with a note beside it reading that the leading v is not included. Every coordinate on the page follows that shape, from `sketch-compose` and `sketch-view` through `sketch-http` to the optional modules, so the version gets substituted by hand at each site rather than resolved by a version catalog.

There are two entry points and they differ by one line. A Compose Multiplatform project takes `io.github.panpf.sketch4:sketch-compose` for the core functions and the singletons and extension functions built on them, plus `sketch-http` for network images. An Android View project takes `sketch-view` in the first position and the same `sketch-http` line in the second. `sketch-http` appears in both lists, so a project that never loads from a URL still resolves it unless it is excluded by hand.

The callout also points at `*-core` variants of both entry modules for anyone who does not want the singleton, and the tree carries separate `sketch-compose-koin/` and `sketch-view-koin/` directories that the install page never mentions.

## Thirty-six modules, seven samples, and a feature list that ends open

The scale of the thing is visible in the directory listing: 36 `sketch-*` modules at the root, plus seven sample applications under `samples/`, covering Android, iOS, js, jvm, macOS, wasmJs and a shared module. The rest of the root is build machinery, with `buildSrc/`, `libs.versions.toml`, `build.gradle.kts`, `mkdocs.yml`, `build_docs.sh`, `components_weight_map.txt`, and a Chinese `CHANGELOG.zh.md` beside the English one.

Some module names describe capability rather than plumbing. `sketch-svg` decodes SVG still images, `sketch-video-ffmpeg` carries an FFmpeg based video frame decoder, `sketch-avif-awxkee` names a third-party AVIF decoder by its author, `sketch-blurhash` handles blurhash placeholders, and the two appicon modules deal with icons belonging to installed packages on Android.

The topic list on the README page ends mid-link. The last entry reads VideoFrames: Decode video frames, and its reference is written `[video_` with the closing bracket and target missing, so that anchor does not resolve. It is the one link a reader following the list in order cannot click.

## Conclusion

Sketch fits a Compose Multiplatform or Android View project that wants network images, animated playback, SVG and video frames out of one dependency set, and the module split lets you leave out what you do not need. Two things deserve a check before you commit to it: the Proguard rule on the JVM target names com.github.panpf.sketch while Maven Central serves io.github.panpf.sketch4, and the animated WebP coordinate is missing from the optional modules block even though the module is in the tree. The sample code on the front page will not compile as printed, so plan on the documentation site rather than the README. The last commit is dated 2026-09-27 and version 4.7.0 shipped the same day.

## FAQ

### What is panpf/sketch for?

It is a Kotlin image loading library for Compose Multiplatform and Android View. It loads images from http, local files, compose resources and Android asset, content and resource URIs, and adds three-level caching, automatic request cancellation, size adjustment, Exif orientation rotation, animated images, SVG, Base64 images and video frames.

### How do I add Sketch to a Compose Multiplatform project?

Add io.github.panpf.sketch4:sketch-compose for the core functions and singletons, and io.github.panpf.sketch4:sketch-http for network images, replacing the ${LAST_VERSION} placeholder in both lines. An Android View project uses sketch-view in the first position instead. You also need to copy compose_compiler_config.conf out of the sketch-core module and wire it into your own Compose stability configuration.

### Does Sketch need Proguard or R8 rules?

Android, iOS and web builds need none. The jvm platforms need one rule that keeps classes implementing com.github.panpf.sketch.util.ComponentProvider, which preserves the components that ServiceLoader discovers at runtime. That group id differs from the io.github.panpf.sketch4 coordinates the artifacts are published under.

### Which HTTP client does Sketch use on each platform?

The sketch-http module depends on sketch-http-hurl on jvm platforms and on sketch-http-ktor3 on non-jvm platforms. The repository also contains sketch-http-okhttp, sketch-http-ktor2 and sketch-http-ktor2-core, which the install page does not assign a role to.

### Can Sketch play animated GIF, HEIF and WebP?

GIF playback comes from sketch-animated-gif, which uses the decoder built into Android or Skia, and sketch-animated-gif-koral, which is Android only and uses the GifDrawable class from android-gif-drawable. sketch-animated-heif is Android only. A sketch-animated-webp module exists in the tree, but the optional modules block ends mid-comment without giving its coordinate.

## Sources

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

---

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