astra-figma-to-md — Документ компонента Astra из Figma
Источник:
ds-docs/src/skills/astra-figma-to-md/SKILL.mdСправочники скилла — вложенные страницы. В вики не выложены, лежат в папке скилла:scripts/fetch-details.js,scripts/section-summary.py,agents/openai.yaml,CHANGELOG.md.
Шапка скилла:
name: astra-figma-to-md
description: Разбирает Figma Section компонента Astra Design System и пишет markdown-документ: дерево слоёв со всеми CSS-свойствами и токенами, компоненты по умолчанию, отличия вариантов и состояний, индекс свойств. Читает через Figma MCP. Формат жёсткий — состав разделов, порядок строк и словарь значений заданы списками и проверяются скриптом, поэтому результат не зависит от исполнителя. Использовать при разборе нового компонента или обновлении существующего документа.
Пересказать компонент, собранный в Figma, в виде markdown-файла: все слои, все значения, все варианты и поведение при изменении размеров.
Результат не зависит от модели
Скилл рассчитан на разные агенты и разные модели. Один и тот же компонент, разобранный дважды разными исполнителями, должен дать одинаковый файл. Поэтому здесь почти нет места решению на вкус: состав разделов, набор свойств, их порядок и словарь значений заданы жёстко.
Три следствия, из которых всё остальное выводится:
- Ничего не выдумывать. В документ идёт только прочитанное из макета. Нет данных — нет строки. Догадка, даже правдоподобная, — ошибка.
- Ничего не пропускать. Читатель макета не видит: незаписанное значение восполнить неоткуда. Набор свойств у слоя пишется целиком, незаданное помечается «нет».
- Ничего не пересказывать дважды. Значение живёт в одном месте — там, где действует. Сводные списки, подсчёты и инвентари в документ не идут.
Меньше текста — лучше. Каждая строка должна нести значение, которое понадобится при реализации. Прозы в документе ровно столько, сколько нужно, чтобы понять назначение слоя.
Документ готов только тогда, когда проходит scripts/check-card.js. Проверка —
не формальность, а способ получить одинаковый результат у разных исполнителей: она стережёт состав
разделов, порядок свойств, словарь значений и формат шапки.
Документы обновляются, а не переписываются
Компоненты меняются, и документ придётся разбирать заново поверх существующего. При обновлении:
- структура файла остаётся прежней — меняются значения, а не форма;
- прозу, уже написанную и выверенную, не переписывать заново без причины: правится то, что разошлось с макетом;
- «Дата изменения» в шапке обновляется всегда, «Версия» — по журналу изменений макета;
- исчезнувший из макета слой или вариант удаляется из документа, а не остаётся «на всякий случай»;
- находки в
audit.mdпересобираются заново: закрытые дизайнером исчезают сами.
Порядок разбора: снизу вверх
Компоненты разбираются от листьев к корню: сначала те, что не используют внутри себя других компонентов, затем те, что их применяют.
Причина не в удобстве. Отличить умолчание компонента от правки поверх него можно только зная
умолчание. Если документа вложенного компонента ещё нет, переопределения не видны, и в документ
попадает «используется Icon Container» — без того, что иконку подменили, перекрасили
и растянули. А это ровно та часть, которую разработчику придётся воспроизводить руками.
Порядок такой:
- Атомы — компоненты без вложенных инстансов.
- Молекулы — те, что используют атомы.
- Организмы и шаблоны — всё остальное, по нарастанию вложенности.
Как определить, что компонент — лист: в ответе get_metadata у него нет узлов типа instance,
кроме служебных (⚒︎, 🥁).
Если разобрать вложенный компонент прямо сейчас нельзя, документ всё равно пишется, но факт идёт
находкой в audit.md: «переопределения инстанса X не проверены — его документа нет». Молча
писать «используется X» нельзя: это выглядит как полное описание, хотя им не является.
Что читать перед работой
references/figma-conventions.md— словарь макета: префиксы, контейнеры, свойства, словарь состояний, деление на статичные и кликабельные. Без него имена слоёв читаются наугад.references/document-format.md— формат документа: разделы, что в каждом, чего в документе нет вовсе.references/instance-overrides.md— как снять и записать разницу между умолчанием вложенного компонента и его значением в этом месте. Нужен, как только в дереве попался узел-инстанс, то есть почти всегда.- Базу astra-doc:
README.md,meta/how-to-use.md, существующий документ компонента, если он есть. Не создавать дубликат: сверить по имени, алиасам и ссылке источника. ds-docs/foundations/haptic.md— карта виброотклика: словарь триггеров и список откликов. Нужен, как только в мастере попался слой с барабаном в имени.
Заранее сообщённые пользователем дизайн-факты принять и не переспрашивать.
Откуда берутся данные
Источник — Figma MCP. Раскладка читается из свойств узла, имена токенов приходят готовыми. Ничего не выводить из разностей координат, если то же самое можно прочитать напрямую.
Имя токена — из Local Variables, а не из code syntax. MCP отдаёт var(--имя); отбросить
обёртку мало — там, где вместо имени подставлен шаблон (ИмяТокенаЗаднегоФона-hover), настоящую
переменную ищут по значению в выгрузке токенов. Подробности и таблица соответствий —
в references/document-format.md, раздел «Имя токена».
Ссылка на макет одна — в шапке документа. Node-id, ссылки на варианты и на блоки Section не переносятся: они живут до следующей перестройки макета.
Общее знание о дизайн-системе в карточку не переписывается. Оговорки вроде «токены
существуют, вложенные компоненты описаны отдельно» и пересказы правил фундаментов (слой
состояния, сетка, типографика, хаптики) живут здесь, в скиле, и в самих фундаментах — по одному
разу. В карточке остаётся то, что принадлежит этому компоненту, плюс ссылка. Проверка:
абзац, который без правки переносится в другую карточку, — лишний. Подробнее —
в references/document-format.md, раздел «Общее знание не повторяется».
Находки — в ds-internal/audit/, отдельной папкой: один файл audit-<раздел>.md на раздел
Figma. В самом документе находок нет.
Порядок работы
1. Определить границу и состав
fileKey и nodeId из ссылки. Ближайшая содержащая Section — граница семейства.
get_metadata(Section) даёт карту блоков и мастеров.
Читаются три блока: История изменений, Спецификация, ❖ Компонент. Остальные —
Рекомендации, Доступность, Интерактивность, Примеры — пропускаются целиком: их данные
в документ не идут, и их отсутствие находкой не является. Блок Анимация планируется описывать
в будущем, но сейчас тоже не читается.
Определить ядро семейства — компонент, внутрь которого складывают остальные. Обзор состава
пойдёт в его файл; отдельного README не создаётся. Каждый вложенный компонент, у которого есть
свой набор вариантов, получает свой файл.
Классифицировать мастера по figma-conventions.md: ✱ — атом, ⚒︎ — служебный, ❌ —
устаревший, [Имя Container] — слот.
Три вещи, которые пропускаются чаще всего. Проверять их отдельно, до записи документа:
- Скобки в имени слоя снимаются.
[Content Container]в документе — простоContent Containerсо знаком▣. Скобки — разметка канваса, а не часть имени. Swapper UtilityиSwapper— не компоненты, а заглушки пустого слота. Пишется «сюда подставляется другой компонент, по умолчанию пусто», а не «стоитSwapper Utility».- У каждого инстанса проверяются переопределения — растяжение, заданный размер,
прозрачность, подменённый текст, скрытые слои. Закрытый перечень и форма записи —
в
references/document-format.md, раздел «Свойства инстанса». Пустой узел утверждает, что компонент взят как есть; не проверили — так и пишется.
1a. Отсеять устаревшее
Устаревшее опознаётся по трём признакам: префикс ❌ в имени, имя вида «(используйте …)», ось
Version со значением ❌ Deprecated.
Устаревшие мастера в блоке ❖ Компонент — это нормально. Они там лежат специально, чтобы
старые макеты не разъехались. Само их присутствие ничего не нарушает и поводом
остановиться не является.
Нельзя брать устаревшее за основу документа. Ни базовым вариантом, ни источником анатомии, ни источником геометрии, ни источником состава свойств. Разбирается только живой мастер.
Отдельно про блок «Спецификация»: он часто иллюстрирован картинками и примерами, собранными на старых мастерах. Анатомия и раскладка читаются из живого мастера, а не из этих иллюстраций, даже если они выглядят убедительнее.
В документ попадает ровно один абзац в «Структуре»: что устарело, сколько таких мастеров и чем заменено. Свойства, слои и размеры устаревших вариантов не документируются.
Крайние случаи:
- Живого мастера нет, все устарели — документ не создаётся. Это блокер: сказать пользователю
и записать находку в
audit.md. - Устарел весь компонент, замена указана — документ не создаётся, компонент отмечается в документе замены как то, что он собой заменил.
- Устарела часть осей или значений — эти значения в «Свойства» не попадают, но факт устаревания упоминается в «Структуре», а у некорневой карточки — в описании.
1b. Отсеять дизайнерскую разметку
Ось Format — не про интерфейс, а про режим работы в Figma. Значений два, и первое
называется по-разному в разных разделах — встречаются и Layout, и Layer:
Layout(он жеLayer) — мастер показывает всё содержимое страницы. Для режима Design. Высота растёт по содержимому: 375 × NNN.Prototype— мастер показывает содержимое, урезанное по высоте, чтобы влезть в экран. Для режима Prototype. Размер 375 × 812.
Правило:
- ось
Formatв раздел «Свойства» не попадает; - в «Вариантах» подраздела по ней нет;
- анатомия, геометрия и состав свойств читаются с ветки
Layout/Layer— с той, что показывает компонент целиком.
Ветка называется в строке базового варианта «Анатомии», вместе с остальными осями:
«Описан базовый вариант Format = Layout, is Web = False…». Мастер должен адресоваться
однозначно — иначе непонятно, с чего снята анатомия, и сверить её не с чем.
Ветки бывают собраны по-разному, и это надо проверить, а не предположить. Спецификация
описывает Format как разницу высоты, но у Bottom Sheets между ветками расходятся
вложенность и позиционирование: Fix element в Layout лежит внутри листа в потоке,
в Prototype — в корне, absolute, прижатый к низу; шкала z-index внутри листа 4·3·2·1
против 3·2·1; порядок первых двух детей корня обратный; высота листа 262 против 230.
Если ветки расходятся структурно, различие называется абзацем в «Структуре»: описана одна,
и читатель должен знать, чем отличается вторая.
Правило действует только на ось Format. Другие оси, даже названные Prototype
или Animate State, под него не попадают: они документируются как обычные свойства.
2. Прочитать базовый вариант вглубь
get_design_context на базовый мастер каждого документируемого компонента. Это основной источник:
направление, выравнивание, поля, промежутки, размеры, обрезка, а также булевы свойства и слоты
— они приходят как showИмя и swapИмя и разворачиваются обратно в Show Имя
и Swap Имя Container.
Часть свойств MCP не отдаёт. Вывод get_design_context — рендер в React с Tailwind, и всё,
чего Tailwind не выражает, из него пропадает молча: выравнивание рамки, сглаживание углов, рисунок
пунктира, привязки, режим наложения, угол градиента. Полный список и что с ними делать —
в references/document-format.md, раздел «Чего не видно в выводе MCP».
Проверять их наличие надо осознанно: отсутствие такого свойства в выводе не значит, что его нет в макете.
Аннотации читаются обязательно. get_design_context возвращает их атрибутом
data--annotations на том узле, к которому дизайнер их прикрепил. В них лежит то, чего
в свойствах нет: что можно менять, что передаётся снаружи, чем варианты отличаются по замыслу.
Аннотация — слово автора компонента и главнее вывода из свойств. Если она говорит «отступы
можно менять», а по макету стоит конкретное значение, то значение — умолчание,
а не зафиксированное правило. Расхождение аннотации с тем, что видно в свойствах, — находка
MISMATCH в audit.md, а не повод выбрать по своему усмотрению.
Пропустить аннотацию легко: она приходит атрибутом внутри кода, а не отдельным блоком. Искать
по data--annotations в ответе на каждый разобранный мастер.
get_variable_defs на тот же узел — имена токенов. Сверить с foundations/tokens/*.json: имени
нет в выгрузке — это находка, а не повод писать несуществующий токен.
get_variable_defs — словарь, а не разметка. Он возвращает плоский список: какие переменные
вообще встречаются в поддереве, с их значениями. К какому слою и к какому свойству привязана
каждая — он не говорит. Поэтому по нему нельзя утверждать, что вот эта высота привязана вот
к этому токену: имя в списке доказывает только, что переменная где-то здесь используется.
Словарь нужен для другого — проверить, что имена существуют, и увидеть, чего нет в выгрузке.
Порядок источников
Правило одно и применяется к каждому свойству отдельно:
- MCP.
get_design_contextназывает токен прямо на свойстве —w-[var(--space-2xl,32px)]. Назвал — пишем имя токена. - REST. MCP свойство потерял целиком (список потерь — в разделе 2a) — добираем
fetch-details.js. - Физическое значение. Ни один источник токена на этом свойстве не назвал, а значение
есть — пишем значение:
height: 4.
Третий пункт не запасной вариант, а полноценный ответ: число означает «привязки нет», и это такой же факт о компоненте, как имя токена. Догадываться, что за числом «наверное, стоял токен», потому что похожее имя нашлось в словаре, — нельзя.
2a. Дочитать то, чего MCP не отдаёт
FIGMA_TOKEN=… node <skill-dir>/scripts/fetch-details.js <fileKey> <nodeId>[,<nodeId>...]
Узкий запрос к Figma REST: скрипт берёт только те поля, которые теряет рендер в Tailwind, — выравнивание и рисунок рамки, толщину по сторонам, сглаживание углов, привязки, режим наложения, прозрачность заливки, тип градиента, обрезку текста, вписывание картинки.
Печатает только заданные значения: слои, где всё по умолчанию, в вывод не попадают. Пустой ответ — это ответ: значит, ничего из списка потерь в компоненте не задано.
Токен берётся из FIGMA_TOKEN либо из файла по пути в FIGMA_TOKEN_FILE. В репозитории токен
не хранится и в документ не попадает.
Без токена шаг пропускается, а перечисленные свойства остаются неизвестными — это находка
в audit.md, одна на компонент.
3. Остальные варианты — диффом
Не читать каждый вариант целиком. Для дельты хватает:
get_variable_defsна вариант — покажет смену цветов, теней, скелетон-токенов;get_metadataна вариант — покажет смену раскладки: координаты и размеры детей отвечают на вопросы вроде «куда уехала иконка» точнее, чем чтение всего поддерева.
Так 40 вариантов закрываются пятью-шестью вызовами вместо сорока.
4. Разложить отступы по владельцам
Пройти по дереву и для каждого видимого зазора записать слой-владелец. Это самая частая ошибка разбора: два соседних промежутка бывают одинаковыми по значению и разными по происхождению. В документ идёт единая таблица раскладки по слоям, а не картинка с числами.
Отдельно отметить заданные, но не проявляющиеся отступы — промежуток в контейнере с одним элементом.
4a. Собрать виброотклик
Слой с барабаном в имени — 🥁 Виброотклик / Обязательный или 🥁 Виброотклик / Опциональный —
в дерево слоёв не переносится. Вместо него собираются данные для раздела «Интерактивность»:
- Имя слоя даёт обязательность:
ОбязательныйилиОпциональный. - Свойство
Haptic IDу этого слоя даёт идентификатор отклика. Скрытый или пустой — так и писать: не задан. - Блок «Интерактивность» в Section даёт действие и триггер. Читается — в отличие от «Рекомендаций» и «Доступности».
- Триггер сверяется со словарём в
ds-docs/foundations/haptic.md. Своих имён не выдумывать.
Расхождение между свойством слоя и блоком «Интерактивность» — находка класса MISMATCH,
а в таблицу идёт то, что написано в блоке.
5. Написать документ
По references/document-format.md. По-русски, имена слоёв и свойств — дословно из макета. Внутрь
готовых компонентов не спускаться: перечислить ролью в «Компоненты по умолчанию».
6. Вынести находки
Файл ds-internal/audit/audit-<раздел>.md — один на раздел Figma, не на карточку. Если раздел
дал несколько карточек, находки по ним лежат вместе, а карточки перечислены в шапке файла.
Строка находки: класс (GAP / MISMATCH / SUSPECT), находка, что предлагается. Кликабельный
компонент без состояний из обязательного набора — GAP. Расхождение спецификации и мастеров —
MISMATCH. Похожее на случайность — SUSPECT.
После записи файла добавить строку в ds-internal/audit/README.md: раздел, файл, число находок,
карточки.
7. Проверить
node scripts/check-card.js <папка-с-документами>
Она стережёт всё, что задано списками: состав и порядок разделов, состав и порядок строк в узле, словарь значений, вердикты в отличиях, формат шапки и даты, отсутствие node-id, жаргона и находок в документе, существование всех упомянутых токенов.
Отдельно — целость разметки: обрубки таблиц и обрывки списков, которые остаются, когда раздел или пункт удалили не полностью.
Документ не готов, пока проверка не проходит. Ошибки печатаются с именем слоя или номером строки — править по ним.
Оценка — часть разбора, а не отдельный проход
Сразу после проверки формата:
node scripts/score.mjs --card <имя> --audit ../ds-internal/audit
Скрипт печатает список критериев с состоянием: закрыт · не закрыт · неприменим.
Полнота — это закрытые из применимых, а не баллы: знаменатель виден, и критерий,
к компоненту не относящийся, из него выброшен.
Правило готовности. Разбор не закончен, пока не выполнено оба:
- все обязательные критерии закрыты — шапка, разделы, дерево слоёв, названный мастер. Провален хоть один — карточка не сдаётся, а дорабатывается;
- важные критерии либо закрыты, либо объяснены. «Не закрыт» без объяснения означает, что разбор недоделан. Если критерий не закрыть нельзя — например, блоков спецификации в разделе Figma нет вовсе, — это пишется прямо в карточке, а не оставляется молчанием.
Желательные критерии не блокируют.
Оценка проставляется в саму карточку, а не только печатается:
node scripts/score.mjs --card <имя> --audit ../ds-internal/audit --write
В шапку идут две строки — полнота и решённость, — а в конец карточки раздел
## Что не решено, собранный из находок аудита. Обе части генерируются: править их руками
бессмысленно, следующий прогон затрёт.
Решённость считается по аудиту, а не по карточке. Поэтому порядок такой: сначала находки
разбора уходят в ds-internal/audit/audit-<компонент>.md, потом --write. Если сделать
наоборот, карточка объявит компонент решённым, хотя разбор только что нашёл в нём дыры.
Падение решённости после переразбора — нормальный исход. Он означает, что мы стали больше знать о компоненте, а не что компонент испортился.
Бюджет чтения MCP
На компонент — четыре-шесть вызовов:
get_metadata(Section) | Карта семейства и состав мастеров | 1 на семейство |
get_design_context(базовый мастер) | Раскладка, слоты, булевы свойства | 1 на компонент |
get_variable_defs(базовый мастер) | Имена токенов | 1 на компонент |
get_variable_defs(вариант) | Дельта по цветам и эффектам | по одному на непохожий вариант |
get_metadata(вариант) | Дельта по раскладке | только при смене раскладки |
get_screenshot(мастер) | Свериться глазами: порядок слоёв, что с чем выровнено | 1 на компонент, в файл не попадает |
Тексты тянуть точечно. get_design_context на блок Спецификация целиком возвращает больше
ста тысяч символов и не влезает в ответ. Читать конкретные ds-paragraph и ds-log, а не фрейм
целиком. Если ответ всё же ушёл в файл — извлекать тексты поиском по содержимому,
а не читать дамп подряд.
Не делать: get_design_context по каждому варианту; get_metadata всего файла;
повторные скриншоты вариантов.
Что спрашивать у пользователя
Только дизайн-факты, которых нет в макете: отсутствующий токен, неоднозначная геометрия, противоречие вариантов. Не больше пяти за подход, в разговоре, а не в документе. Вопросы про props, события и API не задавать: документ описывает макет, а не реализацию.
Спросить обязательно, если у набора есть ось Format со значениями Layout и Prototype
и ветки расходятся структурно: какую из них описывать. Анатомия и геометрия по умолчанию
читаются с ветки Layout / Layer — с той, что показывает компонент целиком (см. 1b);
подтвердить до разбора, а не после.
Формат завершения
Путь документов, тип каждого компонента (статичный или кликабельный), число вариантов, число
находок в audit.md. Отдельно — разделы, которые не написаны из-за отсутствия данных в макете.