Files
vidconf/design/backgrounds/space-station.svg
Max Ronzhin 17437880b1 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 и фон молча не включался.
2026-08-10 08:59:47 +03:00

151 lines
7.0 KiB
XML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<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>