Most mobile UI bugs ship because the developer only ever rendered the happy path. Generate Compose and SwiftUI previews for every state — loading, error, empty, RTL, dynamic type, dark mode — so verifying a screen means clicking through a preview gallery, not building the app six times.
Tier: Foundation · Workflow area: Mobile engineering & release
This playbook makes the state matrix a generated artifact: AI enumerates and writes the previews, you render and judge them, and the gallery becomes the screen's living spec.
Skip it for pure-logic changes with no visual surface, and for throwaway spikes that will not be reviewed.
@Preview rendering in Android Studio, or SwiftUI #Preview in Xcode's canvas. If previews are broken, fix that first — everything here depends on cheap rendering.PreviewData/fixtures file.Have AI enumerate the matrix before writing any preview. Enumeration is where humans under-count, so make it explicit:
Here is OrderHistoryScreen and its UiState. List every visually
distinct state a user could see. Cover: loading (first load and
pagination), error (retryable and fatal), empty, partial data,
longest realistic content, single item, and offline. Then cross with
presentation axes: dark mode, RTL, dynamic type at the largest
accessibility size, and smallest supported screen width.
Output a table: state x axis, marking which combinations matter.
Prune the table — you want the 10–20 combinations that can actually differ, not the full cross-product.
Generate the previews from the table. For Compose:
Write @Preview functions for each row of the approved table. Use
PreviewParameterProvider for the UiState variants. Use
@Preview(uiMode = UI_MODE_NIGHT_YES) for dark, locale = "ar" for RTL,
fontScale = 2f for large text, and device/widthDp for the small-width
case. Pull fixture data from PreviewData. One file:
OrderHistoryScreenPreviews.kt.
For SwiftUI, the same request maps to multiple #Preview blocks with .preferredColorScheme(.dark), .environment(\.layoutDirection, .rightToLeft), .environment(\.dynamicTypeSize, .accessibility3) and fixture-injected view models. In Android Studio you can also use the Gemini preview-generation assist on a composable and then ask for the missing variants — the assist gives you one preview; the matrix is what you add.
Render the gallery and actually look. Open the preview grid and inspect every cell for the classic failures: truncated text at large type, layouts that do not mirror in RTL, hardcoded white backgrounds in dark mode, empty states that render as a blank screen, spinners with no minimum height causing layout jumps. Fix in the component, not the preview.
Ask AI to critique the rendered states. Screenshot the grid (or individual odd cells) and feed it back:
Here is the preview grid for OrderHistoryScreen. Flag: text that
looks truncated or clipped, contrast problems in dark mode, spacing
that collapses at fontScale 2, and any state where a user would not
know what to do next. Rank by severity.
Multimodal critique catches things you scroll past; you still adjudicate every flag.
Commit the previews as the screen's spec and wire them forward. The preview file ships with the screen and is updated in the same PR as any state change. If you have screenshot testing (Paparazzi, Roborazzi, swift-snapshot-testing), point it at these same previews so the matrix becomes a CI regression net rather than a manual gallery.
The unit of review for a screen is the rendered state matrix, not the code diff. AI makes the matrix cheap to enumerate and generate; your job is the two minutes of actually looking at every cell.
#Preview variants directly in-file; the canvas's device and color-scheme toggles complement the coded variants."Test User" everywhere.Preview generation works entirely on code you paste, so a local model (Ollama/LM Studio) handles steps 1–2 acceptably — enumeration and preview boilerplate are not frontier-model problems. The multimodal critique in step 4 needs a vision-capable model; where screenshots cannot leave the machine, replace it with a manual checklist pass (truncation, contrast, RTL mirroring, tap-target size) over the same grid.
Preview screenshots of an unreleased product are still confidential product material — treat them with the same care as source when choosing which model sees them.