ユーザーと Claude(AI)の対話だけで、ゼロからフル機能アプリが完成するまでの全記録
その日、ユーザーはWindows PCに Claude Code(AnthropicのAI搭載CLIツール)をインストールしたばかりでした。AIがコードを書いてくれるらしい、という話は聞いていたものの、ドキュメントも読まず、チュートリアルもやらず、とりあえず何か作ってみようと思い立ったのがこのアプリの始まりです。
前情報ゼロ、手探りの状態から「QRコードの読み取りアプリを作りたい」とだけ伝えて開発スタート。コードは1行も手書きしていません。すべてClaudeが生成し、ユーザーがブラウザで動作確認してフィードバックを返す、というサイクルで開発されました。
すべてはこの一言から始まりました。
XAMPPのインストールが完了した後、Claudeが基本アプリを一気に生成。カメラ映像からjsQRでリアルタイム読み取り、画像アップロードでhtml5-qrcodeによるスキャン、PHPで履歴の保存/読み出し/ログ記録までの一通りの機能が最初の数回のやりとりで動き始めました。
基本機能が動いた直後、最初の壁にぶつかりました。
通常のQRコードリーダーは「白い背景に黒いモジュール」を前提に設計されています。オレンジのグラデーション背景に白いモジュールのQRは、まったく検出できませんでした。
まず試したのは、画像の全ピクセルの色を反転する方法。白→黒、オレンジ→青に変わります。しかしオレンジのグラデーション背景は反転しても均一な白にはならず、検出率は上がりませんでした。
色の「鮮やかさ(彩度)」に注目するアイデアを発見。オレンジは彩度が高く、白は彩度がほぼゼロ。この差を利用して:
テスト画像には5個のQRコードが含まれていました。しかし検出できるのは常に1個だけ。
Chrome/Edgeに搭載されたネイティブAPI。複数QRを一度に返せる唯一のブラウザAPI。しかし対応ブラウザが限られ、検出精度も不安定でした。
QRを検出したら、その領域を白で塗りつぶして再スキャン。これを最大10回繰り返す方法。
画像を2x2、3x3、4x4のグリッドに分割し、各セルを個別にスキャン。セル間は20%オーバーラップさせて境界上のQRも取りこぼさない設計。
これらすべてを組み合わせて 4件まで到達。しかし5件目(App StoreのQR)がどうしても取れません。
コントラスト強調、閾値の変更、グリッドパターンの追加(2x3、3x2)... あらゆる手を尽くしましたが、JavaScript のQRライブラリではこの5件目のQRを認識できませんでした。
JavaScript単体での限界を感じたユーザーから、重要な提案がありました。
まず scan_test.py(テスト用)を作成して手元で検証。結果は劇的でした。
5件すべて検出成功! pyzbar の認識力は jsQR/ZXing を大きく上回っていました。
しかし最初の統合ではうまくいきませんでした。PHPから Python を呼び出して結果を受け取る部分でつまずきます。
Python が失敗した場合にJSフォールバックに切り替わっていたため、常に4件(JSの限界)で止まっていたのです。scan.php のエラーハンドリングを修正し、Python の出力をJSON形式で正しくパースするよう改善。
2>/dev/null と書いていてWindowsで動かなかった。2>NUL に修正する必要がありました。
QRコードが検出された後、「どこにあったか」が視覚的にわかるアノテーション画像を生成する機能を追加。
Python の PIL(Pillow)で元画像の上にカラー枠と番号バッジを描画。検出されたQRの位置を色分けしたポリゴンで囲み、丸い番号バッジを付けます。
ここからUIの微調整が始まります。
3回のやりとりで、バッジのサイズ感がちょうど良く調整されました。生成された画像はBase64エンコードでJSONに埋め込んでフロントに返し、クリックで全画面プレビューできるようにしました。
iPhoneで撮影した写真(4032x3024ピクセル)をアップロードすると、処理に1分以上かかっていました。前処理バリアント7種 × グリッドパターン5種 × 全ピクセル操作が原因でした。
最適化のポイント:
スキャン機能が安定した後、履歴まわりの機能が次々とリクエストされました。
重複URLのグルーピング表示と時刻の右寄せレイアウトを実装。
Gmail送信(Gmailの作成画面URL)、標準メーラー送信(mailto:)、クリップボードコピーの3つのアクションボタンが追加されました。
レスポンシブ対応で、680px以下の画面幅ではフルテキストの代わりに短縮ラベル(Gmail / Mailer / Copy)+ アイコンで表示。
localStorageにUUIDを保存し、APIリクエストに client_id として付与する仕組みを実装。サーバー側では data/history_{client_id}.json のように分離保存。同じPCでもChromeとEdgeで履歴が別になります。
「カメラ」と「画像アップロード」の切り替えが分かりにくいという問題を解決。
ブラウザのタブバーを模したデザインに変更。アクティブタブは白背景で上部に青いボーダー、非アクティブはグレー背景。パネルの青い枠線がタブに直接つながるように border-bottom: 2px solid white + margin-bottom: -2px で重ね合わせ。
タブのラベル名も何度か微調整して、最終的に「カメラでQR読取」「画像からQR検出」に落ち着きました。
Claude Codeをインストールした直後、チュートリアル代わりに約2時間かけて作った別プロジェクトのQRリーダーがありました。そのカメラスキャンコードを今回のアプリに移植します。
旧アプリのjsQRベーススキャンから、ZXingベースに全面書き換え。大きく進化したポイント:
スキャンフレーム(赤い角マーク付き)は、中央60%の領域を示し、周囲を暗くすることでQRコードを合わせやすくなりました。白QRコードも自動で色反転して検出するため、「反転モード」ボタンが不要に。
PCでは max-height: 360px に制限し、スキャンフレームを height: 80% + aspect-ratio: 1 で常にビデオ内に収まるよう調整。
仕上げとして、ヘッダーに3点メニューを追加。
「使い方」は各機能の使い方をわかりやすく説明するページ。「できるまで」はこのページ ── 開発の全過程をダイジェストとしてまとめたものです。
運用面での改善が2つ加わりました。
履歴の取得時に3時間以上前のエントリを除外し、APIアクセスのたびに更新のない古い履歴ファイル自体も削除する仕組みを追加。一時的な読み取り用途のアプリなので、データが自動で消えるのは理にかなっています。
履歴JSONやスキャンログがWeb公開ディレクトリ内にあると、URLを直接叩けばアクセスできてしまいます。htdocsの外(C:\xampp\****\)に移動して、PHPからのみアクセス可能にしました。
ローカルのXAMPP環境で完成したアプリを、インターネットに公開することに。
VPSにはWebサーバーもPHPも入っていない素の状態。Claudeがセットアップスクリプト(setup_ubuntu.sh)とデプロイスクリプト(deploy.sh)を生成し、SSH経由でリモート実行。
途中、いくつかの壁にぶつかりました:
libgl1-mesa-glx → libgl1)php-mbstring が未インストール → メタ情報取得が500エラーscan.php の 2>NUL(Windows) → OS自動判定に修正Cloudflareでドメイン(kjm3.tech)を設定し、SSL/TLSをFlexibleモードに。HTTPSで全機能が動作するようになりました。
getUserMedia(カメラAPI)が使えない。Cloudflareの無料SSLで解決。
7つのQRコードがある画像で3つしか検出できない問題が発覚。
各セクションの隅に配置された小さなQRコードが、グリッド分割しても解像度不足で検出できていませんでした。
さらに、大きな画像の処理に時間がかかりすぎる問題に対して、10秒のタイムアウトを実装。時間内に見つかったQRコードだけを返し、「処理時間超過のため途中結果です」と表示します。
読み取ったQRコードがURLだった場合、そのサイトのメタ情報(description)を自動取得する機能を追加。
PHPでURLのHTMLを取得し、og:description や meta description をパースして履歴データに保存。スキャン履歴のURL下に概要文が表示されるようになりました。メール送信・コピー時にも概要が含まれます。
仕上げとして以下も追加:
このアプリは、ユーザーと Claude(AI)の対話だけで、環境構築から機能実装・デバッグ・UI調整、さらにVPSへの本番デプロイまですべてを1日で完成させました。
開発時間の大半を費やしたのがこの問題です。jsQR、ZXing、BarcodeDetector、マスクループ、グリッド分割... JavaScriptだけで5種類以上のアプローチを試しましたが、5件中4件が限界。最終的に Python(pyzbar + OpenCV)をサーバーサイドに導入することで突破できました。
「QRコードは黒い」という常識を覆す白QRコード。単純な反転では解決できず、「彩度」という画像処理の概念を使った独自フィルターが鍵でした。
アノテーションのバッジサイズ、タブのデザイン、ボタンのレスポンシブ対応... UIの調整は何度もスクリーンショットを見ながら微調整する対話が必要でした。「もうちょっと小さく」「中間くらい」「680くらいがいいかも」── このやりとりこそが、AIとの共同開発の醍醐味かもしれません。
開発者より
Claude codeはじめてちゃんとさわってみたけどなんこれすごい。
ブラウザとJS任せで画像からQRコード読んでもうまくとれなかったので、外部のプログラムで処理してよとか、VPSが安いやつなんで処理途中で切ってみてよとか無茶ぶってもすぐ対応。
適当に借りたVPSへのアップまでほぼノータッチでやってくれちゃったりしました。
途中処理が重くなったり、会話履歴忘れられたりとかしてましたが、そこらへんはこれから勉強していけばなんとか対応できそうよね。
何より、ほんとコード一回も書いてないのにできちゃったのがすごい通り越して怖い。
今日の11時ごろに思い立ってClaude code入れて、なんかQR読み取り機作らせてみたらこれそのまま最後まで行けんじゃね?と思ってから現在20時ちょうど、昼飯・休憩で2時間引いても7時間でできるんだね。
すごい時代になったもんだ。
2026/3/8 KJM3
Built with Claude Code (claude-opus-4-6) + XAMPP + Python
Deployed on Ubuntu VPS + Cloudflare
2024-2026 - Made through human-AI collaboration