Six Years Perfecting Maps on watchOS

Design Diary

Cloughhead

I love going on wilderness adventures. I am rarely happier than when I am far off into the mountains without a soul in sight. As a result, I have spent a lot of time learning how to safely explore and navigate when I’m away from civilization. The most important habit I’ve found for not getting lost is to be very regular in checking your location as you go, and the best way I’ve found to do that is to have a map on my wrist.

Pedometer++

For more than six years I’ve been working towards creating the best possible mapping experience on the Apple Watch. With yesterday’s launch of Pedometer++ 8, I feel like this design journey has reached a meaningful destination. I would contend that Pedometer++’s watchOS mapping support is the absolute best available on the App Store.

So I wanted to walk through the journey it took to get here.

Early Efforts

I have wanted a good map on my wrist since the Apple Watch launched. This wasn’t realistically possible until watchOS 6, which brought SwiftUI to the platform and, for the first time, made “real” apps possible. But in those early days, the screens were tiny, and the processors slow. I couldn’t quite get to where I wanted.

This was my very first attempt that shipped in Pedometer++. These maps were generated completely on the server, which involved sending the relevant workout data roundtrip every time I wanted to refresh the display. This system let me validate the idea, but it was never going to be practically useful for navigation or regular use, and could never work offline.

Custom Mapping Engine

I knew that if I wanted to make progress towards this goal, I’d need to work at a lower level, so I got to work building a fully SwiftUI-native map rendering engine. SwiftUI was the only choice because it’s all that watchOS supported, and proved to be helpful for putting maps into widgets, which also only support SwiftUI.

In 2021, I got this engine to a place where I could reliably and performantly render a map on watchOS. With it, I can render any tile-based maps and overlay location information on top.

Map Designs

Next came the question of how best to surface data to users. App design on watchOS is a really fun — but frustrating — challenge. You are designing for a relatively tiny screen, which must be operated one-handed. In this case, I want the user to be able to read the map and use it to navigate, while also having access to other workout-related information.

This began a long series of design attempts, most of which (if I’m being honest) were kinda awful.

Bad designs

In the end, I settled on a “modal” approach where the user can switch between a map screen and a metrics screen using a button on the top-left corner.

Modal Maps

This interface provides one context where the user can freely pan/zoom around the map and another where I can use the more standard watchOS tabbed page interface for metrics and controls. I shipped this to Pedometer++, but there was always something that didn’t quite sit right with me about it.

This design felt like a compromise, and not in a good way. I felt that in order to achieve the goal of making the map interactive, I couldn’t have the map be part of any UI structure that involved swipes. As the screens on Apple Watches got larger, it felt less needed in order to give the map enough space to be useful.

So I set about trying alternative designs. SO many designs.

Many more designs

For a while, I thought that I needed to find a way to put the metrics at the bottom of the screen. However, that would lead to other problems on longer outings or for workouts that aren’t navigation-focused. So I kept iterating and came up with even more designs.

Even more designs

All of these designs suffered from the same fundamental issue: they required the app to display only a fixed set of fields at a time.

I could make the interface configurable, but one of the fundamental rules of watchOS design is that you should avoid any interaction that takes more than a few seconds on the watch. Any user-configurable setup is inherently fiddly, so I didn’t like this approach.

Dark Mode, Liquid Glass, & Cartography

Around the same time I was still wrestling with the design challenges of how best to structure the app, Apple announced watchOS 26, and the arrival of Liquid Glass. One of the core design aspects of Liquid Glass is layering stacking elements on top of each other, but another is the types of colors that work best with each other.

I was previously using Thunderforest Outdoors as my basemap for the app. I love the content this map includes, but when I started overlaying glassy elements over it I found that it wasn’t well-suited for Liquid Glass.

So… I commissioned a custom map. Working with the incredible cartographer Andy Allen, we created a completely new basemap that would look fantastic with Liquid Glass.1

