
v0でUI遷移検出&遷移図編集アプリを作る: スマホ録画から画面候補を抽出しSupabaseに保存
はじめに
ゲーム UI の見積もりでは、画面数だけでなく、画面遷移の構造も見たくなる場面があります。たとえば、同じ画面に見えても遷移条件が多いと、実装とテストの負荷が増えます。
一方で、画面遷移図を手作業で作るのは負担が大きいです。Figma のようなツールにスクリーンショットを貼り、矢印を引き、バージョン差分も追うとなると、見積もり前の準備だけで時間がかかります。
そこで今回は、スマホの画面録画 (縦長 1080 x 1920 / 30 fps / 最長 5 分) を入力し、動画から画面候補と遷移を自動抽出して、遷移図として確認できるアプリを v0 + Supabase で作りました。自動抽出は 100% を狙いません。自動で十分な精度まで出し、残りを手で補う前提です。

v0 と Supabase の概要
v0 は、Vercel が提供する AI 開発環境です。自然言語の指示をもとに Next.js などのアプリを生成し、出力物をプレビューしながら追加の指示で修正できます。Integration 機能で簡単に Supabase を接続でき、画面実装だけでなくデータの永続化まで含めてアプリを作れます。
Supabase は、Postgres を中心に、Auth や Storage などをまとめて使える BaaS (Backend as a Service) です。今回の検証では、Postgres をメタデータ保存に使い、Storage をサムネイルの保存に使いました。
本記事では以下のような方針で v0 と Supabase を使用します。
- UI は v0 に任せ、まず動く形をすばやく作成
- 動画はサーバへアップロードせず、ブラウザでフレーム抽出とハッシュ計算
- 動画ファイルを API 経由で扱うとサイズ制限や処理時間の制約に当たりやすいため
- 生成したサムネイルとメタデータだけを Supabase に保存
対象読者
- v0 を初めて触るが、v0 + Supabase でどこまで作れるかを知りたい方
- コーディングの時間を抑えて、ゲーム UI の見積もりや仕様整理に使う画面遷移図を作りたい方
参考
作ったもの
Screen Transition Mapper は、読み込んだ録画から画面候補を抽出し、遷移をグラフで表示するアプリです。UI からは Sampling FPS / Hash Threshold / Stability Frames を調整でき、Graph View と Table View を切り替えられます。

