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:
@@ -1,6 +1,9 @@
|
||||
import { songs } from '../audio/songs';
|
||||
import type { MusicTrack, SoundId } from '../audio/types';
|
||||
|
||||
/**
|
||||
* Central registry of every graphic the game uses. Replace the files in /public/assets
|
||||
* (or point these paths elsewhere) to change the look without touching components.
|
||||
* Central registry of every graphic and sound the game uses. Replace the files in /public/assets
|
||||
* (or point these paths elsewhere) to change the look and sound without touching components.
|
||||
*/
|
||||
|
||||
/** Resolves a file in /public relative to where the site is served (works under sub-paths). */
|
||||
@@ -62,8 +65,26 @@ export const uiAssets = {
|
||||
/** Optional logo image. When null the text logo is rendered. */
|
||||
logo: null as string | null,
|
||||
favicon: asset('assets/favicon.svg'),
|
||||
soundOn: asset('assets/ui/sound_on.svg'),
|
||||
soundOff: asset('assets/ui/sound_off.svg'),
|
||||
};
|
||||
|
||||
/**
|
||||
* Optional audio files that replace the synthesized sound effects. Put the files in
|
||||
* /public/assets/sounds/. Effects without an entry (or whose file fails to load) use the synth.
|
||||
*/
|
||||
export const soundFiles: Partial<Record<SoundId, string>> = {
|
||||
// lineClear: asset('assets/sounds/line_clear.wav'),
|
||||
};
|
||||
|
||||
/** Background music, played as a shuffled playlist during matches. Add as many tracks as you like. */
|
||||
export const musicTracks: MusicTrack[] = [
|
||||
{ id: 'pixel_rush', title: 'Pixel Rush', kind: 'synth', song: songs.pixelRush },
|
||||
{ id: 'neon_stack', title: 'Neon Stack', kind: 'synth', song: songs.neonStack },
|
||||
{ id: 'last_line', title: 'Last Line', kind: 'synth', song: songs.lastLine },
|
||||
// { id: 'my_track', title: 'My Track', kind: 'file', src: asset('assets/sounds/music/my_track.mp3') },
|
||||
];
|
||||
|
||||
export function itemVisual(id: string): ItemVisual {
|
||||
return itemVisuals[id] ?? unknownItem;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user