Trepo Android — UI density audit

All 56 captured screens measured · build from 2026-09-02 · SM-A366U, 590×1280

The observation holds, and it is measurable. The problem is not that screens carry too many features — it is that every element is sized as if it were the only thing on screen. The result is simultaneously too dense (nothing fits) and too empty (median 21% of each screen is void). Those are the same bug seen from two sides.
Correction, 16:35. The first version of this page listed a finding “content is clipped mid-word in three places”. That was wrong and has been withdrawn. I read three ordinary mid-scroll screenshots as clipping defects. Checked on the handset and in source: the LIST suggestion chips are a deliberate horizontal strip with a 32 dp fade ramp ported from ContentView.swift:522; the KITCHEN item sheet is a scrolling column with a 24 dp bottom margin; and the LIST scrolls cleanly to its last row with a gap above the composer. None of the three is a bug. Finding 3 below is its verified replacement, driven on the device.
21%median dead space
26.8%mean dead space
16screens >45% empty
48pxtab title cap height
2.5×title scale spread
~30%of screen is content

Shipped — before / after

Both changes are committed and running on the handset (48b15583, built and installed on RFCY322W52W). Full unit suite 2,847 green, 13 of them new. Nothing was written to the live shopping list — the planners are pure, so the wiring was exercised in tests rather than against the household.
Correction on my own estimate. I said the title change would buy ~90px. Measured on the device by aligning the before/after captures, it buys exactly 33px on all four tabs — 2.9% of the usable screen, not 8%. The 90px came from measuring the title’s ink and assuming the padding around it would collapse too; it does not. The change is still worth having and it puts the code back in agreement with spec/DESIGN_SYSTEM.md, but it is a third of what I promised, and the density problem is not mostly the title.

1 · Screen titles: 44sp → 28sp

LIST

list before
BEFORE · title 44sp
list after
AFTER · title 28sp · +33px

KITCHEN

kitchen before
BEFORE · title 44sp
kitchen after
AFTER · title 28sp · +33px

COOK

cook before
BEFORE · title 44sp
cook after
AFTER · title 28sp · +33px

DISH LOG

dishlog before
BEFORE · title 44sp
dishlog after
AFTER · title 28sp · +33px

2 · Shopping rows carry the buyable name

Not photographable as a before/after — the fix changes rows written from now on, and the fat rows already on the list keep the names they were saved with. So it is pinned by test instead, against the exact Honey Garlic Shrimp lines that produced them:

Recipe line (before)Shopping row (after)
1/3 cup honeyhoney
1/4 cup soy sauce (we usually use reduced sodium)soy sauce
2 garlic cloves, minced (or 1 teaspoon jarred minced garlic)garlic cloves
optional: 1 teaspoon minced fresh gingerfresh ginger
optional for garnish: chopped green oniongreen onion
1 lb medium shrimp, peeledshrimp size dropped — known, pinned
1 tablespoon olive oilskipped — pantry staple, unchanged

Longest row goes from 60 characters to 13. The correctness half is pinned too: a list already holding “Soy Sauce” now suppresses the verbose duplicate, which it did not before. What it deliberately does not do is reduce “garlic cloves” to “garlic” — that needs a noun-head model, and getting it wrong puts someone in a shop holding the wrong thing.

Findings — ranked

CRITICAL

1The screen is mostly furniture, not content

On a 1280 px screen, the four main tabs give the user's actual data a window of roughly 350–400 px. Everything else is permanent chrome.

KITCHEN spends ~1000 px of chrome to show one category card. COOK has 8 saved recipes and shows one. LIST has 10 items and shows two and a half — the third row is sliced in half by the composer. The content window is ~30% of the display; the other 70% is header, title, search, filters, composer and nav.

kitchen-01-main
kitchen-01-main1 item → ~200px of content 16.1% dead
cook-01-recipes
cook-01-recipes8 saved → 1 visible 25.9% dead
list-01-populated
list-01-populated10 items → 2.5 visible, 3rd guillotined 4.8% dead

Fix · Collapse the header on scroll, and drop the persistent composer to a single FAB action.

CRITICAL

2Three title scales — and the spec and the code disagree

Tab titles render at a 48 px cap height. PAIR HALO is 32 px. PROFILE is 19 px. Same app, 2.5× spread.

“KITCHEN”, “LIST” and “COOK” are set in all-caps extra-bold at 48 px cap height and consume ~90 px including padding — to repeat a word the highlighted nav tab already says. This is the single cheapest ~90 px on every primary screen. That the app already ships a 19 px title on PROFILE shows the big one is not a system, it is just big.

kitchen-01-main
kitchen-01-mainKITCHEN — 48px cap 16.1% dead
chrome-03-profile-scrolled
chrome-03-profile-scrolledPROFILE — 19px cap 31.0% dead

Fix · Matt’s call, not a bug. 44sp is a deliberate iOS parity port (Theme.kt:TrepoScreenTitle, citing .font(.system(size: 44, weight: .black))) — but spec/DESIGN_SYSTEM.md:50 says “screen titles: ~28sp”. One of them is wrong. Shrinking to 28sp buys ~90 px on every primary screen and restores the spec, at the cost of deviating from iOS.

