Tube TV · v0.11
Интерактивная комната середины 90-х: ламповый телевизор в нише стенки, июньский свет, тюль на окне, жизнь квартиры вокруг. Сцена — готовые картинки; всё живое (экран, свет, дождь, звук, пасхалки, приставка) — слои поверх.
Чистые HTML/CSS/JS, без сборки. Сайт: https://havanbro-commits.github.io/RetroTV/
index.html разметка слоёв
style.css стили, подсказки, меню приставки, калибровка
main.js вся логика: раскладка, комната на WebGL, кинескоп, эфир, свет, дождь, звук, зоны, приставка
config.js ВСЁ, что настраивается: зоны, каналы, громкости, картриджи, тексты
sega.html приставка: эмулятор Mega Drive в рамке за кинескопом
assets/ сцены (день, закат, вечер, ночь, пасмурно, ливень), крупный план, карты света
assets/eggs/ вырезанные пасхалки и «чистые подложки» под ними
carts/ свои картриджи (исходники в carts/src)
sounds/ записанные звуки (см. sounds/README.md)
vendor/ejs/ EmulatorJS + Genesis Plus GX (см. vendor/ejs/README.md)
Запуск локально
Нужен любой локальный сервер (двойной клик по index.html не даст загрузить звуки и приставку):
python3 -m http.server 8000
Откройте http://localhost:8000.
Деплой
GitHub Pages: Settings → Pages → Deploy from a branch, ветка main, папка / (root).
Управление
| Действие | Как |
|---|
| Включить / выключить ТВ | кнопка внизу под динамиком |
| Переключить канал | клик по верхней ручке — мягкий щелчок тумблера; Shift+клик или правый клик — назад; колесо над ручкой |
| Громкость ТВ | колесо над нижней ручкой или потянуть её |
| День → закат → вечер → ночь | клик по торшеру |
| Ясно → морось → ливень | клик по окну |
| Закрыть / открыть окно | клик по тяжёлой шторе слева от тюля; колёсико — плавно |
| Приставка | клик по Sega на полу — меню картриджей |
| Другая комната | кнопка «Комната» / «Зал» вверху — вторая комната с теми же каналами, приставкой и погодой |
| Звук | кнопка в правом верхнем углу или M; ползунки «ТВ» и «Комната» |
| Сесть перед телевизором | кнопка вверху, S или двойной клик по экрану; Esc — встать |
| Калибровка | клавиша D |
Каналы
Массив channels в config.js, порядок = порядок переключения:
- Архив — заставки и передачи ТВ из Internet Archive, «прямой эфир»: включаетесь с того места, где передача идёт сейчас.
- Старое видео — VHS-записи и советская мультипликация из Internet Archive.
- Реклама и 4. ТВ СССР — ролики RuTube.
- Утро, 6. Тест (испытательная таблица), 7. Помехи.
Своего плеера чужих кнопок нет: файлы архива играют в <video>, кадры рисует шейдер кинескопа, звук идёт в «динамик» телевизора. RuTube — официальный плеер в «голом» режиме под стеклом; картинка открывается, только когда пошёл сам ролик. Если запись не отвечает, через 15–45 с включается следующая; сеть пропала — синий экран «НЕТ СИГНАЛА» и повтор через 30 с.
Типы каналов: archive (items: [{ id, file? , match? }]), video (свои файлы), rutube (items: [id]), morning, testcard, static.
Приставка
Клик по Sega на полу → меню картриджей. Три своих игры («Змейка», «Кирпичики», «Звёздный патруль») или «Свой картридж…» — любой файл .md / .bin / .gen / .smd / .zip (можно перетащить на страницу; файл не покидает браузер). Телевизор сам переключается на вход AV, камера садится перед экраном.
- Клавиатура: стрелки, A S D — кнопки A B C, Q W E — X Y Z, Enter — Start, Esc — меню.
- Геймпад (Xbox, PlayStation, 8BitDo и др.): подключите и нажмите кнопку. Второй геймпад — второй игрок; в «Звёздном патруле» — кооператив.
- Свои картриджи: «Моя библиотека» в меню — файлы или папка, хранятся в браузере.
- На телефоне и планшете — экранная крестовина и кнопки.
- Картинка идёт через тот же кинескоп, что и эфир (строки, кривизна, свечение на стене), звук — через динамик телевизора. Игра считается ровно 60 кадров в секунду на любом экране.
- Ручка каналов — обратно в эфир (игра на паузе, можно вернуться), «Выключить приставку» — в меню.
Звук
Записанные слои дождя, гром, собака, кухня — sounds/; остальное синтезируется Web Audio. Объёмный звук для наушников (HRTF): двор справа за окном, кухня сзади слева, телевизор впереди. Окно — модель пространства, а не фильтр (подробно — sounds/README.md).
Отладка
В консоли доступен TubeTV: TubeTV.Events.play('siren'), TubeTV.setMode('night'), TubeTV.setWeather('downpour'), TubeTV.TV.toggle(), TubeTV.Sega.openMenu().
Что нового в v0.11
- Библиотека картриджей: в меню приставки — «Добавить файлы…» и «Добавить папку…» (или перетащить на страницу). Файлы хранятся в браузере (IndexedDB), никуда не отправляются, список сохраняется между заходами. Коммерческих ROM в проекте по-прежнему нет — эмулятор (Genesis Plus GX) и так полный, библиотека — для ваших собственных образов.
- Два геймпада: первый подключённый — игрок 1, второй — игрок 2. Xbox 360/One и DualShock/DualSense в «стандартной» раскладке плюс запасные схемы для браузеров без неё (Linux, часть Firefox). Переключатель «Клавиатура — второй игрок».
- «Звёздный патруль» вдвоём: второй игрок нажимает Start на втором геймпаде — с титула или прямо посреди волны; у каждого свои корабли и жизни, очки общие, враги целятся в ближайшего.
Что нового в v0.10
- Вторая комната (кнопка «Комната» вверху, или
?room=bedroom): свои сцены (день, закат, вечер, ночь, пасмурно, ливень), свет экрана, дождь на окне, мигалка, приставка, фосфорный олень на тумбе. Карты глубины у неё пока нет — солнце не трассируется, сцены переключаются картинками. Выбор запоминается.
- Закат без «двойного» света: старое солнце снимается с мебели точнее, и расчётные пятна ложатся на чистое дерево; пасмурные сцены пересобраны.
- Архив: у каналов есть запасной источник (RuTube), если archive.org не отвечает; архив пробуется снова каждые 5 минут. Страница
check.html показывает, что именно не отвечает на вашей сети.
- Предметы на полках: записанные звуки (мишка-«рычун» с мехом и язычком, пьезо брик-гейма, пластик кубика, кассета на карандаше, музыкальная шкатулка, фарфор, хрусталь), без «ореола» при наведении — предмет чуть приподнимается, будто его тронули.
- Олени светятся как на референсе (зелёно-белый фосфор), ночь светлее. RTX убран.
- Мигалка проходит сквозь тюль: красный и синий свет ложатся на стены рисунком кружева и ползут по комнате, пока машина едет.
Что нового в v0.9
- Каналы без YouTube. Его интерфейс больше не может появиться — YouTube не используется вовсе. Первый канал — архив передач, второй — старое видео, дальше RuTube. Исправлена бесконечная «настройка»: у каждого ролика есть сторож, неработающие записи пропускаются.
- Новая комната (день и вечер от автора) и все сцены из неё: закат, вечер, ночь, пасмурно, ливень. Подробный крупный план для режима «сесть».
- Олени из фосфора в серванте среди хрусталя: днём копят свет, ночью еле заметно светятся. RTX — блики с дисперсией, каустики и отсветы экрана в хрустале; кнопка RTX включает и выключает.
- Ручки телевизора без странного свечения; переключение каналов — мягкий щелчок тумблера.
- Дождь заново: восемь записанных слоёв (шум двора, листва, лужи, водосток, стекло, отлив), капли и струйки на стекле с преломлением, молния освещает комнату, гром по расстоянию.
- Окно можно закрыть: улица переезжает в плоскость окна — через стекло проходит низ, растёт отзвук комнаты; капли по стеклу остаются.
- Собака и яичница — далеко во дворе и за стеной кухни, с реальными записями и отражениями.
- Приставка Sega с картриджами и геймпадом (см. выше).
- Убраны видик, радио, будильник, календарь и драже.
Что нового в v0.2
- Пасхалки двигаются в объёме. Каждый предмет вырезан из картинки, под ним лежит дорисованный фон, поэтому при движении нет «двойника». Пакетик встряхивается и поворачивается к свету, тамагочи крутится на цепочке, брик-гейм поднимается экраном к вам и на нём падают кирпичики, мишка качается как неваляшка, у кассеты крутятся катушки, чайник дребезжит.
- Кубик Рубика — настоящий 3D-куб из 27 кубиков: появляется на месте фото, поворачивает две грани и возвращается.
- Статуэтка вращается вокруг оси. WebGL-шейдер натягивает фото на поверхность вращения по силуэту статуэтки; бока и спина дорисовываются как фарфор с бликом и складками. Это иллюзия из одного снимка: с настоящей 3D-моделью (.glb) спина была бы точной.
- Тюль без шва. Волна ходит туда-обратно с плавным разворотом, петля больше не «перескакивает».
- Яичница слышна из кухни. Плотный треск масла, пропущенный через «стену» (срез верхов выше ~1,7 кГц), короткое эхо кухни, глухие стуки лопатки.
- «Сесть перед телевизором». Камера плавно наезжает, телевизор занимает ~80% экрана, края темнеют; экран перерисовывается в повышенном разрешении.
- Плейлисты на видео-каналах: новый ролик при каждом переключении, режимы по порядку / случайно / «живой эфир».
Вырезки в assets/eggs/ сделаны под текущие room-day.png и room-evening.png. Если перегенерируете сцену, их нужно вырезать заново.
Что нового в v0.3
- YouTube-каналы «Старого телевизора». Два канала в
channels играют случайные ролики из загрузок YouTube-каналов staroetv через официальный встраиваемый плеер (youtube-nocookie.com), с случайного места, как будто эфир шёл без вас. Громкость — с ручки телевизора. Плеер лежит «под стеклом»: строки развёртки, теневая маска, виньетка, отражение комнаты, мерцание; включение/выключение и помехи — общие для всех каналов. Полного шейдерного кинескопа здесь нет: браузер не отдаёт пиксели чужого плеера.
- Работает на GitHub Pages / Netlify / localhost. В превью на claude.ai встраивание чужих сайтов запрещено — там канал покажет «YouTube недоступен».
- Если владелец отключил встраивание ролика, плеер сам перескочит на следующий.
- Пасхалки без двойников. Подложки под предметами перерисованы алгоритмом восстановления текстуры (раньше там оставался размытый силуэт). Кубик вырезан целиком с боковой гранью. Подсветка наведения гаснет на время анимации.
- Ветер. Тюль дышит постоянно, а раз в 7–18 секунд приходит порыв: нарастает 1–2 с, держится, стихает 3–5 с; подол чуть приподнимается. Порывы слышны (гул и шелест в окне) и сносят пылинки. В дождь ветер сильнее. Всё настраивается в
wind.
- Пыль «как споры». Три слоя глубины, медленный дрейф во все стороны по вихревому полю, ярче в лучах света, ближние — крупным размытым боке. Количество —
light.spores.
- Мигалка сквозь тюль. Свет проходит через узор кружева (текстура из
curtain.png) и ложится на всю комнату, бежит по стене в обратную сторону, а на самом тюле — по ходу машины. Машины реже: не чаще раза в 5 минут гарантированно, иначе по весу.
- Закат — третий режим торшера (своя картинка, стрижи, свет теплее).
- Погода по клику на окно: ясно → морось → ливень. Пасмурная сцена, капли за стеклом, звуки дождя, капли по отливу, водосток, в ливень — молнии и гром.
- Яичница — ваши два файла, случайно, через «стену» кухни (
audio.kitchenCutoff).
- Далёкая собака во дворе — редко, с эхом между домами.
- Чёткий телевизор в режиме «сесть». Корпус и ниша увеличены нейросетью Real-ESRGAN ×4 (
assets/hires/) и подгружаются при наезде.
Картинки room-sunset.png и room-overcast.png собраны цветокоррекцией из ваших дневной и вечерней. Если сгенерируете свои с той же композицией — просто замените файлы (и при желании пересоберу вырезки пасхалок и assets/hires/).
Что нового в v0.4
- Форточка вместо ползунка «фон». Клик по тяжёлой шторе: закрыта → приоткрыта → открыта (колёсико — плавно). Улица и события снаружи становятся тише и глуше, а закрытая форточка ещё и почти останавливает ветер в тюле. Тон комнаты, кухня и часы от форточки не зависят. Уровень запоминается в браузере. Общий уровень фона стал ниже. Настройки —
audio.windowLevels.
- YouTube почти без «кинескопа»: накладки на 10% (
embed.crt), плеер рендерится крупно (1280 px) и уменьшается, поэтому YouTube выбирает высокое качество и в режиме «сесть» картинка чёткая.
- Надписи YouTube спрятаны: пока ролик стартует, буферизуется или стоит на паузе, экран показывает снег и «НАСТРОЙКА…»; картинка открывается через ~3 с после старта, когда YouTube убирает название и логотип (
embed.revealDelayMs). Края кадра срезаны «оверсканом», как у настоящего кинескопа (embed.overscan).
- Субтитры выключены (
embed.captions: false, язык интерфейса плеера — русский).
- Исправлено: плеер YouTube не запускался из-за пустого ID ролика (v0.3.2).
Что нового в v0.5
Видео Luma использовано как референс (сам ролик в проект не входит):
- Закат, морось и ливень перекрашены по распределению света из референса: насыщенный оранжевый закат с полосами света; морось — серо-синяя комната; ливень — отдельная, более тёмная сцена
room-storm.png. Пасхалки и чёткая версия телевизора пересобраны под новые картинки.
- Порыв ветра: подол тюля выгибается внутрь комнаты и заходит на тяжёлую штору, верх на карнизе неподвижен; в этот момент в комнату врывается полоса света (днём тёплая, на закате оранжевая, в дождь — холодная и слабая). Сила —
wind.billow, яркость — light.scenes.*.gust.
- Капли на стекле: бусины дождя на окне, которые срываются и стекают, оставляя след; в ливень их больше.
Что нового в v0.6
- YouTube снова играет (v0.5.1): плеер больше не прячется прозрачностью — Chrome и Safari не запускают «невидимое» видео; надписи закрывает непрозрачная заглушка.
- Комната рендерится на WebGL. Дневная фотография разложена на саму комнату и карту солнечных пятен (
assets/sunmap.webp). При переключении торшера день → закат солнце садится на глазах (≈7 с): лучи поворачиваются и вытягиваются вокруг окна, поднимаются по шкафу, свет краснеет, тени густеют. Закат → вечер — солнце гаснет, загорается торшер. Параметры — sun в config.js.
- Тюль в шейдере: бегущие складки с подсветкой по наклону ткани, порыв мягко уводит подол в комнату без швов и «вырезанных кусков» (
wind.billowPx).
- Дождь заново: струи видны сквозь тюль там, где через него идёт свет, косые на ветру; капли на стекле; свет из окна «дышит» от облаков; в ливень — молнии.
- Микшер «ТВ / Комната» в правом верхнем углу (запоминается), яичница тише; форточка по-прежнему регулирует улицу.
- Картинки сцен в WebP — страница грузится в несколько раз быстрее.
- Если WebGL недоступен, сайт автоматически работает по-старому, на картинках.
Что нового в v0.7
- Пасхалки снова отвечают всегда. С v0.5 торшер переключает три режима (день → закат → вечер), а статуэтка и сервиз по-прежнему «спали» везде, кроме вечера, — после первого щелчка торшера (закат) они не реагировали. Теперь все предметы активны в любом режиме.
- Статуэтка при повороте больше не превращается в белый силуэт: обратная сторона строится из той же фигурки (цвета волос, платья, корзинки на местах), профиль хранится с 16-битной точностью — без полос.
- Объём у плоских предметов: пакетик, тамагочи, брик-гейм, кассета, мишка получили толщину — при наклоне видно ребро.
- Радиоточка на телевизоре: три программы («Первая», «Маяк», «Юность») — записи старых передач из Internet Archive, случайное место эфира. Щелчок — следующая программа, колёсико или ползунок «Радио» — громкость.
- Объёмный звук для наушников (HRTF): двор — справа за окном, кухня — сзади слева через коридор, телевизор впереди (и ближе, когда сидишь), радио — в нише. Тёплый «ламповый» мастер и отзвук комнаты. Кнопка с наушниками — переключить на обычное стерео для колонок.
- Быстрее: картинки сцен и предметов грузятся по мере надобности, кадры не чаще 60 в секунду, тюль в покое — 30 кадров, плёночное зерно вдвое легче, шрифты не задерживают первый показ.
Источники радио: Radio USSR, Soviet Radio, News And Music 1976 — Internet Archive, проигрываются напрямую с archive.org.
v0.7.1 — проверка и исправления
- YouTube: если переключить канал, пока ролик ещё грузится, его звук больше не играет поверх другого канала; канал «Архив» не подхватывает чужой плейлист.
- Кинескоп на iPhone: шейдер считает время по кругу и в повышенной точности — после получаса картинка не чернеет.
- Если iOS отберёт WebGL (нехватка памяти, сворачивание), комната тихо переходит на картинки, а не становится чёрной.
- Объёмный звук: короткие звуки (капли, птицы, щелчки) садятся в общие «точки» вокруг слушателя — узлы больше не копятся (было ~350 за минуту, стало ~40 всего); эхо кухни больше не нарастает.
- Радио: запуск прямо в щелчке (требование Safari), понятная просьба «щёлкните ещё раз», если браузер не дал включить звук; запасной режим без CORS и выключение звука работают и на iPhone.
Что нового в v0.8
- Закат считается физически. У каждого пикселя комнаты есть точка в пространстве (карта плоскостей
assets/geo.png + камера). Луч из неё идёт к солнцу, проходит балконный блок в правой стене (рамы и перемычки дают косые полосы), тюль (кружево из фото curtain.png, полутень растёт с расстоянием — диск солнца и рассеяние в нитях), крону во дворе (пятнышки-«солнечные зайчики»). Цвет и сила — по воздушной массе: чем ниже солнце, тем краснее и слабее. Солнце опускается — пятна ползут вверх по стенке, лучи становятся положе; в режиме «закат» оно продолжает медленно садиться. Лучи в воздухе — объёмный проход по лучу камеры. Порыв ветра колышет тюль — пятна шевелятся вместе с ним.
- Ночь (четвёртый щелчок торшера): торшер погашен, синева из окна, натриевый фонарь во дворе светит снизу сквозь тюль (тот же расчёт), комнату освещает телевизор. Свой звук: редкие сверчки, далёкий поезд.
- Статуэтка — настоящая 3D-модель (поле расстояний, трассировка лучей): юбка колоколом со складками и оборкой, фартук, рукава-фонарики, капор, корзинка с цветами, мягкие тени и блик глазури; лицевая сторона расписана самим фото.
- Будильник на телевизоре — настоящее время, тикает, звенит по щелчку. Отрывной календарик в нише — сегодняшнее число 1995 года с восходом и заходом, листок отрывается.
- Видеомагнитофон «Луч» под телевизором — корпус встроен в саму сцену (его освещает тот же свет), табло с часами; щелчок — кассета въезжает, телевизор переключается на «ВИДЕО» с дрожанием и полосой трекинга. Без кассеты — синий экран AV.
- Пачка фруктового драже вместо размытой упаковки — своя, нарисованная кодом, в свете каждой сцены; при встряхивании подпрыгивают конфетки.
- YouTube без кнопок: экран открывается только когда плеер спрятал свои надписи, «закрывается» мгновенно, за 22 секунды до конца ролика — переход на следующий (там YouTube показывает подсказки), кадр шире заходит за края.
- Превью ссылки для Telegram/WhatsApp (
assets/og.jpg), значок сайта, заставка «кинескоп включается» при загрузке.
- На закате пасхалки берутся «из кадра», а под ними сцена дорисовывает комнату без них — никаких застывших прямоугольников.