We simplified the map visually, increased the contrast of the elements, and made the map elements more saturated to prevent them from becoming a muddy mess when shown below glass.

With this work done, I had another opportunity: I could finally have a dark mode variant of the map tiles. While helpful on iOS, this really shines on watchOS. Andy and I really worked toward something which would be incredibly legible at arm’s length.

The result of these efforts is that now I have a great map for watchOS… but a design that didn’t match that greatness.

Striving for Great

I kept trying. To get me out of my design rut, I enlisted the help of the fantastic designer Rafa Conde. I needed a fresh set of eyes on this and very quickly, this partnership paid off. They proposed a variety of alternative layouts, but when I saw this one I knew it was the one.

The layering of the metrics on the top-left corner, with the map being the top page of a vertical stack, was the correct answer. This design handles interactivity by requiring a tap on the map first to enter “browse mode”.

Tweaking and Polishing

Now that I had the overall concept locked in, the real fun began, actually building the app and dialing in all the details. I fairly quickly took Rafa’s concept and turned it into a working prototype. This let me validate the idea in the field… literally. After walking a few hundred miles with it, I was confident it was the correct approach.

Next, I needed to dial in the font and make more subtle design choices.

Map fonts

After a bit more iteration, I arrived at the design that shipped yesterday. It is legible, useful, and (in my humble opinion) beautiful.

It feels really good to be able to cap off this six-year journey with a design I couldn’t be more proud of. This screen represents so much accumulated effort and learning. It finally gives me a design which feels native on the platform, but also novel and unique.

Here is the evolution of this design over the last six years:

Postscript: Considering MapKit

While my work on watchOS mapping massively predates the arrival of Apple’s MapKit onto the platform, it is probably worth explaining why I decided to do all of this custom work to avoid using it.

Fundamentally, I find that MapKit is great for basic uses, but doesn’t provide nearly the level of configurability and utility which I want Pedometer++ to offer. For example:

  • MapKit on watchOS always shows in dark mode, which generally is a good default, but closes the door on some accessibility and user choice reasons. I needed it to be a user-selectable option.
  • While MapKit on watchOS has gotten better over time in terms of what you can do with it, I still find it a bit limiting in terms of animations and overlays.
  • MapKit’s coverage is improving with regards to topographic contours and trail marking, but there are far too many places where the MapKit map is essentially blank, but I know there should be more rich details available. For example, here is my map vs MapKit at the trailhead of one of my favorite hikes in Scotland.

MapKit comparision

  1. I still find it so cool that my work on this allows me to say that I “commissioned a cartographer” to work on something for me. 😁 

David Smith




Pedometer++ v8: Designed for Adventure

Today I’m beyond delighted to announce the release of Pedometer++ version 8. I worked with legendary designer Rafa Conde to re-design the appearance and layout of the watchOS app to make it the most capable, yet intuitive, walking app on the App Store.

Pedometer++ has been on the Apple Watch from day one twelve years ago. Over that time I’ve built dozens of designs and features, today’s redesign learns from that journey and arrives at an incredible place.

The Home Screen has been clarified to make it more legible at a glance. A bright, colorful display of your daily step count makes it easy to see your progress towards your goals. This animates as you move and celebrates when you reach your goal.

Swiping up brings you to straightforward workout list screen where you can choose from a walk, run or hike. If you have a planned route for your outing you can select the route you configured on your iPhone here.

There is a new Expedition Mode workout type which dramatically reduces the battery usage during adventures to allow for longer outings. In my testing I found that this mode can extend your watch’s battery life by up to 40%.

If you’re a premium subscriber when you start a workout you’ll be immediately brought to your new maps screen which shows your workout on a live updating map. This map will overlay your planned route, if selected.

This screen now features our completely custom dark mode map. I worked with a cartographer to design a map which looks perfectly at home on the Apple Watch, which is highly legible even at arms length and includes all the topographic and wayfinding information you need to keep you on track.

