compose-preview-cli

module
v0.4.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 26, 2026 License: MIT

README

compose-preview

A terminal UI for browsing and running Jetpack Compose @Preview composables — without launching Android Studio.

Go License Platforms

The problem

You want to check a Compose preview. You open Android Studio. You wait 2 minutes for it to index. You navigate to the file. You wait for the preview to render. All that just to see a button in dark mode.

compose-preview scans your project for @Preview functions and lets you browse and launch them on a connected device — directly from the terminal, in seconds.

Screenshot

 Compose Preview Browser — umobKMP · Pixel_6a
 / Filter: login
╭ 1 Modules ──────────╮╭ 2 Previews (8) ──────────────────────╮╭ 3 Preview ─────────╮
│ ▸ :composeApp (0)    ││ ▸ LoginScreenEmptyDarkPreview        ││                     │
│   :feature:auth (8)  ││   LoginScreenEmptyLightPreview       ││   ┌───────────┐     │
│   :feature:booking   ││   LoginScreenFilledDarkPreview       ││   │           │     │
│     (0)              ││   LoginScreenLoadingDarkPreview      ││   │  preview  │     │
│   :feature:home (0)  ││   LoginScreenErrorDarkPreview        ││   │  image    │     │
│   :feature:map (0)   ││   LoginFormContentEmptyDarkPreview   ││   │           │     │
│   :feature:settings  ││   LoginFormContentFilledDarkPreview  ││   └───────────┘     │
│     (0)              ││   LoginFormContentLoadingDarkPreview ││                     │
│                      ││                                      ││ w for HD preview    │
│                      ││                                      ││   in browser        │
╰──────────────────────╯╰──────────────────────────────────────╯╰─────────────────────╯
╭ Details ────────────────────────────────────────────────────────────────────────────╮
│ FQN: com.example.feature.auth.LoginScreenPreviewKt.LoginScreenEmptyDarkPreview     │
│ File: feature/auth/src/androidMain/.../preview/LoginScreenPreview.kt:42            │
│ Params: showBackground=true, backgroundColor=0xFF111111                            │
╰─────────────────────────────────────────────────────────────────────────────────────╯
 ● Launched: LoginScreenEmptyDarkPreview (com.example.app.dev)
 enter run · s screenshot · f fullscreen · w web · i install · / filter · d device · x kill emu · q quit

What it does

  • Scan — Discovers all @Preview composables across all Gradle modules automatically
  • Browse — Navigate modules and previews in a three-panel TUI with keyboard and mouse
  • Search — Live filter bar (/) matches preview names across all modules, counts update in real time
  • Run — Launch any preview on a connected device via ADB with Enter
  • Screenshot — Capture a preview screenshot (s) displayed directly in the terminal
  • Fullscreen HD — Press f to view the screenshot fullscreen using your terminal's native graphics protocol (Kitty, iTerm2, WezTerm, Ghostty), navigate between previews with ↑/↓
  • Crash detection — Automatically detects when a preview crashes and shows the root cause error in the preview panel
  • HD Web Preview — Press w to open a local web viewer in your browser with full-quality preview rendering
  • Install — Trigger Gradle install tasks (i) with automatic variant detection (dev, qa, accept, production)
  • Device / Emulator picker — Press d to select a connected device or launch an AVD emulator, with optional fast mode (headless + Quick Boot)
  • Kill emulator — Press x to list running emulators and kill one (useful for headless emulators)
  • Details — See fully qualified name, file path, line number, and @Preview parameters
  • Composable count — Shows total @Composable functions per module, helping identify preview coverage gaps
  • Stale detection — Warns when source files are newer than the installed APK

Install

Homebrew (macOS & Linux)
brew tap ignaciotcrespo/tap
brew install compose-preview-cli
Go
go install github.com/ignaciotcrespo/compose-preview-cli/cmd/compose-preview@latest
Binary download

Grab the latest release from GitHub Releases.

Usage

# From your Android/KMP project directory:
compose-preview

# Or specify a path:
compose-preview /path/to/android/project

