"Authoring s&box .sound events by hand"
You have an MP3 (or want to skip the editor click-ops) and need a playable s&box sound event as text in the repo.
The engine already accepts MP3 as a source asset. There is no .vsnd source file you author — only compiled .vsnd_c. The .sound JSON event references "sounds/<name>.vsnd" and the pipeline maps the mp3 onto it.
Chain
Assets/sounds/<name>.mp3
Assets/sounds/<name>.sound
↓ compile
<audio>.vsnd_c + <name>.sound_cReference in the event as "sounds/<name>.vsnd" (engine maps mp3 → vsnd). No ffmpeg / wav conversion required — the install's own addons/menu/Assets/sounds/box_open.mp3 sits next to box_open.sound.
JSON schema
Copy addons/menu/Assets/sounds/box_open.sound and edit:
| Field | Notes |
|---|---|
UI | true = 2D / false = 3D positional |
Volume / Pitch | strings in the stock schema |
Decibels | |
SelectionMode | |
Sounds | list of vsnd refs |
| Occlusion / Reverb / AirAbsorption / Transmission | bools |
Distance | max range in UNITS (inches) — ~1575u ≈ 40 m positional; ~15000 for UI |
Falloff | bezier curve |
DefaultMixer | |
__version |
Play from code
Sound.Play("sounds/impact/boing_a.sound"); // 2D — full path WITH extension
Sound.Play("boing_a"); // OR bare filename
var h = Sound.Play("sounds/impact/boing_a.sound", worldPos); // 3D → SoundHandleSoundHandle: .Volume .Pitch .Position .IsPlaying .Finished .Stop(fadeSeconds) .IsValid().
Wrap in try/catch so a not-yet-generated event can't break gameplay. No component wiring required for one-shots.
Path rules that mute you: custom-sound-wont-play. Looping: soundevent-no-looping-field.
ModelDoc-style compile turns mp3 + .sound into the runtime resources. Authoring JSON as text keeps SFX in source control and matches what the menu addon already ships — you're not inventing a format, just filling the stock schema.