| name | ux-visibility-review |
| version | 1.0.0 |
| description | 色合いのキツさ・隣接要素の色被り・トーン不統一・視認性の悪さを使用感ベースのUX観点で検出し、修正案を標準出力に報告する。報告のみでコードは変更しない。WCAG コントラスト比など数値基準の準拠検証は style-review を使う |
UX Visibility Review
実装コードからカラー定義と使用箇所を抽出し、「人間の目で見た時に見づらい・疲れる・区別しにくい」問題を検出するスキル。
WCAG 準拠の技術的検証ではなく、実際の使用感に基づくUXレビュー(WCAG 検証は /style-review の担当)。
ガードレール
- このスキルは 検出と報告のみ を行う。コードや色定義の修正は行わない(修正案を提示し、適用はユーザーの指示を待つ)
Quick Start
/ux-visibility-review [対象ディレクトリ]
対応プロジェクト
- Swift App: SwiftUI / AppKit(Color, NSColor, Asset Catalog)
- Electron App: CSS / テーマファイル(CSS変数, color プロパティ)
検出する問題
1. 色がキツい(目が疲れる)
高彩度・高明度の色が広い面積で使われていると視覚的に攻撃的になる。
検出基準(HSL ベース):
- 彩度 (S) > 80% かつ 明度 (L) が 40〜60% の色 → 「ビビッドすぎる」
- 純色に近い原色(#FF0000, #00FF00, #0000FF 付近)がテキストや背景に使われている
- ネオンカラー(高彩度 + 高明度)が UI 部品に使われている
修正案の方向:
- 彩度を 10〜20% 下げる(鮮やかさを落としてトーンを揃える)
- 明度を調整して「落ち着いた」バリエーションを提案
- 例:
#FF0000 → #DC2626(少しだけ暗く)、#00FF00 → #22C55E(彩度を落とす)
2. 隣接要素の色が似すぎて区別しにくい
横並び・縦並びで隣り合う UI 要素の色が近すぎると、境界が曖昧になり認知負荷が上がる。
検出基準(CIE ΔE 2000):
- 隣接要素間の色差 ΔE < 5 → 「ほぼ同じに見える」(High)
- 隣接要素間の色差 ΔE < 10 → 「似ていて区別しにくい」(Medium)
- 背景色とボーダー色の ΔE < 5 → 「ボーダーが見えない」
隣接要素の推定方法:
- Swift: 同一
VStack/HStack/List 内の子ビュー同士
- CSS: 同一親セレクター内の兄弟要素、
flex/grid コンテナの子要素
- タブバー・ナビゲーション・ツールバー内のアイテム同士
修正案の方向:
- 色相 (H) を 30° 以上離す
- 明度 (L) を 15% 以上離す
- ボーダーや余白で視覚的な区切りを追加する提案
3. 前景と背景のトーンが合っていない
テキスト色と背景色の「暖色/寒色」や「彩度レベル」が不統一だと違和感が生まれる。
検出基準:
- 背景が暖色系 (H: 0〜60°) なのにテキストが寒色系 (H: 180〜270°)、またはその逆で彩度が共に高い
- 背景がパステル調 (S < 30%, L > 80%) なのにテキストがビビッド (S > 70%)
- 同一画面内でトーン(暖色/寒色/無彩色)が3種以上混在
修正案の方向:
- 同一トーンファミリーに揃える提案
- 無彩色(グレースケール)をベースにしてアクセントカラーを1〜2色に絞る
4. 似た役割なのに異なる色
同じ意味の要素に別の色が使われていると、ユーザーが混乱する。
検出基準:
- 「プライマリボタン」相当の要素に2種以上の色が存在
- エラー表示に異なる赤系の色が複数使われている
- リンクテキストの色が画面ごとに異なる
修正案の方向:
- カラーパレットの統一(セマンティックトークンの提案)
- 「この色をこっちにも使えば統一される」という具体案
5. Dark モードでの色の破綻
Light モードでは問題ないが Dark モードに切り替えると破綻するパターン。
検出基準:
- Light で映える中間色が Dark 背景で沈む(テキストと背景の明度差 L < 30%)
- Dark モードなのに明るすぎる背景色(L > 40%)が残っている
- シャドウや微妙なグラデーションが Dark モードで消失(背景との ΔE < 5)
実行フロー
1. プロジェクト種別判定
├── *.xcodeproj / Package.swift → Swift App
└── package.json / *.css → Electron App
2. カラー定義の抽出
├── Swift: Asset Catalog JSON + コード内 Color/NSColor/UIColor
├── CSS: 変数定義 (:root) + プロパティ値
└── テーマファイル: エクスポートされた色定数
3. 色の使用コンテキスト分析
├── どの要素にどの色が使われているか
├── 隣接関係の推定(レイアウトコンテナの解析)
└── Light/Dark 両モードでの色マッピング
4. 問題検出
├── HSL 変換して彩度・明度チェック
├── CIE ΔE 2000 で隣接色の色差計算
├── トーンの一貫性チェック
└── セマンティック色の統一性チェック
5. 修正案の生成
├── 具体的な色コード(HEX)を提案
├── 変更前後の色差を数値で示す
└── 標準出力に Markdown で報告
カラー抽出の具体的手順
Swift App
1. Glob: **/*.colorset/Contents.json → Asset Catalog の色定義
- "components" の r/g/b/a 値を抽出
- "appearances" から Light/Dark の色を分離
2. Grep: Color\(|\.foregroundColor|\.foregroundStyle|\.background|\.tint
→ コード内の色使用箇所
3. Grep: \.primary|\.secondary|\.accentColor → システムカラー使用
4. レイアウト構造: VStack/HStack/List/ForEach を追跡して隣接関係を推定
Electron/CSS
1. Glob: **/*.css, **/*.scss → スタイルファイル
2. Glob: **/theme*.{ts,js}, **/colors*.{ts,js} → テーマ定義
3. Grep: --[a-z-]*color|--bg-|--text-|--border- → CSS 変数
4. :root と prefers-color-scheme: dark の色を分離
5. flex/grid コンテナ内の子セレクターから隣接関係を推定
色差の計算
CIE ΔE 2000(隣接要素の区別しやすさ)
人間の色知覚に基づく色差指標。数値が大きいほど違って見える。
| ΔE 値 | 体感 |
|---|
| < 1 | 人間には区別不能 |
| 1〜5 | 注意すれば分かる程度 |
| 5〜10 | 一目で分かるが「似ている」 |
| 10〜25 | 明確に異なる色 |
| > 25 | 全く別の色 |
HSL 分析(色のキツさ判定)
RGB → HSL 変換:
H (色相): 0〜360°
S (彩度): 0〜100%(0=無彩色, 100=純色)
L (明度): 0〜100%(0=黒, 100=白)
「キツい色」= S > 80% かつ 40% < L < 60%
出力形式
## UX Visibility Review
### 概要
- プロジェクト種別: Swift App
- 検証ファイル数: 12
- 検出問題数: 7 (High: 2, Medium: 3, Low: 2)
---
### High: サイドバーのアイテム色が隣接で区別できない
**場所**: `Views/SidebarView.swift:34-52`
**問題**: `HStack` 内の `.labelColor (#3B82F6)` と `.iconColor (#4F8EF7)` の色差 ΔE = 3.2 で、ほぼ同じに見える
**修正案**:
- `.iconColor` を `#1D4ED8` に変更 → ΔE = 18.5(明確に区別可能)
- または `.labelColor` をグレー系 `#374151` にしてアイコンに色を持たせる
---
### High: アクションボタンの赤がキツすぎる
**場所**: `Styles/buttons.css:23`
**問題**: `.btn-danger` の `background-color: #FF0000` は彩度 100% の純色で、長時間の使用で目が疲れる
**修正案**:
- `#DC2626` に変更(S: 89%, L: 50% → 十分に「赤」だがトーンが落ち着く)
- Hover 時: `#B91C1C`
---
### Medium: ナビゲーションタブの選択/非選択が似ている
**場所**: `Components/TabBar.swift:18-25`
**問題**: 選択タブ `#2563EB` と非選択タブ `#3B82F6` の色差 ΔE = 7.8 — 区別はつくが弱い
**修正案**:
- 非選択を `#9CA3AF`(グレー系)にして明度差で区別 → ΔE = 32
- または非選択のテキストを細字にして色 + ウェイトで区別
---
### Low: ダークモードでセカンダリテキストが沈んでいる
**場所**: `Assets.xcassets/secondaryText.colorset/Contents.json`
**問題**: Dark モードの `#6B7280` は暗い背景 `#1F2937` に対して明度差が小さく読みにくい
**修正案**:
- Dark モードの secondaryText を `#9CA3AF` に変更(明度差 +15%)
severity 定義
| severity | 基準 | 例 |
|---|
| High | 隣接要素が区別できない (ΔE < 5)、または色がキツすぎて不快 | 同色のタブ、純色の大面積使用 |
| Medium | 区別しにくい (ΔE 5〜10)、トーン不統一、Dark モード破綻 | 似た青の並び、暖色寒色混在 |
| Low | 改善すれば快適になる | 微妙な明度差の不足、パレット未統一 |
エラーハンドリング
| 状況 | 対応 |
|---|
| カラー定義が見つからない | "カラー定義が検出できませんでした" と報告 |
| 隣接関係が推定できない | 色の一覧を出して「手動で隣接確認を推奨」 |
| CSS 変数が外部参照で解決不能 | "解決不能" マーク + 手動確認推奨 |
連携エージェント
| Agent | 役割 | 起動条件 |
|---|
css-expert | CSS カラー分析、セレクター隣接解析 | Electron/CSS プロジェクト |
swiftui-macos-designer | SwiftUI ビュー構造・カラー分析 | Swift プロジェクト |