У opolyx появился голос: звуки и кнопка отключения
Игра была абсолютно беззвучной. Теперь звучат кубики, фишки, деньги, таймер аукциона и финальный аккорд победы — и всё это выключается одной кнопкой.

Простыми словами
До этого обновления opolyx не издавала ни звука. Не «тихая игра», а буквально беззвучная: во всём приложении не было ни одного аудиофайла. Выпавшая шестёрка и банкротство ощущались одинаково.
Теперь важные моменты слышны. Ничего не играет по кругу и ничего не звучит фоном — каждый звук привязан к тому, что только что произошло на поле:
- кубики в момент нажатия «Бросить» — и ещё раз, когда они замирают на своих числах;
- ваша фишка: по шагу на каждую клетку, пока она идёт по полю;
- движение денег: аренда, налог, покупка поля, строительство;
- таймер аукциона в последние пять секунд вашей ставки;
- барабан Джекпота и финальный аккорд победы или поражения.
Звук включён по умолчанию. Если вам удобнее играть в тишине, кнопка с динамиком в верхней панели выключает всё одним нажатием, а выбор запоминается на этом устройстве — это первая настройка, которую opolyx вообще для вас сохраняет.
Клипы, которые мы публикуем в YouTube, Instagram и TikTok, тоже были беззвучными. Теперь в них те же звуки, что и в игре, — банкротство в клипе звучит так же, как банкротство за столом.
Для тех, кому интересны детали
Воспроизведение построено на Web Audio, а не на отдельном аудиоэлементе под каждый звук. Декодированные буферы дают полифонию (приземление кубиков поверх шага фишки), точное по сэмплам планирование и укладываются в действующую политику безопасности контента — все файлы отдаются с нашего собственного домена.
Какой звук соответствует какому событию, определяет исчерпывающий switch по объединению событий движка: добавление нового доменного события ломает проверку типов до тех пор, пока кто-нибудь не решит, должно ли оно звучать:
// lib/sound/events.ts — exhaustive over DomainEvent['kind']
export function soundForEvent(e: DomainEvent, viewerSlot: number | null): SoundId | null {
switch (e.kind) {
case 'rent_paid':
return e.payload.amount >= BIG_RENT ? 'cash-big' : 'cash';
case 'player_bankrupt':
return 'bankrupt';
// …every kind handled; no default, so a new event is a type error
}
}Четыре звука привязаны не к событию, а ко времени, потому что момент прихода серверного события — не тот момент, когда игрок воспринимает действие. Бросок звучит в момент клика (0 мс), приземление — по окончании укладки 3D-кубиков, шаг — на каждую клетку в очереди прыжков фишки, а победа и поражение — при появлении экрана результатов.
| Звук | Срабатывает по |
|---|---|
| dice-roll | клику, а не ответу сервера |
| dice-land | окончанию анимации укладки 3D-кубиков |
| move-step | каждой клетке в очереди прыжков фишки |
| tick | последним 5 секундам вашего хода или ставки |
| victory / defeat | появлению экрана результатов |
Все 26 файлов — CC0: обрезаны, нормализованы по пику до −3 dBFS и закодированы в моно-MP3. Именно MP3, а не Ogg, потому что Safari на iOS не умеет декодировать Ogg Vorbis. Скрипт сборки проверяет пик уже после кодирования: более ранняя версия выпускала файлы правильной длительности и правильного размера, в которых не было слышно ничего, — фильтр затухания заглушал всё, что выходило за его окно.