You can also select a light mode if you prefer. If you are in the United Kingdom, you can also select to use an Ordnance Survey map.

The overall structure of the workout app has been simplified to make it easier to quickly navigate. Swiping to the left from any screen brings you to the workout controls. Swiping to the right brings up the media controls.

Swiping up from the map will bring you to the detailed workout stats, organized by type. You can quickly see your current heart rate zone, your speed or the elevation gain you’ve accomplished on the walk.

This new layout allows for flexibility without fiddily-ness. I’ve taken this new layout out on dozens of all-day adventures and I can say with confidence it gets the job done. Pedometer++ is still the most capable workout app on the App Store, but now provides that power without visual complexity.


David Smith




Generally Useful Prompts

The last few months have involved a major shift in how I do my work. With things like the Codex app and GPT-5.3+ reaching a level of code quality and consistency which has made them properly helpful. While my use of these tools for general purpose programming is still something I haven’t fully settled my workflow for, there are several uses for these tools which I have found I use very regularly.

These are prompts which I find are just generally useful, without requiring changing the inherent workflows I use for programming my apps. While I’m starting to tactically deploy agents for general programming tasks, I feel like the line of when I manually code and let the agent do it is currently more fluid.

Previews

Add a SwiftUI preview for TrainingBlockDraftEditorView, including data variants for each of the flows through the view

SwiftUI previews are huge benefit for my productivity when iterating on the UI/UX of a view, but I find the setup and creation of the data needed to drive them a bit of a pain to setup. But this is a perfect thing for an LLM to generate. I even had a great use recently where I was working on a weather view and I asked it to create different data blocks for different locations (to see how rainy vs sunny would render) and it worked out the API keys necessary to do some CURL requests to get actual data to use.

Realtime Documentation

Look at the publishSnapshot: method. Identify all the uses of it and determine what it does and how it is used. Describe its function and how it acts in all different uses of it

While I in theory it would be good for every one of my methods to been neatly documented, in practice that almost never happens. I work by myself in the code, so rarely need to document things like I would if I worked as part of a larger team. All the same, sometimes I find old code which I don’t fully remember or am making a change to something which I want to have full understanding of all uses of it. This ‘realtime documentation’ works a treat and has the added advantage over static documentation of being 100% up-to-date (rather than slowly slipping out of sync with reality of time).

Newly Localizable Strings

Look at the git diff since XXXX and locate any newly introduced user visible strings in the app which need to be localized. Add entries for each of these strings to each language supported by this app with relevant translations.

A pattern I’ll use for many of these prompts is the “Look at the diff since XXXX” where XXXX is the git hash of the last released version. This helps narrow down the changes and lets me isolate the updates to the relevant, new code.

In this case I want to have it seek out any newly added user-facing strings which were introduced and then add translations to the .strings files for each supported language. For years I’ve used LLMs to power the baseline translations I use in the app, so this shortcuts the process. It also has helped me to identify spots where I was using strings in a way which wouldn’t actually get triggered by the localization system (like a string literal passed into a view).

Testing plan

Look at the git diff since XXXX and create a recommended testing plan to provide good coverage of the areas of the app which are either new or were changed. Including likely user paths which could now include incorrect behaviour. Generate the export as a nicely formatted PDF checklist.

This works to evaluate all the code which has changed and then it gives me a list of things which I should do to make sure the app update didn’t introduce regressions. This has a few times identified little user paths which I might not have thought to test, or just generally helps me find areas to be more thorough with.

New Bugs

Look at the git diff since XXXX and explore whether the newly added code has introduced any bugs or likely unexpected results. Consider how the newly added code interacts with existing code and whether it will change existing behavior. Also, identify any areas where the newly added code is inconsistent with the general style and design pattern of the related, existing code.

The hit rate for this prompts I relatively low (maybe 20%), but the reality is I am always very grateful for any bug which I can find before it ships to customers, so having a second opinion on things is great.