CRITICAL

3The list stores raw recipe ingredient lines as item names

A row reads “2 garlic cloves, minced (or 1 teaspoon jarred minced garlic)”. It renders 135 px tall against 41 px for a normal item — 3.3× — and is still truncated.

ADD MISSING TO LIST writes recipe.ingredients through to the row name verbatim (MealListPlanner.ktPlannedItem(name)); nothing extracts the product from the measurement and prep note. Four consecutive rows on the live handset read “1/4 cup soy sauce (we usually use reduced so…”, “2 garlic cloves, minced (or 1 teaspoon jarred…”, “optional for garnish: chopped green onion”, “optional: 1 teaspoon minced fresh ginger”. You do not buy “optional: 1 teaspoon minced fresh ginger” — you buy ginger. Same root cause breaks correctness: the planner's own comment concedes the kitchen check “will not catch ‘2 cloves garlic’ against a kitchen row named ‘Garlic’”, so verbose names also defeat the de-duplication and put things on the list you already own. It is not confined to LIST. On COOK / EXPLORE the same array is joined with bullets and used as the recipe card’s subtitle — “1/3 cup honey • 1/4 cup soy sauce (we usually use reduced sodium) • 2 garlic cloves, minced (or 1 teasp…” — two lines of measurements where a subtitle should carry time, servings or a description. Same array, same verbatim reuse, second surface.

live-list-ingredients
live-list-ingredientslive handset — 4 ingredient rows, 2 truncated
cook-03-explore
cook-03-exploresame strings as a recipe card subtitle 8.6% dead

Fix · Extract the product from the ingredient line before it becomes a row name; keep the full line as secondary text if it is worth showing at all. This is an iOS port, so it needs the same fix on both arms.

HIGH

10The app already contains its own fix, three times over

The density problem is not a missing capability. Trepo already ships a compact, well-proportioned answer for each of its worst screens — on a neighbouring screen.

EXPLORE vs RECIPES, same tab: EXPLORE drops the composer, leads with the photo and runs 8.6% dead; RECIPES keeps the composer, shows one small card and runs 25.9% dead. The kitchen row vs the item sheet: the category modal says everything worth knowing about a lemon — emoji, name, “2 count · Fridge”, “1d old”, Rename, Remove — in about 90 px; the item detail screen spends a ~320 px emoji hero to say less. PAIR HALO vs the main tabs: a 32 px title, one card, one action, no composer — it is the best-composed surface in the app. So this is not a redesign. It is applying the app’s own better pattern to the four screens that do not use it.

cook-03-explore
cook-03-exploreEXPLORE — 8.6% dead, image-forward 8.6% dead
cook-01-recipes
cook-01-recipesRECIPES — 25.9% dead, one card 25.9% dead
kitchen-04-category
kitchen-04-categorythe compact kitchen row, ~90px 4.8% dead
halo-01-pairing
halo-01-pairingPAIR HALO — one card, one action 45.1% dead

Fix · Port EXPLORE’s composition to RECIPES, and the category modal’s row to the item sheet. No new design language required.

HIGH

4Sixteen screens are more than 45% empty

Across all 56 captures, median dead space is 21% and mean is 26.8%. The worst are near two-thirds void.

Sign-in, every Halo pairing step, and the camera-permission screens cluster their content in the top third and leave a 500–625 px void beneath. The content is not too big for the screen here — it is stranded at the top of it. Same root cause as the density complaint: a layout system that top-aligns everything and never centres or fills.

auth-01-signin
auth-01-signin62.4% dead — 578px void 62.4% dead
halo-09-prov-00
halo-09-prov-0063.7% dead — 625px void 63.7% dead
halo-03-scanning
halo-03-scanning60.7% dead — 591px void 60.7% dead

Fix · Vertically centre single-purpose screens; the pairing card should sit at optical centre, not pinned under the header.

HIGH

5Three competing ways to add an item, all on screen at once

A text field, a full-width primary button, and a floating + — simultaneously, on every tab.

The composer stack is ~155 px, the nav is ~110 px, and the red + FAB overlaps both. That is ~265 px (21% of the display) permanently reserved for one job, presented three ways. On KITCHEN the same band also carries CLEAN and CLEAR ALL as equal-weight full-width buttons — a destructive action given the same visual authority as the primary one, parked above the fold.

kitchen-01-main
kitchen-01-mainCLEAN + CLEAR ALL + composer + FAB 16.1% dead
cook-01-recipes
cook-01-recipesPHOTOS + SAVE RECIPE + composer + FAB 25.9% dead

Fix · Keep the FAB, drop the persistent composer to a sheet it opens. Demote CLEAR ALL to the overflow menu.

HIGH

6Detail sheets bury the thing you opened them for

On the recipe sheet, INGREDIENTS starts 78% of the way down. You see 1.5 lines of the first one.

A 3-line title at display size, a RECIPE badge, a byline, ADD MISSING TO LIST and a HAVE 5/7 banner all land before any ingredient. The KITCHEN item sheet is the same shape: a ~320 px emoji hero, a name, a 4-line prose paragraph and a best-within line before QUANTITY at y 985 — the controls you came to use start ~77% down.

cook-06-recipe-detail
cook-06-recipe-detailingredients begin at 78% depth 0.0% dead
kitchen-06-item-detail
kitchen-06-item-detail~320px emoji hero, controls at 77% 24.3% dead

Fix · Shrink the hero to a 96 px thumbnail, put title+meta on one row, and let content start in the top third.

MEDIUM

7Zero states get hero treatment

Dish Log spends ~420 px rendering four zeros.

A calorie ring, three macro tiles and an empty-state card all render at full size to say “nothing logged”. “You’re all clean!” takes a whole modal (56% of it empty) for a message that is a snackbar. Empty states should shrink, not occupy the same footprint as populated ones.

dish-02-scrolled
dish-02-scrolled420px to display 0/0g/0g/0g 19.6% dead
kitchen-03-clean
kitchen-03-cleanfull modal, 56% dead 56.2% dead

Fix · Collapse the macro row to a single line when all values are zero; make “all clean” a snackbar.

MEDIUM

8Heavy borders and hard shadows multiply the weight

Every card carries a ~3 px black border plus an offset hard shadow.

The treatment is consistent and it is part of the brand, but it is applied at the same weight to a 700 px hero card and a 40 px chip. At small sizes the border is a large fraction of the element, which is a real contributor to “everything looks too large” even where the box is not.

dish-02-scrolled
dish-02-scrolledborder weight constant across scales 19.6% dead
list-01-populated
list-01-populated3px border on 40px chips 4.8% dead

Fix · Scale border weight with element size — 3 px on heroes, 1.5 px below ~64 px.

MEDIUM

9Small correctness bugs the audit surfaced

Three that are cheap to fix and read as sloppiness.

1 days in the kitchen” — unpluralised. The sign-in phone field renders a red error border in its resting empty state, before the user has typed anything. The Profile founder letter is ~450 px of prose (39% of the screen) below the settings cards.

kitchen-06-item-detail
kitchen-06-item-detail“1 days in the kitchen” 24.3% dead
auth-01-signin
auth-01-signinred error border, untouched field 62.4% dead
chrome-03-profile-scrolled
chrome-03-profile-scrolled450px founder letter 31.0% dead

Fix · Pluralise; make the field border neutral until validation fails; move the letter behind an About row.

Full census — all 56 screens by dead space

ScreenDead Dead pxVoids Largest
capture-02-denied65.5%7507364px
halo-09-prov-0063.7%7293625px
auth-01-signin62.4%7143578px
halo-03-scanning60.7%6953591px
halo-05-empty-scan59.5%6813577px
capture-03-voicetext59.3%6794572px
kitchen-03-clean56.2%6447321px
halo-02-connecting55.9%6403536px
halo-01-joining-ap53.1%6083504px
halo-07-manual-ssid53.1%6083504px
auth-03-code53.0%6074432px
halo-14-failed-retry49.3%5643468px
halo-10-prov-2348.9%5603456px
halo-11-success47.4%5432483px
halo-15-failed-noretry47.2%5403445px
halo-01-pairing45.1%5163412px
err-05-dishlog-offline38.3%4396165px
halo-08-credentials37.0%4243320px
chrome-03-profile-scrolled31.0%3551064px
capture-01-permission29.1%3335185px
chrome-04-thyme26.0%2986104px
cook-01-recipes25.9%2974211px
halo-04-select-network24.7%2833179px
halo-06-refreshing24.7%2833179px
kitchen-06-item-detail24.3%278849px
auth-02-phone-filled23.3%2674108px
kitchen-05-search-miss23.1%2645134px
chrome-05-profile-halo22.4%257842px
chrome-02-profile19.7%226660px
dish-02-scrolled19.6%2243158px
kitchen-07-item-detail-scrolled19.2%220667px
kitchen-02-timeline19.0%217589px
chrome-01-help18.8%215647px
halo-12-manual-join17.7%203399px
err-04-cook-offline16.9%1934107px
chrome-08-account-actions16.7%191642px
chrome-07-feedback16.2%185556px
kitchen-01-main16.1%184559px
kitchen-08-item-actions15.5%177550px
chrome-09-logout-confirm14.2%163542px
halo-13-manual-idle13.4%153367px
chrome-06-notif-priming11.7%134355px
dish-01-empty10.2%117439px
err-03-kitchen-offline8.7%100348px
cook-03-explore8.6%98343px
auth-04-signed-in4.8%55229px
cook-02-thisweek4.8%55229px
kitchen-04-category4.8%55228px
list-01-populated4.8%55229px
list-02-composer4.4%50150px
err-01-list-offline2.5%29129px
err-02-list-dismissed2.5%29129px
cook-06-recipe-detail0.0%000px
cook-07-recipe-ingredients0.0%000px
cook-08-recipe-steps0.0%000px
halo-00-devpicker0.0%000px