Решили: граница между экранным View и его владельцем проходит по кадру. Во View — всё, что видно на снимке: дерево, подписи, состав табов, растяжка по слою. У владельца — модель, подписки, кнопки. Так собраны SettingsScreenView и LoadoutScreenView, вынесенные из MenuRouter.

Почему: сборка, запертая приватным методом роутера, недоступна стенду превью — и стенд пересобирал экран вручную, а кадр такого экрана показывает стенд, а не игру. Отвергли вариант «View берёт всё себе, включая VM»: экран, который сам ходит в модель, в изоляции уже не собрать, а именно изоляция и даёт кадр. Отвергли и отдельный Presenter на каждый экран — на два экрана это два новых класса без новой работы; у предметов и отряда Presenter есть потому, что там он читает RunState, а не ради симметрии.

Сказано: «Как мы фоткаем экраны каждый? Они же бывают разные. Создаются некоторые кодом, некоторые нет.» (23.08.2026, сессия 14ae129e). Правило достоверности — оттуда же: стенд и игра собирают экран одним кодом, иначе кадра нет.

Грабли: переезд проверяется кадром, и это дешевле любого теста — settings.png совпал до байта между прогоном «до» и «после», то есть вид не поехал. Обратный случай тоже нашёлся сразу: кадр главного меню был без правой панели, потому что каталог звал MainMenuScreenView.Build без CommunityConfig, а параметр необязательный. Необязательный параметр вида — тихая дыра: игра передаёт, стенд забывает, и разницу видно только на снимке.

Третий метод трогать не пришлось: BuildProfileScreen длинный не от сборки, а от числа колбэков — ProfileScreenView.Build уже был статическим. Длина метода не признак того, что в нём заперт вид.

Владелец правды: SettingsScreenView.cs, LoadoutScreenView.cs, UiPreviewCatalog.cs.