はじめに
2026年9月19日の朝に空のフォルダから作り始めた定点撮影アプリ「Then & Now」が、9月23日にApp Storeで公開されました。
apps.apple.com実装はClaude Code (Fable 5.1) に任せ、私がやったのは最初のプロンプトを書くこと、実機で触って気づいたことを伝えること、App Store Connectの操作、そしてアイコン画像をGeminiに描かせることでした。コードは1行も手で書いていません。
「AIにアプリを作らせてみた」という記事はもう珍しくありませんが、審査に出して公開されるところまで通すと、コードを書く以外の作業が思ったより多いことが分かります。位置合わせのアルゴリズムで一工夫が必要だったこと、実機で初めて出た不具合、スクリーンショットの素材問題、そのあたりも含めて書いていきます。
作ったもの
同じ場所から同じ構図で撮り続ける「定点撮影」に特化したカメラアプリです。ベランダの木の季節変化、リフォームの進行、子どもの背丈のような、月単位・年単位の変化を写真で残すためのものです。
定点撮影が続かない理由は、構図を合わせるのが難しいことと、撮りに戻るのを忘れることの2つだと考えました。既存のアプリの多くは「前の写真を半透明で重ねる」までは実装していますが、そこから先はユーザーの手作業です。そこで、この2点に機能を絞りました。
- 自動位置合わせ: 前回の写真とライブ映像のズレをリアルタイムに計算し、「少し右に」「少し近づく」のように案内する。ズレが閾値内に入って0.6秒続いたら自動でシャッターを切る
- 撮りどきの通知: 前回から N 日経ったら通知する。その場所に戻ったらジオフェンスで通知する

