feat(room): замена фона видео на картинку — только на десктопе
Кнопка «Фон» в тулбаре комнаты и выбор фона в превью на входе: три готовые
сцены и свои картинки из профиля. Фон применяется процессором к самому
публикуемому треку (`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 и фон молча не включался.
This commit is contained in:
150
design/backgrounds/space-station.svg
Normal file
150
design/backgrounds/space-station.svg
Normal file
@@ -0,0 +1,150 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1280" height="720" viewBox="0 0 1280 720">
|
||||
<title>Космическая станция — дефолтный фон замены фона видео</title>
|
||||
<desc>Собственная векторная сцена VidConf. Интерьер модуля станции: панели,
|
||||
подсветка, иллюминатор с Землёй. Центр кадра спокойный — там человек.</desc>
|
||||
<defs>
|
||||
<linearGradient id="hull" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0" stop-color="#2b3446"/>
|
||||
<stop offset="0.5" stop-color="#222a3a"/>
|
||||
<stop offset="1" stop-color="#161c28"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="panel" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0" stop-color="#39445a"/>
|
||||
<stop offset="1" stop-color="#28304180"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="strip" x1="0" y1="0" x2="1" y2="0">
|
||||
<stop offset="0" stop-color="#4fd7ff" stop-opacity="0.1"/>
|
||||
<stop offset="0.5" stop-color="#7fe8ff" stop-opacity="0.9"/>
|
||||
<stop offset="1" stop-color="#4fd7ff" stop-opacity="0.1"/>
|
||||
</linearGradient>
|
||||
<radialGradient id="earth" cx="0.36" cy="0.32" r="0.78">
|
||||
<stop offset="0" stop-color="#7fd1f5"/>
|
||||
<stop offset="0.55" stop-color="#2f7fc4"/>
|
||||
<stop offset="1" stop-color="#0c2c56"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="atmo" cx="0.5" cy="0.5" r="0.5">
|
||||
<stop offset="0.78" stop-color="#8fd8ff" stop-opacity="0"/>
|
||||
<stop offset="0.9" stop-color="#8fd8ff" stop-opacity="0.5"/>
|
||||
<stop offset="1" stop-color="#8fd8ff" stop-opacity="0"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="portGlow" cx="0.5" cy="0.5" r="0.5">
|
||||
<stop offset="0" stop-color="#8fd8ff" stop-opacity="0.4"/>
|
||||
<stop offset="1" stop-color="#8fd8ff" stop-opacity="0"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="spaceVignette" cx="0.5" cy="0.45" r="0.78">
|
||||
<stop offset="0.5" stop-color="#000000" stop-opacity="0"/>
|
||||
<stop offset="1" stop-color="#05080f" stop-opacity="0.65"/>
|
||||
</radialGradient>
|
||||
<filter id="stationSoft" x="-6%" y="-6%" width="112%" height="112%">
|
||||
<feGaussianBlur stdDeviation="4"/>
|
||||
</filter>
|
||||
<filter id="stationSofter" x="-8%" y="-8%" width="116%" height="116%">
|
||||
<feGaussianBlur stdDeviation="9"/>
|
||||
</filter>
|
||||
<!-- Всё, что «за стеклом», обрезается по стеклу: без этого Земля вылезала
|
||||
за переплёт иллюминатора и сцена читалась как наклейка на стене. -->
|
||||
<clipPath id="portholeGlass">
|
||||
<circle cx="640" cy="318" r="192"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
|
||||
<rect width="1280" height="720" fill="url(#hull)"/>
|
||||
|
||||
<g filter="url(#stationSoft)">
|
||||
<!-- Рёбра модуля -->
|
||||
<g fill="#39445a" opacity="0.55">
|
||||
<rect x="0" y="0" width="1280" height="52"/>
|
||||
<rect x="0" y="668" width="1280" height="52"/>
|
||||
<rect x="150" y="52" width="26" height="616"/>
|
||||
<rect x="1104" y="52" width="26" height="616"/>
|
||||
</g>
|
||||
|
||||
<!-- Приборные панели слева -->
|
||||
<g>
|
||||
<rect x="46" y="150" width="220" height="300" rx="14" fill="url(#panel)"/>
|
||||
<rect x="66" y="172" width="180" height="86" rx="6" fill="#101826"/>
|
||||
<g fill="#5ee0a8" opacity="0.85">
|
||||
<rect x="78" y="230" width="120" height="4" rx="2"/>
|
||||
<rect x="78" y="216" width="82" height="4" rx="2"/>
|
||||
<rect x="78" y="202" width="146" height="4" rx="2"/>
|
||||
</g>
|
||||
<g>
|
||||
<circle cx="92" cy="292" r="11" fill="#ff8a5c"/>
|
||||
<circle cx="126" cy="292" r="11" fill="#ffd166"/>
|
||||
<circle cx="160" cy="292" r="11" fill="#5ee0a8"/>
|
||||
</g>
|
||||
<g fill="#4a5670">
|
||||
<rect x="66" y="322" width="180" height="16" rx="8"/>
|
||||
<rect x="66" y="352" width="180" height="16" rx="8"/>
|
||||
<rect x="66" y="382" width="180" height="16" rx="8"/>
|
||||
</g>
|
||||
<rect x="66" y="322" width="104" height="16" rx="8" fill="#7fe8ff" opacity="0.8"/>
|
||||
<rect x="66" y="352" width="62" height="16" rx="8" fill="#7fe8ff" opacity="0.6"/>
|
||||
</g>
|
||||
|
||||
<!-- Стеллаж оборудования справа -->
|
||||
<g>
|
||||
<rect x="1014" y="128" width="230" height="344" rx="14" fill="url(#panel)"/>
|
||||
<g fill="#101826">
|
||||
<rect x="1034" y="150" width="190" height="70" rx="6"/>
|
||||
<rect x="1034" y="238" width="190" height="70" rx="6"/>
|
||||
<rect x="1034" y="326" width="190" height="70" rx="6"/>
|
||||
</g>
|
||||
<g fill="#7fe8ff" opacity="0.6">
|
||||
<rect x="1050" y="176" width="86" height="5" rx="2.5"/>
|
||||
<rect x="1050" y="264" width="126" height="5" rx="2.5"/>
|
||||
<rect x="1050" y="352" width="64" height="5" rx="2.5"/>
|
||||
</g>
|
||||
<circle cx="1206" cy="424" r="14" fill="#ff8a5c" opacity="0.8"/>
|
||||
</g>
|
||||
|
||||
<!-- Иллюминатор -->
|
||||
<g>
|
||||
<circle cx="640" cy="318" r="212" fill="#39445a"/>
|
||||
<circle cx="640" cy="318" r="192" fill="#0b1120"/>
|
||||
<g clip-path="url(#portholeGlass)">
|
||||
<!-- Звёзды -->
|
||||
<g fill="#ffffff">
|
||||
<circle cx="530" cy="200" r="2.5" opacity="0.9"/>
|
||||
<circle cx="596" cy="168" r="1.8" opacity="0.7"/>
|
||||
<circle cx="712" cy="188" r="2.2" opacity="0.8"/>
|
||||
<circle cx="768" cy="252" r="1.6" opacity="0.6"/>
|
||||
<circle cx="500" cy="300" r="1.8" opacity="0.65"/>
|
||||
<circle cx="742" cy="356" r="2" opacity="0.7"/>
|
||||
<circle cx="556" cy="424" r="1.7" opacity="0.6"/>
|
||||
<circle cx="676" cy="456" r="2.3" opacity="0.75"/>
|
||||
</g>
|
||||
<!-- Земля -->
|
||||
<circle cx="596" cy="386" r="150" fill="url(#earth)"/>
|
||||
<g fill="#3f8f5f" opacity="0.75">
|
||||
<path d="M520 330c40-16 74-10 96 14-34 8-64 12-96 6z"/>
|
||||
<path d="M596 430c46-8 84 6 108 40-42 4-80-8-108-30z"/>
|
||||
<path d="M498 404c26 6 46 22 58 46-28-4-50-18-66-38z"/>
|
||||
</g>
|
||||
<g fill="#ffffff" opacity="0.35">
|
||||
<ellipse cx="560" cy="352" rx="70" ry="16"/>
|
||||
<ellipse cx="656" cy="416" rx="86" ry="18"/>
|
||||
</g>
|
||||
<circle cx="596" cy="386" r="150" fill="url(#atmo)"/>
|
||||
</g>
|
||||
<!-- Переплёт иллюминатора -->
|
||||
<circle cx="640" cy="318" r="192" fill="none" stroke="#4a5670" stroke-width="14"/>
|
||||
<circle cx="640" cy="318" r="206" fill="none" stroke="#2b3446" stroke-width="16"/>
|
||||
<g fill="#4a5670">
|
||||
<rect x="622" y="98" width="36" height="34" rx="8"/>
|
||||
<rect x="622" y="504" width="36" height="34" rx="8"/>
|
||||
<rect x="420" y="300" width="34" height="36" rx="8"/>
|
||||
<rect x="826" y="300" width="34" height="36" rx="8"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
|
||||
<!-- Свечение из иллюминатора и световые полосы модуля -->
|
||||
<ellipse cx="640" cy="318" rx="420" ry="330" fill="url(#portGlow)"/>
|
||||
<g filter="url(#stationSofter)">
|
||||
<rect x="176" y="60" width="928" height="10" rx="5" fill="url(#strip)"/>
|
||||
<rect x="176" y="650" width="928" height="10" rx="5" fill="url(#strip)"/>
|
||||
</g>
|
||||
|
||||
<rect width="1280" height="720" fill="url(#spaceVignette)"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.0 KiB |
Reference in New Issue
Block a user