По душе · Android × Figma · 10.09.2026, второй проход

Первый десяток закрыт целиком, начат второй

Десять экранов раздела «Авторизация и регистрация» — от экрана входа до поп-апа «Профиль подтвержден» — собраны не по картинке, а по данным нод: переменным, стилям текста, вариантам компонентов, правилам авто-лейаута, матрицам обрезки растров и режимам наложения. Каждый кадр снят на устройстве в честном масштабе ×3 (1170×2532) и сведён с рендером Figma. Во втором проходе закрыты все пять кадров, что оставались выше порога, и снят кадр, который не сверялся вовсе: теперь все 59 кадров первого десятка зелёные по геометрии. Плюс собран первый экран следующего десятка — страница карты. Ниже — кадр рядом с рендером, четыре числа на кадр и разбор того, что оказалось не так.

58 / 58кадров с зелёной геометрией при пороге 0,3 %
0,000 %лучшая геометрия
0,269 %худшая геометрия — растр карты на новом экране
27расхождений найдено и закрыто
8вопросов к самому макету — дизайнеру

Смотровая

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

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

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

Числа

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

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

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

Разбор

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

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

API говорит «обычное наложение», рендер прожигает

У серого текста полей ввода заливка помечена blendMode: NORMAL, и по этой подсказке цвет над #F5F5F5 должен выйти (163, 164, 167). В рендере он (160,9, 161,8, 164,8) — ровно как при LINEAR_BURN. Прибор — сами чернила плейсхолдера: пять кадров подряд дали одно и то же. Считаем прожигом, как на экране входа.

163 → 160,919 кадров S05
рендер — последнее слово (К-16)

Окно растра вырезано дважды

У аватара заливка IMAGE со scaleMode=STRETCH и матрицей imageTransform. Выгрузка уже применяет это окно, а код вырезал его второй раз — человек в круге оказался крупнее и выше. Проверено средним модулем разницы по кругу: целый растр даёт 0,58 единицы, повторное окно — 25,8.

|Δ| 25,8 → 0,58кадр 292:25561
геометрия 1,161 % → 0,051 %

Переносимый текст встаёт от верха блока, а не вокруг него

Блок описания в ноде 20 dp, а строк в нём три: текст переносится по ширине поля. Поправка «поднять на половину разницы» уводила абзац на строку вверх — она должна уходить в минус, когда строк больше, чем в блоке. Ошибка видна только на длинном тексте.

−20 dpкадр 292:25695
0,489 % → 0,041 %

Рамка вектора и нарисованная часть — разные вещи

Белая точка внутри булавки на карте: рамка 27,01×41,55, а absoluteRenderBounds — 27,01×28. Овал по рамке давал вытянутое пятно, торчащее из булавки. Берётся контур вектора, а не его рамка; та же поправка у маленькой булавки в карточке города.

41,55 → 28кадры 730:75625, 597:55329
рисуем контур, не рамку

Обводка «внутрь» у эллипса — это полоса, а не штрих по центру

Кольца свечения на поп-апе успеха заданы обводкой 24 INSIDE. Штрих шириной 24 по центру ужатого эллипса выглядит похоже, но у эллипса смещённый контур — не эллипс: по горизонтали оставался просвет там, где в рендере сплошная заливка. Рисуется полоса между эллипсом и ужатым на 24 эллипсом (чётно-нечётный контур).

8,14 → 1,98 %кадр 287:27892
по области листа

Compose молча зажимает высоту родителем — дважды за одну сессию

Растр карты 693 dp в рамке 687 сжимался на 0,87 % и к низу уезжал на 7 px; кольца свечения 161 dp в рамке иконки 120 обрезались снизу. Обычная height ограничена родителем — нужна «требуемая» высота. Ловушка та же, что зажимала текст политики на S03.

2 места731:75846 и 287:29258
requiredHeight

Кнопка на фото — стекло Clear, а не Regular

На экране селфи «назад», вспышка и переключение камеры выглядели белыми кружками: код рисовал материал Regular. В ноде у них мастер 177:5375 с материалом Clear — белый 7 % поверх фотографии и светлая кромка. Заодно овал рамки оказался пунктирным: strokeDashes [16, 16].

7,35 → 1,26 %кадр 287:26990
стекло, пунктир, фон

