🙌

公開4日で届いたユーザーの声を、Gemini→Cursorのバケツリレーで即日実装した話──画像圧縮サービスMamePressのUX改善ログ

に公開

はじめに:この記事の立ち位置

私はプログラマーではありません。M&Aアドバイザーを約20年やっている、いわゆるビジネスサイドの人間です。

先日、画像圧縮サービスMamePressGemini + Cursor(Claude Opus)で48時間で開発し、Vercelにデプロイしました。その開発記録をnoteに書いたところ、ありがたいことにTwitter経由でユーザーからフィードバックが届き始めました。

この記事では、ユーザーからのフィードバックを起点に、Geminiで実装方針を構造化し、Cursorでコードを書き、GA4でユーザー行動の計測基盤まで整えた一連のプロセスを、Geminiとの実際のやり取りを交えながら記録します。

エンジニアの方々にとっては「非エンジニアがユーザーの声をAIスタックでどうプロダクト改善に変換しているか」という一種のケーススタディとして、また「ユーザーフィードバック → Geminiでの実装設計 → Cursor用の指示文生成」の具体的なワークフローの参考として読んでいただければ幸いです。

技術的に稚拙な部分も多々あるかと思いますが、むしろそこにこそ「ここ脆弱性あるよ」「この設計はこうしたほうがいい」といったフィードバックをいただけると助かります。


前提:MamePressの技術スタック

まず現状の構成を簡単に共有します。

