Have more questions? Join our Discord

Sounds

A game's React frontend can play uploaded music and sound effects. You say at each play whether a sound is music or an effect, and each player decides, for every game or for one match, which of the two they hear.

Quick answers

Question Answer
What formats can I upload? MP3, WAV, OGG and M4A. Detected from the bytes; renaming a file does not help.
Max size? 10 MB per file.
Which plan can upload sounds? Designer or Professional. Every player hears a game's sounds whatever their plan.
Where do I upload? upload_sound, or Upload sounds in the studio's Sounds view.
How do I play one? useSounds().play(GameSound.Key, { type: "effect" }) from your frontend.
Music or effect? "music" for a soundtrack or ambient loop, "effect" for a sound that answers an action.
Do sounds load with the game? No. A sound is fetched the first time you play it.
Do sounds count against the 1024 KB bundle? No. They are fetched by URL.
Why is there no sound before the first click? Browsers hold sound until the player presses or types in the game. See Autoplay.
Can I synthesize sound with Web Audio? It runs, but the player's settings cannot reach it. Upload a file instead.

Uploading

Formats MP3, WAV, OGG or M4A, read from the bytes. The file is stored unchanged.
Size 10 MB per file.
Key UpperCamelCase ASCII alphanumerics: ^[A-Z][A-Za-z0-9]*$. The key becomes a GameSound member.
State An upload is a pending worktree change. The studio preview plays it at once; commit makes it permanent.
Plan Uploading needs the Designer or Professional plan, else PLAN_REQUIRED.

Sounds live at /sounds/<Key>. Upload the same key again to replace a sound. Rename with rename_file from /sounds/<Key> to /sounds/<NewKey>, and delete with delete_file; in both cases update every GameSound.<Key> reference. A sound and an image may share a key: they are different enums.

Most sound files are too large to pass inline through upload_sound. For a file on disk, call generate_api_token and curl it to the uploadSound endpoint it returns. For a file already online, pass its public https URL as sound.url. Keep inline sound.data for effects of a few KB.

Playing sounds

useSounds() returns the game's sound player. It is stable for the whole match.

import { useEffect } from "react";
import { GameSound } from "boardweaver";
import { useMatch, useSounds } from "boardweaver/react";

export default function App() {
  const match = useMatch();
  const sounds = useSounds();

  useEffect(() => {
    const theme = sounds.play(GameSound.ThemeLoop, { type: "music", loop: true });
    return () => theme.stop();
  }, [sounds]);

  return (
    <button
      onClick={() => {
        sounds.play(GameSound.DiceRoll, { type: "effect" });
        match.click({ type: "Click", buttonId: "roll" });
      }}
    >
      Roll
    </button>
  );
}
Call Does
sounds.play(key, { type, loop?, volume? }) Plays the sound and returns { stop() }. Throws on a key that is not one of the game's sounds.
sounds.stopAll(type?) Stops every playing sound, or every playing sound of one type.
Option Meaning
type Required. "music" or "effect": which of the player's settings governs it.
loop Start again at the end. Defaults to false.
volume 0 to 1, default 1. Best effort: iOS Safari ignores it and plays at full volume.

Start music in an effect hook and stop it in the cleanup, as above, so it ends when the component does. Play an effect in the handler for the action it answers. To make a sound follow other players' moves, play it from an effect on useLastChange (see react-match-api).

What the player hears

Each player has two account settings, music and sound effects, and can override either one for a single match from the sound menu at the table. You do not read or apply them: the player does it for you.

  • An effect played while the player has effects off does nothing. It is not even loaded.
  • Music played while music is off plays muted, so when the player turns music back on it is at the right place in the track.
  • A change takes effect at once on everything that is playing.

useAudioSettings() returns { music, effects } as the player has them right now. Read it only to show the player's choice in your own UI; useSounds already applies it.

Autoplay

Browsers do not play sound until the person has pressed or typed in the page. If your game starts music on load, the player begins the match in silence and the music starts at their first press in the game. An effect played before that first press is dropped, because the moment it belonged to has passed.

Web Audio

AudioContext and oscillators still run in the frame, which is how some games make 8-bit sound. The player's music and effect settings cannot reach a sound you synthesize, so a player who turned sound off still hears it. Upload a short file and play it with useSounds instead.