【個人開発 #6】AIと星空アプリを作ったら「技術選択」で全部変わった話
💡 この記事について AIアシスタント(OpenClaw/スピカ)との会話を元にした学習記録です。 内容は変更される可能性があるため、実際の開発では公式ドキュメントを確認の上、ご自身の判断でお願いします。
この記事で分かること:
- 技術選択がアプリの方向性を決める話
- AIと一緒なら天文計算もセンサー連携も怖くない
- 「動く」と「使いやすい」の間にある、最後の0.5の話
Star Hopper というPWAアプリを作った。スマホで星空を見上げながら、コンパスを使って星を探す——いわゆるスターホッピングを体験できるやつ。
既存の星空アプリはあるけど、「自分で作る」のは全然違う体験だった。
何がどう違ったかというと、作って初めて気づくことが山ほどあった。星は毎秒動いてるとか、3D描画の仕組み(WebGL)は日本語を「???」と表示するとか、タップボタンの3px差が使い心地を激変させるとか。
で、これは一人じゃ無理だった。AIアシスタント(スピカ)と一緒に開発したからこそ、天文計算やセンサー連携みたいな「自分の専門外」に踏み込めた。
この記事では、そのときの技術的な発見を共有する。

星って固定座標じゃないの?
これが開発中に最初にぶつかった壁だった。星座のデータベースを作って「はい完成」じゃない。アプリを開いた瞬間の、ユーザーの場所と時刻で座標を計算し直す必要がある。
実際のコードはこんな感じ。
// RA/Dec(天球座標)→ Azimuth/Altitude(地平座標)変換
const observer = new Astronomy.Observer(lat, lon, height);
const time = Astronomy.MakeTime(date);
const gst = Astronomy.SiderealTime(time);
const lst = gst + (lon / 15);
const ha = (lst * 15) - ra;
ここで astronomy-engine というライブラリを選んだのが、このプロジェクトの分岐点だったと思う。
astronomy-engine はネイティブJSで動く、軽い、精度は十分。他の候補はPythonベースだったりサーバーサイド前提だったりして、PWAには合わなかった。astropyっていうガチの天文計算ライブラリがあって、精度も機能も段違い。でもPythonはブラウザで直接動かない。サーバーを立ててAPIで通信する構成になるから、山の中でオフラインで使うっていうStar Hopperの前提と合わなくなる。ここが個人開発の面白いところで、「何を使うか」の判断ひとつでプロジェクトの難易度が激変する。このライブラリの存在を知らなかったら、「星の方角をリアルタイムで出す」なんて発想自体が出てこなかったと思う。
「あっち向いて!もうちょい右!ビンゴ!」
星の座標がリアルタイムでわかるようになったので、次はスマホのコンパスと組み合わせる。
DeviceOrientation APIっていうブラウザの標準機能で端末の向きを取得して、目標の星のAzimuthとの差を測る。Chrome、Safari、Edge……主要なブラウザはだいたい対応してる。ただしiOSのSafariだけは「ユーザーの許可」が必要で、これのハンドリングも地味に面倒だった。ただ、「248°の方を向いてください」って表示しても、ユーザーは困る。誰も自分が今何度を向いてるかなんて知らない。
だから**「宝探しゲーム」方式**にした。近づいたら色が変わって、バイブレーションが始まる。
| 状態 | 角度差 | フィードバック |
|---|---|---|
| 🧭 探してみよう | 90°以上 | 暗い表示 |
| 😊 近づいてきた | 45°〜90° | オレンジの光 |
| 🔥 もう少し! | 15°〜45° | 赤い脈動アニメーション |
| ✨ ズバリ! | 15°以内 | 金色、効果音、バイブレーション |

