astra-contract-to-figma — Контракт → Figma → сравнение (round-trip)
Источник:
ds-docs/component-contracts/skills/astra-contract-to-figma/SKILL.mdСправочник скилла — вложенная страница. В вики не выложены, лежат в папке скилла:scripts/render.js,scripts/compare.js,references/navigation-bar-pilot.yaml,references/proven.json.
Шапка скилла:
name: astra-contract-to-figma
description: Обратный ход round-trip. Берёт контракт компонента v2 (YAML из astra-component-contract) и собирает по нему набор компонентов в Figma на тестовой странице того же файла, затем сравнивает с оригиналом узел за узлом и раскладывает расхождения по трём классам. Использовать, когда просят «проверь контракт круговым прогоном», «нарисуй компонент по контракту», «round-trip», «собери из YAML в Figma». Только для проверки формата — не для авторинга компонентов.
Контракт полон, если по нему можно собрать компонент заново и он совпадёт с оригиналом — свойствами, слоями, привязками токенов, инстансами и их пробросом наружу. Этот скилл делает обратный ход и измеряет расхождение.
Строим в том же файле, на отдельной странице. Только в нём есть те же локальные переменные,
текстовые стили и дочерние компоненты. Страница называется zz · <Компонент> round-trip (test);
удаляется по отдельной просьбе. Оригинал не трогаем никогда.
Три класса расхождений
Каждое расхождение обязано попасть в один из трёх классов — иначе прогон не закончен.
| контракт не хранит | поле есть в оригинале, в контракте нет места под него | расширить формат либо записать в gaps как сознательную потерю |
| рендер не умеет | контракт знает, Plugin API так не выставил | чинить render.js |
| оригинал непоследователен | контракт нормализует то, что в макете сделано по-разному | либо выразить узким правилом when, либо записать в gaps |
Ноль расхождений достижим только если третий класс тоже выражен правилами. Так был сделан
Tag в августовской редакции контракта; у Button часть оставлена в gaps, и он остановился
на 193. Ноль — свойство версии контракта, а не компонента: после перестройки контракта Tag
по оригиналу прогон 23.09.2026 начался с 467.
Порядок
- Загрузить скилл
figma-use. - Контракт → JSON:
contract.mjs <карточка|yaml> --out <папка>. Разделgapsрендеру не нужен — убрать и минифицировать, чтобы уложиться в лимит кода. У семейства сformsта же команда кладёт рядом по срезу на форму (<slug>-<форма>.contract.json). Рендер работает со срезом, не с семейством целиком: форма — это отдельное базовое дерево, и собирается она отдельным прогоном. - Разведка окружения файла — см. чек-лист,
раздел 6. Результат кладётся в
ENVрендера: id дочерних наборов, умолчания свойств подмены, точные id переменных-дублей, начертания шрифта, текстовые стили, auto-layout и ширина набора. - Рендер —
scripts/render.js, батчами по 30–60 мастеров:- первый батч:
SET_ID = null,CONTRACT_JSON = <строка>— создаёт страницу, кладёт контракт текстовым слоемcontract.json, собирает мастера, объединяет в набор, заводит свойства; - остальные:
PAGE_ID,SET_ID,KEYSиз первого,CONTRACT_JSON = null. - у семейства мастера группируются по имени набора: один контракт даёт несколько наборов,
свойства фильтруются по
whenкаждого набора. Пустойproblemsозначает, что все привязки нашлись.
- первый батч:
- После сборки набора: перенести на него auto-layout и ширину оригинала, затем выставить
мастерам
FILL, если контракт этого просит. До объединения в наборFILLне принимается. - Сравнение —
scripts/compare.js, read-only. Возвращает пропавшие и лишние мастера, расхождения определений свойств, счётчик по полям и шаблоны «поле: оригинал → копия» со счётчиком и примером. - Разобрать шаблоны по классам, починить первые два, перезапустить. Третий — сверить с
gaps: чего там нет, дописать. - Показать сводку и остановиться.
Результаты
references/round-trip.md — протокол по трём компонентам.
Замеры на 23.09.2026:
| Button | 1 | 273 | 3 | 193, все «оригинал непоследователен» |
| Tag, август, прежний контракт | 1 | 54 | 3 | 0 |
| Tag, сентябрь, контракт перестроен по оригиналу | 1 | 54 | 1 | 467, разбор в round-trip.md |
| Navigation Bar (пилот) | 5 из 19 | 20 | 3 | 32, две причины |
Там же: что вскрылось в оригиналах, какие дефекты формата и рендера нашлись, почему схлопывание семейства в один контракт имеет предел, и что дал разбор проброшенных инстансов.
Порядок применения свойств в рендере
Порядок неочевиден и стоил двух прогонов:
- создать узел, назвать, положить к родителю;
- раскладка, обрезка, заливка, скругление;
- текст: стиль файла → выравнивание → цвет → привязки переменных;
- инстанс: свойства → проброс → переопределения;
- размеры —
HUGиFILLтребуют, чтобы узел уже лежал в auto-layout; - после размеров: обрезка строк и
maxLines(их сбрасываетresize), затем скрытие узлов (скрытый узел не пересчитываетHUG).
Что рендер не переносит намеренно
- позиции мастеров на холсте:
defaultVariantберётся из положения, контракт этого не описывает, поэтому мастер по умолчанию просто ставится в верхний левый угол; overridesинстансов сложнее заливки, размера и текстового стиля;- слой виброотклика ставится по
interaction.when, координата — центр верхней кромки.