По душе · Android × Figma · 11.09.2026 · свайпы, уведомления, избранные

Четвёртый десяток собран: три страницы макета закрыты целиком

Тридцать два кадра трёх страниц — «Свайпы событий», «Уведомления» и «Избранные». Карточка свайпа в обоих вариантах набора, фильтрация поверх свайпов, брошенная карточка под углом, гайд-тур первого входа, список уведомлений с двумя исходами заявки, избранные события и люди, и шесть кадров, где готовая «Страница События» и «Страница Карта» стоят инстансами на чужих страницах. Каждый кадр собран из данных ноды и сведён с рендером Figma в масштабе ×3. Попутно доказаны три вещи про стекло Figma, которых в методе не было, и найдены две ошибки в самих измерителях — из-за них числа прошлых десятков были занижены не в ту сторону.

29 / 32кадров с зелёной геометрией при пороге 0,3 %
0,015 %лучшая геометрия
0,915 %худшая — преломление стекла снекбара
16расхождений найдено, 14 закрыто
4дефекта макета — дизайнеру

Смотровая

Кадр рядом с рендером

Тяните шторку, чтобы совместить макет и приложение. «Карта» показывает, где остаётся расхождение: синим закрыт системный статус-бар — его рисует система, в сравнении он не участвует (спека 6.4). Кадры этого десятка все ростом в экран: 390×844.

Рендер кадра из Figma Снимок экрана приложения

Числа

Четыре измерения на кадр

Полное — доля пикселей, отличающихся сильнее ΔE 6 вне масок. Без текста — то же с исключёнными текстовыми блоками. ±1 px — пиксель считается расхождением, только если не совпал ни с одним пикселем рендера в окне ±1: сдвиг растра на долю пикселя не есть ошибка вёрстки. Геометрия — два последних вместе, то есть чистая форма, положение и материал; по ней и выносится вердикт. Подсвечены строки выше порога — у каждой измеренная причина в разделе «Границы».

ЭкранКадрСостояние Полное %Без текста % ±1 px %Геометрия % Шкала до порога 0,3 %

Разбор

Что оказалось не так

Каждая строка — расхождение из реестра docs/figma/fig/ledger.md: что показала нода, что делало приложение и сколько это стоило в числах.

Размытие под полосой страниц видно только под самими полосами

У полосы страниц карточки свайпа объявлен BACKGROUND BLUR 60 при высоте узла 6 dp. Проверка по строке y = 147: в зазоре между полосами (x = 140) рендер и снимок сходятся до уровня, а под полосой (x = 144) расходятся на 41. То есть размытие проявляется только там, где поверх него лежит полупрозрачная заливка ребёнка, а пустое место внутри узла остаётся резким. Модель «размытая подложка + белый 40 %» даёт |Δ| 2,5 против 25,9 у резкой фотографии.

0,447 → 0,120 %узел 617:81587
подложка испечена по окну узла

Прогрессивное размытие доходит до радиуса на endOffset и дальше не растёт

Градиентная панель карточки «первого варианта» несёт blurType: PROGRESSIVE с endOffset.y 0,3239. Подгонка по свободным от текста полосам показала: бокс ядра растёт с 6 px у верхнего края панели до 18 px к 94 dp — это и есть объявленные 32,39 % высоты, — и дальше вниз не меняется. На чистых полосах |Δ| падает с 5,0…5,7 до 1,2…1,7. В figbackblur.py появился ключ --pend.

4,329 → 0,463 %узел 233:30019
радиус 0 → 8 dp к 101 dp

Ядро размытия нормируется и у края самого узла

Самая дорогая находка десятка. У снекбара есть соседний кадр, где снекбара нет, — то есть видно саму подложку. Я взял её, размыл и попытался объяснить рендер: чтобы клампованное размытие (добивка краевым пикселем) сошлось, подложку пришлось бы сдвигать вниз на 11 dp у самой границы, 6 dp на глубине 9 и 3 dp на 21. Это ровно профиль сдвига центра масс обрезанного ядра — значит Figma делит на попавшую внутрь часть, а не добивает край. Modifier.blur так не умеет, но Unbounded даёт премультиплированный слой, и повтор такого слоя поверх клампованного сходится к нормировке.

23 → 5 уровнейузел 231:21434
на верхней кромке снекбара

Та же правка вытащила четыре кадра прошлого десятка

