По душе · Android × Figma · 11.09.2026 · страница «Афиша»

Третий десяток собран, страница «Афиша» закрыта

Тридцать шесть кадров: страница события со всеми состояниями нижней панели, жалоба на событие, подача заявки и её исход, добавление в избранные, «Куда иду» и четыре списка секции «Афиша города» — включая страницу 390×3045, которую пришлось учиться снимать полосами. Каждый кадр собран из данных ноды и сведён с рендером Figma в честном масштабе ×3. Этим десятком страница «Афиша» (117 кадров) закрыта полностью. Попутно измерено пять вещей, которых в методе не было: откуда BACKGROUND_BLUR берёт подложку и как считает ядро у границы, что делает материал GLASS без объявленного размытия, как растёт радиус у PROGRESSIVE и какую сигму на самом деле даёт Modifier.blur.

33 / 36кадров с зелёной геометрией при пороге 0,3 %
0,014 %лучшая геометрия
0,458 %худшая — растр карты и стекло над ней
19расхождений найдено, 17 закрыто
1пара «нода → нода» — дизайнеру

Смотровая

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

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

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

Числа

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

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

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

Разбор

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

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

Один эллипс подсветки под картой складывается, а не кроется

Под карточкой карты лежат четыре размытых эллипса. Три идут обычным наложением, а второй фиолетовый — LINEAR DODGE: он складывается с подложкой. Я рисовал его как остальные, и вся правая половина карточки уходила в насыщенный фиолетовый: по строке y = 305 рендер даёт (250, 237, 249), а снимок (220, 203, 232). Одна строка кода на тринадцати кадрах.

2,375 → 0,442 %узел 229:18755
режим наложения из ноды

Фоновое размытие берёт подложку только в границах узла

У бейджа обложки 66×19 объявлен радиус 60 — больше самого бейджа. Если размывать всю обложку, тон под ним выходит на 20 уровней светлее рендера, и подгонка по двум параметрам (радиус и прозрачность) не сходится ни при каком сочетании: лучшее |Δ| 9,6. Если размывать только то, что попадает в рамку узла, — |Δ| 5,3 и совпадение по тону уже при объявленных R = 60 и альфе 0,16.

0,363 → 0,214 %узел 233:29323
окно узла, а не слоя

Фоновое размытие Figma считается тремя проходами бокса, а не двумя

Подложка страницы события — растр под BACKGROUND_BLUR радиуса 500. Модель подбиралась по самому рендеру: при трёх проходах минимум отклонения стоит ровно на объявленных 500 dp, при двух (как у LAYER_BLUR) уезжает на 625. Это разные ядра у двух родственных эффектов, и раньше они считались одинаковыми.

500 dpузел 229:18724
минимум ровно на объявленном

У края кадра ядро нормируется, а не добивается краевым пикселем

На «Киновечере» верх фотографии очень яркий. С добивкой краевым пикселем подложка шла на 29 уровней темнее рендера у верхней границы, и кадр держал 2,954 %. С нормировкой ядра по попавшей в кадр части — 0,678 %. На тёмной подложке мастера модель не меняется (0,160 → 0,171 %), поэтому раньше разницы не было видно.

2,954 → 0,678 %кадр 836:108903
край кадра ≠ край картинки

Материал GLASS размывает подложку и без объявленного размытия

У стеклянных кнопок нижней панели в ноде нет ни одного эффекта размытия — только GLASS внутри Glass Effect. А в рендере карта под ними ровная: у полупрозрачной заливки она осталась бы читаемой. Под кнопки подрисована размытая копия слоёв кадра с той же сигмой, что у снекбара.

0,540 → 0,373 %кадр 232:27767
материал, а не эффект

Modifier.blur(r) даёт σ ≈ 0,59·r, а не 0,79·r

