Кнопка «Фон» в тулбаре комнаты и выбор фона в превью на входе: три готовые
сцены и свои картинки из профиля. Фон применяется процессором к самому
публикуемому треку (`LocalVideoTrack.setProcessor`), а НЕ пересозданием
`RoomOptions` — ссылка на них обязана оставаться стабильной, иначе
`LiveKitRoom` переподключается к комнате.
Фича только для ДЕСКТОПА, и «десктоп» определяется по возможностям устройства
(`pointer: fine` + `hover: hover` + `maxTouchPoints`), а НЕ по ширине окна:
узкое окно на десктопе — всё ещё десктоп, а широкий планшет — всё ещё планшет,
который сегментация греет. На мобильном кнопки нет вовсе, а не задизейбленной.
Ассеты сегментации отдаются СО СВОЕГО домена: библиотека по умолчанию тянет
wasm с jsdelivr, а модель с storage.googleapis.com, и в закрытом контуре фича
молча не работала бы. Модель (Apache 2.0, см. NOTICE.txt) лежит в репозитории,
wasm-рантайм (~19 МБ) копируется из node_modules плагином сборки. Сама
библиотека и модель грузятся ЛЕНИВО — только когда фон реально включают, вход
в конференцию не стал медленнее.
Три дефолтные сцены — собственные векторные рисунки (`design/backgrounds/`),
а не фотографии из интернета: у нарисованной сцены нет чужой лицензии, а
продукт расходится по инсталляциям, и проверять права на каждую копию некому.
Свои картинки — в профиле, до 10 штук, с уменьшением до 1280px и переводом в
WebP прямо в браузере перед отправкой. Удаление применённого сейчас фона
сбрасывает выбор на «без фона»: хранится ключ записи, а не URL картинки.
Смена камеры фон не теряет (`restartTrack` перезапускает процессор сам),
выключение и включение камеры — навешивает его на новый трек заново.
⚠️ Прокси dev-сервера для `/media/` — обязательно со слэшем: ключ `/media`
Vite матчит префиксом и перехватывает заодно `/mediapipe/...`, из-за чего
модель получала 404 и фон молча не включался.
96 lines
3.5 KiB
CSS
96 lines
3.5 KiB
CSS
/*
|
||
* VidConf — превью камеры на входе (сессия 33, `JoinPage`; LoginPage
|
||
* превью не показывает — см. `DeviceCheckCard` не используется там).
|
||
* Свой файл: компонент самодостаточный, стили ему не нужны нигде за
|
||
* пределами компонента.
|
||
*/
|
||
|
||
.device-check { margin: 0 auto var(--space-5); }
|
||
|
||
/* Окошко превью и кнопки под ним — одна композиция шириной в половину
|
||
карточки (`.flow-card`, куда компонент вложен): проценты сами масштабируются
|
||
от фактической ширины родителя без хардкода пикселей. */
|
||
.device-check-inner { width: 50%; margin: 0 auto; }
|
||
|
||
.device-check-frame {
|
||
position: relative;
|
||
width: 100%;
|
||
aspect-ratio: 4 / 3;
|
||
border-radius: var(--radius-lg);
|
||
overflow: hidden;
|
||
background: var(--color-bg-alt);
|
||
border: 1px solid var(--color-border);
|
||
}
|
||
|
||
.device-check-video {
|
||
width: 100%;
|
||
height: 100%;
|
||
object-fit: cover;
|
||
/* Своё видео принято показывать зеркально — так человек видит себя
|
||
привычно, как в зеркале, а не «как его видят другие». */
|
||
transform: scaleX(-1);
|
||
}
|
||
|
||
.device-check-placeholder {
|
||
position: absolute;
|
||
inset: 0;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: var(--color-ink-400);
|
||
}
|
||
.device-check-placeholder .lucide { width: 26px; height: 26px; }
|
||
|
||
/* Кнопки без подписи, только пиктограммы — их совместная ширина равна
|
||
ширине окошка превью (тот же `.device-check-inner`), за края не выступают. */
|
||
.device-check-toggles {
|
||
display: flex;
|
||
gap: var(--space-2);
|
||
margin-top: var(--space-2);
|
||
}
|
||
|
||
.device-check-toggle {
|
||
flex: 1;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 8px 0;
|
||
border-radius: var(--radius-lg);
|
||
border: 1px solid var(--color-border);
|
||
background: var(--color-bg-alt);
|
||
color: var(--color-ink-500);
|
||
cursor: pointer;
|
||
}
|
||
.device-check-toggle .lucide { width: 18px; height: 18px; }
|
||
.device-check-toggle.is-on {
|
||
background: var(--color-accent);
|
||
border-color: transparent;
|
||
color: var(--color-accent-text);
|
||
}
|
||
.device-check-toggle:disabled { opacity: 0.5; cursor: not-allowed; }
|
||
|
||
.device-check-hint {
|
||
text-align: center;
|
||
margin-top: var(--space-3);
|
||
}
|
||
|
||
/* Выбор фона под кнопками превью (сессия 35).
|
||
Здесь плитки идут ОДНОЙ прокручиваемой строкой, а не сеткой, как в комнате
|
||
и в профиле: карточка входа и без того высокая, а число своих картинок
|
||
доходит до десяти — сетка выросла бы на шесть рядов и увела бы кнопку
|
||
«Продолжить» за нижний край экрана. Строка держит высоту постоянной при
|
||
любом числе картинок. Сами плитки — общие, см. virtual-background.css. */
|
||
.device-check-backgrounds {
|
||
margin: var(--space-4) auto 0;
|
||
}
|
||
.device-check-backgrounds .bg-grid {
|
||
display: flex;
|
||
gap: var(--space-2);
|
||
overflow-x: auto;
|
||
padding-bottom: var(--space-2);
|
||
}
|
||
.device-check-backgrounds .bg-tile {
|
||
flex: 0 0 auto;
|
||
width: 72px;
|
||
}
|