/* global React, ReactDOM, useTweaks, TweaksPanel, TweakSection, TweakColor, TweakRadio, TweakToggle */ const { useState, useEffect } = React; const TWEAK_DEFAULS = /*EDITMODE-BEGIN*/{ "accent": "#a855f7", "texture": "clean", "heroVariant": "manifest" }/*EDITMODE-END*/; /* ─── Icons (Tabler outline, inlined) ─── */ const Icon = ({ paths }) => ( {paths.map((p, i) => )} ); const StarMark = ({ size = 16 }) => ( ); /* ─── Chat reel for hero preview ─── */ const CHAT_LINES = [ { u: "андрей_к", c: "привет всем" }, { u: "лена.пб", c: "из Питера" }, { u: "max_94", c: "огонь как звучит" }, { u: "vegastudio", host: true, c: "откуда смотрите?" }, { u: "irina_m", c: "Казань на связи" }, { u: "denч", c: "ждём 1 сентября" }, { u: "polly", c: "это что, без монтажа?" }, { u: "vegastudio", host: true, c: "да, всё в прямом эфире" }, { u: "kirill.t", c: "наконец-то по-русски" }, { u: "майя", c: "красиво" }, { u: "rusl4n", c: "звук чёткий" }, { u: "olesya", c: "vegatv.ru запомнила" }, { u: "никa", c: "когда iOS?" }, { u: "vegastudio", host: true, c: "iOS и Android — в день запуска" }, ]; function ChatRoll() { const [visible, setVisible] = useState(() => CHAT_LINES.slice(0, 4).map((m, i) => ({ ...m, k: i, fresh: false })) ); const idxRef = React.useRef(4); const keyRef = React.useRef(100); useEffect(() => { const id = setInterval(() => { const next = CHAT_LINES[idxRef.current % CHAT_LINES.length]; idxRef.current += 1; keyRef.current += 1; const k = keyRef.current; setVisible((prev) => { const arr = [...prev, { ...next, k, fresh: true }]; return arr.length > 4 ? arr.slice(arr.length - 4) : arr; }); // next frame: drop the "fresh" flag so the CSS transition fires requestAnimationFrame(() => { requestAnimationFrame(() => { setVisible((prev) => prev.map((m) => (m.k === k ? { ...m, fresh: false } : m))); }); }); }, 2200); return () => clearInterval(id); }, []); return ( ); } const FeatIcons = { broadcast: , chat: , duet: , reactions: , privacy: , monetize: , search: , device: , }; /* ─── Hero copy variants ─── */ const HERO_VARIANTS = { manifest: { pre: "РОССИЙСКАЯ ПЛОЩАДКА ДЛЯ СТРИМОВ", title: <>Социальная сеть.
В прямом эфире., lead: <>Никаких записей и монтажа. Только то, что происходит прямо сейчас — у тебя, у друзей, у тех, кого ты ещё не знаешь., }, poetic: { pre: "РОССИЙСКАЯ ПЛОЩАДКА ДЛЯ СТРИМОВ", title: <>Жизнь идёт в прямом эфире.
Мы её просто показываем., lead: <>Открытая лента, где каждый — автор и зритель одновременно. Включай эфир, заходи в чужой, оставайся тем, кто ты есть., }, data: { pre: "РОССИЙСКАЯ ПЛОЩАДКА ДЛЯ СТРИМОВ", title: <>Вега.ТВ —
стримы по-русски., lead: <>Площадка прямых эфиров с встроенной соцсетью. Лента, чаты, совместные эфиры, реакции в реальном времени — на одном экране, без задержки., }, }; /* ─── Marquee tape data ─── */ const TAPE = [ "Запуск · 01.09.2026", "Социальная сеть в прямом эфире", "Совместные эфиры до 4 человек", "iOS · Android · Web", "На русском", "Никакого монтажа", ]; /* ─── Sample feed ─── */ const TILES = [ { title: "Утренний кофе из Питера", ch: "@lina_morning", v: "1.2K", cat: "ВЕДУ ЭФИР" }, { title: "Кодим бэкенд под чай", ch: "@backwave", v: "312", cat: "IT · ЖИВЬЁМ" }, { title: "Прогулка по Тбилиси", ch: "@goga_walks", v: "4.8K", cat: "IRL · 04:12" }, { title: "Реакция на новый трейлер", ch: "@react_max", v: "2.4K", cat: "РЕАКЦИЯ" }, { title: "Мама учит готовить хинкали", ch: "@hinkali_mom", v: "850", cat: "ЕДА · ЭФИР" }, { title: "Турнир по Counter-Strike", ch: "@ru_cs2", v: "12.3K", cat: "ИГРЫ · FINAL" }, { title: "DJ-сет, ночь", ch: "@nightowl", v: "5.1K", cat: "МУЗЫКА · LIVE" }, { title: "Чат с подписчиками", ch: "@askruslan", v: "921", cat: "Q&A · ОТКР." }, ]; function App() { const [t, setTweak] = useTweaks(TWEAK_DEFAULS); const [login, setLogin] = useState(""); const [password, setPassword] = useState(""); const [showPass, setShowPass] = useState(false); const [authError, setAuthError] = useState(""); useEffect(() => { const root = document.documentElement; const c = t.accent; root.style.setProperty("--sv-accent", c); root.style.setProperty("--sv-accent-hover", shift(c, 12)); root.style.setProperty("--sv-accent-press", shift(c, -10)); root.style.setProperty("--sv-accent-soft", hexA(c, 0.14)); root.style.setProperty("--sv-accent-softer", hexA(c, 0.04)); root.style.setProperty("--sv-shadow-glow", `0 0 0 3px ${hexA(c, 0.22)}`); }, [t.accent]); const hero = HERO_VARIANTS[t.heroVariant] || HERO_VARIANTS.manifest; async function submit(e) { e.preventDefault(); setAuthError(""); try { const res = await fetch("/api/login", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ login, password }), }); const data = await res.json().catch(() => ({})); setAuthError(data.error || "Неверный логин или пароль"); } catch { setAuthError("Неверный логин или пароль"); } } const texClass = t.texture === "grain" ? "tex-grain" : t.texture === "scan" ? "tex-scan" : ""; return (
{hero.pre}

{hero.title}

{hero.lead}

setLogin(e.target.value)} autoComplete="username" />
setPassword(e.target.value)} autoComplete="current-password" />