Инструмент blurfit.py берёт подложку из того же кадра без снекбара, размывает её с разной сигмой, накладывает объявленные слои узла и ищет минимум. У рендера он стоит на σ = 10,5 dp — это R/2 при R = 20, то есть та же модель трёх проходов. У моего снимка при blur(12,66) — на σ = 7,5. Отношение даёт константу Skia 0,577·r + 0,5, и прежнее значение 0,79 было ошибкой измерителя.

0,79 → 0,59узел 231:21434
константа измерена, а не взята

Отклик стекла зависит от яркости подложки

Над тёмным фоном у стекла узкая светлая кромка в 1 dp — так было измерено на чипах интересов. У снекбара над картой кромка шире: у самой границы доля белого 0,45, дальше внутрь спад с 0,15 на 1 dp до 0,04 на 7 dp. А интерьер маленькой кнопки 40×40 над светлой картой в рендере на 0,42 белее подложки. Перенести широкую кромку на все кнопки нельзя: кадры над тёмным от этого портятся (0,168 → 0,351 %), поэтому остаток записан как материал.

2,720 → 0,467 %кадр 231:21433
кромка измерена профилем

PROGRESSIVE: радиус растёт не линейно

У панели крупной карточки и у подписи плитки размытие типа PROGRESSIVE — радиус растёт от 0 сверху к 24 снизу. Форма подбиралась по свободной от содержимого полосе панели: линейный рост даёт |Δ| 5,89, показатель 2 — 5,33, 3 — 4,80, 4 — 4,34, 6 — 4,48. Альтернативная модель (размытый на полный радиус слой подмешивается с линейной прозрачностью) хуже: 5,66.

5,89 → 4,34узел 802:33362
показатель 4, а не 1

Кадр выше экрана: две ловушки склейки

Страница 3045 dp снимается полосами по 844. Первая ловушка: requiredHeight и requiredSize центруют содержимое в приходящих ограничениях — кадр 1730 на экране 844 уезжал вверх ровно на 443 dp, и метрика показывала 96,4 %. Вторая: андроидный статус-бар попадал в середину склейки на y = 844 и 1688.

96,4 → 3,6 %кадр 232:28888
(1730 − 844)/2 = 443

Затемнение стоит до нижней панели и равно 23 %

На кадре с системным листом отмены участия затемнение Overlay — это #000 23 %, и в дереве оно стоит до панели: кнопки панели им не гасятся. У меня оно рисовалось последним и с альфой 0,4, и интерьер кнопок уходил на 30 уровней темнее рендера.

10,714 → 0,122 %кадр 231:21452
порядок слоёв из дерева

Колонка дней плоская, а плашка цены прижата вправо

В «Ближайших днях» заголовок дня, карточки и разделители — соседи одной колонки с зазором 20, а не вложенные секции: с вложением последняя карточка уезжала на 8 dp. А плашка цены стоит у правого края, потому что строка организатора рядом с ней идёт во всю ширину.

15,929 → 0,207 %кадр 838:111252
читать дерево, а не картинку

Пара «нода → нода» — дизайнеру

Один и тот же градиент шапки и нижней панели описан тремя способами: у мастера страницы события это #232B48 при непрозрачности заливки 1, у кадров второго события — #000000 при 0,2, а у четырёх кадров секции «Афиша города» заливок нет вовсе. Кадры воспроизведены как есть, но это расхождение макета с самим собой.

14,751 → 3,006 %693:76739 и 693:76748
каждый кадр как он есть

Границы

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

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

КадрыГеометрия %Класс остатка
232:288880,470перевыборка обложек рельса на дробной координате 1371,81 и растр карты
231:193700,360интерьер стеклянной кнопки над светлой картой: в рендере он на 0,42 белее подложки
232:286730,357преломление стекла снекбара в две строки
Стали зелёными после нормировки: 231:21433 и 231:22023 — 0,393 → 0,280, 232:28174 — 0,362 → 0,250, 232:27767 — 0,287 → 0,280, пять кадров стеклянных кнопок нижней панели — 0,313…0,387 → 0,254…0,283.