¿Qué hace CSS/JS?
Скилл переводит макет лендинга из Figma в статичную вёрстку на HTML, CSS и JS. Работа идёт по одному блоку: после каждого блока агент останавливается и ждёт подтверждения пользователя.
Правила самой вёрстки (структура, БЭМ, единицы, картинки, hover и т.д.) лежат в templates/AGENTS.md этого скилла. На шаге 3 этот файл копируется в корень проекта и дальше действует всегда.
Требования
- Подключён Figma MCP (
get_metadata,get_design_context,get_screenshot, при наличии —get_variable_defs). Если его нет — сказать пользователю и остановиться. - Пользователь дал ссылку вида
https://www.figma.com/design/:fileKey/:fileName?node-id=1-2. - Для сервера, скриншотов и WebP нужен Node.js. Команды
npxпри первом запуске качают пакеты из сети — Codex может запросить разрешение, это нормально.
Порядок работы
Шаги выполнять по порядку, не пропуская.
Шаг 1. Разобрать ссылку
fileKey— часть после/design/. Если в ссылке есть/branch/:branchKey/, использоватьbranchKey.nodeId— значениеnode-id, дефис заменить на двоеточие (1-2→1:2).- Ссылка может вести на весь документ, на страницу, на десктоп-фрейм или на мобильный фрейм. Тип определить на шаге 2.
Шаг 2. Карта макета
- Вызвать
get_metadataдля узла из ссылки (для всего документа — безnode-idили с корневой страницей). - Найти фреймы-версии лендинга: десктоп, мобилка, иногда планшет. Ширины определить из макета, не подставлять стандартные. Также найти отдельно лежащие фреймы модальных окон (попапов) и открытого мобильного меню, если они есть на странице.
- Внутри каждого фрейма выделить секции верхнего уровня (шапка, hero, преимущества, отзывы, футер и т.д.).
- Сопоставить секции между версиями: «десктоп-секция ↔ мобильная секция» (по названию слоя, порядку и содержимому).
- Показать пользователю карту и дождаться подтверждения:
Ширины: десктоп 1440, мобилка 375
1. header — 12:30 ↔ 40:2
2. hero — 12:45 ↔ 40:18
3. advantages — 13:10 ↔ 41:5
...
Модальные окна / меню:
- mobile-menu — 45:12
- popup-order — 46:01
Если мобильной версии нет — сказать об этом и спросить, как действовать.
Шаг 3. Каркас проекта и базовый UI
- Если в корне проекта нет
AGENTS.md— скопироватьtemplates/AGENTS.mdиз папки скилла. Заполнить в нём раздел «Этот лендинг» (ширины, контейнер, шрифты) по данным шага 2. Брейкпоинты оставить по умолчанию; менять, только если вёрстка этого макета ломается на других ширинах, — и тогда записать новые. - Создать структуру:
index.html,style.css,script.js,assets/icons/. index.html:<!doctype html>,lang="ru",charset,viewport,<title>и<meta name="description">по смыслу лендинга. Фавикон не добавлять.script.jsподключать сdefer.- Шрифты: взять из
get_design_context/get_variable_defs, подключить через Google Fonts только нужные начертания,display=swap. Если шрифта нет в Google Fonts — попросить у пользователя файлы, подключить через@font-faceизassets/fonts/. style.css: сброс стилей (см.AGENTS.md), затем:rootс переменными цветов, шрифтов, отступов, ширины контейнера. Значения брать изget_variable_defs, если в макете есть переменные; иначе — собрать из макета и округлить.- Базовые компоненты: выделить сквозные элементы макета (кнопки, заголовки секций, поля ввода) в переиспользуемые классы (
.btn,.section-title,.input,.container). Если в макете нет UI-кита с состояниями (hover,focus,active), один раз спросить у пользователя правила наведения для типовых кнопок и ссылок на весь проект. Ответ записать в строку «UI-состояния» раздела «Этот лендинг» вAGENTS.md. - Инструменты (один раз):
- запустить в фоне локальный сервер из корня проекта:
npx -y serve -l 3000(запасной вариант —python3 -m http.server 3000). Все скриншоты снимать сhttp://localhost:3000, не сfile://; - проверить, чем снимать скриншоты: Playwright MCP, если подключён; иначе — скрипт
scripts/shot.cjs(см. «Самопроверка»); - проверить конвертер картинок (см. «Картинки») и запомнить результат.
- запустить в фоне локальный сервер из корня проекта:
- Сообщить пользователю, что каркас готов, и перейти к первому блоку.
Шаг 4. Блоки по одному
Для каждой секции из карты, строго по порядку сверху вниз (включая секции с формами):
- Данные.
get_design_contextиget_screenshotдля десктоп-секции и для её мобильной пары.- Если ответ обрезан или слишком большой —
get_metadataпо секции и забирать дочерние узлы по отдельности. - Код из ответа (обычно React + Tailwind) — только справка о размерах, цветах и структуре. Не копировать его стиль.
- Если ответ обрезан или слишком большой —
- Картинки. Скачать и обработать ассеты блока (см. «Картинки»).
- Вёрстка. HTML блока в
index.html, стили вstyle.cssотдельным разделом с комментарием/* ===== hero ===== */, JS (если нужен) вscript.js. Использовать базовые классы из шага 3.6, не дублируя код кнопок и заголовков. Сначала десктоп, затем адаптив до мобилки черезclamp()и медиазапросы.- Для
headerна мобильной ширине сразу сверстать бургер-меню (по фрейму из карты или уточнив вид у пользователя). - Если в блоке есть форма — сверстать её с базовыми браузерными атрибутами валидации (
required,type="email",type="tel",pattern), но без JS-логики отправки.
- Для
- Самопроверка. Снять только текущую секцию на ширине десктопа, мобилки и промежуточных (1024, 768). Сравнить со скриншотами Figma: отступы, размеры, шрифты, цвета, переносы. Исправить найденное и переснять.
- Через Playwright MCP — скриншот элемента секции на каждой ширине.
- Без MCP — скрипт из папки скилла:
Скрипт сохраняет# один раз mkdir -p .screens && cp <папка-скилла>/scripts/shot.cjs .screens/ npm i playwright --prefix .screens && npx -y playwright install chromium # после каждого блока node .screens/shot.cjs http://localhost:3000 .hero 1440,1024,768,375.screens/<секция>-<ширина>.pngи пишет⚠ горизонтальный скролл, если страница вылезает за ширину экрана. Любое такое предупреждение — исправить причину (не прятать черезoverflow: hiddenнаbody). - Снимки секций удалять после подтверждения блока; сам скрипт и
node_modulesв.screens/— на шаге 6.
- Отчёт и стоп. Коротко написать пользователю: что сделано, где были отклонения от макета и почему, что нужно уточнить по уникальным интерактивным элементам блока (нестандартный hover карточек, параметры слайдера). Ждать подтверждения. Правки пользователя внести в этот же блок, затем снова ждать.
- Только после «ок» — следующий блок.
Шаг 5. Модальные окна и логика форм
После вёрстки всех основных секций:
- Сверстать скрытые модальные окна (попапы), если они были найдены на шаге 2, и подключить триггеры открытия/закрытия (кнопки,
Esc, клик по оверлею). Поведение — по разделу «JavaScript» вAGENTS.md. - Каждое окно — как отдельный блок: самопроверка скриншотами в открытом состоянии, отчёт и ожидание подтверждения.
- Проверить работу всех форм на странице. Отправку данных (
fetch/AJAX) никуда не делать, пока пользователь сам не попросит и не даст адрес (endpoint) или ТЗ.
Шаг 6. Финал
После подтверждения последнего этапа: проверить всю страницу целиком на всех ширинах, удалить временные файлы и папки (assets/_raw/, .screens/ целиком), остановить фоновый локальный сервер, удалить неиспользуемые стили и картинки. Написать короткий итог.
Картинки
- Ассеты блока брать из ответа Figma MCP (ссылки на изображения в
get_design_context). Если отданlocalhost-адрес — скачивать по нему как есть. Не использовать заглушки и сторонние наборы иконок. - Скачивать во временную
assets/_raw/<блок>/, растровые картинки — в 2 раза крупнее (2x), чем они стоят в макете. - Адаптивная графика: если в мобильной версии блока используется кадрированная (другие пропорции) или другая по смыслу картинка — скачивать обе версии (
hero-bg-desktop.webpиhero-bg-mobile.webp) и подключать через<picture>. - Сортировка:
- мелкие иконки внутри интерактивных элементов (кнопки, ссылки), которые должны менять цвет (
fill/stroke) при наведении → инлайн<svg>в HTML сfill="currentColor"(или через CSSmask-image); - статичные иконки, логотипы, простая графика → SVG в
assets/icons/через<img>(или в папку блока, если это крупная графика). Если иконка пришла растром — сказать пользователю; - фото и сложные изображения → WebP в
assets/<блок>/.
- мелкие иконки внутри интерактивных элементов (кнопки, ссылки), которые должны менять цвет (
- Конвертация в WebP, качество 80. Порядок попыток:
npx -y sharp-cli -i in.png -o out.webp -f webp -q 80(нужен Node.js);cwebp -q 80 in.png -o out.webp;- ничего нет — оставить исходный формат и один раз сказать пользователю, что поставить (Node.js или
cwebp), не останавливая работу.
- Если WebP получился тяжелее оригинала — оставить оригинал.
- Имена файлов: латиница, нижний регистр, через дефис, по смыслу (
hero-photo.webp,arrow-right.svg). - После подтверждения блока удалить
assets/_raw/<блок>/.
Hover, анимации, слайдеры
- Hover: для базовых кнопок и ссылок — правила из строки «UI-состояния» в
AGENTS.md. Если в блоке есть уникальные интерактивные карточки/элементы без состояний в макете — не придумывать, а спросить у пользователя в отчёте по блоку. - Анимации при прокрутке и кастомные анимации — только если пользователь сам попросил. Сначала уточнить, что именно должно происходить. Простое (появление при прокрутке) —
IntersectionObserver; тяжёлое (привязка к колесу, «залипающие» секции, параллакс) — GSAP через CDN, только после согласия пользователя. Всегда учитыватьprefers-reduced-motion. - Слайдер: простой (стрелки, точки, свайп) — свой на CSS
scroll-snap+ немного JS. Сложный (бесконечный, автоплей, эффекты, связанные слайдеры) — Swiper через CDN.
Частые проблемы
- Ответ Figma обрезан →
get_metadataпо секции, затемget_design_contextпо дочерним узлам. - Не видна мобильная пара секции или фрейм мобильного меню → спросить пользователя, а не придумывать.
- Шрифт не совпадает по ширине с макетом → проверить начертание и
letter-spacing, не подгонять размер шрифта. - Картинки не скачиваются → проверить, что Figma MCP запущен; ссылки использовать без изменений.
- На скриншоте слетели шрифты или иконки → проверить, что сервер на
localhost:3000запущен и снимок идёт с него, а не сfile://. - Скрипт пишет «горизонтальный скролл» → найти элемент шире экрана (фиксированная ширина, большой
gap, декор за краем) и исправить; для декоративных элементов за краем —overflow-x: clipна их секции. - Отклонение от макета ради доступности или технических ограничений → допустимо, но упомянуть в отчёте по блоку.