Skip to content

Ali0092/Sketchy

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

14 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Sketchy

Hand-drawn, animated illustrations & empty states for Jetpack Compose.

Sketchy is a Kotlin/Compose library of sketch-style, line-art artwork β€” the kind of warm, human illustration you'd want for onboarding flows and empty states β€” drawn entirely on Canvas, animated out of the box, and fully themeable to match your app.

License Kotlin Jetpack Compose Min SDK PRs Welcome


Demo

sketchy_new.mp4

Why Sketchy

Most illustration libraries ship static SVGs or Lottie files β€” dependencies outside Compose's own rendering pipeline, hard to restyle, and rarely animated in a way that feels alive. Sketchy takes a different approach:

  • Pure Compose, zero image assets. Every illustration is vector line-art drawn with DrawScope, so it's crisp at any size and ships as pure Kotlin β€” no drawables, no Lottie JSON, no binary bloat.
  • Animated by default. Each scene has its own small, purposeful motion β€” a sweeping stopwatch hand, a ringing bell, a heartbeat pulse β€” not just a generic fade-in. Turn it off with a single animate = false when you want a static frame instead.
  • Hand-drawn by default, painted on request. Every scene renders as a pure outline sketch β€” ink lines on a transparent canvas, nothing filled in, lifted only by small accent marks. Pass colorful = true and the same scene is painted in full: shaded surfaces, contact shadows, highlights. No second set of artwork, and never a background of its own either way.
  • Genuinely reskinnable. Both catalogs take color, size, and copy as plain parameters (SketchyColors, Dp, String, TextStyle) β€” no XML theming, no design-system lock-in. It doesn't even depend on Material.

What's inside

Catalog Count Entry point
Featured illustrations 5 elaborate full scenes SketchyIllustration(modifier, sketch, animate, colorful, colors)
Onboarding illustrations 15, across 6 categories SketchyIllustration(modifier, sketch, animate, colorful, colors)
Empty states 20, across 4 categories SketchyEmptyState(state, modifier, animate, colorful, colors, illustrationSize, title, subtitle, titleStyle, subtitleStyle, spacing)

Every one of the 40 scenes draws two ways from the same code β€” a colourless hand-drawn outline by default, or fully painted with colorful = true.

A :app module ships alongside the library as a live, searchable catalog of every illustration and empty state β€” the fastest way to browse what's available and copy the exact usage snippet for whatever you pick.

Two looks, one drawing

Sketchy never ships two sets of artwork. Each scene is written once, and the colorful flag decides how the palette hands its colours back to the drawing code:

colorful = false (default) colorful = true
Look Pure line-art β€” ink outlines, nothing filled in Gradient-shaded surfaces, contact shadows, highlights, under the same outlines
Palette slots used ink, inkSoft, inkFaint + the four accents All of the above plus the light and material slots
Colour Only small accent marks β€” a sparkle, a glint, one highlighted bar Full colour throughout
Background Transparent Transparent
Best for Minimal / monochrome UIs, dark mode, matching a single brand ink Onboarding heroes, marketing screens, playful apps

Neither mode ever paints a background of its own, so a scene drops onto whatever surface your screen already has.

How it works: when a scene is outlined, every surface, light and material slot of the palette reads back as Color.Transparent, so the fill simply isn't painted and what survives is the ink outline of the same shape. That's why colorful is one boolean and not a second catalog.

Installation

Sketchy is published on JitPack.

Add the JitPack repository:

// settings.gradle
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        mavenCentral()
        maven { url 'https://jitpack.io' }
    }
}

Then add the dependency:

// app/build.gradle
dependencies {
    implementation 'com.github.Ali0092:Sketchy:1.0.2'
}

Usage

An onboarding illustration

import com.sketchy.library.illustrations.Sketch
import com.sketchy.library.illustrations.SketchyIllustration

SketchyIllustration(
    sketch = Sketch.PlanTasks,
    modifier = Modifier.size(280.dp)
)

Every Sketch scales to whatever size you give it and animates on a loop by default. Pass animate = false to freeze it on its resting frame β€” handy for lower-power devices or a still hero image.

The same illustration, colourless or colourful

