Two Web Audio synthesised tones, no asset shipping required:
- playToneJoin: C5 -> E5 ascending major-third chime (~340ms total),
fires on every peer-joined. Server broadcasts peer-joined to
everyone except the joiner via broadcastExcept, so existing members
always hear it for new arrivals only.
- playToneRaise: single A5 triangle blip (~260ms), fires on
hand-raised UNLESS it's the raiser's own hand (server broadcasts
hand-raised to all so we filter on m.uuid !== myUUID).
Tones share a lazily-instantiated AudioContext (the user already
gestured to enter the room, autoplay policy is satisfied). Skipped
when document.hidden so background tabs stay quiet. Short
exponential attack + decay envelope avoids click artifacts.