Audio System
Система звуковых эффектов для TMA. Singleton AudioManager с предзагрузкой и интеграцией в settingsStore.
Цель: Мгновенное воспроизведение звуков без задержек, глобальное управление через настройки.
1. Summary
Goal: Обеспечить тактильную обратную связь через звуковые эффекты при ключевых действиях пользователя (получение наград, открытие кейсов, повышение уровня).
Architecture:
- AudioManager — Singleton, предзагружает все звуки при первом взаимодействии
- useAudio — React hook для удобного использования в компонентах
- settingsStore — глобальный toggle звука (синхронизируется с backend)
2. Sound Library
| Имя | Файл | Когда использовать | Длительность |
|---|---|---|---|
scrap | scrap.mp3 | Получение Scrap | ~2 сек |
xp | xp.mp3 | Получение XP | ~2 сек |
lvlup | lvlup.mp3 | Повышение уровня | ~2 сек |
opencase | opencase.mp3 | Открытие кейса (анимация) | ~9 сек |
prizecase | prizecase.mp3 | Выигрыш из кейса / рулетки | ~1.5 сек |
takereward | takereward.mp3 | Клик при сборе награды | ~0.2 сек |
spin | spin.mp3 | Вращение колеса удачи | ~3 сек |
Расположение файлов: frontend/public/sounds/
Требования к звукам:
- Формат: MP3 128kbps
- Длительность: 0.2-9 сек (зависит от use case)
- Размер: < 50 KB (короткие эффекты)
3. Usage
Через хук (рекомендуется для компонентов)
import { useAudio } from '../hooks/useAudio';
const MyComponent = () => {
const { play } = useAudio();
const handleClaim = () => {
play('scrap');
};
return <button onClick={handleClaim}>Забрать</button>;
};
Напрямую через AudioManager (для non-React кода)
import { audioManager } from '../utils/AudioManager';
audioManager.play('opencase');
audioManager.play('prizecase', { volume: 0.7 });
- useAudio — внутри React компонентов (HomeScreen, RaffleModal и т.д.)
- audioManager — в анимациях, таймерах, callback-ах вне React lifecycle (CaseOpening, DailySpinScreen)
4. API
useAudio Hook
const { play, toggleMute, setVolume, status } = useAudio();
| Метод | Параметры | Описание |
|---|---|---|
play(name, config?) | name: SoundName, config?: { volume, loop } | Воспроизвести звук |
toggleMute() | — | Переключить звук вкл/выкл (через settingsStore) |
setVolume(volume) | volume: number (0-1) | Установить глобальную громкость |
| Поле status | Тип | Описание |
|---|---|---|
isEnabled | boolean | Звук включён (из settingsStore) |
isMuted | boolean | Звук выключен (инверсия isEnabled) |
volume | number | Текущая глобальная громкость (0-1) |
loadedSounds | number | Количество загруженных звуков |
AudioManager (Singleton)
| Метод | Возврат | Описание |
|---|---|---|
play(name, config?) | HTMLAudioElement | null | Воспроизвести (null если звук выключен) |
stopAll() | void | Остановить все звуки |
setVolume(volume) | void | Глобальная громкость (0-1) |
getDuration(name) | number | Длительность в ms (из метаданных файла) |
getStatus() | object | { isEnabled, isMuted, volume, loadedSounds, initialized } |
destroy() | void | Cleanup (отписка от store, очистка ресурсов) |
audioManager.toggleMute() помечен как deprecated. Используй settingsStore.toggleSound() или useAudio().toggleMute().
5. Architecture
Инициализация
User Interaction (click/touch)
↓
AudioManager.init()
↓
┌─────────────────────────────┐
│ 1. Subscribe to settingsStore│
│ 2. Preload all 7 sounds │
│ 3. Save durations from metadata│
└─────────────────────────────┘
AudioManager инициализируется lazy — при первом click или touchstart пользователя. Это обходит ограничения браузеров на autoplay.
Воспроизведение
play('scrap')
↓
┌─────────────────────────┐
│ 1. Check settingsStore │──→ sound=false → return null
│ 2. Find preloaded sound │──→ not found → return null
│ 3. Stop previous (same) │
│ 4. Clone HTMLAudioElement│
│ 5. Set volume + loop │
│ 6. Play clone │
│ 7. Auto-cleanup on end │
└─────────────────────────┘
Клонирование: Каждое воспроизведение создаёт clone от оригинала. Это позволяет:
- Воспроизводить один звук несколько раз подряд
- Не ждать окончания предыдущего
- Автоматически удалять clone после окончания
Интеграция с settingsStore
settingsStore.toggleSound()
↓
Zustand state: sound = false
↓
┌──────────────────────────┐
│ settingsStore subscriber │
│ → audioManager.setEnabled(false)│
│ → audioManager.stopAll() │
└──────────────────────────┘
↓
Debounced sync to Backend (500ms)
↓
Zustand persist to localStorage
6. Добавление нового звука
1. Добавь файл
Положи MP3 в frontend/public/sounds/my-sound.mp3
2. Зарегистрируй в AudioManager
В frontend/src/utils/AudioManager.ts:
// 1. Добавь в SoundName type
type SoundName =
| 'scrap'
// ...
| 'my-sound'; // Новый звук
// 2. Добавь путь в soundPaths
private soundPaths: Record<SoundName, string> = {
// ...
'my-sound': '/sounds/my-sound.mp3',
};
3. Используй в компоненте
const { play } = useAudio();
play('my-sound');
4. Обнови эту документацию
Добавь новый звук в таблицу Sound Library (секция 2).
7. Файлы системы
| Файл | Назначение |
|---|---|
frontend/public/sounds/*.mp3 | Звуковые файлы |
frontend/src/utils/AudioManager.ts | Singleton менеджер (preload, play, volume) |
frontend/src/hooks/useAudio.ts | React hook для компонентов |
frontend/src/stores/settingsStore.ts | Хранение toggle звука (sound: boolean) |
Related
- Animation System — визуальные анимации
- Client-Side Storage — хранение настройки sound в localStorage
- Design Principles — UI/UX принципы