January 2nd, 2025

Open sourcing Storma 2.0

I’ve started developing Storma 2.0, and my to-do list is packed! Here are some of the features I’m hoping to deliver:

  • A better iPad experience.
  • Mac and Apple Watch versions.
  • Optimized map performance.
  • The ability to look back in time and track storm paths.
  • Customizable alert radius settings.

Creating a Mac version means improving the iPad experience, which I currently find underwhelming. I initially relied on the standard NavigationSplitView and .inspector() components, but they didn’t integrate well with a map-focused interface. So, I decided to build my own NavigationCard component. It mirrors the functionality of NavigationStack but adapts to show cards on iPad and sheets on iPhone.

NavigationSplitView iPad The current iPad version using NavigationSplitView and .inspector().

NavigationCard iPad The iPad version of Storma 2.0 with NavigationCard, offering a more cohesive navigation experience.

NavigationCard iPhone The iPhone version of Storma 2.0 with NavigationCard, featuring sheet-based navigation without extra code.

struct ContentView: View {
    @State private var path: CardPath = .init()
 
    var body: some View {
        NavigationCard(path: $path) {
            strikeMap
        } card: {
            alertList
                .cardTitle("Alerts")
                .cardToolbar {
                    CardDismissButton()
                }
                .cardDestination(for: Alert.self) { alert in
                    AlertDetailView(alert: alert)
                }
        }
    }
}

Apple Watch Challenges

Developing the Apple Watch app has been a challenge. The iOS app struggles in areas with heavy storm activity, and the Apple Watch’s capabilities are more limited than the iPhone’s. I had to rewrite the map entirely to make it as performant as possible.

Storma on Apple Watch Storma 2.0 on Apple Watch with enhanced performance.

To achieve this, I used a quadtree algorithm. While there are several open-source implementations in Swift, I chose to write my own, ensuring it’s generic and fully compatible with Swift 6.

// Define a quadtree that stores `Strike` and uses `MKCoordinateRegion` as the boundary.
// `Strike` conforms to `QuadtreeElement`.
// `MKCoordinateRegion` conforms to `QuadtreeRect`.
let quadTree: QuadTree<Strike, MKCoordinateRegion> = .init(
    boundary: .world,
    capacity: 10
)
 
quadtree.insert(strike) // Insert a strike in the quadtree
let strikes = quadtree.query(region) // Query all strikes in a given region

Going Open Source

The biggest news? I’m making these components open source! Sticker, NavigationCard, and Quadtree are the core of Storma, and they’ll soon be freely available on my GitHub.

I’ve thought about open-sourcing an app for a long time but always hesitated, fearing my code might be stolen. With Storma, it’s different. The app is free and relies on open-source licensed data that prohibits commercial use.

While the future remains uncertain, I believe the benefits outweigh the risks:

  • It invites contributions from other developers, enriching these projects with their ideas and expertise.
  • It allows potential clients to explore my coding style and project organization.
  • It pushes me to modularize my code even more.

Sticker is already available (I talked about it in a previous article). NavigationCard and Quadtree will follow soon. Stay updated by following me on Bluesky and Mastodon, or subscribe to the RSS feed!