По любви · Android × Figma · 12.09.2026
Два последних раздела приложения, у которых есть макет: экран сообщества с логотипом и пилюлей видимости значка, список доступных сообществ с поиском, пустые состояния, приглашения поверх ленты — и реферальная программа: шкала приглашённых, история, подарочная подписка, снеки и карточка «Премиум в подарок». Плюс последний кадр шестёрки «Обновление и техработы» — «Технические работы» на табе профиля, который ждал собранного таба. Каждый кадр снят на устройстве в честном масштабе ×3 (1170×2532) и сведён с рендером Figma; кадры выше экрана — по частям с прокруткой. Это продолжение артефактов по кадрам S01–S10, S11–S20, S21–S30, S31–S40, S41–S50 и S51–S60.
Главная находка партии — про свечение: круг под размытием в ответе API отдаётся габаритом повёрнутой рамки, а не самой фигуры, и по нему свечение выходит втрое ярче — кадр давал 23,8 % расхождения на верной в остальном вёрстке. Вторая — про раскладку инстанса: у ячейки списка с однострочным именем дамп хранит числа двухстрочного мастера, и рендер считает по содержимому, а не по дампу. Третья — про меру: слишком длинный контур из макета не влезает в предел строки aapt, ресурс собирается обрезанным, и приложение падает — снимок при этом выходит «просто не тем».
Смотровая
Тяните шторку, чтобы совместить макет и приложение. «Карта» показывает, где остаётся расхождение по геометрии: синим закрыты системный статус-бар, полоска home, клавиатура и диалоги разрешений iOS — их рисует Android, они в сравнении не участвуют (спека 6.4).
Числа
Полное — доля пикселей, отличающихся сильнее ΔE 6 вне масок. Без текста — то же с исключёнными текстовыми блоками. ±1 px — пиксель считается расхождением, только если не совпал ни с одним пикселем рендера в окне ±1: сдвиг растра на долю пикселя не есть ошибка вёрстки. Геометрия — два последних вместе, то есть чистая форма, положение и материал; по ней и выносится вердикт. Шкала показывает геометрию относительно порога 0,3 %.
| Экран | Кадр | Состояние | Полное % | Без текста % | ±1 px % | Геометрия % | Шкала до порога 0,3 % |
|---|
Разбор
Каждая строка — расхождение из реестра ловушек спеки: что показала нода, что делало приложение и сколько это стоило в числах.
На чёрном экране сообщества три круга Brand/Terracotta размыты на 120 и 226 dp.
В ответе API у повёрнутого круга absoluteBoundingBox — габарит
повёрнутого прямоугольника рамки: 147,67 при круге 114. Размытие, посчитанное по
рамке, светит втрое сильнее и накрывает пол-экрана.
Настоящие полуоси и угол лежат в дампе .fig (size и
matrix), середину даёт сам бокс — поворот её не меняет. После правки кадр
13738:50794 ушёл с 23,8 % на 0,8 %, а подгонка σ по рендеру
(tools/glow_fit.py) дала лучший множитель 0,42 при постоянной проекта 0,410
— разница в остатке 1,20 против 1,29 единицы канала.
.figPIL размывает картинку покомпонентно, и цвет тянется к чёрному фону прозрачных пикселей: в центре свечения выходило (64, 36, 27) вместо (198, 111, 83) — на снимке оно было впятеро бледнее рендера при верной геометрии. Слой с одной краской размывается по альфе, цвет остаётся постоянным.
В ячейке списка сообществ имя «Храм Христа Спасителя» занимает одну строку — и её высота в дампе верна (20). А счётчик участников под ней стоит на 640 — от двухстрочного мастера (596 + 44), и разделитель ячейки — на 674 вместо 654. Рендер считает по содержимому: счётчик на 620, разделитель на 654.
Пересчёт вертикальной стопки включается, только если сумма высот детей не сходится с высотой контейнера, и только у контейнера «по содержимому»; дети с абсолютным позиционированием (свечения и ручка шторки) в стопку не входят, ряд с переносом не считается вовсе, а высота ряда пересчитывается лишь тогда, когда внутри уже что-то поехало. Без этих четырёх ограничений пересчёт уводил содержимое на сотни dp.
Ладошка иллюстрации приглашения разбирается из .fig в 7 172 точки —
47 340 знаков pathData при пределе строки aapt 32 767. Ресурс
собрался обрезанным, и Compose упал с Unknown command for: R: снимок вышел
домашним экраном Android — «просто не тем кадром». Контур прорежен до 378 точек
(5 072 знака), картинки до и после совпадают.
У иллюстрации «две мордочки» рамка shape-brand равна габариту тела, и
обрезка свечения по ней оставляла в углах светлый прямоугольник, которого в рендере нет.
Маской служит альфа того же контура, нарисованного со своим поворотом.
Тело мордочки нарисовано краской #E7C9B2 при opacity 0,9 —
и ассет из .fig уже несёт её в альфе заливки. Приложение умножало на ту же
прозрачность второй раз, и тело выходило на 26 единиц темнее рендера.
Разделитель ячейки стоит на y = 244 с обводкой 1 dp «по центру», а
рендер закрашивает 243…244 — проверено на шести разделителях списка и трёх строках
истории приглашений. Полоса рисуется как (y − толщина, толщина).
У пилюли «Значок видно всем» обводка 3 dp стоит снаружи: в рендере она начинается на 82 dp при узле на 85. Нарисованная внутрь, она давала тридцать тысяч расходящихся пикселей на каждом кадре экрана сообщества.
Подпись карточки набрана «дней подписки⏎получено» собственным переводом строки Figma (U+2028) при ширине «по содержимому». Запрет переноса по ширине в Compose обрезал текст до одной строки, и блок уезжал на 10 dp.
У панели кадров реферальной программы заливка переопределена на Brand/Pale Beige, а рендер рисует там чёрный фон кадра. Контейнер панели (мастер 375 в кадре 390) рендер растягивает на всю ширину, и его чёрная заливка закрывает бежевую. У списка сообществ заливки у контейнера нет — и видна белая панель.
Иллюстрация пустого состояния на страницах V4 и V5 называется одинаково, но лица разные: на V4 грустное (бровь домиком и дуга рта вниз), на V5 — довольное. Один ассет на оба давал ровную геометрию и неверную картинку — поймала сплошная сверка кадра рядом с рендером.
У ответа анкеты стрелка «→» набрана серым, а сам ответ — чёрным: в одной ноде два
стиля через characterStyleOverrides. Правка нашлась на уже закрытых кадрах
редактирования анкеты, когда двигатель научился собирать такие куски.
В ячейке «Surf» списка сообществ логотип — росчерк, а в макете его нода называется «Union» — ровно как одиннадцать нод креста другого сообщества. Карта по имени рисовала в этой ячейке крест: кадр целиком оставался зелёным, а часть с прокруткой держала 0,340 % — два пятна на тысячу с лишним пикселей каждое. Логотип теперь берётся по адресу ноды, а не по её имени.
У кружка значка сообщества обводка 1,5 внутрь, а в файле лежит кольцо двойной толщины по центру: так Figma хранит внутреннюю обводку и обрезает её самой фигурой при отрисовке. Резчик ассетов заливал кольцо целиком — значок выходил и крупнее, и вдвое толще. Наружная половина теперь отрезается контуром узла.
Бровь мордочки нарисована в макете полупрозрачной, и резчик ассетов положил эту прозрачность внутрь картинки. На экране узел просит ту же половину ещё раз — бровь выходила вчетверо бледнее. Такие картинки — трафареты: контур кладётся плотным, а краску и прозрачность даёт узел.
У ячейки списка сообществ имя занимает одну строку, а файл макета хранит раскладку двухстрочного мастера. Пересчёт стопки чинил имя и счётчик, но значок «вступить» оставался центрированным по старой высоте ряда — на 10 dp ниже, чем в рендере. Кадру это стоит 0,04 %, и метрика молчала: нашла сплошная сверка ассетов.
Экраны
Экран сообщества и реферальная программа собраны тем же способом, что редактирование анкеты: кадр — список примитивов в порядке обхода ноды. Слой примитивов переехал из экрана профиля в кит и стал общим.
Экран сообщества (значок виден и скрыт, с соседями и без, приватное и открытое,
со снеком и с системным диалогом выхода), список доступных сообществ (пустой поиск,
ввод, «ничего не найдено», вступление) и пустые состояния. Логотипы сообществ — векторы
из .fig: знак без круга, потому что круг рисует сама нода своей краской.
Четыре состояния счётчика, шкала 0…20, история приглашений, две иллюстрации (коробка с карточками «+5» и две мордочки с ладошкой), загрузка и ошибка, подарочная подписка тремя текстами и снеки «ссылка уже использована», «ты уже участвуешь», «нельзя пригласить себя».
Разбор кадра в примитивы (прямоугольник, значок, растр, текст) вынесен в
ui/kit/NodeCanvas.kt и обслуживает три экрана и две шторки поверх ленты.
В двигатель фикстур добавились повороты и отражения из матриц .fig,
посимвольные краски, пересчёт устаревшей раскладки и крики о незнакомых значках,
стилях и контурах — генератор больше не молчит.
Вопросы
Здесь не ошибки вёрстки, а места, где макет спорит сам с собой или с собственным рендером. Мы делаем как в рендере и передаём пару дизайнеру.
| Что | Где | Как сейчас |
|---|---|---|
| Заливка панели | 13026:8410 и соседние |
переопределена на Brand/Pale Beige, а рендер рисует чёрный фон кадра: 15 dp справа от контейнера 375 |
| Ячейка списка с коротким именем | 17060:59606 |
счётчик и разделитель стоят по числам двухстрочного мастера, рендер считает по содержимому — на 20 dp выше |
| Сердечки иллюстрации | 13180:42135 · 13180:42142 |
прозрачность задана дважды — заливкой (0,5) и узлом (0,6 и 0,85), у соседних сердечек её нет вовсе |
| Подпись шкалы | 13390:2948 |
«Пригласиеще 4 друга» — пропущен пробел |
| Текст шторки приглашения | 13738:51268 против 13738:50794 |
«Все сообщества приватны…» и «Сообщество приватно…» — два текста одного состояния на соседних кадрах |
| Два логотипа под одним именем | 14314:6634 против 17060:85295 |
росчерк «Surf» и крест «Храма» названы одинаково — «Union»: по имени их не различить, и картинку приходится брать по адресу узла |