SFXMint

Add sound effects to a Phaser web game

Free, CC0, no API key. Pick one coherent kit, preload it straight from the URLs, play cues on game events, loop an ambience bed. Works in Phaser 3 with the default Web Audio manager.

1. Pick a set

A set is one sound per role, chosen so the kit sounds like one game. platformer covers jump, land, coin, hit, sword, gunshot, explosion, footsteps, door, checkpoint and death; retro-game is the chiptune version; puzzle-game has match, combo, bonus, win and lose; horror-game has drone, stinger, heartbeat and creak. All 15 sets are at /sets.

curl "https://sfxmint.com/api/v1/sets/platformer"

The response has a sounds object per role (slug, acoustics, two alternates) and a flat urls map you can paste as-is:

"urls": {
  "jump": "https://sfxmint.com/dl/retro-game-jump-06.mp3",
  "land": "https://sfxmint.com/dl/impact-thud-33.mp3",
  "coin": "https://sfxmint.com/dl/retro-game-coin-13.mp3",
  "hit": "https://sfxmint.com/dl/impact-punch-25.mp3",
  "sword": "https://sfxmint.com/dl/impact-sword-02.mp3",
  "gunshot": "https://sfxmint.com/dl/impact-gunshot-01.mp3",
  "explosion": "https://sfxmint.com/dl/retro-game-explosion-25.mp3",
  "footsteps": "https://sfxmint.com/dl/footsteps-wood-18.mp3",
  "door": "https://sfxmint.com/dl/door-open-25.mp3",
  "checkpoint": "https://sfxmint.com/dl/feedback-confirm-24.mp3",
  "death": "https://sfxmint.com/dl/retro-game-game-over-24.mp3"
}

Picks can change as the library grows; the URLs you paste never do.

2. Preload

Loop over the map in preload(). Absolute URLs are fine — no setBaseURL, no setCORS needed.

// sfx.js — paste the "urls" map from the set response
export const SFX = {
  jump: "https://sfxmint.com/dl/retro-game-jump-06.mp3",
  coin: "https://sfxmint.com/dl/retro-game-coin-13.mp3",
  hit: "https://sfxmint.com/dl/impact-punch-25.mp3",
  checkpoint: "https://sfxmint.com/dl/feedback-confirm-24.mp3",
  death: "https://sfxmint.com/dl/retro-game-game-over-24.mp3",
};

// GameScene.js
import { SFX } from "./sfx";

export class GameScene extends Phaser.Scene {
  preload() {
    for (const [key, url] of Object.entries(SFX)) this.load.audio(key, url);
  }
}

3. Play on game events

create() {
  this.physics.add.overlap(this.player, this.coins, (_player, coin) => {
    coin.destroy();
    this.sound.play("coin", { volume: 0.6 });
  });
}

update() {
  if (this.cursors.up.isDown && this.player.body.blocked.down) {
    this.player.setVelocityY(-330);
    this.sound.play("jump", { volume: 0.5 });
  }
}

this.sound.play(key, config) creates a throwaway sound each time, which is right for short cues. For something you trigger dozens of times a second (footsteps, machine-gun fire) keep one instance with this.sound.add(key) and call .play() on it.

4. Background ambience on a loop

Ask for a loop role — rain-loop, forest-loop, wind-loop, drone-loop, engine-loop — and you get a sound with loopable: true. Use its wav_url: the WAV is gapless at the seam, the MP3 has a few milliseconds of codec padding you will hear as a tick.

curl "https://sfxmint.com/api/v1/roles/forest-loop"
# → { "role": "forest-loop", "loopable": true, "wav_url": "https://sfxmint.com/dl/<slug>.wav", ... }
preload() {
  this.load.audio("ambience", "<wav_url from the response>");
}

create() {
  const startAmbience = () => this.sound.add("ambience", { loop: true, volume: 0.3 }).play();
  if (this.sound.locked) {
    this.sound.once(Phaser.Sound.Events.UNLOCKED, startAmbience);
  } else {
    startAmbience();
  }
}

this.sound.locked is true until the player has clicked or tapped — browsers refuse to start audio before a gesture. Cues you play from input handlers are already inside a gesture; the ambience is the one thing that starts on its own, so it waits for Phaser.Sound.Events.UNLOCKED.

5. Why hotlinking just works

6. One-off sounds: roles and search

curl "https://sfxmint.com/api/v1/roles/chest-open"            # QA-checked default + alternates
curl "https://sfxmint.com/api/v1/roles/laser?style=crisp"       # re-rank the family by acoustics
curl "https://sfxmint.com/api/v1/search?q=crate+breaking&category=impact&limit=5"

Roles are the reliable path: one deterministic default per purpose, aliases accepted, listed at /roles. Search results carry matchrole and exact are safe to ship blind, partial and semantic deserve a listen. Every result includes acoustics (attack, tail, brightness) so you can pick the punchier or darker variant without opening a DAW.

License

Every SFXMint sound is CC0 1.0: commercial use, no attribution, no signup, no credits screen required. Full terms at /license.

Building with an AI agent?

Claude Code, Cursor and similar agents can install the skill and follow this workflow on their own — role first, then set, then search — instead of inventing URLs:

npx skills add flreey/sfxmint-mcp -y

MCP: claude mcp add --transport http sfxmint https://sfxmint.com/mcp exposes get_role_sound, get_sound_set and search_sounds. Full reference: API docs.