Upload your own sound effects, at all three layers

Featurekamo-internal
Shipped
August 15, 2026 at 12:35 AM UTC
Author
kamo
Commit
49251c8

The system could only ever play the thirty-nine tones it shipped with. Now any layer can add its own file — the platform's catalogue, an organization's, a member's — and assign it to any event exactly like a built-in tone. ONE ID SPACE. An assigned sound is a single string, `custom:<uuid>` for an upload and a tone id otherwise, so the three layers merge it the same way and only the player has to know the difference. Custom ids are accepted on SHAPE, not on existence: the library loads asynchronously, and rejecting them until it lands would flip every assigned upload to the platform default for the first second of every page load — which reads as the setting having been lost. A genuinely retired sound fails softly at play time and falls back to the layer beneath. PLAYING HAS TO BE SYNCHRONOUS TO BE ON TIME. An event that awaits a fetch before making a noise arrives after the thing it was announcing, so the first play of an undecoded upload is silent by construction. The provider therefore primes the decode from the resolved settings — by the time a message arrives, the sound assigned to it is already an AudioBuffer. Previews await, because there the member pressed a button and is expecting the delay. TWO TABS, because they answer different questions. Assigned Sounds is about EVENTS ("what should a new message sound like"); Sound Effect Library is about FILES ("what have we got, who added it, is anything using it"). One screen meant fifty event rows each carrying an upload control, and no way at all to see a sound nobody had assigned yet. The library says what each file is in use by, because the one thing someone about to delete a file needs to know is what will go quiet. Waveforms for uploads are computed from the DECODED AUDIO, not faked. A plausible-looking shape would be a picture claiming to be this file and is not, and telling two sounds apart before playing them is the entire reason the waveform is there. The description is asked for with the file, not afterwards: a library of "recording_final_2.wav" is one nobody can use six months later, and the description is the only part of a sound file a person can search. Gates: tsc clean, 1894 tests pass (6 new for custom ids), next build compiles, i18n guard clean. Dictionary pushed first, as always.

All changes

Like what you see shipping?

Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.

Start Free ForeverView Pricing