| name | figma-pixel-perfect |
| description | Используй ВСЕГДА, когда в сообщении есть ссылка на figma.com (figma.com/design/, figma.com/file/, figma.com/proto/, node-id=...) или пользователь просит сверстать/поправить UI "по макету", "как в фигме", "pixel perfect", "implement this Figma design". Скилл — жёсткий протокол вёрстки строго по данным Figma MCP: без придуманных иконок, размеров, цветов и шрифтов, с численной самопроверкой (измерение DOM против спеки) и честным репортом проблем вместо импровизации. |
figma-pixel-perfect
Протокол вёрстки по макету Figma без отсебятины. Главная идея: ты не дизайнер, ты фотокопир с линейкой. Любое значение (размер, цвет, шрифт, отступ, радиус, иконка) существует в макете — твоя работа его достать и потом измерить, что оно легло в рендер. Если достать не получилось — это проблема, о которой надо сказать, а не место для творчества.
Железные правила
- Источник истины — данные из Figma MCP. Не память о «типичных дизайнах», не «обычно 16px», не глазомер по скриншоту. Каждое значение в коде прослеживаемо до ответа MCP.
- Иконки и картинки не рисуются — скачиваются. Ни одной SVG «по памяти», ни эмодзи вместо иконки, ни иконки из lucide/heroicons/fontawesome, если её нет в макете. Не выгрузился ассет → стоп и репорт.
- Размеры не округляются и не «гармонизируются». В макете 13px — значит 13px. Нет подходящего токена/класса — используй точное значение (
p-[18px]), а не ближайший красивый (p-4).
- Проверка — измерением, не глазами. «Вроде похоже» ≠ pixel perfect. Сверяй числа: rect и computed styles из рендера против спеки.
- Непонятно / не достаётся / противоречиво → репорт, не догадка. Одним блоком в конце работы.
Шаг 0. Ссылка и выбор MCP-сервера
Распарси URL:
figma.com/design/<FILE_KEY>/<name>?node-id=123-456 → fileKey = <FILE_KEY>, nodeId = 123:456 (дефис в URL = двоеточие в API).
- Ссылка без
node-id — весь файл. Не гадай и не передавай пустой nodeId: возьми get_metadata по странице, покажи список фреймов, спроси какой верстать.
figma.com/proto/... — прототип; попроси ссылку на design-фрейм (Copy link to selection).
Серверов может быть несколько (разные проекты — разные аккаунты). Найди все инструменты вида get_design_context (ToolSearch, если отложенные). Если серверов больше одного — дешёвый пробный вызов (get_metadata на fileKey) на каждом; 403/404 → следующий. Ни у кого нет доступа → стоп и репорт с именами проверенных серверов. Вёрстка вслепую по скриншоту запрещена.
Подробная карта инструментов и различий серверов: references/mcp-tools.md.
Шаг 1. Данные (до первой строчки кода)
get_design_context на целевой ноде — первый и главный вызов. Возвращает референс-код (React+Tailwind), скриншот и хинты. get_metadata/get_screenshot — НЕ замена ему: metadata — для ориентации и точной геометрии, screenshot — для финальной сверки.
get_metadata — дерево слоёв с точными x/y/width/height. Отсюда: размер вьюпорта для проверки и таблица ожидаемых габаритов ключевых элементов.
get_screenshot — сохрани в файл (_figma_ref.png) как визуальный эталон.
get_variable_defs — имена токенов (цвета/размеры).
Большая нода (целый экран): у корневого ответа детали урезаются — вызывай get_design_context дополнительно на ключевых дочерних нодах из metadata.
Ошибки MCP: прочитай сообщение прежде чем ретраить; таймаут → запроси ноду поменьше; и никогда не «ладно, сверстаю по скриншоту» — это гарантированные выдумки.
Заверши шаг дистилляцией: заполни _figma_spec.md (шаблон) — размеры, токены, таблица ожиданий, ассеты, тексты. Дальше работаешь из него, к MCP не возвращаешься (см. «Экономия лимитов»).
Шаг 2. Референс-код ≠ финальный код
Ответ get_design_context — референс, не готовый код. Адаптируй его под стек и конвенции проекта, применяя хинты по приоритету (ранний источник бьёт поздний):
- Code Connect → используй замапленный компонент из кодовой базы как есть.
- Ссылки на доки компонентов → следуй им.
- Аннотации дизайнера → это прямые указания, выполняй.
- Дизайн-токены (CSS-переменные) → мапь на токен-систему проекта.
- Сырые hex / абсолютные координаты → переноси дословно.
Правило про токены: вычисленный результат обязан совпасть с макетом, но выражай его через то, что уже есть в проекте. Есть в проекте токен --color-primary: #6C5CE7 и в макете этот же цвет — используй токен. Нет ничего подходящего — точное литеральное значение. Запрещено «округлять к токену», который даёт другое число: это дрейф от макета.
Перед вёрсткой проверь проект: существующие компоненты (кнопки, инпуты), утилиты, шрифты. Повторное использование > генерация дубля.
Шаг 3. Ассеты
- Из metadata выпиши слои-иконки/иллюстрации/фото (
VECTOR, IMAGE, компоненты icon/...).
- Скачай их (
download_assets / ссылки из design context). SVG для иконок, PNG/WebP для растра.
- Посчитай: N ассетов скачано → в рендере должно быть ровно N соответствующих
<svg>/<img>. Эта проверка входит в аудит (шаг 5) и ловит и выдуманные, и задублированные иконки.
Шаг 4. Вёрстка
- Значения из design context — дословно: hex полностью, line-height/letter-spacing/font-weight числами.
- Шрифты — те же семейства, что в макете. Недоступен → системный с похожей метрикой + запись в репорт (молчаливая замена запрещена).
- Auto-layout → flex/grid с теми же gap/padding/alignment.
- Фиксированный фрейм (375×812 и т.п.) → верстай на этом вьюпорте. Про адаптив вне макета не фантазируй — спроси про брейкпоинты, если просят адаптив с одним макетом.
- Ничего сверх макета: ни ховеров, ни анимаций, ни состояний, которых там нет.
Шаг 5. Самопроверка: сначала цифры, потом картинка
5а. Численный аудит (главная проверка)
«Похоже/не похоже» — не аргумент. Аргумент — дельта в пикселях.
- Таблица ожиданий уже готова в
_figma_spec.md (ключевые элементы → width/height/font-size/line-height/color/gap/padding).
- Отрендери на вьюпорте ровно в размер фрейма и измерь DOM:
getBoundingClientRect() + getComputedStyle() через browser-инструменты / Playwright. Готовый снипет: scripts/measure_dom.js.
- Сравни числа. Расхождение формулируется конкретно: «спека: font-size 24px, рендер: 28px» — и чинится по данным, не подгонкой.
- Проверь количества:
document.querySelectorAll('svg, img').length против числа ассетов из шага 3; тексты — дословно из макета (не перефразированы).
5б. Визуальная сверка (вторичная)
- Скриншот рендера →
python3 scripts/pixel_diff.py _figma_ref.png _render.png --out _diff.png — даст % расхождения и heatmap с локализацией по зонам.
- Heatmap нужен, чтобы найти структурные промахи: пропавший элемент, съехавший блок, не тот фон. Нашёл зону → выясни правильное значение в данных Figma → почини → перемерь (5а).
- Антиалиасинг и рендер шрифтов дают фоновый шум 1–3% — это норма, не расхождение. Железное правило: если значение совпадает со спекой по цифрам, его НЕ трогают ради снижения diff. Иначе цикл «поменял 14→15px, сломал line-height, чиню три итерации проблему, которой не было».
Лимит итераций
Максимум 3 круга правок по визуальному diff. Не сходится — причина не в пикселях: либо компонент надо резать на части и сверять по отдельности, либо расхождение объективно (шрифт, рендер) — тогда оно объясняется в репорте, а не замазывается.
Экономия лимитов (токенов и вызовов Figma MCP)
Design context экрана — тысячи токенов, каждый просмотр картинки — ещё сотни, у Figma MCP есть rate-лимиты. Правила экономии — они же правила аккуратности:
- Один заход за данными. По metadata спланируй, какие ноды нужны, и вызови
get_design_context по одному разу на каждую. Полученное не перезапрашивается.
- Сразу дистиллируй в спек-файл. После шага 1 выпиши все нужные значения в
_figma_spec.md (шаблон: templates/figma-spec.md) и дальше работай только с ним. Сырые ответы MCP второй раз не читаются.
- Проверяй текстом, не картинками. Числа из measure_dom.js и вывод pixel_diff.py — копейки. Эталонный скриншот смотри один раз при получении; heatmap открывай только когда diff выше порога. «Сравню глазами обе картинки ещё разок» на каждой итерации — запрещено.
- Правки пачкой. Один аудит → полный список дельт → одна серия правок → одно повторное измерение. Не чини по одной дельте с перемером после каждой.
- Ассеты — одним batch-вызовом, не по одному.
Когда остановиться и сказать, а не придумать
Копи проблемы по ходу, выдай блоком «⚠️ Проблемы по макету» в конце:
- Ассет не выгружается / шрифт недоступен
- Ссылка без node-id (какой фрейм?)
- Ни один MCP-сервер не имеет доступа к файлу
- В макете одно состояние (нет hover/empty/error) — состояния не выдумываются
- Данные противоречат друг другу (context ≠ скриншот — макет правили?) → сними скриншот заново, скажи
- Текст-заглушка в макете (lorem, «Название») — что подставлять?
Формат финального ответа: что сверстано → результаты аудита (таблица дельт: ожидание/факт по ключевым элементам, % визуального diff) → «⚠️ Проблемы по макету». Пустой репорт при заметных расхождениях — красный флаг: скорее всего, что-то придумано вместо того, чтобы спросить.
Типичные ошибки (не делай так)
| Анти-паттерн | Почему провал |
|---|
| Нарисовал SVG «по смыслу» / взял из icon-пака | Пользователь получает не свой дизайн. Только ассеты из макета. |
| Цвет пипеткой со скриншота | Скриншот сжат, цвет искажён. Цвет — из design context / variables. |
Округлил 13px → 12px, p-[18px] → p-4 | Pixel perfect умер. Точное значение важнее красивого класса. |
| Молча заменил шрифт | Метрика плывёт. Замена только с пометкой в репорте. |
| Сверстал по скриншоту, не вызвав design context | Все размеры — догадки. Скриншот — эталон проверки, не источник значений. |
| Гоняет pixel-diff, меняя верные значения | Шум антиалиасинга не чинится вёрсткой. Совпадает со спекой — не трогай. |
| Сдал без численного аудита | «Вроде похоже» — так и появляются 28px вместо 24px. |
| Добавил ховеры/анимации от себя | Отсебятина. Только по просьбе пользователя. |