そのほかにタイムラインでのパラパラ再生、ビフォー・アフターの比較スライダー、安定化つきのタイムラプス書き出し、Face IDによるロック、ウィジェット、Siriショートカットが入っています。無料で、機能制限はなく、収益化は投げ銭だけです。
技術的な前提は、iOS 26以上、Swift 6のstrict concurrency、SwiftUI、SwiftData、画像処理はVisionフレームワークのみでOpenCVには依存しない、という構成にしました。
最初のプロンプトで決めておいたこと
プロンプトは日本語で、およそ200行書きました。振り返ると、効いたのは機能の羅列ではなく、次の3つの区画でした。
「確定事項」を冒頭にまとめる
最低対応OS、言語、永続化、画像処理ライブラリ、収益化、ローカライズ、写真の保存先。こういう決め打ちを「勝手に変えないこと」という見出しの下に並べました。実装の途中で「OpenCVを入れたほうが精度が出そうです」のような提案で脱線しないための柵です。実際、位置合わせの精度で苦労した場面がありましたが、Visionの範囲内で解決策を探してくれました。
マイルストーンごとに区切って報告させる
M1 (基礎)、M2 (位置合わせ)、M3 (リマインダー)、M4 (仕上げ) の4段階に分け、各段階で xcodebuild によるビルドとテストを通してから報告することを指示しました。結果として、初日の午前中にM1からM4までが一通り動く状態になりました。段階ごとに区切ったことで、報告を読んで方向を確認しながら進められました。
「やらないこと」を書く
クラウド同期、SNS連携、フィルター、有料プラン、長いチュートリアル。これらは「提案も実装もしない」と明記しました。自律的に動くエージェントは、放っておくと親切心で機能を足していきます。やらないことを書いておくと、その分の判断を毎回しなくて済みます。
位置合わせはVisionで足りた、ただし一工夫が要った
ここが一番の技術的な見どころです。
Visionには VNTranslationalImageRegistrationRequest (平行移動) と VNHomographicImageRegistrationRequest (ホモグラフィ) という2つの画像位置合わせAPIがあります。ライブ映像を約5fpsに間引き、長辺512pxのグレースケールに落としてから、まず平行移動を求め、手が落ち着いたらホモグラフィを求めて平行移動・回転・拡大率の3成分に分解する、という設計です。
ホモグラフィは大きなズレを過小評価する
既知の変換 (30px移動、5度回転、1.1倍) を適用した画像ペアをテストフィクスチャとして用意し、算出値を検証するようにプロンプトで指示していました。この検証で分かったのが、ホモグラフィ単体では30pxの移動が12pxとして返ってくることでした。回転と拡大は正確でしたが、移動量が小さすぎるのです。おそらく反復的な最適化が局所解で止まるためだと思われます。
Claude Codeが取った対策は、まず平行移動の推定値でフレームをずらしてからホモグラフィを解き、あとで2つを合成する、というものでした。これで30pxの移動が29.99pxとして返るようになりました。
信頼度は自分で計算する
もう1つのハマりどころは、Visionのregistration APIは信頼度を返さないことです。夜景や白い壁でも、何かしらの行列は返ってきます。それをそのまま使うと、でたらめな矢印が表示されます。
そこで、推定した変換で2枚を実際に重ね、正規化相互相関で「本当に一致しているか」を確かめる検証層を入れました。相関が閾値を下回れば「解なし」として扱い、3秒間解が出なければ「この場面では自動ガイドを使えません。重ねて手で合わせてください」と表示して手動モードに落ちます。黙って動かなくなるのが最悪なので、フォールバックには必ず理由を出す、というのは最初のプロンプトから入れていた要件です。
この設計はあとで実物の写真で試すことになります。2021年12月の夜に撮った目黒川の写真と、2026年9月の昼に撮った同じ場所の写真を通したところ、想定どおり「解なし」になりました。昼と夜では画素の特徴が対応しないためで、手動モードに落ちる正しい動きです。ただ、最初の1フレームだけ「右に75%ずれている」というでたらめな推定が検証を通っていました。2枚の重なりがごくわずかで、その部分がたまたま相関していたのが原因です。重なりの割合を条件に加えて直しました。
実機で初めて分かったこと
シミュレータにはカメラがないので、Claude Codeはシミュレータ専用の合成シーン (手ぶれのように漂う図形) を用意して、ガイドと自動シャッターの流れを検証していました。それでも、実機に入れて初めて出た問題がいくつかあります。
しばらく撮っているとプレビューが止まる
原因を実機のログで確定できたわけではありませんが、一番疑わしかったのは、SwiftUIの再描画のたびに新しい AVCaptureSession を作っては捨てていたことでした。カメラ画面の @State で CameraModel() を初期化し、その init でセッションを作っていたため、撮影するたびに親ビューが再描画され、使われないセッションが積み上がっていたのです。セッションの生成を start() に遅らせ、あわせて中断・実行時エラーの監視、フレームが3秒来なかったら再起動する監視、発熱時の処理頻度の抑制を入れました。修正後は再発していません。
1枚目を撮ると、すぐ2枚目が撮られる
これは設計の穴でした。1枚目を撮った直後にその写真が基準になり、端末はまだ同じ場所を向いているので、位置合わせは完全一致の状態になります。0.6秒後に自動シャッターが切れて、不要な2枚目が保存されます。新規ユーザーが全員最初に踏む問題だったので、審査に出した翌日に取り下げてビルド2で再提出しました。
権限ダイアログが3回出る
場所リマインダーをオンにすると、位置情報「使用中のみ」→「常に許可」→通知、と3つのダイアログが続けて出ていました。最初のプロンプトで「まず使用中のみを要求し、常には後から」と書いたのを、そのまま実装した結果です。iOSは requestAlwaysAuthorization を最初から呼んでも、その場では1つのダイアログしか出さず、「常に許可のままにしますか?」の確認は後日バックグラウンドで位置情報を使ったときに自分で出してくれます。2回で済むように変えました。
「ダイアログが出なかった」を時間で判断していた
許可したのにトグルがオンにならないことがある、という現象がありました。許可ダイアログの結果を待つ処理が「0.7秒待ってアプリがアクティブなままなら、ダイアログは出なかった」と判断していたのが原因です。位置情報のダイアログは地図つきで、表示に0.7秒以上かかることがあります。許可状態の変化そのものをポーリングする方式に変えました。
こうした問題は、どれも私が実機で触って「こうなった」と伝えただけで、原因の特定と修正はClaude Code側でした。ログが取れない実機の現象でも、コードから原因の候補を挙げてつぶしていく進め方で解決できています。
ストアに出すまでの作業もほぼ任せられた
コードが動いてからが長い、というのが今回の実感です。
アイコンはGeminiに描かせた
Claude Codeに「Gemini向けのプロンプトをください」と頼み、それをGeminiに貼りました。iOSが角丸マスクをかけるので画像側で角を丸めない、文字を入れない、透過なし、60ptに縮小しても読めること、という制約が入ったプロンプトでした。出てきた案をClaude Codeに渡すと、iOSの角丸をかけて60ptまで縮小した比較画像を作って評価してくれます。「照準を太くしたらプラス記号に見えて写真追加アプリに見える」という指摘は、自分では気づかなかったと思います。
スクリーンショットは写真がなくて詰まった
ストアのスクリーンショットには「昔と今」の写真のペアが必要ですが、作ったばかりのアプリにそんな写真はありません。フリー素材のタイムラプス動画からコマを抜く案も試しましたが、13秒の動画では変化が小さすぎて使えませんでした。
最終的に、Claude Codeがシミュレータ専用のコードとしてフラットなイラストのシーン (季節が変わる木、建っていく家、育つ菜園) を描き、過去日付のデモデータを流し込んで、6.9インチのシミュレータで6画面を日英で撮影、見出しつきの1320x2868に整形するところまでやりました。この間、私は写真を1枚も用意していません。

