Skip to content

Add sound to a game

The fastest path to audio in a FreeGameStore game.

1. The setup is already done

If you scaffolded with npx fgs init, your App.tsx already wraps your game in <GameShell> and your topbar already shows the mute button. That’s everything the audio system needs.

2. Call useGameSounds from your game

web/src/components/Game.tsx
import { useGameSounds } from '@freegamestore/games';
export function Game() {
const sounds = useGameSounds();
function onPlayerMove() {
sounds.playMove();
}
function onPointScored() {
sounds.playScore();
}
function onLifeLost() {
sounds.playError();
}
function onGameOver() {
sounds.playGameOver();
}
// ...
}

That’s it. The mute toggle in the topbar already controls everything.

3. Pick from the 8 sounds

FunctionWhen
playMovePiece moves, card flips, button presses
playScorePoint scored, match found, correct answer
playErrorWrong answer, hit, lose a life
playGameOverGame ends
playLevelUpBeat a level, unlock an achievement
playDropBlock lands, weight drops
playClearLine clears, combo, sweep
playTickTimer warning, countdown

Full reference: useGameSounds.

What you don’t need to do

  • Wire mute state. The topbar reads useSound(). useGameSounds() reads useSound(). Same state — toggling the icon mutes everything.
  • Defer audio context creation. useGameSounds creates it lazily on the first non-muted call, so the browser’s autoplay policy is satisfied (a user gesture has already happened — they tapped the unmute icon).
  • Ship audio files. All 8 sounds are synthesized.

When you need more than the 8

  • A custom timbre? Use useSound and write your own oscillator inside a hook — mirror the structure of useGameSounds.ts.
  • An actual audio sample (a voice clip, a snare drum)? Follow Custom audio that respects mute.
  • Background music? Strongly discouraged. The catalog is muted-by-default and music auto-play would have to wait on user gesture anyway. If you really need it, gate it on useSound().muted like everything else, and expect the compliance check to scrutinize it.

Common mistakes

  • Calling useGameSounds() in App.tsx above <GameShell> — the returned functions silently no-op because they read a default-muted context. Call them from <Game> or anywhere inside the shell.
  • Bypassing useGameSounds and using new Audio() directly — the compliance suite blocks this. See why.