Privacy-Period-Tracker/docs/design/dist/README.md

146 lines
7.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Onboarding illustrations — the decided direction
```
Status: Current
Owner: _null
Last reviewed: 2026-08-18
Governs: docs/design/dist/** — the onboarding illustration set and what it is for
Review trigger: Any illustration added or replaced here; the onboarding artwork
in issue #29 landing in the app
```
> **References, not shipping assets.** Nothing in this folder goes in the APK.
> These are the decided direction for onboarding, drawn from
> [`../BRAND_GUIDE.md`](../BRAND_GUIDE.md) §22's master prompt. The vectors that
> eventually ship are drawn *from* these.
Seven illustrations in a matched light/dark pair, named for the composables they
replace in
[`../../../core/designsystem/src/main/kotlin/dev/privacyllc/period/designsystem/art/Illustrations.kt`](../../../core/designsystem/src/main/kotlin/dev/privacyllc/period/designsystem/art/Illustrations.kt):
| File stem | Onboarding step | Composable |
| --- | --- | --- |
| `01_WelcomeIllustration` | 1 Welcome | `WelcomeIllustration` |
| `02_LastPeriodIllustration` | 2 Last period start | *new* |
| `03_PeriodEndIllustration` | 3 Period end | *new* |
| `04_LearningIllustration` | 4 Previous history | `LearningIllustration` |
| `05_PrivacyIllustration` | 5 Privacy promise | `PrivacyIllustration` |
| `06_NotificationPrivacyIllustration` | 6 Reminder privacy | *new* |
| `07_ForecastIllustration` | 7 First forecast | *new* |
| `EmptyStateIllustration` | — not onboarding | `EmptyStateIllustration` |
Each stem exists as `Light/<stem>_light.webp` and `Dark/<stem>_dark.webp`, at
the **same aspect ratio**, so a theme switch swaps the image without moving the
layout. Fifteen are 2048 × 1365; `07_Forecast` dark is 1536 × 1024, which is the
same 3:2 to within 0.02% — 274.00 dp tall against 273.93 at a 411 dp hero.
**They are 3:2 landscape, composed for a full-bleed hero.** That is the second
attempt. The first delivery met the canvas size by upscaling the old portrait
art ~2.8× and padding the sides with a blurred copy of itself: measured edge
detail fell 2.1×8.8× in the outer quarters on 15 of 16 files, and at real hero
size a hard seam showed around the sharp centre. The canvas was right and the
composition was still portrait.
The set here is natively wide — real painted content to all four edges, verified
by measuring detail across each image and looking for a step change that would
betray a pasted rectangle. None has one.
`EmptyStateIllustration` is the odd one and deliberately unnumbered: it is
Today's "nothing logged yet" state, not an onboarding step, and it is also drawn
in the onboarding previews. Its ring is empty because nothing has been logged —
the same ring the other illustrations fill with cycle-day markers, which is what
makes the empty state read as *waiting* rather than *broken*.
## What these got right, and why it is worth not undoing
Each of these was a correction during review, and every one of them would be easy
to reintroduce by regenerating carelessly:
- **No text of any kind is painted into the pixels.** The app renders all seven
titles and subtitles itself through `Heading(...)` in `OnboardingScreen.kt`.
Art carrying its own title prints every heading twice, cannot be translated,
cannot scale with the user's font size, and is invisible to TalkBack.
- **No step-number badge.** `LearningIllustration` is not only onboarding step 4
— it is also the Insights empty state, where a "4" means nothing. Baked numbers
also freeze the running order, and this flow has already changed shape once. A
step indicator, if wanted, belongs in live UI where TalkBack can read it.
- **`07_Forecast` shows a calendar and a cycle arc, and names no fields.** An
earlier draft drew a forecast panel listing *Fertile window* and *Ovulation*,
which the real first-forecast screen deliberately does not show — on a fresh
install it reports confidence Low and Today reads "Not enough history to
estimate". A later draft named the correct fields but painted *Confidence —
Low* permanently, which is wrong for anyone with a settled cycle. Naming
nothing is the only version that cannot contradict the live forecast.
- **The dark set is a real dark composition**, not the light one dimmed — the
midnight-plum ground `BRAND_GUIDE.md` §22 specifies.
## These now ship
**#29 is closed.** All eight are in the app, in both themes, as WebP drawables in
[`../../../core/designsystem/src/main/res/`](../../../core/designsystem/src/main/res/)
`drawable/` for light and `drawable-night/` for dark, so Android resolves the
theme rather than any code of ours. The files here stay as the full-resolution
sources; the shipped copies are downscaled to the height they are actually drawn
at.
They are **not** redrawn as vectors, which is what #29 originally called for.
That was the right plan for artwork that did not exist and the wrong one for
gradient landscapes: there is no honest `VectorDrawable` of one, §42 objects only
to *unnecessary* raster, and the whole set costs 130 KB of the release APK.
`CycleMarkers.kt` keeps its vectors, because a marker's shape carries meaning and
the progress arc is drawn from the user's own cycle.
**The painted-in corners needed clipping.** Each drawing is composed as a card
with its own rounded corner, so the pixels outside that curve are the card's own
backdrop — near-black in the dark set, near-white in the light one. Drawn
unclipped they showed as four notches against the app background: obvious on a
device, invisible in code review. `Illustration` in `Illustrations.kt` clips just
inside the painted curve, and what is left reads as a deliberate rounded card.
## `splash.webp` — the redrawn lockup
Not an onboarding illustration, and it sits here because it arrived with them.
It is the full brand lockup — emblem, wordmark, divider, tagline — and it is the
artwork that closed **#28**: the first lockup set the name as
*Privacy:Period Tracker* with no space after the colon, disagreeing with
`app_full_name` and with every document.
`../../data/img/logo.webp` and `banner.webp` are generated from it:
```bash
magick splash.webp -trim +repage -resize 900x900 lockup.png
magick -size 1024x1024 xc:'#F0E6F0' -fill '#FAF0F5' \
-draw 'roundrectangle 8,8,1015,1015,88,88' \
lockup.png -gravity center -composite -quality 86 logo.webp
```
The banner is the same recipe on a 2176×725 canvas with a 660px square card
centred. **It is composed, never cropped** — the lockup is square and a 3:1 crop
takes the wordmark's ends off, which is the trap the first pass at these assets
hit.
No flood-fill this time: `splash.webp` has real transparency, where the earlier
sources rendered their rounded corners against black.
## Format
WebP at the delivered resolution — 4.2 MB for all sixteen, and the same format
[`../../data/img/`](../../data/img/) uses for the marks privacyllc.dev renders.
The delivery `.zip` archives are deliberately not tracked; see
[`.gitignore`](.gitignore).
**These are sources, not shipping assets, and the size is why that matters.** A
2048 px file dropped into a density-less `drawable/` is decoded at the device's
bucket and costs ~11 MB of heap on every device. The shipped copies are
downscaled into `drawable-*dpi` buckets — see the KDoc in `Illustrations.kt`.
## Two things left unmatched, deliberately
- **`07_Forecast` light and dark are different compositions.** Light draws a
partial ring of hollow beads; dark draws a full arc of dashed circles ending
in an arrow. Dark states "predicted" more clearly, so it is the one to copy if
they are ever reconciled — not the other way round.
- **Eight of the sixteen have a busy bottom quarter**, mostly the dark set,
where foliage and water reach into the band the fade covers. The fade still
works; it simply covers more drawing than intended.