// 方角の正規化 ← これ忘れると壊れる
let diff = targetAz - currentHeading;
if (diff > 180) diff -= 360;
if (diff < -180) diff += 360;
あとバイブレーションのスロットリング。何もしないと、コンパスの値が毎秒何十回も更新されて「ブブブブブブブ」って鳴り止まなくなる。on-targetで500ms間隔、hotで2秒間隔、というようにレート制限をかけた。
こういう細かいUXの調整は、AIに「バイブレーションが止まらない」って相談すると「スロットリングパターンはこう」ってすぐ返ってくる。自分でStack Overflowを掘り返すより圧倒的に速い。
Canvas2Dで十分だったワケ
星座の形と、星同士のつながりを「わかりやすく」見せたい。だったら、線と点で描くスケマティック(模式図)のほうが学習効果は高い。
● ベテルギウス
/|
/ |
リゲル ●───●──● 三ツ星
\ |
\|
● サイフ
みたいなイメージ。Canvas2DのAPIで星を点として描いて、線で結ぶ。
技術的には、星座データにCanvas上の座標を0〜350の範囲で正規化して持たせてる。リアルなRA/Decとは別に、「見せるための座標」を定数で持つ設計。
// 星座データの例
orion: {
name: "オリオン座",
stars: {
betelgeuse: { x: 120, y: 80, magnitude: 0.5, color: '#ffaa44' },
rigel: { x: 80, y: 250, magnitude: 0.1, color: '#aaccff' },
// ...
},
lines: [['betelgeuse', 'bellatrix'], ['mintaka', 'alnilam'], ...]
}
Three.jsを使わない分、バンドルサイズが小さい。PWAで山の中で使うアプリだから、オフラインで動くことが優先。これも技術選択の話。
3D地球儀で日本語が「???」になった日
ただし、Star Hopperの全部が2Dというわけじゃない。
これ、普通にハマると心折れる。「Globe.gl 日本語」で検索してもまともな情報がほとんど出てこなかった。
AIアシスタント(スピカ)に聞いたら「WebGLネイティブラベルは諦めて、HTMLオーバーレイに切り替えるのが定番」とのこと。Globe.glには htmlElementsData メソッドがあって、3D空間上の座標にHTMLのDOM要素を重ねて表示できる。
// WebGLラベル → HTMLオーバーレイに切り替え
globe.labelsData([]) // WebGLラベルを空にして
.htmlElementsData(spots) // HTML要素でラベルを描画
.htmlElement(d => {
const el = document.createElement('div');
el.textContent = d.name; // ← 日本語がちゃんと出る!
el.className = 'globe-label';
return el;
});
ラベル問題が解決したら、今度はモバイルでの動作が重い。大気エフェクト(showAtmosphere)を切って、回転速度を制限して、テクスチャ解像度を下げて……と、チューニングの連続。
AIがいなかったら、Globe.glの制約もHTMLオーバーレイという回避策も、たぶん見つけられなかった。ドキュメントにちゃんと書いてないことが多い。
動くだけじゃ足りない。最後の0.5をAIと詰める
ここまでで「動く」アプリは完成した。星を計算して、コンパスで追って、星座を描いて、3D地球儀も動いて。
でも品質スコアは4.5だった。
品質5.0にするために、11項目を改善した。
| 改善 | Before | After |
|---|---|---|
| タッチターゲット | 41px | 44px(Apple推奨準拠) |
| スワイプバック | なし | 全画面で左スワイプ戻り |
| ARIA属性 | ゼロ | Canvas/nav/tab完備 |
| フォーカス管理 | なし | 画面遷移時にフォーカス移動 |
| 権限拒否ガイド | 汎用メッセージ | iOS/Android別の具体手順 |
| 星座神話データ | 一部空欄 | 63星座完全化 |
| PWAショートカット | なし | 3つのクイックアクション |
AIは**「何が足りないか」を見つけるのが得意**。人間は**「それ、やろう」と決められるのが強い**。
63個の星座それぞれに神話テキストと観察豆知識を書くのも、AIとの共同作業。「おおいぬ座の神話は?」「シリウスはギリシャ語で”焼き焦がす”という意味で……」というやりとりを63回繰り返す。一人でやったら何時間かかったか。
作ってみて気づいたこと
振り返ると、3つのことに気づいた。
技術選択で結果が変わる。 astronomy-engineを選んだから天文計算に踏み込めたし、Canvas2Dを選んだから軽量なPWAが実現した。Globe.glを選んだからISS追跡と月面ツアーが実装できた。逆の選択をしていたら、全然違うアプリになってた。
AIがいれば踏み込める。 天文計算もWebGL問題もアクセシビリティも、自分一人の知識だけだと「やめとこう」と判断してたはず。AIに聞ける環境があるだけで、挑戦のハードルが下がる。
最後の0.5は、人間が決める。 AIは「41pxは44pxにしたほうがいい」って教えてくれる。でも、それを「やろう」と決めて、11項目を全部潰すのは人間。面倒くさいけど、ここの差が使い心地に出る。
⚠️ 注意 この記事はOpenClaw/AIアシスタントとの会話を元にした内容です。 実際の運用は自身で確認してください。 技術情報は変わる可能性があるので、公式ドキュメントの確認を推奨します。
シリーズ目次
- VPSとMac Miniの違い
- Groq APIで音声文字起こし
- 喋るだけでブログ記事になる仕組み
- PWAを”本物のアプリ”にしたい
- Google Play ストア公開
- AIと星空アプリを作ったら「技術選択」で全部変わった話 ← 今ここ