// Colourless β€” the default. Ink outlines, a few accent marks, nothing filled in.
SketchyIllustration(
    sketch = Sketch.MorningCoffee,
    modifier = Modifier.size(280.dp),
)

// Colourful β€” the same scene, painted: shaded surfaces, shadows, highlights.
SketchyIllustration(
    sketch = Sketch.MorningCoffee,
    modifier = Modifier.size(280.dp),
    colorful = true,
)

colorful works on every illustration and every empty state, and it's an ordinary parameter β€” drive it from a setting, from isSystemInDarkTheme(), or from a single app-wide constant:

SketchyEmptyState(
    state = EmptyState.EmptyCart,
    colorful = !isSystemInDarkTheme(),
)

A featured illustration

The five Featured scenes are the elaborate ones β€” a whole scene rather than a single motif, one source file each, built on the shading primitives the painted mode uses. They're the ones worth giving a full-bleed hero slot:

SketchyIllustration(
    sketch = Sketch.ReadingNook,   // or MorningCoffee, HomeWorkspace, GroceryRun, RainyWindow
    modifier = Modifier.fillMaxWidth().aspectRatio(1f),
    colorful = true,
)

They take exactly the same parameters as every other Sketch β€” animate, colorful and colors all behave identically β€” and they render colourless just as happily if that's your look. Because they carry the most detail, they also gain the most from colorful = true, so they're the best place to start if you're deciding between the two modes.

An illustration, restyled to match your theme

colors is a plain SketchyColors parameter β€” override any subset of it and every stroke, fill, and sparkle in the scene repaints to match, no XML themes or design-system lock-in required.

A colourless scene only ever draws from the first block of the palette β€” ink, inkSoft, inkFaint and the four accents (accent, accentGreen, accentBlue, accentRed). The light and material slots below them are what the colourful version fills with, so reskinning a colourless app means changing the ink and the accents and nothing else:

import com.sketchy.library.SketchyColors
import com.sketchy.library.illustrations.Sketch
import com.sketchy.library.illustrations.SketchyIllustration

SketchyIllustration(
    sketch = Sketch.BuildBetterHabits,
    modifier = Modifier.size(280.dp),
    colors = SketchyColors(
        ink = MaterialTheme.colorScheme.onSurface,
        accent = MaterialTheme.colorScheme.primary,
        accentBlue = MaterialTheme.colorScheme.secondary,
    )
)

If you use colorful = true, the rest of the palette is worth a look too β€” it's grouped so you can retint a whole painted scene a few slots at a time:

Block Slots What it paints
Ink ink, inkSoft, inkFaint Every outline, in both modes
Accents accent, accentGreen, accentBlue, accentRed Small coloured marks, in both modes
Light & atmosphere paper, sun, sunDeep, glow, sky, skyDeep, shade, shadeSoft Key light, bloom, shadows β€” colourful only
Materials wood, woodDark, leaf, leafDark, terracotta, clay, fabric, fabricDark, metal, metalDark, skin, skinDark, hair, coffee The surfaces themselves β€” colourful only

Overriding a material slot while a scene is colourless is harmless β€” it's simply never read.

An empty state, fully restyled

import com.sketchy.library.SketchyColors
import com.sketchy.library.emptystates.EmptyState
import com.sketchy.library.emptystates.SketchyEmptyState

SketchyEmptyState(
    state = EmptyState.NoInternet,
    colors = SketchyColors(
        ink = MaterialTheme.colorScheme.onSurface,
        accent = MaterialTheme.colorScheme.primary,
    ),
    illustrationSize = 180.dp,
    title = "You're offline",
    subtitle = "We'll sync everything as soon as you're back online.",
    titleStyle = MaterialTheme.typography.titleMedium,
    subtitleStyle = MaterialTheme.typography.bodyMedium,
)

Every knob β€” color, size, copy, typography β€” is an ordinary parameter with a sensible default. Omit title/subtitle entirely (pass null) for an icon-only illustration. SketchyColors is the same type for both catalogs, so one palette restyles your entire onboarding flow and empty-state set at once.

Catalog

Every entry below draws both ways β€” colourless by default, painted with colorful = true.