Release Notes

Look at the git diff since XXXX and identify any new features or changes which would be visible to the user. Write a summarized release notes for the changes organized by size of the change (Major features, minor features, bugfixes).

This isn’t something which I expect to use directly for the user, but is a very helpful baseline for the creation of the real release notes. Also, this has helped me when I’ve been working on a larger, more sprawling update and I forget all of what I’ve done.

David Smith




Display Zoom Statistics

In Widgetsmith 8.2 we added the ability to give your widgets a ‘clear’ background. This isn’t actually clear (since iOS doesn’t allow that without private API use), but instead just crops part of your home screen wallpaper and uses that as the background.

In order for that to work I need to know precisely where each and every widget is on each and every iPhone model. This involved a massive process of screenshotting and a custom app for doing pixel precise analysis. There are 31 iPhone models which support iOS 26 (which I required for this update), so for each of these I needed to collect nine screenshots.

That all went well, but then I was faced with a slight dilemma about how/if I should support Display Zoom. This is a feature which increases the effective size of your iPhone’s controls by rendering your iPhone’s screen at a lower resolution and then enlarging it to fill the actual screen.

Since Display Zoom creates a new virtual resolution for the iPhone I would need to duplicate all the work I did to support the regular widget positions for each iPhone. This effort is made doubly tricky because the iOS simulator doesn’t properly render Display Zoom so I’d have to rely on screenshots from devices to which I have physical access.

To better inform this decision I went looking for statistics about the usage of Display Zoom, but couldn’t really find anything. So in a recent update to Widgetsmith I built in analytics code which reported Display Zoom usage.

What I found was that overall usage of Display Zoom was at 1.9%, which was lower than I would have guessed. For Widgetsmith I see 18% of users with their Text Size set to something larger than the default size, so I’d have guessed the number would have been much higher than 1.9%.

But that helps me to feel better about not supporting Display Zoom for this feature. That is simply not enough users for it to be viable to sustain the effort supporting it would require.

Here is a breakdown of the Display Zoom adoption by iPhone model family. It seems to skew heavily towards the smallest and largest iPhones.

CategoryUserbaseDisplay Zoom
SE 0.5%4.90%
Mini 1.2%4.60%
Air 0.2%3.80%
Plus 5.0%3.20%
Pro Max 20.3%2.70%
Regular 50.9%1.80%
e 1.0%1.80%
Pro 10.8%0.90%
Overall1.90%
David Smith




Widgetsmith Five Years Later

Five years ago, a TikTok video changed my life.

And I can say that without any hyperbole.

The run up

In April of 2020, while the world was struggling through the early stages of the COVID pandemic, I launched an app for creating highly customizable complications for the Apple Watch. Watchsmith was my attempt at filling the void left by the lack of 3rd-party watch faces on watchOS.

It let you chose from loads of different colors, fonts and display types to make your watch face your own.

The app did alright commercially at launch—it was a niche app for a niche purpose. Much like many of my other apps at the time, I was building things which I wanted to exist and hoping that they’d find some audience with folks who had similar needs and desires.

Then that June at WWDC Apple announced iOS 14 and with it the introduction of a new widgets system for iOS. For the very first time iPhone users had the ability to personalize the look of their home screens (beyond their choice in wallpaper).

This then kicked off a busy summer for me adapting the work I’d done for Watchsmith to iOS. Because Watchsmith was my first top to bottom SwiftUI app I could actually re-use a lot of the code between the two and so by mid-July I had the early prototypes of this ready:

I was very much viewing this as a project which would have a similar lifespan as Watchsmith. I was building a niche tool for niche users. I thought it was a good idea, and one I’d enjoy using myself, but at this point my expectations for it were still very managed.

When Apple announced that their September event would be on September 15, I thought I was mostly ready. I had a good basic version of the app with most of the feature-set copied over from Watchsmith.

