17万9千座の山頂データをサブ10msで検索するPWAをClaude Codeで開発した
3秒まとめ
- SOTA(Summits On The Air) という山岳アマチュア無線のプログラム用の山頂検索PWAを作った
- SQLite Wasm + R*Tree空間インデックス で17万9千座の山をサブ10msで検索できる超高速アプリ
- 自分ではコードを1行も書いていない。 Claude Codeとfrontend-designスキルだけで開発した
- PWA対応で 完全オフライン動作。山の上で電波がなくても使える
- インフラ費用は完全無料。 GitHub Pages + GitHub Actionsだけで運用
どんな人向けの記事?
- PWAやSQLite Wasmなど、ブラウザの最新技術に興味がある人
- Claude Codeでアプリ開発をしてみたい人
- 位置ゲー好きな人(Ingress勢、ポケGO勢)
- 個人開発でインフラ費用ゼロを目指したい人
完成したアプリ
まず完成品をお見せします。「SOTA Peak Finder」は、世界中の 17万9,527座 のSOTA対象山頂を検索できるPWAです。
ダッシュボード画面。世界中のSOTA統計情報が一目でわかる
そもそもSOTAってなに?
SOTA(Summits On The Air) は、登山とアマチュア無線を組み合わせた世界的なプログラムです。2002年にイギリスで始まりました。
ざっくり言うと、山に登って、山頂から無線で4局以上と交信すると、ポイントがもらえる というプログラムです。山が高いほど、冬季はさらにポイントが多くもらえます。たとえば 富士山(JA/SO-001)は10ポイント(最高値)、高尾山(JA/TK-034)は2ポイント。1,000ポイント貯めると「Mountain Goat(山のヤギ)」というトロフィーがもらえる。富士山でも100回登らないと届かない計算です。こういうの燃えません?
参加者には2種類います。
- アクティベーター: 自分で山に登って山頂からQRV(無線で電波を出す)する人
- チェイサー: 自宅や別の場所からアクティベーターと交信する人
私のコールサインは JE1WFV です。アクティベーターとして山に登って無線運用しています。
作った背景 ― 位置ゲーマーの血が騒ぐ
私は 位置ゲーが大好き です。Ingressを長いことやっていました。ポータルを巡って街を歩き回る、あの感覚がたまらないんですよね。
で、アマチュア無線を始めて SOTA を知ったとき、「これ、位置ゲーじゃん!」って思ったんですよ。
- 特定の場所(山頂)に行く → Ingressのポータル巡りと同じ
- ポイントを貯める → ゲーミフィケーション
- 世界中にスポットがある → グローバルな位置ゲー
- レアなスポット(未踏峰)がある → コンプ欲を刺激
しかも私は トレイルランニング もやっています。トレランで山を走れば、1日で複数の高ポイント山頂を回れる。SOTAのポイントを効率よく稼ぐのにトレランとの相性が抜群なんです。逆に言えば、SOTAが トレランで山を走る目的 にもなる。「次はあの山頂をアクティベートしよう」と思えば、トレーニングのモチベーションも上がります。
ただ、SOTAには1つ大きな課題がありました。
近くのSOTA対象の山を探すのがめちゃくちゃ面倒。
公式サイトのデータベースは検索しにくいし、一覧性がないし、オフラインで使えない。しかも登山中はキャリアの電波が届かないことが多い。山の中腹から山頂にかけて圏外になるのは日常茶飯事です。つまり、山頂に着いてから「この山SOTAの対象だっけ?」と調べようとしても、そもそもネットにつながらない。だからデータをローカルに持つPWAが必要なんです。
ないなら作ろう。
技術スタック
今回の開発で使った技術スタックはこちらです。
| カテゴリ | 技術 |
|---|---|
| フロントエンド | React 19 + TypeScript 5 |
| ビルドツール | Vite 5 |
| データベース | SQLite Wasm(@sqlite.org/sqlite-wasm v3.52.0) |
| 空間インデックス | R*Tree |
| PWA | vite-plugin-pwa + Service Worker |
| スタイリング | Tailwind CSS |
| デプロイ | GitHub Pages + GitHub Actions |
| データ更新 | GitHub Actions(毎週日曜自動更新) |
主な機能
ダッシュボード
ホーム画面では世界中のSOTA統計情報を俯瞰できます。最高峰・最低峰、高ポイント山頂、人気の山頂、まだ誰もアクティベートしていない未踏峰など。
統計情報セクション。山頂の数だけ見ても世界規模のプログラムだとわかる
GPS検索 ― 近くの山を瞬時に発見
GPSボタンをタップすると、現在位置から50km以内のSOTA山頂を最大20座 表示します。距離、方位、標高、ポイント、アクティベーションゾーン内かどうかまでわかります。
GPS検索結果。距離・方位・標高・ポイントが一覧で見える
Summit一覧 & フィルタリング
17万9千座を自由にフィルタリングできます。アソシエーション(国/地域)、リージョン、標高範囲、ポイント値など、細かい条件で絞り込める。「日本のまだ誰もアクティベートしていない10ポイント峰」みたいな検索がサクサクできます。
Browse画面。多彩なフィルタで目的の山を探せる
Summit詳細ページ
各山頂の詳細ページでは、座標、Maidenheadグリッドロケーター、標高、ポイント、直近のアクティベーション履歴、さらには 7日間の天気予報 まで表示します。天気予報は標高補正済みのデータで、風速30km/h超の場合は警告も出します。
Summit詳細。天気予報まで見られるのは登山計画に便利
ブックマーク機能
各山頂ページのブックマークボタンをクリックするだけで、「Want to Go(行きたい)」→「Activated(アクティベート済み)」→ 解除 と3段階でステータスが切り替わります。登山計画と実績管理がワンタップで完結する。localStorageに保存されるのでサーバー不要、オフラインでも使えます。まさに位置ゲーの「お気に入りスポット」感覚です。
ブックマーク画面。「行きたい」と「アクティベート済み」をワンタップで切り替え
完全オフライン動作 ― 圏外の山頂でこそ真価を発揮
登山をやっている人ならわかると思いますが、山の中はキャリアの電波が届かないことがほんとうに多い。標高が高くなるほど、谷間に入るほど圏外になります。だからこそ、データをローカルに持つPWAという設計が必須 でした。
初回アクセス時にService Workerが全データ(約44MB)をキャッシュします。2回目以降は 完全オフライン で動作します。CacheFirst戦略で90日間キャッシュを保持するので、自宅でアプリを開いておけば、あとは山の上で圏外でも問題なく使えます。
正直、初回ダウンロードの約50MBは軽くはないです。リージョンごとにデータを分割して必要な地域だけダウンロードさせる設計も考えました。でも、「いま日本のデータしか入ってないから海外の山は検索できない」みたいな 機能制限を意識しながら使うストレスのほうがよっぽど大きい。初回だけ我慢すれば、あとは世界中の17万9千座がまるごと手元にある。このシンプルさを優先しました。
技術的なこだわり
SQLite Wasm + R*Tree空間インデックス ― サブ10msの秘密
今回のアプリで一番こだわったのは 検索速度 です。
17万9千座の山頂データをブラウザ内で高速に検索するために、SQLite Wasmを採用しました。しかもただのSQLiteではなく、R*Tree空間インデックス を使って緯度経度のバウンディングボックスクエリを高速化しています。
処理の流れは、R*Treeで大まかな矩形範囲を絞り込み、その後JavaScriptでHaversine公式を使って正確な距離を計算してソートします。この2段階フィルタリングのおかげで、17万9千座の中から近傍の山をサブ10msで検索 できます。
JSONで同じデータを扱うと60%以上サイズが大きくなる上に、空間インデックスも使えないので検索が遅くなります。SQLite Wasmは正解でした。
注意点: SQLite Wasmでは PRAGMA journal_mode = DELETE を使う必要があります。WALモードだと sqlite3_deserialize と互換性がないためです。ここはちょっとハマりました。
PWA ― ネイティブアプリのような体験
vite-plugin-pwaを使って、Service Workerの自動生成とキャッシュ戦略を実装しています。
| リソース | キャッシュ戦略 | 有効期限 |
|---|---|---|
| SQLiteデータベース(44MB) | CacheFirst | 90日 |
| OpenStreetMap タイル | CacheFirst | 30日(最大500枚) |
| 天気API(Open-Meteo) | CacheFirst | 12時間 |
| 標高データ(国土地理院) | CacheFirst | 30日 |
| SOTA API | CacheFirst | 12時間 |
デザインシステム ― Technical Cartography
UIデザインは 「Technical Cartography」 というコンセプトで、ヴィンテージの無線機と地形図からインスピレーションを得ています。ダークベースに琥珀色のアクセント、等高線パターン、CRTスキャンライン効果など、無線の世界観を表現しています。
Technical Cartographyデザイン。等高線パターンとネオングロウがかっこいい
- 背景:
rgb(12, 16, 24)のダークベース - プライマリアクセント:
rgb(255, 169, 51)琥珀色(ボタン、重要データ) - セカンダリ:
rgb(51, 204, 204)ティール(グリッド、ラベル) - GPS/ステータス:
rgb(102, 255, 153)グリーン
フォントも3種類使い分けています。ヘッダーにRajdhani、座標データにJetBrains Mono、本文にDM Sans。技術的な雰囲気を出しつつ、読みやすさも確保しました。
Claude Codeだけで開発した話
ここが今回一番伝えたいことかもしれません。
このアプリ、自分ではコードを1行も書いていません。
全部 Claude Code で開発しました。要件を日本語で伝えて、Claude Codeがコードを生成して、テストして、コミットして、リリースまでやってくれる。v3.1.0からv3.6.0まで、機能追加もバグ修正も全部Claude Codeです。
UIデザインに関しては、Claude Codeの frontend-designスキル(Anthropic公式)を使いました。このスキルは「AIっぽいダサいUI」を避けて、プロダクションクオリティの独創的なデザインを生成してくれます。フォント選定、カラーパレット、アニメーション、背景パターンまで、全部スキルが決めてくれました。
開発の流れ
- 要件定義: 「SOTAの山頂を近くの位置から検索できるPWAを作りたい。オフラインで動くようにしたい」
- 技術選定: SQLite Wasmを使った高速検索、R*Tree空間インデックスの提案もClaude Codeから
- 実装: ページごとに「ダッシュボードページを作って」「GPS検索機能を追加して」と指示
- デザイン:
/frontend-designスキルでUIを洗練 - テスト: Playwright E2Eテストの作成と実行もClaude Codeが担当
- リリース: コミット、タグ付け、リリースノート作成まで自動化
GitHubのコミット履歴を見ると、Claude Codeのセッションリンクが含まれているコミットがあります。開発プロセスが完全にトレーサブルです。
リリース履歴
OSSとしてGitHubで公開しているので、開発の全履歴が見られます。
| バージョン | 主な機能追加 |
|---|---|
| v3.1.0 | ホームページをダッシュボードに変身。統計カード、ヒーローバナー追加 |
| v3.2.0 | 国別フィルタ、色分けインジケーター |
| v3.3.0 | 全ドキュメント英語翻訳、バイリンガルUI対応 |
| v3.4.0 | 山頂ページに7日間天気予報を追加 |
| v3.5.0 | 直近のアクティベーション履歴、アクティベーターページ |
| v3.6.0 | ブックマーク機能、GPSライブポジショニング、ダウンロード進捗バー |
インフラ費用:完全無料
このアプリの運用にかかるインフラ費用は 完全にゼロ です。
| サービス | 用途 | 費用 |
|---|---|---|
| GitHub Pages | ホスティング | 無料 |
| GitHub Actions | ビルド・デプロイ・データ更新 | 無料 |
| SOTA公式CSV | 山頂データソース | 無料 |
| Open-Meteo | 天気予報API | 無料 |
| OpenStreetMap | 地図タイル | 無料 |
| 国土地理院 | 標高データ | 無料 |
サーバーレス。データベースサーバーなし。APIサーバーなし。全部ブラウザ内で完結します。SQLite Wasmのおかげで、サーバーサイドのデータベースが不要になりました。
毎週日曜日にGitHub Actionsが自動でSOTA公式CSVを取得してデータベースを再構築し、GitHub Pagesにデプロイします。完全自動運用です。
まとめ
SOTA Peak Finderは「位置ゲー好き×アマチュア無線家」の自分にとって、最高に楽しいプロジェクトでした。
- SQLite Wasm + R*Tree は、ブラウザ内で大量の地理データを扱うベストな選択肢。サブ10msの検索速度は体感で「一瞬」
- PWA でオフライン動作させることで、電波のない山の上でも使える実用的なアプリに
- Claude Code を使えば、コードを1行も書かずにプロダクションレベルのアプリが作れる時代
- GitHub Pages + GitHub Actions で、インフラ費用完全無料の自動運用が実現
SOTAをやっている人はぜひ使ってみてください。そしてSOTAを知らなかった人は、これを機にアマチュア無線の世界に足を踏み入れてみませんか? 山に登って、無線で交信して、ポイントを貯める。究極の位置ゲー がそこにあります。
おまけ
私のコールサインは JE1WFV です。SOTAでアクティベーションしているときに聞こえたら、ぜひ呼んでください!
Ingressは今でもたまにやっています。位置ゲーの血は抜けないものですね。SOTAはIngressの「ユニークポータル数を稼ぐ」感覚に近い楽しさがあって、ハマっています。
アプリに関するフィードバックやバグ報告は、GitHubのIssueやDiscordで受け付けています。プルリクエストも大歓迎です!
73 & Happy Trails! 🏔️📻