Cornea, deterministic visual inspection について
Corneaは、コーディングエージェント向けの決定論的なWebレイアウト検査エンジンです。CLI、MCP、HTTP APIから利用でき、重なり、はみ出し、コントラスト、ページ品質を構造化モデルで分析し、同じ入力には同じ結果を返します。
主な機能
- 01決定論的なレイアウト分析
- 02重なりとはみ出しの検出
- 03WCAGコントラスト検査
- 04ページ品質の評価
- 05ライブURLの検査
- 06CLI、MCP、HTTPに対応
活用シーン
- 01コーディングエージェントが生成した画面の確認
- 02開発中のローカルページの検査
- 03ページ内テキストの色コントラスト確認
MCP 対応
stdio経由で`layout.*`ツールを公開し、MCPクライアントがHTMLやライブURLを検査して、レイアウトモデルと分析結果を取得できます。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
このサーバーのパッケージやリモートエンドポイントはまだ取得できていません。プロジェクトの README の手順に従ってください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
Cornea
AI エージェント向けの決定論的なビジュアル検査。コーディングエージェントに欠けていた目を提供します。
Cornea は、Web ページを構築するコーディングエージェントに、ページを実際に 見る 手段を提供します。トークン消費が少なく、決定論的な構造モデルなので、コンテキストにメガバイト単位のスクリーンショットや生の DOM を投入せずに、正確に推論できます。
エージェントに必要なのはページの 写真 ではありません。必要なのは、レイアウトが壊れているか、壊れているならどのようにかを知ることです。Cornea はすべての要素(ボックス、位置、重なり順、計算済みスタイル)の抽象的な ビジュアルジオメトリモデル を計算し、検査結果を導き出します。重なり、はみ出し、コントラスト、品質を確認し、CLI、MCP、HTTP APIという3つの窓口からネイティブツールとして公開します。
すべてを支える約束はひとつです。同じ入力 → バイト単位で同一の出力。 Chromium も、サブピクセル単位のばらつきも、サーバーも必要ありません。約1.4 MBの単一バイナリです。
クイックスタート
# Build (Rust 1.98+, edition 2024)
cargo build --release
# Inspect a file, the simplest way to use Cornea
./target/release/cornea tests/fixtures/sample-bugs.html 360
cargoだけが必要です。ブラウザー、Node、システム依存関係は不要です。スマートフォン相当のデバイスでも問題なくビルドできます。
または、npm から cornea コマンドをインストールします(Rust ツールチェーンは不要です)。
npm install -g optrex # provides the cornea command
cornea --help
ビジュアルガイド:Cornea の機能
以下のページを見てください。ソースとしては問題なさそうです。しかし、4つのレイアウトバグが隠れています。Cornea はそのすべてを検出します。
<section class="row">
<div class="card">Card 1</div><div class="card">Card 2</div><div class="card">Card 3</div>
</section>
<div class="overlap-left">Left overlap</div>
<div class="overlap-right">Right overlap</div>
<div class="overflow-bad">...</div>
<p class="low-contrast">Hard to read on white</p>
実行すると、Cornea は問題をすぐに報告します。
$ ./target/release/cornea tests/fixtures/sample-bugs.html 360
{
"html_file": "tests/fixtures/sample-bugs.html",
"viewport_w": 360.0,
"element_count": 17,
"est_tokens": 1068, // <-- entire page read for ~1k tokens
"report": {
"total_elements": 17,
"visible_elements": 14,
"overlaps": [ ... 7 collisions ... ],
"overflows": [ ... 1 clipped ... ],
"contrast": [ ... 2 AA failures ... ],
"quality": { "score": 0.06, "label": "broken" }
}
}
検出結果はそれぞれ正確で、対処に役立ちます。
| 検出結果 | 詳細 |
|---|---|
| 重なり | section.row ⇄ div.overlap-right、面積は20000 px²です。絶対配置されたボックスがカードを覆っています |
| はみ出し | div.overflow-bad:右端の 600 がビューポートの 360 を超えているため、切り取られています |
| コントラスト | blue 上の黒:比率は 2.44:1 です。WCAG AA の基準を満たしていません(4.5が必要です) |
| コントラスト | 白上の #cccccc:比率は 1.61:1 です。WCAG AA の基準を満たしていません |
これが Cornea の価値です。数百キロバイトではなく、数百トークンで、エージェントが対処し、再検証できる決定論的な結果を得られます。
ビジュアルガイド:3つの窓口
Cornea はひとつのエンジンに、3つの窓口を備えています。すべてが単一の共有ディスパッチを通じて処理されるため、どの窓口でも同一の検査 JSON が返されます。
1. CLI。ファイルを検査する
cornea <file.html | http(s)://url> [viewport_width] [viewport_height] [--js]
$ cornea page.html 360
{
"html_file": "page.html",
"viewport_w": 360.0,
"element_count": 42,
"json_bytes": 8124,
"est_tokens": 2193,
"report": { "total_elements": 42, "visible_elements": 38, "overlaps": [], "overflows": [], "contrast": [], "quality": { "score": 1.0, "label": "good" } }
}
2. MCP。stdio 経由のネイティブエージェントツール
cornea --serve
エージェントは layout.* ツールを直接呼び出します。呼び出しごとに、ページのソースまたは
ライブ URL(下記の URL キャプチャを参照)を渡します。
→ {"method":"tools/call","params":{"name":"layout.overlaps",
"arguments":{"html":"<div style=\"position:absolute;left:20;top:20;width:200;height:100\">A</div>..."
,"width":360}}}
← {"id":1,"result":{"content":[{"text":"[{\"a_sel\":\"...div \u21c4 ...div\",\"area\":20000}]"}]}}
| ツール | 返される内容 |
|---|---|
layout.inspect | ビジュアルモデル全体とレポート |
layout.overlaps | ボックスが衝突している要素 |
layout.overflow | 切り取り・折りたたみ・画面外の要素 |
layout.contrast | テキスト要素の WCAG AA 比率 |
layout.quality | 0..1の健全性スコアと問題の一覧 |
layout.fidelity | CSS 機能のうち、正確に処理されるものと近似されるもの |
3. HTTP API。あらゆるものから呼び出す
cornea --serve-http [addr] # default 127.0.0.1:8080
curl -s -X POST http://127.0.0.1:8080/inspect \
-H 'Content-Type: application/json' \
-d '{"html":"<p style=\"color:#cccccc\">bady</p>","width":360}'
{"total_elements":1,"contrast":[{"selector":"...>p","fg":"#cccccc","bg":"#ffffff",
"ratio":1.61,"pass_aa":false}]}
| ルート | メソッド | 返される内容 |
|---|---|---|
/inspect | POST | レポート全体 |
/overlaps | POST | 衝突 |
/overflow | POST | 切り取り・折りたたみ・画面外 |
/contrast | POST | WCAG 比率 |
/quality | POST | 健全性スコア |
/fidelity | GET | エンジンの機能 |
/health | GET | 稼働状態 |
ライブページの監視(URL キャプチャ)
どのインターフェースでも、HTML を指定する場所に URL を渡せます。Cornea はページを取得し、外部スタイルシートと外部スクリプトをインライン化し(相対 URL はページを基準に解決します)、その後、ブラウザーに実際に表示される内容を検査します。これがライブコーディングセッションのループです。開発サーバーを起動し、cornea にその URL を指定して、レイアウトの判定結果を確認します。
cornea http://localhost:3000 390
{ "url": "http://localhost:3000", "width": 390, "height": 844 } // HTTP /inspect
{ "method": "tools/call", "params": { "name": "layout.quality",
"arguments": { "url": "http://localhost:3000", "width": 390 } } } // MCP
キャプチャに関する制約:
- 取得に失敗した場合、元のタグを残して注記を記録するため、レポートの警告で読み込めなかったものが引き続き示されます。
- 正の値を指定した
heightは、固定ビューポート(スクリーンショットのフレーム、iframe、メール)を再現し、画面下部でのクリッピング確認を有効にします。デフォルトの 0 は、スクロール範囲に制限のないページを意味します。 - キャプチャはある時点のスナップショットです。決定性はエンジン側で保証されます。同じ取得バイト列からは、常に同じレポートが生成されます。
- プレーン HTTP はネイティブでサポートされています。HTTPS ページには TLS スタックが必要ですが、バイナリには含まれていません。ローカルの HTTP 開発サーバーからキャプチャするか、独自の取得レイヤーでページを事前にインライン化してください。
アーキテクチャ
┌─────────────────────────────────────┐
HTML + CSS ──► │ cornea (one binary) │
│ │
│ dom.rs html5ever ──► tree │
│ css.rs <style> + inline │
│ │
│ layout.rs deterministic layout │
│ (block/inline/flex, │
│ box model, z-index) │
│ │ │
│ model.rs Visual Geometry Model │
│ │ │
│ inspect.rs overlap / overflow / │
│ contrast / quality │
│ │ │
│ rest.rs canonical dispatch │
└───────┬─────────────┬───────────────┘
│ │
┌─────┴────┐ ┌────┴───────────────┐
│ CLI │ │ MCP (stdio) / HTTP│
│ cornea │ │ layout.* / REST │
└──────────┘ └────────────────────┘
技術仕様の全文を読む: CORNEA-ARCHITECTURE.md
忠実度。近似の範囲を明示します
Cornea は、精度を黙って偽ることはありません。layout.fidelity はエージェントが信頼できる内容を正確に示し、各レポートには、エンジンが検出したものの適用しなかったソース(外部スタイルシート、外部スクリプト、メディアクエリー、未解決の色)を示す独自の warnings が含まれます。
{
"exact": ["box model", "block flow", "inline text estimates", "flex row/column (no wrap)",
"z-index", "visibility", "absolute/fixed left/top", "inline styles",
"class/id/tag selectors", "WCAG contrast (hex, rgb, hsl, alpha)"],
"approximate": ["text glyph width (not shaping)", "flex-grow/flex-basis distribution",
"percentage widths", "overlap semantics ignore intentional stacking"],
"deferred": ["grid (parsed as block flow)", "media queries", "border-radius",
"external stylesheet <link> when not captured",
"complex selectors (combinators, pseudo)"],
"js": {
"engine": "boa",
"phase": "A",
"enabled": "opt-in via --js / js:true",
"dom_shim": "static HTML mirrored in first; getElementById; innerHTML parses markup",
"unsupported": ["async APIs", "event dispatch", "selector engine", "React/SPA mounting (Phase B)"]
}
}
JavaScript による組み込みページ(フェーズ A)
Cornea は、最小限のシムを介して DOM を構築する**インラインの <script>**を実行し、
その結果を同じ決定的なレイアウトエンジンで処理できます。
cornea page.html 360 --js # inline scripts build the DOM first
{ "html": "<p>…</p>", "width": 360, "js": true } // HTTP /inspect and MCP layout.*
- スクリプト実行前に、静的 HTML がシムに反映されます。そのため、スクリプトは
document.getElementByIdで既存のノードにアクセスでき、innerHTMLは実際のマークアップを要素に解析します。静的コンテンツはスクリプト実行後も維持されます。 style.*の代入はstyle="…"にシリアライズされ、重なりとコントラストの確認に適用されます。- 非同期 API(
setTimeout、fetchなど)は、処理が停止したままにならないよう拒否されます。 そのような API の使用はレポートのjs_notesに示されるため、決定性が保証されます。 - 外部の
<script src>は、キャプチャレイヤー(URL キャプチャ)がその本文を先にインライン化した場合にのみ実行されます。 - React/SPA の完全なマウントはフェーズ B(実験的機能)です。進捗は
ROADMAP-JS.mdで管理されています。
ビジュアルガイド:テスト(実績あり)
cargo test で 54 件のテストがすべて成功します。CI では、プッシュのたびにfmt、clippy -D warnings、リリースビルド、テスト、CLI のスモークテストを実施します。
$ cargo test
Running unittests src/lib.rs ... 36 passed // determinism, overlap, overflow,
Running unittests src/main.rs ... 9 passed // contrast, inline flow, flex,
Running tests/endpoints.rs ... 9 passed // nesting, empty input, MCP, CLI, JS, capture
- 決定性。同じページを 2 回検査すると、バイト単位で同一の JSON が得られます(これが中核となる考え方です)。
- バグ検出。フィクスチャの重なり、はみ出し、コントラストの失敗をすべてアサートします。
- エンドツーエンド。コンパイル済みバイナリを起動し、実際の標準入出力を介した MCP で
layout.*を呼び出します。 - HTTP。TCP サーバーを一時ポートで起動し、実際のリクエストを送信します。
- ライブキャプチャ。実際のページをローカルソケット経由で配信し、リンクされた CSS によってコントラストの判定結果が変わることを確認します。
- エッジケース。空の HTML、深いネスト(クラッシュしないこと)、
display:none、長いテキスト、Flex の行・列、インラインの折り返し。
レイアウトのサポート(v1 の範囲)
| 機能 | 状態 |
|---|---|
| ブロックフロー、ボックスモデル(content/border-box) | 正確 |
| インラインテキストの連続表示(横方向、折り返し) | 正確 |
| Flex の行/列(簡易版、折り返しなし) | 近似 |
| 絶対/固定配置(left/top) | 正確 |
z-index、visibility、display:none | 正確 |
.class/#id/tag セレクターとインラインスタイル | 正確 |
| WCAG コントラスト(hex、rgb、hsl、alpha、継承色) | 正確 |
| ライブ URL キャプチャ(CSS とスクリプトのインライン化) | サポート |
| Grid、メディアクエリー、border-radius | 対応延期 |
リポジトリの構成
cornea/
├── Cargo.toml # crate: html5ever + serde/serde_json, release LTO+strip
├── README.md # this file
├── CORNEA-ARCHITECTURE.md # full technical spec
├── src/
│ ├── lib.rs # build_model / analyze pipeline + unit tests
│ ├── dom.rs # html5ever -> lightweight element tree
│ ├── css.rs # <style> + inline style resolution
│ ├── fetch.rs # live URL capture: GET + css/script inlining
│ ├── layout.rs # deterministic layout engine
│ ├── model.rs # VisualModel / ElementView / Rect
│ ├── inspect.rs # overlap / overflow / contrast / quality / warnings
│ ├── rest.rs # canonical endpoint dispatch (shared by all surfaces)
│ ├── main.rs # CLI + stdio MCP server
│ └── server_http.rs # dependency-free HTTP/1.1 API
├── tests/
│ ├── endpoints.rs # end-to-end CLI + MCP binary tests
│ └── fixtures/sample-bugs.html # known-bug fixture for CI smoke
└── .github/workflows/ci.yml
ステータス
MVP は稼働中で、強化済み、実運用でも検証済みです。 CLI + MCP + HTTP API を備えた決定論的な検査エンジンで、ライブ URL のキャプチャ、スクロールせずに見える範囲より下のチェック、レポートの警告、54 件のテスト合格、CI の成功に加え、フェーズ A のインラインスクリプトのレンダリング(--js)に対応しています。ロードマップでは、以降のフェーズを通じて、Cornea と姉妹プロジェクトであるテキストから画像を生成する Crayon の知覚能力をさらに高めていきます。
公開
Cornea は npm(npm install -g optrex で cornea コマンドを利用可能)、crates.io(cargo install cornea)、GitHub Release + Homebrew(brew install)、MCP Registry(エージェントから検出可能な layout.* ツール)の 4 つの方法で配布されます。すべてこのリポジトリ内でステージングされています。トークン、server.json マニフェスト、リリース/タグの手順については、PUBLISHING.md を参照してください。
mcp-name: io.github.AbduljabbarBXR/cornea
ライセンス
MIT。詳細は LICENSE を参照してください。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。