Audio and Video in Decentraland
When to Use Which Media Component
| Need | Component | Key Difference |
|---|
| Sound effect from a file (click, explosion, footstep) | | Local file, spatial, one-shot or looping |
| Background music or radio stream | | External URL, non-spatial, continuous |
| Video on a surface (screen, billboard) | + | Requires a mesh to display on |
Decision flow:
- Is it a local audio file? →
- Is it a streaming URL (radio, live audio)? →
- Is it video content? → on a plane/mesh
Audio Sourcing
Before referencing any audio file path in code, check
{baseDir}/references/audio-catalog.md
. It lists 50 free Decentraland audio clips with direct downloadable URLs that cover most needs (UI clicks, ambients, music, game mechanics, sound effects).
The expected workflow when a user asks for sound:
- Read this skill +
references/audio-catalog.md
.
- If the catalog has fitting clips, surface them to the user as suggestions — name the clip and what it would be used for.
- Ask how they want to proceed. Some creators want catalog clips downloaded; others prefer placeholder paths so they can drop in their own files later. Don't assume.
- If they pick catalog clips: download with
curl -o assets/Audio/<name>.mp3 "<URL>"
— these URLs work directly from , no separate tool needed.
- If they want placeholders: use a clear placeholder path (e.g. ) and tell the user which files to drop in where.
- Reference the resulting local path in .
Things to avoid:
- Telling the user "I can't download audio files." + works fine on the catalog URLs — the capability is there if they want it.
- Recommending external sources (freesound / mixkit / pixabay) without first checking whether the catalog already has a fitting clip.
- Downloading clips without asking — even if the catalog has a perfect match, confirm before pulling files into the project.
AudioSource (Sound Effects & Music)
Attach to any entity for positional sound. Fields:
(local file path, required),
,
,
(default 1.0),
(playback speed, default 1.0),
(playback position in seconds, default 0),
. Audio files go in
. Supported formats:
(recommended for music),
(recommended for sound effects, smaller),
. Keep audio files small — large files increase scene load time.
Audio is
spatial by default — volume decreases with distance from the entity. Set
for non-spatial (same volume everywhere).
Retriggering (play a sound again on every click): use the helper
AudioSource.playSound(entity, clipUrl, resetCursor?)
— do NOT hand-mutate
.
writes a full component (via
/
), so it reliably re-emits even with identical params. Hand-setting
getMutable(entity).playing = true
(or the old "playing=false then playing=true" trick) can be silently swallowed by LWW-CRDT dedup when the values are unchanged — the second and later triggers may do nothing.
stopSound(entity, resetCursor?)
stops it.
defaults to
on both (start/stop at 0); pass
to resume/pause at the current
.
typescript
AudioSource.playSound(entity, 'assets/Audio/click.mp3') // retriggers from 0 every call
AudioSource.stopSound(entity) // stops, resets cursor to 0
Both helpers return
if the entity has no
, so create the component first (e.g.
AudioSource.create(entity, { audioClipUrl, playing: false })
at init).
Players must interact with the scene (click) before audio can play (browser autoplay policy). If an audio file needs to be ready to play the instant the player interacts, use the
component to pre-load the asset.
Before adding audio: Confirm with the user before fetching audio from external sources.
AudioStream (Streaming)
Stream audio from a URL (radio, live streams). Key fields:
(streaming URL),
,
. Non-spatial by default — plays at same volume everywhere. Set
with
/
for distance-based volume.
Query state with
AudioStream.getAudioState(entity)
which returns a
— an object with a
field (a
enum:
,
, etc.) and a
field, not a bare enum. Read the state as
AudioStream.getAudioState(entity)?.state
.
Before adding a streaming URL: If not provided by the user, confirm the source first.
VideoPlayer
Play video on a surface. Key fields:
(URL or local path),
,
,
,
,
(start time in seconds). Non-spatial by default — set
with min/max distances for positional audio.
Setup requires 3 steps: create entity with
, add
, create
Material.Texture.Video({ videoPlayerEntity })
and apply to material. Use
Material.setBasicMaterial
(recommended, better performance) or
with emissive for a brighter screen.
Monitor playback with
videoEventsSystem.registerVideoEventsEntity()
for state callbacks, or
videoEventsSystem.getVideoState()
for polling. States:
,
,
,
,
.
Share one VideoPlayer across multiple screens by referencing the same
in multiple
calls.
To play video on a non-primitive shape (curved screens), use
to swap the material of a GLTF model.
Free Audio Files
The audio catalog is the first place to look — see the
Audio Sourcing section at the top of this skill. It lists 50 free Decentraland clips across music, ambient, interaction sounds, sound effects, and game mechanics, each with a
-ready URL.
Read
{baseDir}/references/audio-catalog.md
before recommending audio so suggestions are concrete, then check with the user whether they want those clips downloaded or prefer placeholders.
Important:
only works with
local files. Never use external URLs for
. Always download into
first.
Asset folder conventions
- Default for audio you download yourself: .
- Legacy scenes may already have audio under — that path still works; reuse it for any new clips in those scenes instead of creating a parallel folder.
- Creator Hub assets: audio imported directly through the Creator Hub UI lands in (same as the standard path). Items from free DCL asset packs land in and custom items in . Older scenes may also have user imports directly under . Reference these paths as-is — never move or rename them.
Always check the scene's existing folders before deciding where to put a new file.
Audio-reactive scenes (visualizers, beat sync)
For real-time amplitude + frequency-band data from any
,
, or
, use the dedicated
skill. It covers the
component (Unity-explorer only) used for music visualizers, equalizer bars, and reactive lights/particles.
Permission for External Media
External audio/video URLs do
not require the
permission. The permission and its
list still exist in
, but no current client enforces them — unity-explorer's hostname check is gated behind the
CHECK_ALLOWED_MEDIA_HOSTNAMES
compile define (set in no build config, so
just does a URL syntax check), and bevy-explorer has no enforcement. Only the retired web client enforced it. Do not add it for new scenes; current clients play external media without it.
Video Limits & Tips
- Simultaneous videos: Avoid playing multiple videos at once. Only play more than 1 simultaneous video if explicitly requested. The maximum depends on each player's quality setting (as low as 1 on Low quality — see the Video Limits table in
{baseDir}/references/media-reference.md
), so treat 1 as the only safe floor.
- HTTPS required: Video sources must be HTTPS URLs — HTTP won't work
- Distance-based control: Pause video when player is far away to save bandwidth
- Supported formats: (H.264), , HLS () for live streaming
- Live streaming: Use HLS () URLs — most reliable across clients
Example scenes
Engine-team test scenes exercised against the real explorer:
- audio-source-retrigger-test — /, same-URL retrigger, URL-swap on one entity, semantics, volume/pitch/loop variations, and why beats hand-mutating (LWW dedup).
- audio-visualization — music visualizer (see the skill).
For full code examples and implementation patterns, see
{baseDir}/references/media-patterns.md
. For component field details, see
{baseDir}/references/media-reference.md
.