Пустой результат стоит под шапкой, а не в списке

Блок «Ничего не найдено» лежит на y=184 — сразу за шапкой, а не внутри контейнера списка с его отступом 12. Из-за отступа 3D-иконка уезжала ровно на 12 dp вниз. Разница видна только замером габарита чернил, глазами — нет.

−12 dpкадр 597:56371
1,729 % → 0,004 %

Три города — три карты

Мини-карта в карточке города — растр из ноды, и у Москвы, Санкт-Петербурга и Перми это разные картинки с разными окнами. Один растр на все кадры давал 9…17 % расхождения. Отдельно нашлось, что у листа выбора места в двух кадрах тоже разные окна одной картинки.

17,3 → 0,155 %кадр 609:75160
окна из imageTransform

Активному чипу не хватало тени стекла

У выбранного чипа района поверх тёмной заливки лежит материал Clear со своей тенью (0,8) r40 20 %. Без неё кромка казалась той же, а число держалось вдвое выше порога. Тень взята из ноды, а не подобрана.

0,695 → 0,155 %кадр 609:75160
тень из материала

Скрипт выгрузки строк заменил пробелы на разделитель строк

В наборе строк S07 и S10 обычный пробел превратился в U+2028: подпись «Разрешите доступ к камере » переносилась по каждому слову и вставала в четыре строки. Семь строк переписаны из characters нод — и это тот случай, когда ошибка не в вёрстке, а в инструменте.

0,448 → 0,073 %кадр 287:26637
7 строк переписано

Растр листа стоит ниже, чем считает нода

Карта на листе выбора места по матрице должна начинаться на 151 dp. В рендере её содержимое стоит на 8 px (2,67 dp) ниже — замер по четырём полосам карты, сдвиг постоянный по всей высоте. Сделано как в рендере, пара «нода → рендер» уходит дизайнеру.

6,57 → 0,221 %кадр 730:75625
сдвиг по замеру

Вопросы

Что стоит посмотреть в макете

Здесь не ошибки вёрстки, а места, где макет спорит сам с собой или с собственным рендером. Мы делаем как в рендере и передаём пару дизайнеру.

ЧтоГдеКак сейчас
Города в списке районов609:74123, 609:74208 последние пять строк списка районов Санкт-Петербурга — «Краснодар», «Воронеж», «Пермь», «Волгоград», «Омск»
Подпись поля пола582:53008, 592:4865 на кадрах системных диалогов вместо «Пол» стоит «Возраст», плейсхолдер прежний — «Выберите пол»
Полоса шагов582:52967 сегменты переставлены: залит второй, а частично — первый; на соседних кадрах наоборот
Счётчик знаков595:53651 показывает «100/150 символов» при тексте в 93 знака
Окно растра карты731:75846 матрица заливки даёт одно положение, рендер рисует на 8 px ниже
Длина кода из СМС261:27191…27200 в макете четыре ячейки, в приложении и тестах — шесть цифр (решение Р-11 за владельцем)
Двойной пробел в подписях маркеров карты178:6044, 178:6053 «Покатушки  на велосипеде», «Представление  в театре» — в строке разделитель строк идёт после пробела
Четыре кадра в реестре S10287:28651, 736:99284, 732:77542, 287:29289 числятся за экраном верификации, а по дереву это сама «Страница Карта» — экран B1

Второй проход

Что закрыто с прошлого раза

Пять кадров стояли выше порога, шестой не сверялся вовсе. Каждый закрыт замером, а не допуском: ниже — что именно измерено и во что это превратило число.

