Назад

Аркада в гостиной

Ретро-аркада с картриджами, в которую действительно можно играть в браузере: облетите 3D-стол с консолью, ЭЛТ-монитором и геймпадом, включите питание, чтобы попасть в библиотеку картриджей, и выберите Snake, Breakout или Blocks — три оригинальные мини-игры без установки и сохранений, лишь один свободный день и ещё один раунд.

Автор: Theodore
Попробовать онлайн
Аркада в гостинойПопробовать онлайн

О проекте

Playroom — это аркада из гостиной, работающая в браузере. Страница открывается на игровом столе в стиле 1989 года — ЭЛТ-монитор, консоль, геймпад и уже вставленный картридж Snake, — который можно вращать и разглядывать; клик по консоли или POWER ON наезжает камерой на экран, проводит её сквозь трубку и приземляет в библиотеке из трёх картриджей.

Все три игры — оригиналы Playroom: Snake — про цепочки укусов в ритме, Breakout приносит три уровня кирпичей и бонусы, а Blocks делает укладку предсказуемой благодаря призраку приземления и мешкам по семь фигур. Ни аккаунта, ни обновлений, ни сохранений — рекорды остаются в вашем браузере, а музыка и эффекты выключаются одной кнопкой.

Весь проект зависит только от Three.js и Vite — без бэкенда и переменных окружения; шесть GLB-моделей оборудования и одна декаль с лицевым знаком Tripo — вот и весь список ассетов. Когда WebGL недоступен, управление берёт текстовое меню, и игры остаются полностью играбельными.

Ключевые моменты

  1. Перетаскивайте, чтобы облететь всю гостиную — ЭЛТ-монитор, консоль, геймпад и картридж, — затем нажмите на консоль или POWER ON: камера наезжает на экран и проходит сквозь ЭЛТ в библиотеку картриджей.
  2. Три картриджа, три оригинальные игры: Snake — цепочка 5× за пять секунд и золотой фрукт на 50 очков; Breakout — три уровня кирпичей и бонусы W (широкая ракетка) и 3 (тройной мяч); Blocks — мешки по семь фигур, призрак приземления и бонусы за комбо.
  3. Стрелки / WASD и пробел на компьютере, P — пауза, ESC — выход, сенсорное управление на мобильных; рекорды хранятся только в вашем собственном браузере.
  4. У каждой игры свой чиптюн-луп и звуковые сигналы, а в меню звучит трек «Trip Of Your Smile» (CC BY 4.0); если WebGL недоступен, аркада переключается на текстовые кнопки и остаётся играбельной.

Технический разбор

  • 3D-ассеты · Шесть GLB-моделей оборудования, перепривязываемых во время выполнения

    ЭЛТ-монитор, консоль, геймпад и три картриджа поставляются в виде шести GLB-файлов (экспортированы через GLTFExporter из Three.js, низкополигональные — по 128–384 треугольника). GLTFLoader загружает их параллельно, и каждый экземпляр — глубокий клон: смещения центрирования, оставшиеся от экспорта, обнуляются, материалы клонируются для каждого экземпляра, а каждый меш отбрасывает и принимает тени. Пластина этикетки картриджа находится по экспортированному локальному смещению, получает имя cartridge-label и перепривязывается к текстуре обложки, нарисованной в Canvas; пиксельный маскот собирается из именованных узлов — mascot-body, обе руки, антенна и декаль логотипа с лицевым знаком Tripo, у которой отключены тональная компрессия и запись глубины, чтобы плоская декаль оставалась чёткой.

    Слой ассетов также оставляет слот для замены: укажите в поле controller файла public/models/manifest.json любой GLB — и fitProp по ограничивающему параллелепипеду отмасштабирует его до 2,54 единицы в ширину, поставит на пол, отцентрирует и займёт позицию исходного геймпада. Собственный (например, сгенерированный в Tripo) геймпад встаёт на место без единой строчки кода.

  • Экран и этикетки · Canvas-текстуры вместо интерфейса

    Сцена не загружает ни одной внешней текстуры. Экран ЭЛТ — это CanvasTexture 1024×700: заставка (PLAYROOM SYSTEM / PLAYER ONE / PRESS START) рисуется кадр за кадром на 2D-контексте и используется одновременно как map и emissiveMap, чтобы трубка светилась. Обложка каждого картриджа — отдельный холст 640×610, который рисуется на лету по цвету, оттенку «чернил», номеру и слогану игры из каталога — вместе с пиксель-артом и надписью заголовка.

    При включении контроллер жизненного цикла экрана подменяет материал текстурой потока данных, пока камера по сферической траектории вокруг центра экрана возвращается к передней стороне трубки, наезжает и в момент прохода сквозь стекло переключается на библиотеку; при prefers-reduced-motion всё движение пропускается в пользу мгновенного переключения.

  • Взаимодействие · Жесты указателя, выбор рейкастом и кинематографичная орбита

    В виде стола одна и та же последовательность указателя — это и перетаскивание орбиты, и клик: контроллер жестов запоминает theta / phi при нажатии, движение больше порога считает перетаскиванием, всё остальное — кликом. Попадания определяются Raycaster: на столе вся установка работает как кнопка питания, в библиотеке попадание поднимается по цепочке родителей до узла с gameId. При отпускании орбита никогда не замирает на месте — кинематографичный контроллер плавно возвращает ручное смещение в медленное автоматическое покачивание.

    Наведение или фокус на картридж поднимает его на 0,24, наклоняет вперёд с лёгким креном и переключает пиксельного маскота в позу этой игры, а каждый картридж покачивается в собственной фазе синусоиды. Все интерполяции в цикле рендеринга используют не зависящее от частоты кадров сглаживание 1 − e^(−5·dt), поэтому медленные кадры никогда не дают скачков.

  • Игры и звук · Автономные 2D-сессии и синтезированный звук

    Три игры — чистые логические модули (create / step / input); слой сессии рисует их на отдельном 2D-холсте — 480×480 для Snake и Breakout, 300×540 для Blocks. requestAnimationFrame планируется только во время игры, так что пауза буквально останавливает кадры, а потолок 250 мс на шаг исключает «туннелирование» после переключения вкладки. Игровые события (съедено, кирпич, линия, бонус, уровень) питают слой частиц и по приоритету сворачиваются в один звуковой сигнал.

    Весь звук синтезируется вживую осцилляторами Web Audio: 16-шаговая чиптюн-мелодия на каждую игру (82–120 BPM) и два десятка сигналов из частотных глиссандо и огибающих, не более 64 голосов одновременно. Трек меню — запись под лицензией CC BY 4.0, при неудачной загрузке заменяемая синтезированным лупом; при скрытой вкладке звук отключается, а аудиоконтекст разблокируется только после первого клика. Рекорды сохраняются в localStorage, а при отказе хранилища — в памяти: неудачное сохранение никогда не прерывает игру.