Graduate thesis · 2026
Fresh Greens
A wayfinding app for Black drivers in America, built solo for my grad thesis. Most navigation weighs time and distance. Fresh Greens weighs safety too, and it treats what a driver knows about a road as seriously as the official map data. Six interviews shaped what it looks for.

- Problem
- Navigation weighs time and distance, not what a driver knows about a road's safety.
- Role
- Solo, design and engineering
- Timeline
- Sep 2025 – Jun 2026
- Stack
- React Native, Expo, TypeScript, Supabase
- Outcome
- 26+ screens shipped, held to a reserved-color rule
Key moves
- Ran community safety reports through the same pipeline as OpenStreetMap, DOT-511, OSRM, and SunCalc, weighted the same way.
- Built the en-route screen around one-thumb reach: turn card, 3D map, and a safety column.
- Shaped the routing signals from six driver interviews.
The problem I set out to solve.
The Green Book was a routing system built on community knowledge, because no institutional one existed.
For a Black driver, a route isn't only time and distance. It's whether the roads are lit, whether a town feels safe to stop in, where police tend to sit. Nav apps don't weigh any of that. Fresh Greens brings that kind of knowledge back into the route.
Listening to six drivers.
Six interviews with Black drivers across the Southern US, anonymized in synthesis and led with joy and fear before any product questions. The timeline was tight, so the synthesis stayed lean: I pulled the recurring trends into four routing markers.
Moments of joy and fear have a lasting effect on how Black drivers interpret the spaces they inhabit. They stick.
Light
6/6
People time trips around daylight and read lighting as safety. It came up in every interview.
- Always leaving in the morning.
- I wouldn't feel comfortable driving at night.
- The street lights were sparse.
Police presence
5/6
Police proximity is a live fear, managed with behaviors taught by family and community.
- Biggest fear is interacting with police.
- If the app said there's cops here, we're going around that.
- Wallet out, phone out, everything visible.
Wildlife
3/6
Deer at dusk reroute people off certain roads after dark.
- Deer at night, so I'd avoid those roads once evening hit.
- Deer-heavy areas.
Road conditions
5/6
Road size, quality, and flooding change the route people are willing to take.
- Narrow backroads that can't fit two cars.
- A lot of places get flooded.
- I cared about road size and road quality.
Community knowledge
Drivers trust people over institutions. That is why community reports carry real weight in the routing, not a footnote next to the official data.
- I'd listen to family over the statistic. The powers that be aren't honest.
- For a new area, I'd ask friends who'd been there.
- I'd call someone who's already at the spot.
They asked for it, unprompted
- “Show the gradient of light, bright where you are and dark where you arrive. Your projected light coverage.”The daylight-graded route.
- “Poor road conditions highlighted along the route.”The road-conditions marker.
- “If the app said there's cops here, we're going around that.”Police presence in the route score.
My first instinct was to stack every safety layer onto the screen. But the interviews also said driving already takes focus, so I pulled most of it back. The safety toolkit stays hidden until a driver reaches for it.
Turning the interviews into a scoring system.
Community reports and public data share one adapter and one scoring function, with a single audit trail behind both.
Every route is scored on four things the interviews kept raising: light, police presence, wildlife, and road conditions. A community report feeds those same four markers. It's weighted exactly like the data from OpenStreetMap or SunCalc and runs through the same pipeline as everything else. Each score carries its source, so a driver can see whether a segment scored low from the sun angle or from a report.
The en-route screen is where it all lands: a turn card, a 3D map that drags with the drive, and a safety column within thumb's reach.
Designing for the pulled-over moment.
The interface asks before it assumes, so a driver stays in control under pressure.
Every prompt in a safety moment is set in Libre Franklin Regular, not Bold. The safety modal asks "What's going on?" The share sheet asks "What's the situation?" A driver who just got pulled over doesn't need "REPORT INCIDENT" shouted at them in a heavier weight than their own thoughts.
That came from the interviews too. People said the moments the app matters most call for a companion. So Bold appears only on facts the app is sure of, like ETA and the /emergency countdown.
/safety opens on the driver's own question./pulled-over opens on reassurance in the reserved serif, one of the six emotional moments the app spends it on. Recording has already started, quietly.The other safety surfaces (/roadside, /unfamiliar, /share-location, /emergency) use the same voice, each a first-class route that works with no signal.
The direction I tried first.
The first pass was a Google Maps feature.
First pass
At first I imagined Fresh Greens as a feature inside Google Maps, so v1 wore Google's turn banner and map chrome, with my safety controls down the side. That moved fast, and it capped the whole idea at Google Maps with a safety layer bolted on.
The break
Rebuilding it as its own app is what let the safety signals become the interface. The route preview grades the road by daylight, reads safety at a glance, flags a station you trust, and carries its own glyphs on the warm surfaces.
Choosing type and color.
Warm surfaces and a reserved serif give type and color a job at each phase of a trip.
I swapped iOS's cool grays for five warm surfaces, all built in OKLCH on the brand-green hue, so the whole app shares one tonal source.
Type took three tries. Jost first, then Space Grotesk, then Libre Franklin, which carries the whole hierarchy now. DM Serif Display shows up in exactly six emotional moments, like the emergency reassurance line and the "Thanks for sharing" on /trip-summary. Reserving it for those six is what keeps them landing. Type and color both shift across the session, calm at entry, heightened en-route, resolved at the trip summary.
Color, and the job each one holds
Green carries the work
- freshgreen#41AD49primary CTA, in-flow links
- wiltedgreen#326936secondary CTA, headers
- burntgreen#003F04deep accents
Four reserved safety signals
- orange#FF9500hazard
- red#FF3B30alert
- yellow#FFCC00caution
- navy#041E49safety affordances
Warm surfaces
- surfacePage#F4F4EDpage, warm paper
- surfaceCard#FEFDFBcard surface
Spacing, a 4pt ramp
- xs4
- sm8
- md16
- lg24
- xl32
- xxl48
theme/colors.ts and theme/spacing.ts. The spacing scale started implicit and drifted to stragglers at 5, 6, 13, and 18. Making the 4pt ramp explicit is what made that drift easy to catch.Holding four colors in reserve.
Four colors and the daylight gradient are held to safety signals, with documented carve-outs.
Green carries every button and link. Red, orange, yellow, and navy are reserved for safety signals, each tied to one meaning, so a red dot always points to something specific. Across 26+ screens, the rule holds, with documented carve-outs.
Green carries every CTA, link, and affordance — the only non-reserved color. Four colors are held to safety-signal work; the documented carve-outs are below.
- RedAlert
- Live audio-capture indicator A pulsing dot for the active recording state on /pulled-over.
- Destructive-action labels Remove, unpublish, and sign-out.
- Error copy on light Swaps to the darker severityCritical token for AA (~5.6 : 1 vs red’s ~3.5 : 1).
- iOS red on dark auth The contrast argument inverts, so default red passes there.
- OrangeHazard · caution
- Community-report pin Marks community observations apart from the institutional feeds.
- Report FAB The same orange — the contribute-back affordance.
- Route-preview hazard chips Police presence and low-light segments.
- YellowCaution
- General caution teardrops Map hazards and weather advisories.
- Trusted-station gold star A documented carve-out from the caution role.
- NavySafety affordance
- En-route Shield Safety mode itself; never data state or sync.
- /emergency SOS disc Kept distinct from the destructive-action red.
And where color is the data:
- DaylightRoute grade
- Daylight polyline Color IS the data — a per-segment daylight score. A solid → dashed → dotted cadence carries it for WCAG 1.4.1.
The daylight gradient is the one non-reserved color the system allows itself. On /route-preview, a sun-to-moon dashed band traces what the light will do along the route.
Where color is the signal, a second channel rides with it. On /report, severity pairs a filled warning glyph with the color, so the cue survives for anyone who can't rely on hue (WCAG 1.4.1).
Keeping community reports trustworthy.
The pipeline only works if community reports can be trusted like public data. Bad-faith and mistaken reports have to be caught without falling back to distrusting community data. That's what /moderation is for.
Every report enters a queue with an investigation panel: the source device, prior and nearby reports, and coordination checks for duplicate IPs and devices. Nothing publishes without a human decision, and every publish and unpublish is logged.
Enters
A report joins the queue
Investigation panel
- Source device
- Prior reports at the same spot
- Nearby reports
- Coordination: duplicate IPs and devices
Human decision
Published or held, every action logged
It's where community reports and public data meet the same review. A planned transparency page will publish the outcomes so the queue is auditable from outside.
What shipped, and what didn't.
The honest split between what's in the build and what's still on the list.
Shipped
- Equal-weighting routing pipeline across OpenStreetMap, DOT-511, OSRM, SunCalc, and community reports
- Six-surface safety toolkit, with
/pulled-overcarrying ACLU-sourced guidance, on-device audio capture, and the Held-Question voice - Warm surface ramp and reserved-color discipline holding across 26+ screens and 300+ accessibility attributes
/moderationqueue with per-report investigation panels, coordination detection for IP and device duplicates, and a hold-to-remove destructive gesture- Design system published as a Figma library: 62 variables at 1:1 parity with
theme/colors.ts, scoped per token role
Also on the list:
- Daylight-graded route polyline with a WCAG dash pattern
- Six-category report picker
- Four-layer Mapbox fallback chain (Mapbox → OSRM → cache → mock)
- Two-font Franklin plus reserved DM Serif Display
- Departure-reminder local notifications
- Delight layer of arrival and community-confirmation moments
- Supabase community cloud with anonymous device-UUID auth and Postgres row-level security
Next, v2
- Moderator-role bootstrap automation (currently a manual SQL insert in prod)
- Push notifications for new moderator-queue items (local notifications ship today, remote push doesn't yet)
- Public transparency page for
/moderationactivity - Broader on-device test matrix beyond iPhone
What comes next is mostly about accountability. The transparency page is the one I care about most. It puts the /moderation queue's decisions in public, so the trust the whole system runs on can be checked from outside.