Что былоЧто оказалосьЧисло
Материал GLASS выбранных чипов
284:25738
у самой границы внутрь идёт светлая полоса шириной 1 dp: три ряда пикселей при ×3 дают 150 / 111 / 49 над базой 33. Пик альфы зависит от направления нормали — сверху 0,63, слева 0,62, снизу 0,41, справа 0,46, то есть 0,52 ± 0,11 по вертикали и ± 0,10 по горизонтали. Это аффинная функция координат, поэтому кромка ложится одним наклонным градиентом. Внутренний градиент ±7 уровней в метрику не попадает: ΔE2000 ≤ 2,2 при пороге 6 0,307 → 0,171 %
Тень чипа, которой нет
284:25738
в ноде тень (0,8) r40 12 %, а в рендере вокруг чипа только ореол в 2–4 dp. Доказано соседом: у чипа Default та же тень выключена, а ореол одинаковый до уровня; при этом у кнопки бренда того же кадра тень r40 широкая. Значит дело в материале, а не в радиусе — воспроизведён ореол (0; 0,6) r 4,3 часть тех же 0,171 %
Пунктир овала на селфи
287:26990 · 287:27445
прежняя версия — «перевыборка растра превью, 68 % плохих пикселей» — замером не подтвердилась: карта плохих пикселей показала контур овала и кольцо затвора, а не поле фотографии. Figma подгоняет пунктир под замкнутый контур: на 850,51 dp она кладёт 28 периодов по 30,375 вместо 32, конец круглый, штрих стоит серединой на начале контура. Кольцо затвора — полоса от r=33 до r=36, а не штрих по r=36 1,264 → 0,209 %
Ореол системных диалогов iOS
610:75380 · 286:26404
маска сравнения считалась по рамке узла, а слой Blur рисует на 40 dp дальше — это видно в самой ноде: габарит отрисовки 380×755 против рамки 300×675. Маска переведена на габарит отрисовки; доля кадра под ней теперь печатается и стоит в карточке (93 % у 610:75380), чтобы вердикт читался вместе с ней 0,731 → 0,054 %
0,335 → 0,091 %
Барабан даты рождения
732:78559
он не системный: на Android барабан рисует само приложение. Считать дугу не пришлось — в ноде каждая строка отдельный текстовый узел со своим кеглем (22,17 / 18,37 / 14,57 / 11,40 / 5,07) и прозрачностью 0,35. Собран по 27 узлам и убран из маски: кадр сверяется целиком, вместе с барабаном 0,270 → 0,056 %
Поп-ап успеха и диалог поверх карты
287:27892 · 736:98793
под ними лежала несобранная «Страница Карта». Она собрана — оба кадра сняты целиком: первый больше не мерится «по области листа», второй сверен впервые 0,293 → 0,244 %
— → 0,262 %
Перенос по дефису
292:25695
Figma рвёт строку сразу после дефиса, Compose переносит слово целиком, и ни Hyphens.Auto, ни LineBreak.Paragraph этого не меняют. После дефиса между буквами ставится нулевой пробел — он невидим и без ширины полное 2,077 → 1,747 %
Фильтры растра на экране входа
158:9505
у 3D-питомца в ноде стоят contrast 0,16 и saturation 0,57, и они считались невоспроизведёнными. Проверка формулой по ровным местам вырезки: без поправки средний |Δ| 4,34, с формулой — 4,8…18,2 при любой силе и в обоих пространствах. Figma эти фильтры в рендере не проявляет строка закрыта

Границы

Что не закрыто

Первый десяток зелёный целиком. Открытым осталось то, что вёрстке не подчиняется, и первый экран нового десятка.

ЧтоПочемуЧто нужно
Страница карты
180:8884 · 0,542 %
собрана и сведена с 94,7 % до 0,542 %, но остаток разложен так: растр карты и фон 0,160, обложки маркеров 0,132, карточки рельса и таб-бар 0,095, чипы 0,109, булавка 0,035. Больше половины — перевыборка растров: исходник карты 717×1213 на кадр 1170×1980, фотографии маркеров повёрнуты. Сдвига нет — минимум подгонки ровно в нуле, средние совпадают до 0,4 уровня исходник карты покрупнее либо решение считать растровую область картой и маскировать её, как живую (Р-7)
Остальные 20 кадров экрана карты собран мастер страницы; варианты отличаются составом маркеров, активными чипами, набором кнопок и наличием булавки следующий шаг работы
Длина кода из СМС
Р-11
в макете четыре ячейки, в приложении шесть. Форма кадров закрыта на четырёх решение владельца: править бэк или макет
Плотность чернил узкое начертание SF Pro Condensed берётся статической нарезкой: ширина заголовка −0,67…−1,33 dp, чернила −1,4…−5,2 % при пределе 2 %. Форма при этом закрыта вариативный файл SF Pro или согласие считать это остатком (Р-3)
Поведение экранов сверена форма. Трасса запросов не снята, живой карты в приложении нет — мини-карта показывает растр ноды (BACKEND-GAP) карта из SDK и лог запросов в debug-сборке