I remember watching the video keynote, enjoying it as it went right up until this moment when Tim said:

Tim Cook saying iOS 14 will come out tomorrow

…tomorrow! Usually we get a few days between when Apple releases their final “Gold Master” versions of an iOS version and when it will come out to the public. But in this case we had less than 24 hours to get our apps submitted, approved and ready for the world.

So I frantically got to work on final touches and build and at 5:54pm, I got it submitted.

Phew.

Then 6 hours later (at 11:30pm) Widgetsmith was approved by Apple, ready for when iOS 14 would be released the next day.

The Initial Response

So at 4:21PM on Wednesday, September 16, I hit release for Widgetsmith v1.0. The app launched as part of a much wider release schedule I was mananging at the time with updates for Pedometer++, Sleep++ and Watchsmith all going out that same day.

The initial response to the app was warm but nothing out of the ordinary. Widgetsmith was the 59th app I had launched so I’d been through this process a lot over the preceding twelve years of indie app development. Typically you see a little swell of interest in the first few days. Then things settle down into a stable level and you move onto the maintenance and gradual improvement of the app.

This was what I thought would happen with Widgetsmith and the indications for the first few days were that this was exactly what would happen.

So the next day I left home with my family for our first proper holiday since the start of the pandemic, heading down to the beach.

The Turn

That Friday (September 18) I awoke and went about my morning like normal. Checking in on things a bit here and there but mostly enjoying some welcome down-time with my family. We went for a walk in a local nature preserve and generally had a nice quiet day.

It wasn’t until we got back from our walk that I had my first indication that something was up. Someone reached out to me on Twitter saying they’d seen Widgetsmith getting mentioned on TikTok. I click through to the video they linked to and discovered that there was a walkthrough video by Katarina Mogus which was going viral at the moment. Her video showed how to use Widgetsmith to make your home screen look Aesthetic AF.

@katamogz Reply to @an.elementopqrs #ios14 #ios14update #iphonetricks #iphonehack #ios14homescreen #learnontiktok ♬ Daisy (I’m Crazy But You Like That) - Ashnikko

I then opened my helpdesk page and I was shocked by what I saw. There were new emails coming in at a rate of several per second. A literal waterfall of customer outreach. I couldn’t even tap on things because the rate was too high. I was rather bamboozled at to what exactly is happening but at this point I realized something was different.

Widgetsmith had taken off in a way I could never have had the imagination to hope for. It was everywhere. It was being mentioned in the news, I even recall it getting a shout out in Vogue. Complete madness.

Widgetsmith quickly became the #1 App in the App Store, and remarkably stayed there for a couple of weeks.

I will be forever grateful for the App Store for the opportunity it allowed me. It still, to this day, doesn’t seem like it should be possible for a solo, indie developer to build something on their laptop. Hit submit, and then have it end up on over a hundred million people’s phones.

Five Years Since

The initial few weeks after Widgetsmith’s launch are a bit of a blur to me now. I remember frantically coding up requested features, trying to keep up with the outreach, and generally trying to keep holding everything together.

Eventually things settled down out of the frantic stage and into a new only-slightly-frantic stage. The app matured and developed and I was able to craft and adjust it towards the features its newly found audience wanted. What I had built as a niche tool for niche users had become a mainstream tool for mainstream users.

I wasn’t ever really sure if it would be a flash in the pan — a meteoric rise followed by a meteoric crash. Happily, five years on I can report that it was not a flash in the pan. Widgetsmith’s usage and userbase continue to grow. As of my writing this the app has received around 131 million downloads.

I continue to find enjoyment from coming up with ways to enhance and improve the app. Most recently with a fresh new re-design for iOS 26 and support for the new Liquid Glass widget styles.

I have no idea how long Widgetsmith will continue to be relevant, but I do know for sure that I am incredibly grateful for the opportunities and experience it has provided me.

David Smith