# Open HD web preview in browser:
compose-preview --web

# Web preview on a custom port (default: 9999):
compose-preview --web --port 8080

# List all previews as JSON (for scripting/CI):
compose-preview --list

# Run a specific preview on a connected device:
compose-preview --run SplashScreenPreview

# Take a screenshot of a preview (saves to preview.png):
compose-preview --screenshot SplashScreenPreview

# Custom output file and render delay (default: 1s):
compose-preview --screenshot SplashScreenPreview --output splash.png --delay 3

# Clear cached screenshots:
compose-preview --clear

# Dismiss "built for older Android" dialog automatically:
compose-preview --dismiss-dialog
Layout
┌──────────────────────────────────────────────────────────────────────────────┐
│ Compose Preview Browser — <project> · <device> (d to change)                │  header
├──────────────────────────────────────────────────────────────────────────────┤
│ / Press / to filter previews                                                │  search bar
├──────────────┬──────────────────────────┬────────────────────────────────────┤
│ 1 Modules    │ 2 Previews (88)          │ 3 Preview                         │
│              │                          │                                   │
│ ▸ :app (2)   │ ▸ AppAndroidPreview      │   ┌────────────┐                  │
│   :feature:  │   AppPreview             │   │  preview   │                  │
│     auth (30)│                          │   │  screenshot│  screenshot panel│
│   :feature:  │                          │   └────────────┘                  │
│     home (11)│                          │                                   │
│   ...        │                          │ w for HD preview in browser       │
├──────────────┴──────────────────────────┴────────────────────────────────────┤
│ Details                                                                      │
│ FQN: com.example.MainActivityKt.AppAndroidPreview                           │  details
│ File: composeApp/src/androidMain/.../MainActivity.kt:41                     │
├──────────────────────────────────────────────────────────────────────────────┤
│ ⚠ sources changed since last build — press 'i' to install                  │  status
├──────────────────────────────────────────────────────────────────────────────┤
│ enter run · s screenshot · f fullscreen · w web · i install · / filter · d device · x kill emu · q quit │  help
└──────────────────────────────────────────────────────────────────────────────┘
Key bindings
Key Action
/ Focus search bar — type to filter previews live
Tab Exit search / switch between Modules and Previews panels
Enter Run selected preview on device (auto-captures screenshot)
Esc Clear filter and exit search
j/k or ↑/↓ Navigate items in focused panel
s Capture screenshot of the selected preview
f Fullscreen HD preview with native terminal graphics — ↑/↓ to navigate between previews
w Toggle HD web preview viewer in browser
i Install APK via Gradle (auto-detects build variants)
d Open device / emulator picker (press f in picker to toggle fast mode)
x Open kill emulator picker — select a running emulator to stop it
R Refresh project scan
1 / 2 Focus Modules / Previews panel directly
q Quit
Mouse click Select item in any panel
Mouse wheel Scroll within panels
Search / Filter

Press / to activate the search bar. As you type, previews are filtered across all modules in real time:

 / Filter: dark█
╭ 1 Modules ─────────────╮╭ 2 Previews (23) ─────────────────────────────────╮
│ ▸ :feature:auth (12)    ││ ▸ LoginScreenEmptyDarkPreview (Login - Dark)     │
│   :feature:home (5)     ││   LoginScreenFilledDarkPreview (Login - Filled)  │
│   :feature:map (4)      ││   LoginScreenLoadingDarkPreview (Login - Loading)│
│   :feature:settings (2) ││   LoginScreenErrorDarkPreview (Login - Error)    │
│   :composeApp (0)       ││   ...                                            │
╰─────────────────────────╯╰──────────────────────────────────────────────────╯
 type to filter · tab panels · esc clear · enter confirm

Module counts update to show only matching previews. Press Tab to move to the panels with the filter active, or Esc to clear it.

Screenshots

Press s to capture a screenshot of the selected preview. The screenshot is rendered directly in the terminal using half-block characters. Screenshots are cached — a dot marker () next to a preview name indicates a cached screenshot.