Featured illustrations (5)
Sketch Scene
Sketch.MorningCoffee A Slow Morning Coffee
Sketch.HomeWorkspace Your Workspace at Home
Sketch.GroceryRun The Weekly Grocery Run
Sketch.ReadingNook A Quiet Reading Corner
Sketch.RainyWindow Rainy Day Indoors
Onboarding illustrations (15)
Category Illustrations
Productivity Plan Every Task Β· Find Your Focus Β· Never Miss a Meeting Β· Capture Every Thought Β· Build Better Habits
Finance Track Every Expense Β· Watch Your Savings Grow
Fitness Train Anywhere, Anytime Β· See Your Progress
Food Delivery Order Your Favorites Β· Fast, Fresh Delivery
Travel Plan Your Perfect Trip Β· Explore The World
Music Your Soundtrack, Anywhere Β· Discover New Sounds
Empty states (20)
Category Empty states
Connectivity & Errors No Internet Β· Server Error Β· Sync Failed Β· Under Maintenance Β· Location Not Found
Content & Search No Results Β· No Data Β· No Comments Β· No Messages Β· Page Not Found (404)
Saved & Commerce Empty Cart Β· Empty Wishlist Β· No Favorites Β· No Bookmarks Β· No Downloads
Everyday & Productivity Empty Inbox Β· No Notifications Β· Empty Calendar Β· No Photos Β· All Done

Project structure

Sketchy/
β”œβ”€β”€ library/    # The published artifact β€” pure Compose, no app dependencies
β”‚   └── src/main/java/com/sketchy/library/
β”‚       β”œβ”€β”€ SketchyColors.kt           # Shared reskinnable palette (both catalogs)
β”‚       β”œβ”€β”€ SketchyStyle.kt            # Outlined vs. painted β€” how one scene renders both ways
β”‚       β”œβ”€β”€ illustrations/
β”‚       β”‚   β”œβ”€β”€ SketchyIllustrations.kt  # Sketch enum, SketchyIllustration composable
β”‚       β”‚   β”œβ”€β”€ Featured*.kt             # …the elaborate full scenes, one file each
β”‚       β”‚   └── Onboarding*.kt           # …grouped by category, 2-5 scenes each
β”‚       β”œβ”€β”€ emptystates/
β”‚       β”‚   β”œβ”€β”€ EmptyState.kt            # EmptyState enum, SketchyEmptyState composable
β”‚       β”‚   └── EmptyStates*.kt          # …grouped by category, 5 scenes each
β”‚       └── utils/
β”‚           β”œβ”€β”€ Extensions.kt            # DrawScope drawing extensions (stroke, sketchLine, …)
β”‚           β”œβ”€β”€ Painting.kt              # Fills, shading, brushes, limbs β€” the painted half
β”‚           └── Utils.kt                 # Ink/accent color constants, wave(), DesignSize
└── app/        # Demo app β€” searchable, categorized gallery of everything above

Contributing

New illustrations are very welcome. A new scene is just an internal DrawScope function plus one enum entry β€” no boilerplate beyond that:

  1. Pick a category (or propose a new one) and add an entry to the Sketch or EmptyState enum with its display copy and category.
  2. Write the scene as internal fun DrawScope.drawYourScene(t: Float, colors: SketchyStyle) in the matching illustrations/Onboarding*.kt or emptystates/EmptyStates*.kt file, reusing the shared extensions from utils/Extensions.kt (stroke, sketchLine, sketchCircle, twinkle, wave, groundHint/groundLine) for a consistent hand-drawn look β€” and always paint from colors.* (never the raw Ink/Accent constants in utils/Utils.kt) so the scene stays themeable.
  3. Wire it into the when dispatcher and open a PR.

Please keep new scenes framework-agnostic (no Material/Material3 imports inside :library) so the empty-state API stays usable in any design system.

License

Sketchy is available under the MIT License.

Muhammad Ali

Email Portfolio LinkedIn GitHub

❀️ Created with love by Muhammad Ali

"Empty screens deserve better than a spinner."

About

🎨 Hand-drawn, animated illustrations & empty states for Jetpack Compose β€” 35 scenes, pure Canvas, zero image assets, fully themeable.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages