/* 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 (
{visible.map((m) => (
{m.u}
{m.c}
))}
);
}
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}
{authError
? {authError}
: <>вход откроется 01.09.2026 >}
О платформе
Лента, в которой никто не нажал кнопку «опубликовать».
Вега ТВ собирает соцсеть и стрим-платформу в одно. Эфир здесь — это и есть пост: открыл приложение, нажал, и аудитория появилась рядом. Не нужно записывать, монтировать, выкладывать, ждать просмотры.
Под каждым эфиром — живой чат, реакции прямо поверх кадра, возможность позвать гостя одним свайпом. Алгоритм показывает эфир тем, кому он интересен, поэтому аудитория растёт не от подписной базы, а от темы.
Российская команда, российские серверы, оплата картой любого банка. На русском без машинного перевода — потому что мы и пишем на нём.
Стримерам
Аудитория приходит на тему.
Можно начинать с нуля. Алгоритм показывает эфир тем, кому он интересен — даже если у тебя пока ни одного подписчика. Студия в приложении, OBS не нужен, гости — одним свайпом.
Монетизация с первого дня: чаевые, платные эфиры, подписки на канал. Комиссия фиксированная и видна на каждом платеже. Никаких скрытых вычетов.
Зрителям
Соцсеть, где всё уже сейчас.
Не приходится листать вчерашние видео. Лента собирается под тебя — по темам, городам, друзьям. Открыл — и кто-то уже в эфире.
Можно смотреть тихо, можно зайти в чат, можно сесть рядом гостем. Никакой обязанности подписываться, ставить лайки и оставлять реакции, если не хочется.
ВЕГА. ТВ
Где мы
iOS · Android
vegatv.ru
Москва, Пресненская наб., 12
БЦ «Башня Федерация», офис 41-08
пн–пт · 10:00–19:00 МСК
© 2026 Вега ТВ
vegatv.ru
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( );