項目 技術
フレームワーク Next.js(App Router)
画像処理 ブラウザ内Canvas API(完全ローカル処理)
ホスティング Vercel
バージョン管理 GitHub
アクセス解析 GA4(@next/third-parties/google
開発AI Gemini(設計・プロンプト生成)→ Cursor + Claude Opus(実装)

画像がサーバーに送信されない「完全ローカル処理」が設計思想の中核です。圧縮処理はすべてブラウザ内のCanvas APIで完結しており、Vercelへのデプロイで自動的にHTTPSが強制されます。


届いたフィードバックをGeminiで「実装仕様」に変換する

公開から数日で、Twitterに3件のフィードバックが届きました。

  • 副業ブロガーの方:「スクショをいちいちペイントに保存して圧縮ツールに上げるのがしんどい。Ctrl+Vで直接貼り付けられたら最高なんですけど」
  • Web制作会社のデザイナーの方:「ドロップ領域が狭くて、1日何十枚も処理するとストレス。TinyPNGやNotionみたいに画面のどこに落としても反応してほしい」
  • 子育てブロガーの方:「子どもの写真をブログに載せてるんですが、位置情報ってちゃんと消えますか?」

どれも具体的で、言われてみれば「確かに」と思うものばかりでした。

ただ、私はプログラマーではないので、「Ctrl+Vで貼り付け」と言われても、それがブラウザのどのAPIを使えば実現できるのか見当がつきません。そこで、これらのフィードバックをGeminiに渡して、「ユーザーからこういう要望が来ている。実装の方針と優先順位を整理してほしい」と相談しました。

Geminiが返してきたのは、UX向上度と実装コストのバランスで優先順位をつけた実装方針でした。以下に要点を抜粋します。

Geminiの整理:ユーザーの声を実装仕様に落とし込む

1位:クリップボードの入出力完全対応(Ctrl+V / コピーボタン)

副業ブロガーの方の要望を受けて、Geminiはこの機能の実装価値を分析しました。

  • スクリーンショットは「無駄に重い」──Snipping ToolやMacのスクショは基本的にPNG形式でクリップボードに保存される。高解像度ディスプレイの普及で、ただのWebブラウザの画面を切り取っただけでも数MBになりがち
  • 「一旦デスクトップに保存する」という手間が消滅する──通常の圧縮ツールでは「キャプチャ→ペイントに貼り付けて保存→圧縮ツールにD&D」という中間保存が必須。Ctrl+V対応で中間保存を完全にスキップできる
  • ローカル処理とのセキュリティ上の相性──スクショには社内システムの管理画面や顧客とのチャット履歴など機密情報が含まれがち。「スクショを軽くしたいけど、海外の圧縮サーバーには送りたくない」というニーズに刺さる

さらにGeminiは、ユーザーの要望(入力側のCtrl+V)に加えて、出力側のクリップボードコピーも提案しました。圧縮後の画像をダウンロードせずにワンクリックでコピーし、そのままWordPressやSlackに貼り付けられる、というフローです。ユーザーの声を起点に、「だったらこっちも欲しくなるはず」と連鎖的にニーズを拡張してくれるのは、AIとの壁打ちならではの副産物でした。

実装の難易度について「ブラウザの標準機能(Clipboard API)を使えば、現在のドラッグ&ドロップの処理にpasteイベントのコードを少し書き足すだけ」という見立てでした。

2位:EXIF(位置情報)削除の明示

子育てブロガーの方の不安に応えるための改善です。ここが技術的に面白いポイントでした。Geminiの分析によると、MamePressのCanvas API圧縮処理の過程で、EXIFなどのメタデータはすでに自動的に削ぎ落とされているとのことでした。

つまり、新しい機能を実装するのではなく、既存の仕様をUIで明示するだけ。実装コストが極小でありながら、ユーザーの不安を直接解消できる改善です。「安心です」とひと言画面に書いてあるだけで、信頼感はまるで変わる──これは、機能を作ることだけがプロダクト改善ではないという気づきでもありました。

3位:ドラッグ&ドロップ領域の全画面化

デザイナーの方が挙げてくれたNotionSlackの事例は、Geminiにとっても明確な実装リファレンスになりました。「フルスクリーン・ドロップゾーン」パターンの導入です。Geminiの提案では、dragenter/dragover/dragleave/dropのイベントリスナーをページ全体に設置し、ドラッグ中は半透明のオーバーレイを表示する設計でした。


ユーザーの声 → Geminiの設計 → Cursor用の指示文

ここがこのワークフローの肝です。Geminiはユーザーの要望を分析・整理するだけでなく、Cursorに渡すための具体的な実装指示文(プロンプト)まで生成してくれます。

たとえば、クリップボード対応の指示文はこのような形でした(一部抜粋)。

## 1. 入力:Ctrl+V(ペースト)での画像読み込み
メインのアップロードコンポーネントに、グローバルな `paste` イベントリスナーを追加してください。
- ユーザーが画面上のどこかで `Ctrl+V` を押した際、クリップボード内のデータ
  (`e.clipboardData.files`)を確認する。
- データが画像ファイル(`image/*`)であった場合、既存のファイル選択・ドロップ時と
  同じアップロード処理を実行する。
- 処理終了後はデフォルトのペースト動作を `e.preventDefault()` で防ぐ。

## 2. 出力:圧縮後画像のクリップボードへのコピー機能
圧縮完了後の画像リストに「コピー」ボタンを追加してください。
- `navigator.clipboard.write` と `ClipboardItem` を使用して、
  圧縮後の画像データ(Blob/File)を直接クリップボードにコピーする。
- コピー成功時は視覚的フィードバック(トースト通知またはアイコンの
  チェックマーク化)を行う。

フルスクリーン・ドロップゾーンの指示文も同様に具体的でした。

## 1. 状態管理とイベントリスナー
- ページ全体に `dragenter`, `dragover`, `dragleave`, `drop` イベントリスナーを追加。
- `isDraggingGlobal` ステートを管理。

## 2. UIのオーバーレイ表示
- `isDraggingGlobal` が `true` の場合、画面全体を覆う半透明のオーバーレイ
  (`fixed inset-0 z-50 bg-background/80 backdrop-blur-sm`)を表示する。

Tailwindのクラス名まで指定してくるあたり、Geminiがプロジェクトの技術スタックを理解した上でプロンプトを生成していることがわかります。

非エンジニアにとっての意味

このワークフローの重要なポイントは、私自身はClipboard APIの仕様もdragenterイベントの挙動も理解していないということです。ユーザーの声を受け取り、Geminiに「どう実装すべきか」を相談し、出てきた指示文をCursorに貼り付けて、動作確認をする。ユーザーとGeminiとCursorの間を行き来する、いわば「伝書鳩」のような役割です。

ユーザーの「Ctrl+Vで貼り付けたい」という一言が、Geminiを経由してe.clipboardData.filesnavigator.clipboard.writeといった具体的なAPI呼び出しに変換され、Cursorが動くコードにする。この変換プロセスが成立していること自体、エンジニアの方々にとっても何らかの示唆があるのではないかと思います。


GA4カスタムイベントの計測基盤を整える

機能の実装だけでなく、ユーザー行動の計測基盤もGeminiの提案で整備しました。

MamePressのような1ページ完結型のツールでは、通常のGA4のページビュー計測だけでは「来てくれたけど使わずに帰ったのか」「30枚圧縮して満足して帰ったのか」の区別がつきません。Geminiはこの課題を指摘した上で、計測すべき5つのカスタムイベントを提案しました。

イベント名 トリガー パラメータ
upload_images 画像アップロード時 count(枚数)
compression_complete 圧縮完了時 saved_bytes(削減量)
download_image ダウンロード実行時 type(single/zip)
switch_mode モード切り替え時 mode(smart/size_limit)
copy_to_clipboard コピーボタン押下時 ──

実装は@next/third-parties/googlesendGAEventを各ハンドラーに追記する形です。Geminiが生成したCursor用指示文では、各イベントの発火ポイントまで具体的に指定されていました。

// 画像がドロップされた時の処理内に追加
sendGAEvent('event', 'upload_images', { count: files.length });

// ダウンロードボタン押下時
sendGAEvent('event', 'download_image', { type: 'single' });

GA4のカスタム定義も忘れずに

Geminiから受けた重要な注意点がありました。イベント名は自動的にGA4に反映されるが、パラメータ(counttypeなど)は管理画面で「カスタム定義」を手動で登録しないとレポートに表示されないということです。

具体的には、GA4の管理画面 → データの表示 → カスタム定義 → カスタムディメンションを作成、という手順で以下を登録します。

ディメンション名 イベントパラメータ
アップロード枚数 count
DLタイプ type
利用モード mode

saved_bytes(削減量)は数値データなので、カスタムディメンションではなくカスタム指標として登録します。これにより、将来的に「MamePressが合計で〇〇GB削減した」というデータを集計できるようになります。

発火確認の方法

実装後の動作確認には、Chromeのデベロッパーツール(F12)→ ネットワークタブでcollectをフィルタリングする方法が手軽でした。GA4へのリクエストが飛んでいることを確認し、ペイロードのen(Event Name)パラメータにupload_imagesなどが入っていれば成功です。

GA4のリアルタイムレポートでも確認でき、操作から数秒〜数十秒で反映されます。標準レポートへの反映には24〜48時間のタイムラグがあるので、実装直後のテストにはリアルタイムレポートを使うのが正解です。


実装の結果:Cursorでの反映はスムーズだったか

結論から言うと、今回の3つの改善はGeminiの指示文をCursorに貼り付けるだけで、余計なやり取りなしにきれいに反映されました。GA4のカスタムイベントも同様です。

ただし、これが毎回うまくいくとは限りません。以前の開発では、Cursorが既存のコードとの整合性を見失って、意図しない箇所を壊してしまうこともありました。今回スムーズだったのは、各改善が機能的に独立していたことが大きいと思います。Geminiの指示文でも「1つずつCursorに入力して段階的に実装・動作確認を進めるのが安全」と注記されていました。

デプロイはCursorからGitHubへコミット&プッシュ → Vercelに自動連携、というお決まりの流れです。


考察:AIスタックにおけるGeminiの「役割」

今回のプロセスを振り返ると、Geminiが担っていた役割は大きく3つに分類できます。

1. プロダクトマネージャー的な役割
ユーザーから届いた生のフィードバックを受け取り、実装の優先順位をUX向上度と実装コストのバランスで整理する。「クリップボード対応は重要度★5で実装コスト低」「EXIF明示は重要度★4で実装コスト極小」といった判断は、PMがバックログの優先順位を決める作業に近いです。さらに、ユーザーの要望(入力のCtrl+V)から「だったら出力のコピーも欲しくなるはず」と連鎖的にニーズを拡張してくれる点は、ただの翻訳者を超えた価値だと感じました。

2. テクニカルライター的な役割
改善案を、Cursor(Claude Opus)が正確に解釈・実装できる粒度の指示文に変換する。APIの具体名(navigator.clipboard.writeClipboardItem)やUIフレームワークのクラス名(Tailwind)まで含めた記述ができる点が、汎用的なチャットAIとの差異だと感じます。

3. アナリスト的な役割
GA4のカスタムイベント設計において、「どの行動を計測すべきか」「パラメータに何を持たせるべきか」「カスタム定義の登録が必要」といった知識を、ツールの特性を踏まえて提案する。

非エンジニアの私にとって、Geminiは「ユーザーの声を実装可能な仕様に翻訳してくれる一人PMチーム」のような存在になりつつあります。ただし、Geminiの提案をそのまま採用するのが常に正しいとは限りません。今回も、ZIP一括ダウンロード機能を追加提案として挙げてきましたが、これはすでに実装済みでした。AIはプロジェクトの現状を完全には把握していないので、人間側の判断は依然として必要です。


まとめ:「ユーザーの声→実装→計測」のサイクルを回す

今回のサイクルをまとめると、以下のようになります。

ユーザーの声(Twitter)

Geminiで実装方針の構造化・優先順位づけ・ニーズの拡張

GeminiがCursor用の実装指示文を生成

Cursorで実装 → GitHubにプッシュ → Vercelに自動デプロイ

GA4のカスタムイベントで効果計測

ユーザーに報告 → 次のフィードバックへ

起点はあくまでユーザーの声です。Geminiはその声を「実装可能な仕様」に変換する翻訳エンジンであり、Cursorはそれを動くコードにするビルダーです。このサイクルが「公開4日目」の段階で回り始めたことには、正直なところ自分でも驚いています。実装の中身を詳細に理解しているわけではないので、技術的な負債がどこに溜まっているのかは見えていません。

そういう状況のため、もしお使いの方で「ここはこうしたほうがいい」「この設計には問題がある」というフィードバックをいただける場合には、とてもありがたいです。MamePressという名前には「まめに働く」という意味を込めたので、いただいた声にはできるかぎりまめに対応していきたいと思っています。

気になった方はぜひ触ってみてください。
MamePress|マメプレス

Discussion