Documentation
Preview Screenshot
HotSwan includes a captureAllPreviews Gradle task that automatically finds every @Preview function in your project, launches each one on a real device, captures a screenshot, and generates a browsable HTML catalog. No test code to write. Just run the task and share the result.
Screenshot testing requires the Preview Runner setup. If you have not configured it yet, follow the Preview Runner Setup guide first.
Capture All Previews
./gradlew captureAllPreviewsThe task scans all .kt files under src/, detects @Preview annotations, and launches each composable on the connected device one by one. After all captures complete, an index.html file is generated in the default output directory: .hotswan/preview-captures/
HTML Catalog Features
The generated HTML catalog is a self-contained file you can open in any browser, share with your team, or host as documentation.
Dark / Light theme
Toggle between dark and light mode. Dark mode is the default.
Search
Filter previews by name or module with instant search.
Module grouping
Previews are grouped by Gradle module. Toggle grouping on or off with a single click.
Fullscreen modal
Click any preview screenshot to view it at full resolution in an overlay modal.
Device & timestamp info
Each report includes the device model, app package name, and generation timestamp.
Gradle Configuration
HotSwan provides a preview configuration block inside hotSwanCompiler for customizing the preview capture behavior:
hotSwanCompiler {
preview {
// Output directory for captured previews (relative to project root)
outputDir.set(".hotswan/preview-captures")
// Delay between launching a preview and capturing its screenshot
renderDelayMs.set(2500L)
// Enable SDK documentation mode for rich API docs
sdkModeEnabled.set(false)
}
}outputDir
Directory where preview screenshots and the HTML catalog are saved. Relative to the project root. Default: .hotswan/preview-captures.
renderDelayMs
Milliseconds to wait after launching a preview before taking the screenshot. Increase this for composables that load data asynchronously. Default: 2500.
sdkModeEnabled
When enabled, the HTML catalog includes KDoc descriptions and parameter tables extracted from the composable that each preview wraps. Ideal for design system libraries. Default: false.
Per-Preview Render Delay
Some previews need more time than others. A simple static layout is ready in under a second, but a composable that loads a network image may need several seconds. Instead of raising the global delay for every preview, you can use @PreviewScreenshot to set a delay per preview.
@Preview
@PreviewScreenshot(renderDelay = 5000)
@Composable
fun NetworkImagePreview() {
AsyncImage(
model = "https://example.com/photo.jpg",
contentDescription = null,
)
}Previews without @PreviewScreenshot use the global renderDelayMs value. Previews with the annotation use the specified delay instead. This keeps fast previews fast while giving slow ones the time they need.
@PreviewScreenshot
renderDelay — Milliseconds to wait before capturing. Overrides the global renderDelayMs.SDK Documentation Mode
For design system and library/SDK developers, enable sdkModeEnabled to generate rich API documentation alongside your preview screenshots. HotSwan traces each @Preview function to find the composable it wraps, then extracts the KDoc description, parameter names, types, and default values.
hotSwanCompiler {
preview {
sdkModeEnabled.set(true)
renderDelayMs.set(3000L)
}
}With SDK mode enabled, each card in the HTML catalog shows:
- ✓Composable name chip: the actual composable being previewed (not the preview wrapper function)
- ✓KDoc description: extracted from the composable's documentation comment
- ✓Parameter table: name, type, default value, and
@paramdescriptions - ✓Collapsible parameters: composables with more than 5 parameters show an expand/collapse toggle
This replaces the need for separate tools like Showkase or manual component documentation. Run captureAllPreviews in CI to automatically generate and publish your component catalog on every pull request.
CI Integration
Because captureAllPreviews is a standard Gradle task that uses ADB, it works in any CI environment that provides an Android emulator. GitHub Actions with reactivecircus/android-emulator-runner is the simplest setup:
- name: Run emulator and capture screenshots
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 31
arch: x86_64
profile: pixel_6
script: |
adb install -r app/build/outputs/apk/debug/app-debug.apk
adb shell am start -n com.your.app/.MainActivity
sleep 10
./gradlew :app:captureAllPreviewsThe captured screenshots can be uploaded as build artifacts or deployed directly to GitHub Pages to create a living component catalog that updates on every push.
Comparison with other tools
Tools like Paparazzi and Roborazzi take a different approach to composable screenshot capture. They render composables on the host JVM using a layout rendering engine, which means they run without a device or emulator. This makes them well suited for fast regression testing in CI.
HotSwan captures screenshots on a real device or emulator. This gives you the actual rendering your users will see, including system UI, font rendering, and device specific behavior.
| HotSwan | Paparazzi / Roborazzi | |
|---|---|---|
| Rendering | Real device or emulator | Host JVM approximation |
| System UI | Included (status bar, navigation bar) | Not included |
| Runtime behavior | Full (image loading, network, database) | UI shell only |
| Test code required | None. Scans @Preview automatically | Test class per composable |
| Output | Image files + searchable HTML catalog with module grouping | Image files |
| SDK documentation | KDoc + parameter table extraction | Not available |
| CI integration | Emulator required (GitHub Actions supported) | No emulator needed |
The two approaches are complementary. Paparazzi and Roborazzi are focused on regression testing with golden image comparison. HotSwan is focused on visual cataloging and documentation, with screenshots that reflect actual device behavior. You can use both in the same project for different purposes.