← all writing tech

Designing a map that gets out of the way

Building a good in-app map is almost entirely an act of deletion, and the only thing I let stay is the one label nobody thinks about.

The good in-app maps, the ones in the ride-hailing apps everyone already trusts, are not designed by adding anything. They’re designed by deleting almost everything. I spent a week making a map look calm and confident, and the diff that did it was a long list of things turned off, plus exactly one thing I refused to remove.

I came at it the way you’d expect. The default basemap is right there, free, and it looks busy in a way that reads as “real,” so the instinct is to keep it and maybe drop a nicer pin on top. That instinct is the whole trap. A logistics app’s map is not a place to explore. It exists to answer one question, where is this thing right now, and every business pin, transit line, and little fork-and-knife icon competing for the eye is noise sitting on top of the only signal that matters.

A map is a config file, not a canvas

The thing nobody tells you starting out is that you don’t design this map by drawing. You design it by writing a style JSON and feeding it to the map renderer. The look lives in config, which means the whole aesthetic is reviewable, diffable, and reproducible, the same as any other code. That reframing alone changed how I worked. I stopped squinting at the screen trying to “make it look cleaner” and started writing explicit rules for what each layer was allowed to show.

And the rules were almost all subtraction:

  • Kill every point-of-interest label and icon. No restaurants, no shops, no gyms. None of it tells a driver or a customer anything about the delivery, and all of it adds clutter the eye has to wade through.
  • Turn off transit entirely. Bus and rail lines are a different mental model from a road delivery. They’re just colored spaghetti in this context.
  • Mute the roads. Keep them, because they give shape, but pull them back so they read as faint structure, not as the subject.
  • Soften the water and the landscape fills. Lower the contrast so parks and rivers stop shouting. They become background texture instead of features.

By the time I was done, most of the work was things that had been switched off. The map looked, at a glance, like nothing much happened to it. That was the point.

The one thing I refused to delete

There’s a temptation, once you’re in the deletion groove, to keep going until the map is a featureless gray sheet with a dot on it. That’s overcorrecting, and it leaves the user lost in a different way. A pin floating in blank space tells you a position but not a place.

So I kept exactly one category of label readable: the neighbourhood and locality names. The district, the estate, the town. That is the only context a person needs to orient. “It’s in that area, near there” is the question a human actually asks of a tracking map, and the area name answers it without dragging the whole busy basemap back in to do it.

A map for an app should hold its tongue about everything except the one fact the user came to find. Restraint is the feature, and the layer you keep is the design decision, not the ones you cut.

The last move was making restraint enforceable. The style JSON went into the repo with a short spec next to it, “POI off, transit off, roads muted, locality labels on,” so the next person who opens this, including future me, knows the bare look is deliberate and not an unfinished job. Without that note, somebody helpful eventually re-enables a layer to “improve” it and quietly hands the noise back.

A map that gets out of the way looks like almost no work was done to it. Underneath, it’s the most opinionated config in the app.

Email