Add sound effects, background music and a sound menu
Generate retro sound effects and music in the browser with the Web Audio API, so no audio files are needed. Any sound can still be replaced by a file. Audio (src/audio/): - 16 effects (move, rotate, hold, hard drop, lock, line clears, garbage, items, countdown, knockout, win/lose), triggered by comparing match snapshots, so the server is unchanged - Background music as a shuffled playlist of any number of tracks, either synth songs or audio files; 3 original songs included, tempo rises with the level - SoundPlayer interface, so the audio engine can be replaced - Audio files and music tracks are registered in theme/assets.ts (soundFiles, musicTracks) - All volume levels for developers are in config/sound.ts (master, sfx, music, per effect, per track, default slider positions) UI: - Speaker button fixed in the top right corner of every screen; opens an inline strip with a mute button and volume slider for SFX and music that doesn't cover the boards or pause the game - Leave button below it in the lobby and the game; in a running match it asks for a second click because leaving gives up the match - Lobby Music panel to switch single tracks on or off - Keys: M all sound on/off, B music on/off, N next track - Settings are saved in localStorage Docs: audio section in frontend.md, sound and music guide in extending.md, new keys in game-rules.md and the README.
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
import { useSound } from '../audio/SoundContext';
|
||||
import { musicTracks } from '../theme/assets';
|
||||
import styles from './MusicTracks.module.css';
|
||||
|
||||
/** One checkbox per registered music track; unchecked tracks are skipped by the playlist. */
|
||||
export function MusicTracks() {
|
||||
const { settings, setSettings } = useSound();
|
||||
|
||||
const toggleTrack = (id: string, enabled: boolean) =>
|
||||
setSettings({
|
||||
disabledTracks: enabled ? settings.disabledTracks.filter((t) => t !== id) : [...settings.disabledTracks, id],
|
||||
});
|
||||
|
||||
return (
|
||||
<ul className={styles.tracks}>
|
||||
{musicTracks.map((track) => (
|
||||
<li key={track.id}>
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={!settings.disabledTracks.includes(track.id)}
|
||||
onChange={(e) => toggleTrack(track.id, e.target.checked)}
|
||||
/>
|
||||
{track.title}
|
||||
</label>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user