Нормировка — общее правило материала, поэтому её стоило проверить на всём, что уже закрыто. Снекбары «Афиши» пошли 0,393 → 0,280 и 0,362 → 0,250, стеклянные кнопки нижней панели — 0,313…0,387 → 0,254…0,283, прокрученная страница события — 0,442 → 0,360. Красных кадров в третьем десятке осталось три вместо шести.

6 → 3 красныхтретий десяток
кадры пересняты и сверены заново

Маска текста в измерителе бралась не из того источника

Числа «без текста» и «геометрия» считаются с исключёнными прямоугольниками текстовых нод. Прямоугольники брались из дампа .fig, а там у инстанса лежит вариант мастера по умолчанию: у карточки «первого варианта» тексты записаны на y = 568/604/630, тогда как в кадре они на 498/534/564. Маска ложилась на фотографию, а сам текст оставался в метрике — и «геометрия» показывала расхождение там, где ошибки вёрстки нет. Дерево кадра теперь берётся из ответа API. Числа ранее закрытых кадров при этом не изменились.

0,463 → 0,195 %кадр 617:88179
измеритель, не вёрстка

Второй измеритель молча выбрасывал все тексты кадра

Замер текста берёт список системных узлов у пакетного сравнения, но без его исключения для затемнения Context Menu - Dimming. На любом кадре с затемнением (а это весь гайд-тур и вся фильтрация) затемнение 390×844 считалось системным элементом и накрывало собой всё: замер честно печатал «текстов 0» и шёл дальше. Теперь у кадров гайд-тура меряются все тринадцать строк.

0 → 13 строккадр 703:94289
плотность чернил −1,24 %

Строка карточки уведомления набрана Semibold, а не Medium

Вес взят из блока style ответа API: body-medium/semibold при textAutoResize: TRUNCATE в две строки. С Medium экран выглядел «почти так же», но плотность чернил кадра шла −9,5 %: ровно тот случай, ради которого замер текста и сделан. С правильным весом — −2,1 %.

4,15 → 2,27 %узел 288:29958
полное расхождение кадра

Обводка «наружу» — это фигура позади заливки, а не border

У точки непрочитанного 12×12 и у значка исхода 20×20 обводка белым 2 dp стоит OUTSIDE. Modifier.border в Compose рисует внутрь и съедал заливку: красный кружок выходил на 4 dp у́же. Кольцо рисуется отдельной фигурой на 4 dp крупнее позади заливки.

12 → 16 dpузлы 288:29960 и 390:48640
кольцо позади, а не поверх

У карточки города в фильтрации не было обводки

Карточка с мини-картой несёт обводку белым 60 % шириной 1 INSIDE — на глаз её почти нет, а в числах это самый крупный прямоугольник расхождения: по столбцу x = 100 нижняя строка карточки в рендере (218, 237, 247), а в снимке (167, 214, 239). Правка общая с прошлым десятком: все двенадцать кадров фильтрации «Афиши» стали лучше.

0,301 → 0,168 %узел 599:61335
и −0,05…−0,13 п. п. у S14

Свойство компонента может врать, а текстовый узел — нет

У карточки «Новое событие» в componentProperties инстанса стоит заголовок «Прогулка с собаками», а текстовый узел и рендер показывают «Пикник с собаками». Значение свойства осталось от прошлой правки: верен узел (К-1). Если бы фикстура собиралась по свойствам, кадр разошёлся бы по всей строке заголовка.

узел, не свойствокадр 233:32184
проверено рендером

Четыре дефекта макета — дизайнеру

«воскресение» вместо «воскресенья» и «Организатор отклонилв ваше участие» в карточках уведомлений; у подсвеченной копии одной и той же кнопки в гайд-туре радиус 32 на первой подсказке и 40 на второй; на одном кадре избранного сердце в шапке заполненное, а на соседнем — контурное, хотя событие то же и снекбар говорит «Вы убрали событие из избранных». Все кадры воспроизведены как есть (К-14), расхождения записаны в раздел 4 спеки.

4 парыР-9
каждый кадр как он есть

Границы

Что осталось выше порога и почему

Три кадра держат число выше 0,3 % по «геометрии». В каждом карта плохих точек лежит внутри растровых или стеклянных областей: расхождений вёрстки в них не осталось.

КадрыГеометрия %Класс остатка
293:282430,918преломление стекла снекбара над неоднородной подложкой: рендер по строке y = 712 даёт 92 уровня слева и 121 справа при подложке, ровной в пределах 10 уровней, а нормированное размытие даёт 110 всюду
288:29990, 293:259620,530точные копии мастера карты 180:8884 — тот же остаток растра карты, что и у самого мастера (0,530)