Running a preview with Enter also auto-captures a screenshot after a short delay.

Press f to enter fullscreen HD mode using your terminal's native graphics protocol for pixel-perfect quality. Use ↑/↓ to navigate between previews — cached screenshots display instantly, uncached ones are captured on the fly. Supported terminals: Kitty, iTerm2, WezTerm, Ghostty. Other terminals fall back to half-block rendering. Press any other key to return to the TUI.

The --screenshot CLI command also displays the image inline using the native graphics protocol.

Crash detection

When a preview crashes on the device, the error is automatically detected from logcat and displayed in the preview panel with the root cause exception and source location. This replaces the blank/broken screenshot you would otherwise see.

HD Web Preview

The terminal screenshot is low resolution. For full-quality rendering, press w to start a local web viewer. This opens your browser with an HD version of the preview, served from a local web server. Press w again to stop the server.

Device / Emulator picker

Press d to open a modal listing connected devices and available AVD emulators. Select a device to target, or pick an emulator to launch it.

Press f inside the picker to toggle fast mode — launches the emulator headless (no window, no audio) with Quick Boot snapshots and host GPU acceleration. This is significantly faster than a cold boot and ideal for CI or when you don't need the emulator UI.

Kill emulator

Press x to open a modal listing all running emulators. Select one and press Enter to kill it. This is especially useful for headless emulators launched in fast mode, which have no window to close.

╭ Kill Emulator ───────────────────────╮
│ ▸ Pixel_6_API_34 (emulator-5554)     │
│   Pixel_7_API_35 (emulator-5556)     │
│ ↑↓ navigate · enter kill · esc cancel│
╰──────────────────────────────────────╯
Install variants

When you press i, compose-preview queries Gradle for all available install tasks. If your project has multiple build variants (dev, qa, accept, production), a picker modal appears:

╭ Select Install Task ─────────────╮
│ ▸ installDevDebug                │
│   installAcceptDebug             │
│   installQaDebug                 │
│   installProductionDebug         │
│ ↑↓ navigate · enter select · esc │
╰──────────────────────────────────╯

Select a task with Enter. The choice is remembered for subsequent installs.

Requirements

  • ADB on your PATH (from Android SDK platform-tools)
  • A connected Android device or emulator
  • The debug APK must be installed on the device (use b to build+install)
  • androidx.compose.ui:ui-tooling as a debugImplementation dependency in your app module:
// In your app's build.gradle.kts
debugImplementation("androidx.compose.ui:ui-tooling")

How it works

  1. Discover — Walks your Gradle project to find modules via build.gradle.kts files
  2. Scan — Parses .kt files for @Preview annotations using regex (fast, no compilation needed)
  3. Resolve — Extracts package name, JVM class name (FileNameKt), function name, and preview parameters
  4. Launch — Sends adb shell am start -W with the composable FQN to PreviewActivity (waits for Activity to be displayed)
  5. Detect — Auto-discovers the installed app package, trying all flavor variants

Works with both pure Android and Kotlin Multiplatform (KMP) projects.

Supported project structures

  • Single-module Android projects
  • Multi-module Android projects with feature modules
  • Kotlin Multiplatform (KMP) projects with composeApp module
  • Projects with product flavors (dev, qa, staging, production, etc.)
  • Projects using applicationId, namespace, or both

License

MIT

Directories

Path Synopsis
cmd
compose-preview command
internal
adb
server
Package server provides a localhost HTTP server that embeds the TUI in a browser via xterm.js + WebSocket, with a live preview image panel.
Package server provides a localhost HTTP server that embeds the TUI in a browser via xterm.js + WebSocket, with a live preview image panel.
types
Package types defines shared enums used across layers.
Package types defines shared enums used across layers.
ui
ui/imgrender
Package imgrender renders images in terminal cells.
Package imgrender renders images in terminal cells.
ui/screenshot
Package screenshot manages a disk-backed cache of device screenshots keyed by composable FQN.
Package screenshot manages a disk-backed cache of device screenshots keyed by composable FQN.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL