pixelpact について
pixelpactはウェブページやFigmaフレームからデザイン契約を作成し、実装ページとの差を測定します。UIをプロパティ単位で確認・調整したいフロントエンド開発者やコーディングエージェント向けです。
主な機能
- 01ページやFigmaフレームからJSON契約を抽出
- 02描画プロパティを測定して差異を報告
- 03ホバー、フォーカス、アニメーション、デザイントークンを記録
- 04スクリーンショットをピクセル単位で比較
- 05MCPサーバー経由で測定機能を提供
- 06GitHub Actionsでチェックを実行
活用シーン
- 01コーディングエージェントによるUI修正の支援
- 02新しいページを参照デザインと照合
- 03プルリクエストでUI測定結果をレビュー
- 04CIでプレビュー環境をチェック
MCP 対応
pixelpact-mcpは、契約の抽出、実装チェック、ピクセル差分、契約サマリーの各ツールをMCPクライアントに公開します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
4掲載時のツール一覧 · 2 週間前に更新
| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| url | string | はい | ビジュアルコントラクトの抽出元となる参照 URL。 |
| wait | integer | いいえ | ナビゲーション後に追加で待機する安定化時間(ミリ秒)。デフォルトは 2000 です。 |
| masks | array | いいえ | 走査対象から除外する CSS セレクター(広告やタイムスタンプなど)。 |
| timeout | integer | いいえ | ナビゲーションのタイムアウト(ミリ秒)。デフォルトは 30000 です。 |
| fullPage | boolean | いいえ | ビューポートだけでなく、スクロール可能なページ全体をキャプチャします。デフォルトは true です。 |
| headless | boolean | いいえ | ブラウザーをヘッドレスモードで実行します。デフォルトは true です。 |
| selector | string | いいえ | 走査範囲を指定した CSS セレクターに限定します。デフォルトは document body です。 |
| maxStates | integer | いいえ | ホバーとフォーカスを調査するインタラクティブ要素の最大数。デフォルトは 120 です。 |
| viewports | array | いいえ | キャプチャするビューポート。デフォルトはデスクトップ 1440x900、タブレット 768x1024、モバイル 390x844 です。 |
| outputPath | string | はい | contract JSON を書き込むファイルシステム上のパスです。例:./contracts/home.json。 |
| maxElements | integer | いいえ | 走査する要素の最大数です。0 は無制限を意味します。デフォルトは 600 です。 |
| screenshotDir | string | いいえ | 参照スクリーンショットを保存するディレクトリです。後で diff_pixels を機能させるには必須です。 |
| freezeAnimations | boolean | いいえ | 測定前に CSS アニメーションを停止します。デフォルトは true です。 |
詳細
コーディングエージェントが CSS を書き終え、「できました」と言います。しかし、実際の結果を見ることはありません。数値を返すものがないため、作業のループを完結できません。エージェントが推測し、あなたがページを開き、内容を送り返し、またエージェントが推測します。やり取りのたびに、エージェントが節約してくれるはずだった時間が奪われます。
エージェントを使わない場合にも、同じ隔たりがあります。チームメイトがセクションの完成を伝えても、その場の誰も測定値を持っていないことがあります。違いは、人なら少なくとも見て確認できることです。
pixelpact はリファレンスページを読み取り、実際のレンダリング内容を記録します。サイズ、色、間隔、タイポグラフィ、ホバーとフォーカスの状態、アニメーションのキーフレーム、デザイントークンなどです。そのファイルが契約になります。pixelpact に実装を指定すると、ずれがあるプロパティごとに1行で結果が返されます。これはまさに、エージェントが修正に活用できる情報です。
npx pixelpact extract https://reference.example.com -o contract.json
npx pixelpact check contract.json http://localhost:3000
対応環境
| MCP クライアント | Playwright | GitHub Actions | あらゆるフレームワーク | Figma |
|---|---|---|---|---|
| Claude Code、Cursor など、stdio MCP に対応するもの | pixelpact が利用するエンジン | プルリクエストにコメントを1件 | スタックではなく DOM を読み取ります | 必要に応じて、リファレンスとしてフレームを指定できます |
ブラウザーでレンダリングできるものなら、pixelpact で測定できます。
コーディングエージェント向け
UI コードを書くエージェントには、うまくいったかどうかを判断できません。pixelpact-mcp は測定結果を提供するため、人を介さずにループを完結できます。最初に契約を抽出したら、あとはエージェント自身に成果物をチェックさせ、差分の一覧を読み、修正し、再びチェックさせます。
// .mcp.json
{
"mcpServers": {
"pixelpact": { "command": "npx", "args": ["-y", "pixelpact-mcp"] }
}
}
公開されるツール:extract_contract、check_implementation、diff_pixels、
read_contract_summary。
ビジュアルリグレッションテストとは異なる理由
Percy、Chromatic、Applitools、BackstopJS、Pixeleye は、いずれもページを以前に承認したベースラインと比較します。この方法は、ページがすでに正しく表示されていて、その状態を維持したい場合に有効です。デザインに向けて構築している途中では、比較対象となるベースラインがありません。リグレッションツールを初めて実行しても、作成したものを記録するだけです。
| ビジュアルリグレッションツール | pixelpact | |
|---|---|---|
| 比較対象 | 以前に承認したスナップショット | リファレンスデザインそのもの |
| 有用な場面 | UI がすでに正しい場合 | UI を構築している場合 |
| 新しいページでの初回実行 | 記録するだけで、判断はできない | リファレンスと照合して測定する |
| 得られる結果 | 目視で確認する画像差分 | 差分付きのプロパティごとの値 |
| 自律型エージェントへの適合性 | 差分の承認に人の手が必要 | 数値によってループが完結する |
この2つの方法は相補的です。完成したページをそのまま保つにはリグレッションツールを使い、ページを完成させるには pixelpact を使います。
pixelpact が解決する課題
| pixelpact がない場合 | pixelpact がある場合 |
|---|---|
| ❌ コーディングエージェントが CSS を書いて作業完了を宣言しても、実際にページを開いて未完成だと確かめるのは人間です。 | ✅ エージェントが MCP サーバーを呼び出し、差異を確認して修正し、もう一度チェックします。途中に人間を挟みません。 |
| ❌ 誰かがセクションの完成を宣言しても、あなたは納得できず、どちらも数値を示せません。声の大きいほうの意見が通ります。 | ✅ リファレンスのすべての値をページと照合します。失敗した項目は、期待値、実際の値、差分とともに一覧表示されます。 |
| ❌ 回帰テストツールは新しいページと比較する対象がないため、初回実行時に、たまたま作成したものをそのまま記録してしまいます。 | ✅ 最初の段階からリファレンスが基準になります。ツールを役立てるために事前承認は必要ありません。 |
| ❌ ホバー、フォーカス、アニメーションの値は、手作業での確認に時間がかかり退屈なため、ほとんどレビューされません。 | ✅ これらも契約の一部なので、ほかの値と同じように実行のたびに測定されます。 |
| ❌ 画像差分では何かが変わったことしかわからず、何が変わったのかを探すのは自分です。 | ✅ 差異には、要素、プロパティ、期待値、測定値が示されます。 |
| ❌ デザインは、コードレビュー中に誰も開かないファイルの中にあります。 | ✅ 契約はコミットできる JSON なので、プルリクエストでどの値が変わったかを正確に確認できます。 |
インストール
pnpm add -D pixelpact playwright
pnpm exec playwright install chromium
playwright はピア依存関係なので、ブラウザーのダウンロードは自分で管理できます。すでに Playwright を導入しているプロジェクトには、余計なものはインストールされません。Node 22.12 以降が必要です。
クイックスタート
1. リファレンスから契約を抽出します。
npx pixelpact extract https://reference.example.com \
--selector "main" \
--viewport desktop,mobile \
--screenshots .pixelpact/shots \
-o contract.json
2. 実装を測定します。
npx pixelpact check contract.json http://localhost:3000 --viewport desktop
3. 報告された箇所を修正してから、もう一度実行します。 すべてが許容範囲内ならコマンドは 0 を、そうでなければ 1 を返すため、スクリプトや CI ジョブにそのまま組み込めます。
契約の形式
契約は読みやすく差分を確認できるプレーンな JSON で、独自形式でも、裏でサービスを必要とする形式でもありません。
{
"version": 1,
"source": { "type": "url", "value": "https://reference.example.com" },
"root": "main",
"extractedAt": "2026-09-06T01:20:44.812Z",
"viewports": [{ "name": "desktop", "width": 1440, "height": 900 }],
"tokens": { "--brand-600": "rgb(11, 114, 133)" },
"keyframes": { "fade-up": [{ "offset": "0%", "css": "opacity: 0" }] },
"byViewport": {
"desktop": {
"documentHeight": 4218,
"elements": [
{
"selector": "main > header > a.cta",
"tag": "a",
"text": "Get started",
"box": { "x": 120, "y": 32, "w": 148, "h": 44 },
"styles": {
"background-color": "rgb(11, 114, 133)",
"font-size": "16px",
"border-radius": "8px"
},
"hover": { "background-color": "rgb(8, 90, 105)" },
"focus": { "outline": "2px solid rgb(11, 114, 133)" }
}
]
}
}
}
ファイルなので、コミットしてプルリクエストでレビューしたり、別の開発者やエージェントに渡したりできます。
チェック結果の出力
pixelpact check FAILED
target http://localhost:4173/impl.html
reference http://localhost:4173/ref.html
viewport desktop 1440x900
elements 14 matched, 0 missing of 14
checks 1056 passed, 10 failed (99.1% of 1066)
deviations (10)
SELECTOR PROPERTY EXPECTED ACTUAL DIFF
body > main > h1 font-size 48px 44px 4px
body > main > a box.width 117.75px 109.75px 8px
body > main > a padding-right 24px 20px 4px
body > main > a padding-left 24px 20px 4px
body > main > a background-color rgb(11, 114, 133) rgb(37, 99, 235) 60.1 (color)
body > main > a border-top-left-radius 8px 4px 4px
body > main > a border-top-right-radius 8px 4px 4px
body > main > a border-bottom-left-ra... 8px 4px 4px
body > main > a border-bottom-right-r... 8px 4px 4px
body > main > a focus.outline rgb(11, 114, 133) s... rgb(37, 99, 235) so... differs
これは、1 ページの 2 つのコピーで 4 つの宣言を変更した実際の実行結果です。4 つの編集から 10 個の差異が測定されます。これは、パディングによってボックスの幅が変わり、1 つの border-radius 短縮形が 4 つの角を設定するためです。同じチェックをリファレンス自体に対して実行すると、1066 個すべてのアサーションに合格します。重要なのはこの性質です。チェックに合格することには、意味がなければなりません。
--json を追加すると、同じレポートをデータ構造として取得できます。CI ジョブやエージェントは、この形式を読み取ります。
サイドバイサイド実行でわかること
check はどの値が変わったかを示します。diff は何ピクセル変わったかを示します。どちらも、どこを見ればよいかは教えてくれません。side は両方のページをセクションに分けて並べ、異なる箇所を囲みます。
npx pixelpact side https://reference.example.com http://localhost:3000 --widths 1440,390
# SECTION WIDTH VERDICT DIFF
01 hero 1440px PASS 0.000%
02 features 1440px FAIL 0.675%
.pixelpact/side/1440/02-features.png
03 pricing 1440px PASS 0.000%
04 foot 1440px FAIL 1.265%
.pixelpact/side/1440/04-foot.png
![]()
これは、examples/side にある 2 つのファイルを使った実際の実行結果です。どちらも同じページのコピーですが、カード間の隙間と角の半径が変更されています。次のコマンドで再現できます。
npx pixelpact side "file://$PWD/examples/side/reference.html" \
"file://$PWD/examples/side/implementation.html" --widths 1440
ページが完成したと誰かに伝える前に実行するコマンドです。
機能
| 参照元に基づくコントラクト 目指すページを読み取り、表示される値をすべて書き留めます。事前の承認は不要です。 | 意見ではなく数値 各差異には、期待値、測定値、および両者の差が示されます。 | レイアウトだけでなく状態も インタラクティブ要素にホバーとフォーカスを適用し、実際に変化するプロパティだけを保存します。 |
| トークンとキーフレーム ルート要素のカスタムプロパティと、名前付きアニメーションキーフレームをコントラクトに含めます。 | ピクセル比較 すべての値が許容範囲内なのに見た目が違う場合は、スクリーンショットを比較して差異の割合を確認できます。 | エージェント対応 MCP サーバーが同じ測定値を公開するため、コーディングエージェント自身でフィードバックループを完結できます。 |
| プルリクエストのチェック 複合 Action がチェックを実行し、プルリクエスト上のコメントを常に最新の状態に保ちます。 | シンプルな JSON コントラクトは読み取り、差分を確認し、レビューできるファイルです。サービスもアカウントも、ログインも不要です。 | フレームワークに依存しない レンダリングされた DOM を測定するため、React、Vue、Svelte、手書きの HTML を区別しません。 |
コマンド
| コマンド | 説明 |
|---|---|
pixelpact extract <url> | 参照元を読み取り、コントラクトファイルを書き出します |
pixelpact check <contract> <url> | 実装を測定して差異を出力し、終了コードを設定します |
pixelpact diff <contract> <url> | コントラクトに保存されたスクリーンショットとピクセル比較します |
pixelpact side <reference> <url> | セクションごとに横並びの画像を表示し、差異を枠で囲みます |
共通フラグでは、ブラウザーコンテキスト(--viewport、--selector、--wait、--timeout、
--locale、--timezone、--channel、--headful)、出力(--out、--json、
--quiet)、および抽出時に上限を設定できる項目(--max-elements、--max-states、
--mask)を指定できます。全フラグの一覧は pixelpact <command> --help を実行して確認してください。
終了コード
| コード | 意味 |
|---|---|
0 | すべて許容範囲内です |
1 | 差異が見つかった、またはピクセルしきい値を超えました |
2 | 使用方法のエラーです。例:フラグが不正、またはコントラクトファイルがありません |
3 | 実行時エラーです。例:ブラウザーを利用できない、またはページを読み込めません |
プログラムからの利用
import { extract, check, formatCheckReport, writeContract } from 'pixelpact-core'
const contract = await extract({
url: 'https://reference.example.com',
selector: 'main',
screenshotDir: '.pixelpact/shots',
})
await writeContract('contract.json', contract)
const report = await check(contract, { url: 'http://localhost:3000' })
console.log(formatCheckReport(report, { color: true }))
if (!report.ok) process.exitCode = 1
すべての型が定義されており、コントラクトとレポートの形式は境界で検証されます。そのため、不正なファイルがあるとスタックトレースではなく、わかりやすいメッセージが表示されます。
CI での利用
この Action は、リポジトリにコミットされたコントラクトを使ってプレビュー環境のデプロイ結果を測定し、プッシュごとにコメントを追加するのではなく、プルリクエスト上のコメントを常に最新の状態に保ちます。
- uses: jamalkamaladdin/pixelpact/action@v0
with:
contract: contract.json
url: ${{ steps.preview.outputs.url }}
viewport: desktop
tolerance: 1
必要な権限は permissions: pull-requests: write で、自動生成される GITHUB_TOKEN 以外のシークレットは不要です。すべての入力、出力、およびワークフローの完全な例は
action/README.md にあります。
Figma フレームの読み込み
extract は Figma の URL を認識し、REST API を通じてフレームを読み込みます。この処理ではブラウザーは起動しません。
export FIGMA_TOKEN=figd_...
npx pixelpact extract "https://www.figma.com/design/KEY/Name?node-id=12-345" -o contract.json
npx pixelpact check contract.json http://localhost:3000
Figma のレイヤーには CSS セレクターがないため、Figma コントラクトは data-contract 属性を通じてマークアップに紐付けます。要素にはレイヤー名を付けると、デザインでフレームがどのようにネストされているかに左右されず、一致させられます。
<a class="btn btn-primary" data-contract="Hero/CTA">Get started</a>
一致するものがない場合は、タグ名から推測せず、見つからないものとして報告されます。
公開されたスタイルはトークンとして取り込まれます。カラーのスタイルは色として、テキストのスタイルは 600 60px/72px Geist のような CSS フォントの省略記法として、エフェクトのスタイルはボックスシャドウとして取り込まれます。グラデーションや画像の塗りには単一の CSS 値がないため、近似せず、警告に名前を記載して省略します。
仕組み
- Playwright は、指定された各ビューポートで参照先を開き、フォント、ネットワーク、描画が安定するまで待機して、Cookie のオーバーレイを閉じます。
- ページ内で単一の関数を評価します。この関数はルートセレクターの下にある DOM をたどり、表示されているすべての要素の計算済みスタイルに加え、カスタムプロパティ、キーフレーム、各ボックスのジオメトリを記録します。
- インタラクティブ要素にホバーし、フォーカスを当てて、実際に変化したプロパティだけを保存するため、コントラクトを読みやすいサイズに保てます。
- チェックでは手順 2 を実装に対して繰り返し、まず
data-contract属性、次にセレクター、最後にタグとテキストで要素を照合し、プロパティごとに比較します。長さはピクセル許容誤差を使い、色は知覚的距離を使います。アニメーションは文字列の完全一致ではなく、名前とタイミングで比較します。
リポジトリの構成
| パッケージ | 公開名 | 内容 |
|---|---|---|
packages/core | pixelpact-core | 抽出、チェック、レポート |
packages/cli | pixelpact | pixelpact コマンド |
packages/mcp | pixelpact-mcp | コーディングエージェント向け MCP サーバー |
action | GitHub から使用 | プルリクエストのチェック用 Action |
よくある質問
エージェントはどのように使いますか? pixelpact-mcp をインストールし、MCP クライアントの接続先に指定して、コントラクトを一度抽出します。その後、編集のたびにエージェントに check_implementation を呼び出させ、返された差異の表を確認します。
Percy や Chromatic とはどう違いますか? これらは、以前に承認したスナップショットとページを比較するため、ページがすでに正しいことを前提とします。pixelpact は参照先と比較します。これは、ページをまだ作成中の段階で実際に手元にあるものです。この 2 つは併用できます。pixelpact でページを正しくし、リグレッションツールでその状態を維持します。
ベースラインは必要ですか? いいえ。参照先がベースラインです。それこそがこのツールの要点です。
マークアップの構造が参照先と一致しません。一致するものはありますか? 要素の照合では、まず data-contract 属性、次にセレクター、最後にタグとテキストを試します。要素に data-contract="hero-cta" を指定すれば、参照先の div がどのようにネストされているかに左右されず、一致させられます。
読み込みのたびに変わるコンテンツがあります。チェックに合格できますか? マスクしてください。--mask ".carousel" を指定すると、領域をピクセル比較から除外できます。また、--max-elements を指定すると、長いページから誰にも読めないコントラクトが生成されるのを防げます。
どのブラウザーに対応していますか? Playwright 経由の Chromium です。エンジンをまたいだマトリクス実行は、意図的に対象外としています。このツールはデザインとの一致度を測るものであり、ブラウザー間の差異を測るものではありません。
チェックに合格すれば、ページは正しいということですか? コントラクト内のすべての値が許容誤差内で一致したという意味です。ページに存在して参照先にない要素は、コントラクトが参照先に含まれるものだけを記述するため、警告されません。余分な要素が一切許されない場合は、diff も実行してください。
ステータス
上記の説明はすべて実装済みで、表示されている数値はすべて実際の実行結果です。実際のページと Figma からの抽出、チェック、ピクセル差分、並べて表示した画像、MCP サーバー、Action が含まれます。
バージョン 0.3 です。使用するには十分に安定していますが、保証するにはまだ至っていません。契約フォーマットには 1.0 より前にフィールドが追加される予定です。必要な値がない場合は、どの値が必要かを記載して issue を作成してください。それが追加される最も早い方法です。
コントリビューション
開発環境のセットアップ、コマンド、プルリクエストの流れについては CONTRIBUTING.md をご覧ください。セキュリティに関する報告は SECURITY.md を通じてお送りください。
ライセンス
MIT © Jamal Kamaladdin
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。