元航空整備士が設計したランニングアプリ
Turn Every
Run Into A Flight.
A320Fの整備士出身の開発者が作ったiOSランニングトラッカー。
GPS、心拍数、ケイデンスを計器のように読み取り、ペースのズレをGPWS警報でお知らせします。
GLIDE PATH
MISSION FLIGHTCRUISE
PACE
5'12"
DIST
2.14km
HR
158bpm
CAD
172spm
FUEL
212kcal
Flight Operations
2つの飛行モード
航空機の運航手順にヒントを得た状態機械が、ランニング全体を管理します。
スタートボタンを押すと離陸シーケンスが始まり、走行中はリアルタイムの計器パネルが待っています。
MODE A
Mission Flight
目標ペースと距離を設定して運航します。許容誤差を外れるとGPWSが即座に警告します。
- 目標ペース ± 許容誤差の設定
- 距離のクイック選択(3K / 5K / 10K / ハーフ / フル)
- 目標距離の50m手前でMINIMUMS警報
MODE B
Free Flight
目標を設定せず自由に走るVFR(有視界飛行方式)モード。手動でTouchdownして終了します。
- 目標設定なし
- GPWS無効
- 自由なペース記録
Ground Proximity Warning System
SINK RATE
目標ペースより遅い
OVERSPEED
目標ペースより速い
MINIMUMS
目標距離の50m手前
iPhone & Apple Watch
2つの画面、1つの飛行
WatchがリードしてもiPhoneがリードしても、両方の端末は同じFlightDataを共有します。
離陸準備から着陸後の記録まで、実際の画面でご確認いただけます。
iPhone · 横にスクロール












Apple Watch



Under The Hood
4つの設計判断
並行処理、状態管理、端末間の同期、GPWS判定ロジック - RunWayを
作る上で最も悩んだ4つのポイントです。
CoreLocation
RunningCenter (actor · serial queue)
AsyncStream<FlightData>
HealthKit + WatchConnectivity
send / receiveViewModel (@Observable) → SwiftUI
なぜこの設計にしたのか
“GPSの更新が連続的に発生し、そのたびにペース・距離・GPWS判定を再計算する必要があるため、この計算ロジックをRunningCenter Actorに隔離して状態の整合性を保証しました。心拍数とケイデンスはWatchConnectivityが受け取り、判定ロジックを持たずスレッドセーフに値を保持するだけのHealthCenter Actorに渡され、RunningCenterが必要なときにそこから値を取得して@Observable ViewModelへ渡します。”
SwiftUIUI
@MainActor + @Observable状態管理
RunningCenter (Actor)並行処理
HealthCenter (Actor)心拍数/ケイデンスのスレッドセーフな保管
AsyncStreamセンサー → ViewModel
FlightPhase enum状態機械
WatchConnectivityiPhone ↔ Watch
SwiftData保存
CloudKit (CKRecord)手動バックアップ/復元 · Private Database
Douglas-Peucker経路の対角線長に比例した誤差でGPS座標を圧縮
MapKit + MapPolylineルート可視化
HealthKit心拍数・ケイデンス・ワークアウトセッション
WidgetKit + ActivityKitDynamic Island
WeatherKitリアルタイム天気
AVSpeechSynthesizerkmスプリット・カウントダウンの音声案内
Combine位置情報・アラート・セッション状態のPublisher + Timer