---
name: ui-compare
description: >-
  Deterministic, measured comparison of a developed UI against a visual
  reference (mockup image, reference app, screenshot of a working example).
  Use this skill whenever the user asks to compare an interface with a sample
  or mockup, verify that UI matches a design or screenshot, find visual
  differences, complains that the UI "doesn't look like" the reference, or
  reports that an element is visible but not clickable (сравнить UI с
  образцом/макетом/скриншотом, проверить соответствие дизайну, найти
  визуальные отличия, "не похоже на макет", "кнопка видна, но не нажимается").
  Also use it to verify your own UI work before reporting completion of any
  task where a visual reference exists. Never judge visual parity by eye from
  screenshots — always run this skill's measured pipeline instead.
---

# Сравнение UI с образцом (ui-compare)

## Оглавление

- [1. Три железных правила](#1-три-железных-правила)
- [2. Подготовка (один раз за сессию)](#2-подготовка-один-раз-за-сессию)
- [3. Сначала выбери режим](#3-сначала-выбери-режим)
- [4. Алгоритм pixel-parity](#4-алгоритм-pixel-parity)
- [5. Алгоритм style-parity](#5-алгоритм-style-parity)
- [6. Решающая таблица](#6-решающая-таблица)
- [7. Ворота приёмки и шаблон отчёта](#7-ворота-приёмки-и-шаблон-отчёта)
- [8. Запрещено](#8-запрещено)
- [9. Углублённый справочник](#9-углублённый-справочник)

## 1. Три железных правила

1. **Вердикт выносит инструмент, а не глаза.** Результат сравнения — это
   строка `СТАТУС: PASS` свежего прогона, а не впечатление «выглядит
   одинаково». Почему: vision-модели (включая тебя) не различают мелкие
   сдвиги, оттенки и отступы, а скриншоты в контексте уменьшены — «на глаз»
   ошибается систематически.
2. **Детали смотри только на кропах.** Полный кадр — лишь для общей
   ориентировки. Инструмент сам сохраняет кропы проблемных зон
   (`crop-*.png`, `element-*.png`) в формате «образец | реализация | diff».
3. **Каждая проблемная зона получает ровно одну метку:** «дефект» (чинить) /
   «шум рендеринга» (принять и записать) / «намеренное отличие» (ссылка на
   документ). Молча пропустить зону нельзя.

## 2. Подготовка (один раз за сессию)

Выполни из корня репозитория:

```bash
node .claude/skills/ui-compare/scripts/ui-visual-tool.mjs
```

- Увидел список команд → окружение готово, полный справочник флагов перед
  тобой (перечитывай его отсюда, не по памяти).
- Увидел `Не найдена зависимость` → выполни
  `npm install --no-save pngjs pixelmatch playwright` и повтори.
- Браузерная команда упала с `Executable doesn't exist` → выполни
  `node node_modules/playwright/cli.js install chromium` и повтори.

Навык установлен не в `.claude/skills/`? Замени префикс
`.claude/skills/ui-compare` на фактический каталог навыка во всех командах.
Все артефакты пиши в `.tmp/ui-compare/` (в репозиторий не коммитить, после
задачи подчистить).

## 3. Сначала выбери режим

| Происхождение образца | Режим | Куда дальше |
|---|---|---|
| Скриншот работающего UI (draft-приложение, прежняя версия, другой рендерер) | **pixel-parity** | [раздел 4](#4-алгоритм-pixel-parity) |
| Сгенерированная картинка (Midjourney и т.п.) или рисунок от руки | **style-parity** | [раздел 5](#5-алгоритм-style-parity) |
| Непонятно | Спроси пользователя; его ответ зафиксируй в отчёте | — |

Почему это важно: сгенерированная картинка нерегулярна по природе, пиксельное
совпадение с ней недостижимо и не требуется — «картинка — концепт, а не
пиксельный эталон» (`docs/architecture/game-ui-mockup-flow.md`).

## 4. Алгоритм pixel-parity

Шаги выполняй строго по порядку. Шаг 0 не пропускай — без него любые
проценты бессмысленны.

### Шаг 0 — предусловия

- [ ] **Данные одинаковы.** Реализация показывает те же тексты, карточки и
  значения, что образец (фикстуры или продвижение по состояниям). Diff
  60–90% почти всегда означает нарушение именно этого пункта.
- [ ] **Ровно один dev-сервер со свежим bundle.** Убей все процессы порта и
  запусти один заново; признаки устаревшего кэша — методология §9.6.
- [ ] **Целевой экран достигается детерминированно.** Если до него нужно
  кликать — опиши шаги в файле `steps.json`:
  ```json
  [{ "click": "#btn-continue" }, { "waitSelector": ".journal-screen" }]
  ```
  (поддерживаются `click`, `waitSelector`, `fill`, `wait`).

### Шаг 1 — образец в PNG

```bash
node .claude/skills/ui-compare/scripts/ui-visual-tool.mjs to-png <ПУТЬ-К-ОБРАЗЦУ> --out .tmp/ui-compare/ref.png
```

Запиши размеры из вывода (например `(1920x1080)`) — это viewport для шага 2.

### Шаг 2 — скриншот реализации

```bash
node .claude/skills/ui-compare/scripts/ui-visual-tool.mjs capture <URL> --out .tmp/ui-compare/impl.png --viewport <WxH-ИЗ-ШАГА-1> --wait-selector <СЕЛЕКТОР-ЦЕЛЕВОГО-ЭКРАНА> --steps steps.json
```

(`--steps` — только если нужен сценарий; `--wait-selector` ставь всегда,
когда знаешь селектор целевого экрана.) Анимации и переходы инструмент
замораживает автоматически; DPR всегда 1 — не меняй.

### Шаг 3 — измерить

```bash
node .claude/skills/ui-compare/scripts/ui-visual-tool.mjs compare .tmp/ui-compare/ref.png .tmp/ui-compare/impl.png --regions <РАЗМЕТКА.design.json>
```

`--regions` подключай всегда, когда у образца есть разметка зон
(`*.design.json` по ADR-016 или массив `[{id,x,y,w,h}]`) — отчёт будет в
терминах элементов («кнопка btn-move: 34%»), а не абстрактной сетки. Без
разметки сетка 4×4 отработает сама.

### Шаг 4 — прочитай вывод

Найди в выводе `СТАТУС:` и действуй по [решающей таблице](#6-решающая-таблица).

### Шаг 5 — проверка по элементам (если есть селекторы и живой URL)

```bash
node .claude/skills/ui-compare/scripts/ui-visual-tool.mjs compare-elements .tmp/ui-compare/ref.png <URL> --regions <РАЗМЕТКА> --steps steps.json
```

На каждый элемент — независимые вердикты: геометрия («не там», допуск ±2px),
внешний вид («не такой», порог 10% по кропу), перекрытие («виден, но клик
уйдёт в чужой слой»), `MISSING` (нет в DOM), `OFFSCREEN` (вне вьюпорта).
Селекторы — поле `selector` в разметке или карта `--selectors map.json`.

### Шаг 6 — локализуй и почини

1. Открой кропы проблемных зон из `.tmp/ui-compare/` — смотри их, не полные
   кадры.
2. Цвет проверяй только числом, по одинаковым координатам выровненных копий
   `ref.png` и `impl.png` из out-dir:
   ```bash
   node .claude/skills/ui-compare/scripts/ui-visual-tool.mjs sample .tmp/ui-compare/ref.png --points "<x,y>"
   node .claude/skills/ui-compare/scripts/ui-visual-tool.mjs sample .tmp/ui-compare/impl.png --points "<x,y>"
   ```
3. Размеры, отступы, шрифт, z-index смотри через `getComputedStyle` в
   Playwright (шаблон — методология §9.1), а не чтением CSS-файла: файл
   говорит, что написано, computed style — что применилось.
4. Внеси один осмысленный фикс.

### Шаг 7 — повтори шаги 2–5

После каждого фикса — свежий прогон. Останавливаться можно только на
`СТАТУС: PASS` во всех прогонах. «Я поправил, теперь должно совпасть» без
прогона — не результат.

### Шаг 8 — отчёт

Заполни шаблон из [раздела 7](#7-ворота-приёмки-и-шаблон-отчёта) и подчисти
`.tmp/ui-compare/`.

## 5. Алгоритм style-parity

Пиксельные ворота здесь не применяются. Вместо них:

1. Составь таблицу дизайн-токенов по зонам образца: фон, акцент, цвет текста,
   шрифт, скругления, шкала отступов. Цвета — только через
   `sample --rect <x,y,w,h>` (среднее по зоне сглаживает шум генерации).
2. Сними те же значения с реализации через `getComputedStyle`.
3. Сведи таблицу «токен → образец → реализация → совпадает?». Расхождение
   цвета заметнее ~2 единиц на канал — дефект.
4. Структуру проверь `compare --regions`: каждая зона образца присутствует и
   стоит в правильном месте (проценты используй для сравнения зон между
   собой, не как ворота).
5. `compare-elements` работает и здесь — для `MISSING`, перекрытий и грубой
   геометрии (`--tolerance 8` и больше, по договорённости с пользователем).

## 6. Решающая таблица

| Что видишь в выводе | Что это значит | Что делать |
|---|---|---|
| Общий diff 60–90%+ | Сравниваются разные экраны или данные | Вернись к шагу 0: фикстуры, steps.json |
| `ВНИМАНИЕ: размеры не совпадают` | viewport ≠ размер образца | Повтори шаг 2 с `--viewport` по размеру образца |
| Общий PASS, но ячейка/регион ≥ 10% | Локальный дефект, «разбавленный» площадью кадра | Это FAIL: смотри кропы зоны, чини |
| Равномерный шум 1–2% по всем ячейкам | Рендеринг шрифтов | Допустимо: метка «шум» в отчёте |
| Ячейка/регион ~100% | Элемент отсутствует или layout сдвинут | Шаг 5 (compare-elements) или кропы + DOM |
| `MISSING` | Элемента нет в DOM | Реализуй элемент; если он есть — исправь селектор |
| `OFFSCREEN` | Элемент вне вьюпорта или нулевого размера | Чини layout; скроллящиеся экраны сравнивай по частям — инструмент не скроллит |
| `ПЕРЕКРЫТ (интерактивный!)` | Кнопка видна, но клик перехватит чужой слой | Оверлею `pointer-events: none` или кнопке `z-index: 1`; НЕ двигай grid-строки (методология §3.8, §7.5) |
| Фиксы «не применяются» визуально | Устаревший bundle dev-сервера | Методология §9.6: убить все процессы порта, запустить один, жёсткая перезагрузка |
| `СТАТУС: PASS` во всех прогонах | Готово | Раздел 7: ворота и отчёт |

## 7. Ворота приёмки и шаблон отчёта

Приёмка пройдена, только если выполнено ВСЁ:

- [ ] `compare`: `СТАТУС: PASS` — общий diff < 5% (без структурных изменений
  < 3%), все ячейки/регионы < 10%;
- [ ] `compare-elements` (когда есть селекторы): `PASS` — нет `MISSING` и
  `OFFSCREEN`, интерактивные элементы не перекрыты;
- [ ] каждая оставшаяся зона имеет метку: исправлена / шум / намеренное
  отличие со ссылкой на документ (ADR или задача).

Шаблон отчёта — заполни каждое поле:

```markdown
## Сравнение UI с образцом
- Режим: pixel-parity | style-parity
- Образец: <путь>; реализация: <URL и состояние>; viewport: <WxH>; DPR: 1
- compare: общий N% (порог M%) — PASS/FAIL; худшая зона: <id> N%
- compare-elements: PASS/FAIL (MISSING: n, OFFSCREEN: n, перекрыто: n)

| Зона | Diff % | Метка | Причина / действие |
|---|---|---|---|

- Исправлено в этой итерации: ...
- Осталось и почему допустимо: ...
```

## 8. Запрещено

- Выносить вердикт, разглядывая два скриншота.
- Объявлять успех без свежего прогона со `СТАТУС: PASS`.
- Повышать пороги (`--gate`, `--cell-gate`, `--tolerance`), чтобы «прошло».
  Пороги меняет только пользователь, решение фиксируется в задаче.
- Сравнивать экраны с разными данными или состоянием.
- Молча игнорировать зону с различиями.
- Включать `--include-aa` или менять `--threshold` без причины, записанной в
  отчёте.

## 9. Углублённый справочник

`docs/processes/UI_MIGRATION_METHODOLOGY.md` (в корне этого репозитория) —
прочитай целиком, когда: переносится целая визуальная парадигма между
приложениями; нужны CSS-override-фиксы поверх чужого рендерера; порог не
достигается после 3+ итераций; подозрение на stacking context (§7). Раздел 10
методологии — теоретическая база этого навыка.

Разработка нового UI по изображению-макету — навык `ui-from-mockup`
(соседний каталог навыков); этот навык служит там воротами приёмки.
