← showcases · case 03 · Rebuild · surface: mobile app (Compose)

pulse — whole screens, both modes, real ergonomics

A health app rebuilt as a system. Dark mode is a feature with its own measurements, not an inversion; every scene is a full 360×760 screen; states appear in the form they actually take; touch, safe-area, and type-scaling constraints are verified, not assumed.

6 whole screen scenes independent light / dark 48dp targets dynamic type 2.0× live probes

Context

Who: people checking a chronic condition several times a day, often at night. Jobs: see the current status, run a guided session, review a weekly report. Constraints: one hand, variable light, OS font scaling, two schemes that are both first-class. The system governs whole screens and states — component samples alone would hide how they meet on a phone.

Scheme: Annotations:

Scenes

Pan the strip. Six screens run real scenarios: status, an immersive session, a report, a whole-screen empty state, onboarding, and a stacked sheet.

9:41▮▮▮ ▾
TodayM
72
resting score · calm
6.4h
sleep
3
sessions
+4%
vs last week
Next
Evening breathing
21:30 · 10 min
Home — the first screen answers one question: “how am I today?” Status is color + number + word.
9:43▮▮▮ ▾
Evening breathing
4:12
in 4 · hold 4 · out 6

Leaving early is always allowed; the session is saved to history.

Immersive session — content centered, no navigation, one escape hatch. Never scrolled.
9:52▮▮▮ ▾
ReportWeek 37
Resting score
72 avg · improving
Insights
Sleep is the strongest factor
Sessions before 21:00 score 8% higher
Thursday is the dip
3 of the last 4 weeks
pattern
Report — data explains itself: label, chart, plain-language sentence.
10:04▮▮▮ ▾
Report

No sessions yet

A report needs at least three sessions. They take ten minutes and the first one counts tomorrow morning.

Whole-screen empty state — distinct from the inline placeholder shown in Components.
10:10▮▮▮ ▾

Three short sessions set your baseline

No account, no wearable. Everything stays on this phone unless you share it.

Onboarding — one idea per screen, progress visible, skip always available.
10:16▮▮▮ ▾
TodayM
Bottom sheet stacked on a real screen with a scrim — interruption in context, not a floating sample.

Typography and color

The system owns the face (SF Pro on iOS, Roboto on Android) and the app owns the scale. Color is two designed palettes with separate measurements — never one palette inverted.

72display 34/40 · hero numbers
Todaytitle 20/26 · screen titles
Evening breathingbody 15/22 · rows, actions
21:30 · 10 mincaption 12/16 · metadata
6.4h · 3 · +4%tabular numerals · statistics

Swatches follow the scheme switch above. Semantic colors (ok, warn, bad) follow the mode, never the scheme; chart colors are data, not decoration.

  • Text scales with the OS to 2.0×; layouts reflow instead of truncating meaning.
  • Weights carry hierarchy (700 title / 600 action / 400 body) — a second face is not the answer.

Components and states

Samples shrink to phone width rather than assuming a desktop canvas. States appear inline exactly where they occur.

Actions

All ≥ 48px tall; primary carries the accent, never two primaries.

Inline states

chart area · “3 more sessions needed”

Inline placeholder for a chart inside a populated screen — different from the whole-screen empty state.

Rows and pills

Evening breathing
21:30 · 10 min
10 min

Icon scale

Every inline SVG carries a default size and is overridden per context — 16/20/24/32/48/64.

Motion

TokenDurationUsed forNever
fast120 msstate change, pressed feedbackdata values
base200 mssheet and overlay entrancescrolling content
slow320 msscreen transitions, scene changeinterruptions
breathe6 s loopthe guided breathing paceanything not breathing
  • Discrete data changes discretely: a score, a count, a health state never tweens — it cuts.
  • Motion is reserved for guidance and transitions, so the breathing guide stays the loudest thing on screen.
  • Under prefers-reduced-motion transitions cross-fade, and the guide is a static ring.

Accessibility

Targets

Every control is at least 48×48 dp; primary actions sit in thumb reach. Toggle the annotations above to see the boxes.

Text scaling

System scaling to 2.0× with reflow, not truncation; the scenes above are the proof.

Not by color alone

Status is color + icon + word; the chart carries labels and a sentence, not only a hue.

Screen readers

Icon-only controls carry labels; overlays trap and restore focus; headings follow the reading order.

Contrast is measured per scheme in Verification — dark is not an inversion, so both tables must pass independently.

Ergonomics

Toggle annotations to see thumb targets and safe areas; switch type scale to stress the layout with OS font scaling.

Type scale:
  • Status bar and home indicator are reserved bands; the bottom bar never overlaps them.
  • Primary actions sit in thumb reach; destructive or rare actions stay out of it.
  • At 2.0× the screens reflow: tiles wrap, labels truncate with an ellipsis, buttons grow — nothing clips.
  • Motion budget: only the breathing guide animates, and it is static under prefers-reduced-motion.

Verification

Live probes

running…

Icon sizes, per-frame overflow, equal frame heights, and reduced-motion support are asserted on this page; resize the window to re-run the overflow probe.

Contrast, per scheme

Pairlightdark

Both schemes are measured independently; dark is a designed palette, not an inversion of light.