処理の流れは次の通りです。動画をローカルで処理し、抽出した結果だけを Supabase に保存します。
Supabase 側の設計
抽出結果を保存できないと、検証結果を見返せません。パラメータを変えて比較したいときも、前回の結果が残っている方が作業しやすいです。そこで、メタデータを Postgres、サムネイルを Storage に保存する構成にします。
テーブル設計
保存対象は 4 テーブルです。runs が 1 回の処理単位で、screens と transitions が抽出結果、edits が手修正の保存先です。
runs: version と処理パラメータを持つ処理セッションscreens: time_ms、hash、cluster_key、thumbnail_path などtransitions: from_screen_id、to_screen_id、confidence などedits: グラフ全体を JSON として保存
Storage 設計
サムネイル画像は Storage の frames バケットに置きます。
v0 に渡したプロンプト
今回 v0 に渡したプロンプトは次の通りです。
Build a full-stack prototype called “Screen Transition Mapper” for game UI estimation.
Context:
- Used by a single developer on desktop Chrome.
- Input videos are smartphone screen recordings: vertical 1080x1920, 30fps, up to 5 minutes.
- Goal is AUTO extraction accuracy first; editor polish is secondary.
- No authentication needed for this PoC.
Tech constraints:
- Next.js App Router + TypeScript + Tailwind + shadcn/ui.
- Use React Flow for the transition diagram.
- Use Supabase (Postgres + Storage) via v0’s Supabase integration (Integrations/Connect).
- Do NOT upload large video payloads through Vercel Functions (4.5MB limit); process the video in the browser and only upload extracted thumbnails/metadata to Supabase.
Core features (MVP):
1) Home page (single page is OK):
- Version input (default “0.0.1”).
- Video import:
a) Upload existing mp4 from disk (primary).
b) Optional “Record a short test video” using MediaRecorder (camera) for quick testing (note: screen recording of other apps is not required).
- Processing controls:
- Sampling FPS selector (default 1 fps).
- Hash threshold slider (default Hamming distance 10).
- Stability requirement (default: accept a new screen only if it persists for 2 consecutive samples).
- Button “Process locally” -> generates candidate screens + transitions.
- Show results:
- A list/table of detected screens with timestamp, thumbnail, hash, and cluster id.
- A React Flow graph (nodes = screens w/ thumbnails, edges = transitions w/ confidence).
- Allow manual edits: rename screen, delete/merge screens, add/remove edges.
- Button “Save to Supabase” saves the run, screens, transitions, and any edits.
2) Video processing algorithm (client-side):
- Load the file into a <video> element via URL.createObjectURL.
- Sample at N fps (default 1) by seeking to timestamps.
- For each sample frame:
- Draw to an offscreen canvas.
- Downscale to something small (e.g., 160px width) and convert to grayscale.
- Compute a 64-bit dHash (or pHash) and store as hex string.
- Clustering / dedupe:
- Compare hash to last accepted screen hash.
- If distance <= threshold -> same screen cluster.
- If distance > threshold, treat as “candidate new screen”, but only accept if it stays different for the next sample too (stability = 2).
- Drop “one-off” transient frames.
- Transitions:
- Create edges between consecutive accepted screen clusters in time order.
- Confidence based on (hash distance, stability count).
- Export:
- Provide “Export JSON” for the current graph.
3) Supabase persistence:
- Use @supabase/supabase-js.
- Read env vars: NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_ANON_KEY.
- Storage:
- Create a bucket name: “frames”.
- Upload screen thumbnails as JPEG (reasonable compression).
- Store object path in DB.
- Database tables (generate SQL file at /supabase/schema.sql and also include in README):
- runs(id uuid, version text, created_at timestamptz, params jsonb)
- screens(id uuid, run_id uuid, version text, idx int, time_ms int, title text, hash text, cluster_key text, thumbnail_path text, created_at timestamptz)
- transitions(id uuid, run_id uuid, version text, from_screen_id uuid, to_screen_id uuid, confidence real, created_at timestamptz)
- edits(id uuid, run_id uuid, version text, graph jsonb, updated_at timestamptz)
- Since there is no auth, keep it simple for PoC:
- Provide SQL to either disable RLS for these tables OR add permissive policies for anon (clearly marked as “PoC only, insecure”).
- Storage policies:
- Supabase Storage requires RLS policies to allow uploads. Provide minimal INSERT policy for storage.objects for bucket_id='frames' (PoC-only). Also provide SELECT policy if needed for listing.
- Put these policy SQL snippets in /supabase/policies.sql and explain in README how to apply them.
4) UX / UI basics:
- Make the UI usable but not over-engineered.
- The graph view should show thumbnails in nodes.
- Provide a right-side inspector panel for selected node/edge.
Deliverables:
- Working Next.js app with the above.
- README.md with:
- How to connect Supabase via v0 integration (Integrations/Connect).
- Where to paste schema.sql and policies.sql in Supabase SQL editor.
- How to run locally (npm install / dev).
- Keep code clean and modular (lib/videoProcessing.ts, lib/hash.ts, lib/supabaseClient.ts, components/*).

Supabase の Integration
Supabase を使うプロンプトを渡すと、v0 側から Supabase のインストールを提案されます。

これに従ってインストールを進めます。Database を作成します。

Database name を決めて Create をクリックします。

Database が作成されたら Done をクリックします。v0 ページにリダイレクトされます。

v0 に対し、自動的に Database 設定が完了した旨のメッセージが渡されるので、引き続き実装を待ちます。

実際に出てきたものと追加の指示
今回は、遷移を表す表示が意図した見た目と異なっていました。具体的には、screen 間に正方形が表示されている状態でした。遷移図としては矢印の方が読みやすいので、矢印に変更する指示を追加しました。
screen 間の transition を示す図形が square なのが気になります。矢印などの表現に変更できますか。
この手の見た目調整は、React Flow のエッジ設定を書き換えれば対応できますが、v0 に指示して反映させる方が速いです。
実装の内容
動画から画面候補を抽出する
スマホ録画は、トーストや軽いアニメーション、スクロールなどで画面が常に揺れます。揺れをそのまま遷移として扱うと、画面数が増えすぎます。そこで、画面を小さくした特徴量で近さを測り、短い揺れを弾く方式にします。
実装では、動画を <video> として読み込み、OffscreenCanvas に描画してフレームを取り出します。フレームは縮小してグレースケール化し、64 bit の dHash を計算します。縮小幅は 160 px 程度にしています。判定は画面全体を対象にし、クロップは行っていません。
- Sampling FPS で、何 fps でフレームをサンプリングするか決定
- 取り出したフレームから dHash を計算
- 直前に確定した画面とハッシュ距離 (Hamming distance) を比較し、Hash Threshold 以下なら同一画面扱いに
- Hash Threshold を超えた場合は、いきなり画面確定にせず候補として保持
- Stability Frames 回連続で同じ候補が続いたら画面遷移として確定
Stability Frames は、短時間だけ出る差分を弾くためのつまみです。たとえば、トーストが一瞬出るだけなら候補としては見えますが、連続して続かないので画面として確定しにくくなります。
パラメータの調整 UI
抽出時の精度を調整できるように、パラメータを UI から変えられるようにしています。
- Sampling FPS: フレームを拾う間隔に影響
- Hash Threshold: どれくらい違うと別画面とみなすかに影響
- Stability Frames: どれくらい続いたら別画面として確定するかに影響
React Flow による遷移図表示と手修正
遷移図の表示は React Flow で実装されています。ノードにサムネイルを表示し、エッジに矢印を付けます。自動抽出は完璧を狙わず、画面数と遷移のたたき台を作って、あとから人手で直す方向です。
Supabase への保存
保存は runs / screens / transitions / edits の 4 テーブルです。サムネイルは Storage の frames バケットに置きます。ブラウザで作った JPEG をアップロードし、オブジェクトパスを thumbnail_path として保存します。
録画用の検証アプリを v0 で作る
検証用にスマホで録画するためのデモアプリも、あわせて v0 で作成しました。画面右上に Screen ID を出し、録画を見返したときに正解の画面が判断しやすいようにしています。トップ画面には Auto Tour があり、確認ダイアログの後に自動遷移を開始します。

動かしてみた
スマホ録画 (縦長 1080 x 1920 / 30 fps) を入力し、Process Locally を押すと抽出が始まりました。検証では約 30 秒の動画を入力し、抽出された画面は 6 枚でした。

Sampling FPS を上げたり、Hash Threshold を下げたりすることで、遷移の判定をより厳しくして抽出できるのも確認しました。同じ画面を別画面とみなしてしまう場合があるので、最終的な調整は手作業で行う必要があります。

まとめ
v0 を使うと、UI だけでなく、動画処理と Supabase 永続化まで含めた検証を短時間で形にできます。今回はブラウザでフレーム抽出と dHash を回し、Supabase にはサムネイルとメタデータだけを保存しました。約 30 秒の動画では 6 枚の画面が抽出されました。パラメータを調整することで、より厳しい遷移判定をさせられることも確認しました。








