Building SPT for Sofia and Zürich

Wed, Oct 7, 2026 2-minute read

I started SPT in May as an experiment with Chinese open-weight models: first DeepSeek 4 Flash, then DeepSeek 4.1 Flash. I also tried different coding harnesses, including Codex and Pi.

A public transport app gave me something useful to build while comparing them: find a nearby stop in Sofia, check when the tram is coming, and work out which connections to take. Five months later, it also works in Zürich.

The first version showed vehicles, stops, and departures. I added favourite lines to filter the map, then saved destinations and route planning. It’s a native Swift app; timetables are stored locally and the route search runs on the phone.

Fixing what annoyed me

Using it kept turning up things to fix. Walking directions drew straight lines instead of following streets. Tapping a saved destination sometimes opened the planner without starting the search. I also wanted to plan for a specific arrival time, not just leave immediately.

In July, I tried planning a trip at 22:30 and got no metro options, even though the metro was still running. We traced it to trip IDs being reused across service dates and fixed the routing bug.

We added service alerts and spent a fair amount of time making the map less irritating: no flashing panels when switching stops, no losing the selected vehicle while panning, and fewer delays after tapping.

SPT showing Sofia tram 15, its route and upcoming stops
Following a tram in Sofia.
SPT journey planner showing metro, bus and walking connections in Sofia
Planning a journey with transfers and walking. Both screenshots are from the website's app gallery.

Adding Zürich

Zürich support shipped in September. While using it there, I noticed vehicles weren’t following the streets and railway lines properly. We added official route colours and geometry; the latest testing builds improve S-Bahn routes and use Swiss realtime predictions to adjust the timing.

Those Zürich positions are estimates, not GPS tracking. Sofia’s buses, trams, and trolleybuses use live positions; the metro uses timetable estimates.

The App Store has version 2.1.5. The newer Swiss realtime and S-Bahn changes are in 2.1.6 testing builds.

SPT simulator showing Zürich S24 following a curved railway route rather than a straight line between stops
S24 following railway geometry in a 2.1.6 simulator preview. This uses a frozen timetable clock, not a live GPS capture.

Working with Pi

Friends and family have been using SPT and sending feedback. Through Surfcode / Englang, I can send that feedback to Pi from my phone, often while out for a walk. I explain the bug, check the changes, try the app again, and follow up when something still isn’t right.

Try SPT

Getting around Sofia or Zürich? Install SPT from the App Store to check departures, find nearby stops, and plan your route.