審査に向けた細かい確認
- ローカライズ: すべてのUI文字列をString Catalogに入れ、コンパイラが抽出したキーと日本語訳の有無を照合するスクリプトで漏れを検出。最終的に186キー
- プライバシーマニフェスト:
UserDefaultsとsystemUptimeの使用理由をPrivacyInfo.xcprivacyに宣言。これがないと ITMS-91053 の警告が来ます - 投げ銭のテスト: Sandboxアカウントと実機での検証が面倒だと言ったら、
StoreKitTestでローカルの.storekit設定に対して購入フローを自動テストする形にしてくれました。審査用のスクリーンショットも、テスト中にセッションを開いたままにしてシミュレータから撮っています - プライバシーポリシー: コードを読んで実態と照合したうえで日英のMarkdownを作成。iCloudバックアップに写真が含まれることも明記しています
「ネットワーク通信ゼロ」は緩めた
最初のプロンプトで「URLSessionを使わない、通信を一切しない」と書いていましたが、v1.1で地図一覧を作ろうとしたところ、MapKitの地図タイル取得がこれに抵触することが分かりました。よく考えると、投げ銭のStoreKitもAppleのサーバーと通信しています。守りたかったのは「開発者のサーバーを持たない、データを開発者にも第三者にも送らない」であって、パケットの有無ではありません。原則をそう書き換えて、プライバシーポリシーの文言も直しました。確定事項として書いたものでも、目的に照らして緩めてよいものはある、という学びです。
まとめ
Claude Codeに定点撮影アプリを作らせて公開するまでで分かったことをまとめます。
- 約5,600行のSwift、85件のテスト、186キーの日英ローカライズを、コードを手で書かずに公開まで持っていけた
- プロンプトで効いたのは、確定事項・マイルストーン・やらないこと、の3つの区画
- Visionのホモグラフィは大きなズレを過小評価する。平行移動で先にずらしてから解くと正確になる
- Visionのregistration APIは信頼度を返さない。推定結果を画素で検証する層を自分で持つ必要がある
- シミュレータで検証できないカメラまわりは、実機で触って現象を伝えれば原因まで辿ってくれた
- ストアに出す作業 (アイコン、スクリーンショット、マニフェスト、IAPのテスト) は、コードを書く時間より長かった
- 「通信ゼロ」のように強すぎる確定事項は、目的に照らして緩めてよい
一番の収穫は、実機で触って「こうなった」と伝えるだけで直っていく体験でした。自分でログを取って原因を追う代わりに、症状の説明に時間を使う。この配分に慣れると、作れるものの範囲がかなり変わりそうです。
参考リンク
- Then & Now - 定点撮影カメラ (App Store 日本)
- Then & Now: Auto-Align Camera (App Store US)
- VNHomographicImageRegistrationRequest (Apple Developer Documentation)
- VNTranslationalImageRegistrationRequest (Apple Developer Documentation)
- Monitoring the user's proximity to geographic regions (Apple Developer Documentation)
- Privacy manifest files (Apple Developer Documentation)
- Claude Code







