# Прокрутка остановок — 11 октября 2026 Сообщение пользователя: тормозит на Xiaomi Mi Box 4 в Hi Browser в обоих профилях. Устройство не подключено к ADB (список устройств пуст). На физическом Mi Box FPS не измерялся; результат ниже — исходный код, сравнительные счётчики в Codex in-app browser и проверка компоновки. ## Причина и изменение В `src/styles.css` ширина ячеек анимировалась через `flex-basis`. Каждый промежуточный размер вызывал `ResizeObserver` в `FittedDestination`, измерение текста canvas и подбор шрифта с чтением/записью геометрии. Заголовки дополнительно пересоздавались при смене роли «крупный/компактный». В `src/NextStops.tsx` выделен мемоизированный `JourneyRail`. Ячейки всегда одинаковой ширины, каждый заголовок имеет два постоянных слоя с заранее подобранным шрифтом. Положение ячеек, увеличение названия и длина линии меняются через `transform`, видимость слоёв — через `opacity`. Коэффициент увеличения согласован со свободным расстоянием до соседней остановки. Анимации ширины, цвета текста и тени маркера удалены. Во время обычного перехода размеры текста не меняются. Тики часов не запускают рендер схемы при неизменных данных; названия, минуты, количество остановок и продолжение сравниваются перед пропуском рендера. Это соответствует [рекомендациям web.dev по анимациям](https://web.dev/articles/animations-guide) и [предотвращению повторных синхронных перерасчётов layout](https://web.dev/articles/avoid-large-complex-layouts-and-layout-thrashing). Фактический эффект на GPU конкретного браузера требует проверки на устройстве. ## Сравнение Одинаковый стенд: 960×540, тёмная тема, расстояние «Близко», Автовокзал, фильтр №4. Сохранённое публичное расписание, тестовые часы/погода. Старая производственная сборка сохранена до правки; новая сравнивалась с ней через те же наблюдатели. По три перехода в каждом профиле, окно 1200 мс после смены остановки. Скрипт не меняет прототипы и состояние приложения, не передаёт данные наружу. Счётчики относятся только к названиям остановок, а не ко всему layout или FPS. | Профиль / переход | Изменения размеров до → после | Записи шрифта до → после | Замены заголовков до → после | | --- | ---: | ---: | ---: | | ТВ, 1 → 2 | 110 → 0 | 842 → 0 | 2 → 0 | | ТВ, 2 → 3 | 110 → 0 | 632 → 0 | 2 → 0 | | ТВ, 3 → 4 | 110 → 0 | 838 → 0 | 2 → 0 | | Уличное табло, 1 → 2 | 38 → 0 | 82 → 0 | 2 → 0 | | Уличное табло, 2 → 3 | 38 → 0 | 160 → 0 | 2 → 0 | | Уличное табло, 3 → 4 | 38 → 0 | 241 → 0 | 2 → 0 | ## Поведение - Сохранены интервалы 4/6 секунд и движение 900/300 мс для ТВ/уличного профиля. Пауза прекращает смену остановок. - Переход 4 → 1 выполняет мягкое появление, без обратного движения всей схемы. - В промежуточных кадрах ТВ: ширина ячейки постоянна **189,29 px**, высота области названия **51 px**, размер шрифта **41,91 px**. Матрица масштаба меняется 0,871 → 0,984 → 1, зазор до соседней остановки — 24,38 → 27,55 → 28,00 px. Наложения нет. - На конечной демонстрационного маршрута без продолжения: длина линии **0 px**, её начало и центр последнего маркера совпадают (65,797 / 65,796 px). Ложного продолжения нет. - 390×667: длинное название «Больница (Новка)» целиком, высота 72,42 px при доступных 76 px; кружок 22 px. - 1920×1080, три карточки: тот же текст высотой 129,17 px при доступных 239 px; кружок 24 px. - Accessibility показывает по одному названию остановки: второй визуальный слой скрыт через `aria-hidden`. - Настройки и API не расширялись. Режим reduced motion отключает переходы и освобождает подсказки слоёв. Счётчики тестового стенда отсутствуют в production bundle и Docker runtime. Проверки: `npm run build` (TypeScript + Vite), 10 тестов маршрута/информационных блоков, синтаксис двух файлов стенда и `git diff --check` прошли. Снимок — `journey-motion-960x540.jpg`. Для обновления серверного табло необходимо развернуть файлы и пересобрать образ.