From fxgl-skills
Play and manage audio in FXGL — trigger one-shot sound effects, loop background music, control master and per-type volume, load sound and music assets, use the AudioPlayer service directly, and speak text via platform TTS. Use this skill when adding sound effects to game events, playing background music, implementing volume sliders, or integrating text-to-speech dialogue in a game.
How this skill is triggered — by the user, by Claude, or both
Slash command
/fxgl-skills:fxgl-audioThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Audio files go in `src/main/resources/assets/`:
Audio files go in src/main/resources/assets/:
assets/sounds/ — short clips (WAV recommended for low latency)assets/music/ — long tracks (MP3 or OGG for size efficiency)// Play a sound effect (one-shot, auto-managed)
FXGL.play("sounds/shoot.wav");
// Loop background music
FXGL.loopBGM("music/theme.mp3");
// Stop / pause / resume background music
FXGL.stopBGM();
FXGL.pauseBGM();
FXGL.resumeBGM();
// Load once (cached), play many times
Sound jumpSound = getAssetLoader().loadSound("sounds/jump.wav");
Music themeMusic = getAssetLoader().loadMusic("music/theme.mp3");
// Play
getAudioPlayer().playSound(jumpSound);
getAudioPlayer().playMusic(themeMusic);
// Loop a specific music object
getAudioPlayer().loopMusic(themeMusic);
// Stop / pause / resume specific music
getAudioPlayer().stopMusic(themeMusic);
getAudioPlayer().pauseMusic(themeMusic);
getAudioPlayer().resumeMusic(themeMusic);
// Global volumes (0.0 = mute, 1.0 = full)
getSettings().setGlobalSoundVolume(0.8);
getSettings().setGlobalMusicVolume(0.5);
// At runtime via AudioPlayer
getAudioPlayer().setGlobalSoundVolume(0.7);
getAudioPlayer().setGlobalMusicVolume(0.4);
// Individual sound volume (set before playing)
Sound s = getAssetLoader().loadSound("sounds/explosion.wav");
s.setVolume(0.5); // half volume for this instance
getAudioPlayer().playSound(s);
// Individual music volume
Music bgm = getAssetLoader().loadMusic("music/boss.mp3");
bgm.setVolume(0.6);
getAudioPlayer().loopMusic(bgm);
@Override
protected void initUI() {
Slider sfxSlider = new Slider(0, 1, getSettings().getGlobalSoundVolume());
sfxSlider.valueProperty().addListener((obs, oldVal, newVal) ->
getAudioPlayer().setGlobalSoundVolume(newVal.doubleValue()));
Slider musicSlider = new Slider(0, 1, getSettings().getGlobalMusicVolume());
musicSlider.valueProperty().addListener((obs, oldVal, newVal) ->
getAudioPlayer().setGlobalMusicVolume(newVal.doubleValue()));
addUINode(sfxSlider, 100, 400);
addUINode(musicSlider, 100, 440);
}
private Music currentMusic;
public void crossfadeTo(String musicFile) {
Music nextMusic = getAssetLoader().loadMusic("music/" + musicFile);
if (currentMusic != null) {
// Fade out current
animationBuilder()
.duration(Duration.seconds(1))
.animate(new AnimatedValue<>(currentMusic.getVolume(), 0.0))
.onProgress(v -> currentMusic.setVolume(v))
.build()
.setOnFinished(() -> {
getAudioPlayer().stopMusic(currentMusic);
nextMusic.setVolume(0);
getAudioPlayer().loopMusic(nextMusic);
// Fade in next
animationBuilder()
.duration(Duration.seconds(1))
.animate(new AnimatedValue<>(0.0, 1.0))
.onProgress(v -> nextMusic.setVolume(v))
.buildAndPlay();
})
.start();
} else {
getAudioPlayer().loopMusic(nextMusic);
}
currentMusic = nextMusic;
}
// In initPhysics() collision handlers — most common pattern
onCollisionBegin(EntityType.PLAYER, EntityType.COIN, (player, coin) -> {
play("sounds/coin.wav");
coin.removeFromWorld();
});
// In component onUpdate for continuous sounds
// (guard with a flag to avoid playing every frame)
public class EngineComponent extends Component {
private boolean enginePlaying = false;
@Override
public void onUpdate(double tpf) {
double speed = entity.getComponent(PhysicsComponent.class).getSpeed();
if (speed > 10 && !enginePlaying) {
engineSound = getAssetLoader().loadSound("sounds/engine_loop.wav");
getAudioPlayer().playSound(engineSound);
enginePlaying = true;
} else if (speed <= 10 && enginePlaying) {
getAudioPlayer().stopSound(engineSound);
enginePlaying = false;
}
}
}
// Add to pom.xml: com.github.almasb:fxgl-intelligence:VERSION
// Register service
settings.addEngineService(TextToSpeechService.class);
// Use (in any init* hook or at runtime)
TextToSpeechService tts = getService(TextToSpeechService.class);
tts.speak("Welcome to the dungeon, adventurer!");
// Configure voice
tts.setRate(1.0); // 0.1 (slow) to 10.0 (fast)
tts.setPitch(1.0); // 0.0 (deep) to 2.0 (high)
tts.setVolume(1.0);
// Wait for speech to finish before proceeding
tts.speakAndWait("Choose your path wisely.");
// Stop BGM
stopBGM();
// Stop all playing sounds (FXGL 21+)
getAudioPlayer().stopAllSounds();
getAudioPlayer().stopAllMusic();
play("shoot.wav") works, but play("sounds/shoot.wav") only
works if the file is actually at assets/sounds/shoot.wav. Omit the sounds/ prefix when
using the FXGL.play() shortcut — it automatically resolves to assets/sounds/ for WAV
and assets/music/ for MP3/OGG.loopBGM() replaces the current BGM — only one loopBGM track plays at a time.
Use getAudioPlayer().loopMusic() directly if you need multiple simultaneous music tracks.DataFile in
writeSaveState() or use getSystemBundle() for per-session persistence.speakAndWait() — call it on a background thread
or use speak() (non-blocking) inside dialogue callbacks.AudioPlayer is replaced with a no-op
stub when no audio hardware is detected. Audio calls are silently ignored.npx claudepluginhub johannesrabauer/fxgl-skills --plugin fxgl-skillsProvides behavioral guidelines to reduce common LLM coding mistakes, focusing on simplicity, surgical changes, assumption surfacing, and verifiable success criteria.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.