{authError ? {authError} : <>вход откроется 01.09.2026}

О платформе

Лента, в которой никто не нажал кнопку «опубликовать».

Вега ТВ собирает соцсеть и стрим-платформу в одно. Эфир здесь — это и есть пост: открыл приложение, нажал, и аудитория появилась рядом. Не нужно записывать, монтировать, выкладывать, ждать просмотры.

Под каждым эфиром — живой чат, реакции прямо поверх кадра, возможность позвать гостя одним свайпом. Алгоритм показывает эфир тем, кому он интересен, поэтому аудитория растёт не от подписной базы, а от темы.

Российская команда, российские серверы, оплата картой любого банка. На русском без машинного перевода — потому что мы и пишем на нём.

Стримерам

Аудитория приходит на тему.

Можно начинать с нуля. Алгоритм показывает эфир тем, кому он интересен — даже если у тебя пока ни одного подписчика. Студия в приложении, OBS не нужен, гости — одним свайпом.

Монетизация с первого дня: чаевые, платные эфиры, подписки на канал. Комиссия фиксированная и видна на каждом платеже. Никаких скрытых вычетов.

Зрителям

Соцсеть, где всё уже сейчас.

Не приходится листать вчерашние видео. Лента собирается под тебя — по темам, городам, друзьям. Открыл — и кто-то уже в эфире.

Можно смотреть тихо, можно зайти в чат, можно сесть рядом гостем. Никакой обязанности подписываться, ставить лайки и оставлять реакции, если не хочется.

setTweak("accent", v)} /> setTweak("heroVariant", v)} /> setTweak("texture", v)} />
); } function hexA(hex, a) { const h = hex.replace("#", ""); const n = parseInt(h.length === 3 ? h.split("").map(c => c + c).join("") : h, 16); const r = (n >> 16) & 255, g = (n >> 8) & 255, b = n & 255; return `rgba(${r},${g},${b},${a})`; } function shift(hex, amt) { const h = hex.replace("#", ""); const n = parseInt(h.length === 3 ? h.split("").map(c => c + c).join("") : h, 16); let r = (n >> 16) & 255, g = (n >> 8) & 255, b = n & 255; r = Math.max(0, Math.min(255, r + amt)); g = Math.max(0, Math.min(255, g + amt)); b = Math.max(0, Math.min(255, b + amt)); return "#" + [r, g, b].map(v => v.toString(16).padStart(2, "0")).join(""); } ReactDOM.createRoot(document.getElementById("root")).render();