taste について
taste は、Web サイトのデザインを分析し、後続のデザイン作業向けに読みやすいガイドと構造化 JSON を生成するスキルです。Playwright MCP でページを取得し、根拠とともにデザイン上の判断を記録します。
主な機能
- 01色や余白などのデザイントークン抽出
- 02デザイン上の判断と根拠の記録
- 03Markdown と JSON ファイルの生成
- 04単一ページまたは関連ページの分析
- 05デザインツール向けルールやスタイルの出力
活用シーン
- 01サイトの見た目をプロジェクトの指針に変換
- 02デザインシステム用のスタイルトークン抽出
- 03競合サイト間のデザイン選択の比較
- 04Cursor や Windsurf 向けデザイン資料の作成
MCP 対応
実行には、ページへアクセスして取得するための Playwright MCP サーバーが接続されている必要があります。ブラウザツールでスクリーンショットと DOM データを収集します。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ senlindesign/ taste-skill --skill tasteインストール後、Claude Code で/tasteを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
README.md.gitignoredocs/Cherry.glbindex.htmlevals/evals.jsonreferences/extract.jsexport-formats.mdstep1-measure.mdstep2-pattern.mdstep4-observer.mdstep3-taste.md詳細
Taste — Web サイトのデザイン DNA をリバースエンジニアリングする
このスキルは、URL から次の 2 つのファイルを作成します。
./{domain}.md— 人が読める形式です。次の 2 つのセクションがあります。- Design Map — 実用的なトークン(色、文字サイズのスケール、間隔、角丸、シャドウ、グリッド)
- Taste DNA — 独自の見解に基づくトレードオフを 3~4 件(きっかけ → 判断 → 理由 → 根拠)
./{domain}.json— 構造化形式です。同じデータを、後続のツール(Cursor、Windsurf、デザインシステム)で解析できる形式で記録します。
このワークフローでは、「すっきりしていてモダン」といった一般論は採用しません。完成した taste.md は、経験豊富なデザイナーが、なぜこのページがこの選択をしたのか、そしてどのような妥当な代替案を退けたのかを説明する内容になっているべきです。
起動するタイミング
ユーザーが、将来のデザイン作業の指針として Web サイトのデザインを調査し、記録したいときはいつでもこのスキルを起動してください。次のすべてに対応します。
- 明示的なスラッシュ形式:
/taste <url> - 自然言語での依頼:「vercel.com のデザインを分析して」「Stripe のサイトがとても優れている理由は?」「linear.app のデザイントークンを抽出して」「are.na のデザイン DNA を教えて」
- 模倣の意図:「ダッシュボードを Linear のような雰囲気にしたい」「 のスタイルでランディングページを作って」「このサイトのデザインを自分のプロジェクトに移植して」
- 競合調査:「競合と見た目を比較して」「 ではどのようなデザイン上の慣例を使っている?」
- ユーザーが URL に触れ、デザインの選択、タイポグラフィ、色、間隔、デザイン思想、または「雰囲気」について尋ねる、あらゆる場面
ユーザーが視覚やデザインに関する話題で URL に触れたら、起動する方向で判断してください。Claude はスキルの起動が不足しがちです。迷ったら起動してください。スキルを無駄に起動するコストは小さい一方、このスキルで具体的かつ根拠に基づく分析を提供できるのに、一般的なデザインのアドバイスを生成するコストは大きいためです。
次の場合は起動しないでください:「Web サイトからデータを抽出して」(スクレイピング用スキルを使用)、「 の内容を要約して」(WebFetch を使用)、「このサイトをデプロイして」(無関係です)。
前提条件
このスキルを利用するには、Playwright MCP サーバー(https://playwright.dev/docs/getting-started-mcp)がインストールされ、接続されている必要があります。次のコマンドで確認してください。
claude mcp list | grep playwright
playwright: ... - ✓ Connected と表示されれば、準備完了です。そうでない場合は、インストールしてください。
claude mcp add playwright -s user -- npx -y @playwright/mcp@latest --isolated
--isolated を使う理由:/taste を実行するたびに新しいブラウザー状態で開始するため、Cookie、ログインセッション、以前のキャッシュが分析対象のページに持ち込まれません。これを使わずに、たまたま Linear にサインインした状態で /taste https://linear.app を実行すると、公開マーケティングページではなくアプリのダッシュボードが分析されてしまいます。対象画面も、デザインの印象も、誤ったものになります。
--browser フラグなしで npx @playwright/mcp@latest を使う理由:Playwright が独自にバンドルされた Chromium(約 100 MB、初回のみ)をダウンロードして使用します。ユーザーのシステムにある Chrome に依存するより移植性が高く、Chrome がインストールされていないマシンでも動作し、ユーザー間で一貫した描画結果が得られます。また、ユーザーの実際のブラウザープロファイルでウィンドウを開くこともありません。
インストール後、MCP ツール(mcp__playwright__browser_*)をこのセッションで使用できるようにするには、ユーザーが Claude Code を再起動する必要があります。このスキルの実行時に Playwright を利用できない場合は、そこで停止し、次のようにはっきり伝えてください:「ページをスクレイピングするには Playwright MCP が必要です。claude mcp add playwright -s user -- npx -y @playwright/mcp@latest --isolated を実行して Claude Code を再起動してから、もう一度お試しください。」
初回の実行では、最初の browser_navigate が結果を返すまでに Playwright が約 30~60 秒かかる場合があります。これは Chromium の初回ダウンロードによるものです。2 回目以降は数秒で開始します。待ち時間を避けるために事前ダウンロードしたい場合は、このスキルを起動する前に一度 npx playwright install chromium を実行してください。
ワークフロー
次の 5 つのフェーズを順番に進めてください。各フェーズには明確な成功基準があります。次のフェーズで必要な成果が現在のフェーズで得られるまで、先に進まないでください。
フェーズ 0 — URL とエクスポート先を解析する
ステップ 1 — URL
ユーザーのメッセージから URL を抽出します。次の形式を受け付けます。
/taste https://linear.app- 「vercel.com のデザインを分析して」(
https://がない場合は追加します) - プロンプト内の任意の場所にある URL
ユーザーが URL を指定していない場合は、URL を尋ねます。ファイルパス、または明らかに URL ではないものが指定された場合は、ホスティングされたページを意味しているのか尋ねます。有効な URL を取得するまで先に進まないでください。
移動する前に、一般的な短縮形式を解決します。linear.app → https://linear.app、https://www.stripe.com はそのままで問題ありません。
ステップ 2 — ファイル名に使うドメインを抽出する
URL からホスト名を抽出し、www. プレフィックスがあれば削除します。例:
https://linear.app→linear.apphttps://www.stripe.com→stripe.comhttps://vercel.com/home→vercel.com
これを {domain} として保存します。すべての出力ファイルには、この名前を使用します。{domain}.md、{domain}.json、およびエクスポートファイルです。ユーザーが同じディレクトリ内の複数のサイトでこのスキルを実行した場合に名前が重複するため、汎用名の taste.md は絶対に使用しないでください。
ステップ 3 — エクスポート先とクロール範囲
ユーザーのメッセージですでにエクスポート先とクロール範囲の両方が指定されている場合は、この質問全体を省略します。いずれかが指定されていない場合は、1 回のメッセージでまとめて尋ねます。
「開始する前に、簡単な質問が 2 つあります。
エクスポート先 — どのツールで開発していますか?
1 Cursor → .cursor/rules/{domain}-taste.mdc 2 Windsurf → .windsurf/rules/{domain}-taste.md 3 Claude Code → CLAUDE.md(Design Taste セクションを追記) 4 GitHub Copilot → .github/copilot-instructions.md(追記) 5 Bolt → .bolt/prompt 6 Antigravity → GEMINI.md 7 v0 by Vercel → taste-tokens.css + 手順 8 Figma Make → taste-figma.css + 手順 9 Lovable → Project Knowledge に貼り付けるテキストを表示 10 スキップ → {domain}.md と {domain}.json のみを保持クロール範囲 — このページのみですか、それともリンク先のページを 2~3 件調査しますか?
1 このページのみ → より速く、指定されたページに集中します 2 リンク先のページを調査 → ナビゲーション内のページを 2~3 件開き、データを統合します ```"
回答を {exportTarget} と {crawlScope} として保存します。デフォルト値は {exportTarget} = "skip"、{crawlScope} = "single" です。再度尋ねないでください。
フェーズ 1 — ページデータを取得する(Playwright MCP)
次の手順を順番に実行します。いずれかの手順でエラーが発生した場合は、パイプラインを停止してエラーをユーザーに報告します。データが不完全な状態で、黙って処理を続けないでください。
-
ビューポートをサイズ変更し、実行ごとに測定値が一致するよう 1440×900 に設定します。
mcp__playwright__browser_resize width=1440 height=900 -
URL に移動します。
mcp__playwright__browser_navigate url=<the URL> -
クライアント側のハイドレーションを待つため、少し待機します。重い SPA(figma.com、notion.so など)では、実際のコンテンツが描画されるまで
domcontentloadedの後に数秒かかります。次を使用します。mcp__playwright__browser_wait_for time=33 秒後もページのスナップショットが読み込み中のスケルトン表示に見える場合は、さらに 3 秒待ちます。それでもスケルトン表示のままなら、最終出力に「ページが完全に描画されていない可能性があり、一部の測定値は概算です」と記載します。
-
スクリーンショットを 2 枚撮影します。まずビューポート、次にページ全体です。
4a. ビューポートのスクリーンショット(1440×900、拡大縮小なし。ステップ 1 で使う主要な視覚資料です):
mcp__playwright__browser_take_screenshot type=jpeg filename={domain}-viewport.jpeg4b. 条件付きのページ全体のスクリーンショット — まずページの高さを確認します。
mcp__playwright__browser_evaluate function=() => document.documentElement.scrollHeight- ビューポートの高さの 6 倍以下(1440×900 では 5400px 以下)の場合:通常のフルページスクリーンショットを撮影します。
mcp__playwright__browser_take_screenshot fullPage=true type=jpeg filename={domain}-fullpage.jpeg - ビューポートの高さの 6 倍を超える場合:フルページ撮影はスキップします(縦に長すぎて、トークンを無駄に消費するため)。代わりに、ビューポート内の指定位置を 2 枚撮影します。
// ページ中ほど(50% スクロール) mcp__playwright__browser_evaluate function=() => window.scrollTo(0, document.documentElement.scrollHeight * 0.5) mcp__playwright__browser_take_screenshot type=jpeg filename={domain}-mid.jpeg // フッター mcp__playwright__browser_evaluate function=() => window.scrollTo(0, document.documentElement.scrollHeight) mcp__playwright__browser_take_screenshot type=jpeg filename={domain}-footer.jpeg // ページ最上部に戻る mcp__playwright__browser_evaluate function=() => window.scrollTo(0, 0)
ステップ 1 では、ビューポートのスクリーンショットを主な視覚的参照として使用します。これはデザイナーが意図した最初の印象を表します。フルページまたは中ほどとフッターのスクリーンショットは、ページ下部にしか現れないパターン(フッターのタイポグラフィ、後半のセクションでの色の変化など)の確認に使用します。JPEG は PNG よりトークンの消費を抑えられます。
- ビューポートの高さの 6 倍以下(1440×900 では 5400px 以下)の場合:通常のフルページスクリーンショットを撮影します。
-
DOM エクストラクターを実行します。
references/extract.jsを読み込み、その全内容をfunction引数として渡します。mcp__playwright__browser_evaluate function=<contents of references/extract.js>ツールは JSON オブジェクトを返します。これを
domDataとして記憶し、ステップ 1 に渡します。 -
(任意のクリーンアップ)ブラウザーはセッション中そのまま開いておきます。ユーザーから求められない限り、閉じる必要はありません。
複数ページのキャプチャ({crawlScope} が "multi" の場合のみ):
メインページのキャプチャ後、ナビゲーションリンクを抽出し、同じサイトから最大 2 ページにアクセスします。
6a. ナビゲーションリンクの抽出:読み込み済みのメインページから取得します。
(function() {
const links = [];
const seen = new Set([location.pathname]);
const skip = /\/(login|logout|signup|sign-in|register|auth|account|checkout|cart|password|reset)\b/i;
document.querySelectorAll('nav a, header a, [role="navigation"] a').forEach(a => {
try {
const u = new URL(a.href);
if (u.hostname !== location.hostname) return;
if (skip.test(u.pathname)) return;
if (seen.has(u.pathname)) return;
if (u.pathname === '/' && location.pathname !== '/') return;
seen.add(u.pathname);
links.push({ href: u.origin + u.pathname, text: (a.innerText || a.textContent).trim().slice(0, 40) });
} catch(e) {}
});
return links.slice(0, 6);
})()
6b. 2 ページを選択:返されたリストから選びます。次の点を優先してください。
- より短いパス(
/product/features/detailより/product) - 異なるセクション名(同じセクション内の異なるスラッグではなく、Product、Community、Pricing、Docs など)
/をすでにキャプチャしている場合は、ルート/を避ける
6c. 追加ページごとに、簡易キャプチャのループ(移動 → 3 秒待機 → ビューポートのスクリーンショットのみ → DOM エクストラクター)を実行します。2~3 ページ目では、フルページや中ほど・フッターのスクリーンショットは省略します。デザインの一貫性を確認するにはビューポートで十分であり、DOM エクストラクターはページ全体を取得します。スクリーンショットには {domain}-viewport-2.jpeg、{domain}-viewport-3.jpeg という名前を付けます。各ページのデータは pages[1]、pages[2] に保存します(pages[0] はメイン URL)。
リンク先ページの読み込みに失敗した場合、またはブロックされた場合は、何も報告せずにスキップし、フェーズ 6 のレポートに記載します。
6d. フェーズ 2 の前にデータを統合します。すべてのページの色候補を統合し(和集合)、タイポグラフィも同様に統合します。2 ページ以上で見られる値はシステムシグナルとして印を付けます。1 ページだけで見られる値はローカルとして扱います。これらも取得しますが、重みは下げます。
ステップ 1~3 では、分析したページ数を必ず記載し(「3 ページ全体では、……」)、システムパターンとローカルパターンを区別します。複数ページでの一致は、デザインの原則を判断するために得られる最も強い証拠です。
フェーズ 1 の成功基準:少なくとも 1 枚のスクリーンショットと、colors、typography、layout、effects、cards、images、spacingSamples、sectionGaps、grid の各フィールドを含む、メインページのデータが入力された domData JSON があること。スクリーンショットに実際のコンテンツが写っているのに、これらのいずれかが完全に空の場合は、エクストラクターの改善が必要です。その旨を記録し、作業を続けてください。
データが不完全な場合の対応:domData.errors が空でない場合、エクストラクターは部分的に失敗しています。ステップ 1 では、影響を受けるカテゴリに ~approx (extractor section failed) と記し、該当する測定にはスクリーンショットを使用します。フェーズ 6 では、失敗したセクションをレポートの注意事項として列挙します。
フェーズ 2 — 4 段階の分析を実行する
スクリーンショットを正とします。 参考ファイルを読む前に、ビューポートのスクリーンショットで、人間が実際に目にするものを確認してください。DOM データには正確な数値が含まれています。両者が食い違う場合は、スクリーンショットを優先してください。DOM に表示されていても、可視領域の 5% 未満しか占めない色は装飾的なものです。ブランドカラーとして列挙しないでください。スクリーンショットに表示されないセクション区切りは、DOM に記載があっても存在しません。視認できないシャドウ(不透明度 ≤3%)は CSS のアーティファクトであり、デザイン上の意図ではありません。
references/ にある 4 つの参考ファイルには、各ステップのプロンプト全文が記載されています。各ステップに進んだときに、そのファイルを読んでください(4 つすべてを一度に読み込まないでください。ステップは意図的に順番に進めるよう設計されており、前のステップでは後のステップの指示は必要ありません)。
各ステップで、次の手順を実行してください。
- 対応する参考ファイルを読む。
- 求められている出力を、自分の回答で生成する。
- 参考ファイルで指定されたマーカー行(例:
### Step 1 Output — Measurements)から出力を始める。 - 次のステップでは、前の出力が入力として使われます。会話内に残し、要約して省略しないでください。
ステップ 1 — 測定
references/step1-measure.mdを読む- 入力:
domData(browser_evaluateからの JSON)+スクリーンショット - 出力:20 カテゴリーの測定値。各値に具体的な px/hex/比率を付記する
ステップ 2 — パターン
references/step2-pattern.mdを読む- 入力:ステップ 1 の出力
- 出力:5~8 個の体系的なパターン。それぞれに Pattern/Evidence/Design Goal を含める
ステップ 3 — デザインの好み
references/step3-taste.mdを読む- 入力:ステップ 1 とステップ 2 の出力
- 出力:4 つのデザイン原則(それぞれ Trigger/Decision/Reason/Evidence を含める)。少なくとも 1 つは抑制に関するトレードオフにする
ステップ 4 — オブザーバー
references/step4-observer.mdを読む- 入力:ステップ 1、2、3 の出力+元の URL(JSON の
sourceフィールドに代入する必要があります) - 出力:フェンス付きの
jsonブロックに続けて、Markdown の Design Map + Taste DNA
フェーズ 3 — 出力ファイルを書き込む
ステップ 4 の回答には、両方の形式が含まれています。それらを抽出してください。
- JSON:ステップ 4 の出力で最初にある
jsonフェンス付きコードブロックを見つけてください。パース可能である必要があります。有効な JSON でなければ、ステップ 4 の失敗です。パースエラーを指摘してステップ 4 を再実行してください。 - Markdown:JSON ブロックの終了後にあるステップ 4 の出力すべてを取得します。先頭の空白は削除してください。
次に、フェーズ 0 で抽出した {domain} を使って、現在の作業ディレクトリに 2 つのファイルを書き込みます(必要であれば pwd で場所を確認してください)。
./{domain}.md— Markdown 部分./{domain}.json— 2 スペースでインデントした整形済み JSON
いずれかのファイルがすでに存在する場合は、確認を求めずに上書きしてください。同じサイトでこのスキルを 2 回実行するユーザーは、最新の分析結果が反映されることを期待しています。
フェーズ 4 — 自己監査(スロップ対策)
Bash ツールで次の grep を実行してください。目視で確認してはいけません。
grep -icE 'clean|modern|sleek|visually appealing|user-friendly|intuitive|seamless|\belegant\b|minimalist|polished|refined|sophisticated|delightful|stunning|\bbeautiful\b|\bpremium\b' ./{domain}.md
件数が 0 なら、ファイルは合格です。0 より大きい場合は、該当する行を表示してください。
grep -inE 'clean|modern|sleek|visually appealing|user-friendly|intuitive|seamless|\belegant\b|minimalist|polished|refined|sophisticated|delightful|stunning|\bbeautiful\b|\bpremium\b' ./{domain}.md
該当箇所ごとに、次のように対応します。
- 引用された対比表現の中(「『すっきりとして現代的』な見た目にもできたのに、あえて別の方向を選んだ……」など)なら問題ありません。合格として数えます。
- このデザインを肯定的に表す記述として使われている場合はスロップです。原則を編集して保存し、件数が 0 になるまで grep を再実行してください。
さらに Bash で次を確認してください。
grep -c "Design Map\|Taste DNA" ./{domain}.md
2 が返される必要があります。それより少ない場合はセクションが欠けています。欠落しているセクションを明示して、ステップ 4 を再実行してください。
JSON を検証します。
python3 -m json.tool ./{domain}.json > /dev/null && echo "valid" || echo "INVALID"
検証に失敗した項目があれば、修正してから再実行してください。
フェーズ 5 — ビルドツール向けにエクスポートする
{exportTarget} はフェーズ 0 ですでに取得しています。再度尋ねないでください。
{exportTarget} が "skip" の場合は、フェーズ 6 に進んでください。
{exportTarget} が "all" の場合は、ファイル形式のすべてのオプション(1–8)を生成してください。
それ以外の場合は、{exportTarget} に基づいてエクスポート先を決定してください。自然言語での同等表現も受け付けます:"cursor"、"windsurf"、"claude" / "claude code"、"copilot"、"bolt"、"antigravity" / "gemini"、"v0"、"figma" / "figma make"、"lovable"。
各ターゲットの正確なファイルパス、フロントマターの構造、コンテンツ仕様については、references/export-formats.md を読んでください。すべての形式は {domain}.json を元にし、同じ Anti-Slop ルールに従う必要があります。曖昧な雰囲気の表現は使わず、具体的な px/hex を示してください。
フェーズ 6 — 報告する
ユーザーに次の内容を表示してください(実際の {domain}、行数、バイト数に置き換えてください)。
✓ Wrote ./{domain}.md (<line-count> lines) and ./{domain}.json (<byte-count> bytes)
[if export file(s) written]: ✓ Also wrote <path(s)>
Sharpest principle: "<name of the strongest taste principle>"
→ <one-sentence quote of its Decision>
Open {domain}.md to read the full Design Map + Taste DNA.
簡潔にまとめてください。ファイルがすべてを語ります。
エラー処理
| 失敗 | 対応 |
|---|---|
| Playwright MCP がインストールされていない/接続されていない | 上記の前提条件セクションに記載されている正確なインストールコマンドを示して停止してください。WebFetch にフォールバックしないでください。スクリーンショットはステップ 1 に不可欠です。 |
| URL にアクセスできない/404/DNS エラー | ページが読み込めなかったことをユーザーに伝えてください。エラーページに基づく分析を提出しないでください。 |
| Cloudflare/ボット検出によるブロック | スクリーンショットには「人間であることを確認してください」というページが表示されます。ステップ 1 で検出してください(広い余白と、「Verify」と表示されたボタンが 1 つ)。サイトが自動アクセスをブロックしていることをユーザーに伝えてください。スクリーンショットが必要であれば、自分のブラウザーで URL を手動で開くか、同じドメインの別のページを試すよう提案してください。 |
| 待機後も SPA のレンダリングが続いている | 3 秒の待機を 2 回行った後、表示されている内容で進めてください。報告に次の注意書きを 1 行追加してください:「ページのハイドレーションが完了していなかった可能性があり、一部の測定値は概算です。」 |
| ユーザーが URL ではなくファイルパスを指定した | ホストされたバージョンを指しているのか尋ねてください。ローカルファイルを開こうとしないでください。このスキルは公開中のページを対象としています。 |
| ユーザーがログイン必須の URL を指定した | パスワード入力欄のあるフォームを検出してログインページと判断してください。このスキルは認証が必要なページには対応していないことを伝え、代わりに公開されているマーケティングページを使うよう提案してください。 |
| ステップ 4 で不正な JSON が返された | 具体的な解析エラーを示して、ステップ 4 を 1 回だけ再実行してください。再度失敗した場合は、生の出力を ./{domain}-raw.md として保存し、ユーザーに手動で確認するよう伝えてください。 |
哲学に関するメモ(一度読んで理解し、その後は基本的に忘れてください)
このスキルの根底には、強い考え方があります。デザイントークンだけでは AI エージェントにとって役に立ちません。トークンは「間隔は 8px」と示しますが、センスは「デザイナーが情報密度より読みやすいリズムを優先したため、間隔を 8px にした。8px は、ズーム倍率 1× でも意図が感じられる最小単位だ」と示します。同じエージェントが数値をコピーするだけでなく、別のページでも優れたデザインを生成できるようにするのは、この理由です。
references/ にある 4 つのプロンプトは、実運用で検証された Gemini ベースのパイプラインを移植したものです。初期バージョンで最大の失敗要因となったのは、汎用的な出力でした。「このデザインは、直感的なナビゲーションを備えた、すっきりとしたモダンな美しさを採用しています」といった、情報がまったく含まれていない段落です。禁止フレーズ、必須の抑制に関するトレードオフ、根拠の提示要件といった Anti-Slop チェックがあるのは、根拠のある原則を 10 個追加するより、弱い原則を 1 つ削除するほうが価値があるためです。
あるセンスの原則が適切かどうか迷ったら、こう問いかけてください。「この特定のウェブサイトを一度も見たことがなくても、これを書けただろうか?」答えが「はい」なら、それはスロップです。削除してください。