blecsd-audio
3
总安装量
3
周安装量
#57317
全站排名
安装命令
npx skills add https://github.com/kadajett/blecsd-skill --skill blecsd-audio
Agent 安装分布
amp
3
github-copilot
3
codex
3
kimi-cli
3
gemini-cli
3
opencode
3
Skill 文档
@blecsd/audio Package Skill
The @blecsd/audio package provides audio management for blECSd terminal applications. It uses an adapter pattern where blECSd manages state and the user provides the actual audio playback implementation. All blECSd functional programming rules apply.
Install: pnpm add @blecsd/audio
Peer dependency: blecsd >= 0.6.0
Import: import { createAudioManager, AudioChannel } from '@blecsd/audio'
Core Concepts
- AudioManager – Manages state (volume, mute, active sounds) without playing audio directly
- AudioAdapter – User-provided interface that does the actual audio playback
- AudioChannel – Two channels:
Music(0) andSFX(1), each with independent volume/mute - SoundTrigger – Event-based sound triggers that automatically play sounds on events
Quick Start
import { createAudioManager, AudioChannel } from '@blecsd/audio';
// Create manager
const audio = createAudioManager();
// Set adapter (user provides their own audio backend)
audio.setAdapter({
play: (opts) => { /* play audio via your backend */ },
stop: (id) => { /* stop audio */ },
stopAll: () => { /* stop all */ },
setVolume: (channel, vol) => { /* set volume 0-1 */ },
setMuted: (channel, muted) => { /* mute/unmute */ },
});
// Play sounds
audio.playSound('click', AudioChannel.SFX);
audio.playMusic('theme', 0.8);
// Full play options
audio.play({
id: 'explosion',
channel: AudioChannel.SFX,
volume: 0.5,
loop: false,
});
API Reference
createAudioManager()
Returns an AudioManager interface:
interface AudioManager {
// State
getState(): AudioState;
// Adapter
setAdapter(adapter: AudioAdapter): void;
clearAdapter(): void;
// Playback
play(opts: PlayOptions): void;
playSound(id: string, channel?: AudioChannel): void;
playMusic(id: string, volume?: number): void;
stop(id: string): void;
stopAll(): void;
// Volume
setVolume(channel: AudioChannel, vol: number): void;
getVolume(channel: AudioChannel): number;
// Mute
mute(channel: AudioChannel): void;
unmute(channel: AudioChannel): void;
toggleMute(channel: AudioChannel): void;
isMuted(channel: AudioChannel): boolean;
// Event triggers
onEvent(bus: EventBus, trigger: SoundTrigger): Unsubscribe;
onEvents(bus: EventBus, triggers: SoundTrigger[]): Unsubscribe;
}
AudioAdapter Interface
The adapter is what the user provides to connect to their audio backend:
interface AudioAdapter {
play(opts: PlayOptions): void;
stop(id: string): void;
stopAll(): void;
setVolume(channel: AudioChannel, vol: number): void;
setMuted(channel: AudioChannel, muted: boolean): void;
}
PlayOptions
interface PlayOptions {
id: string; // Sound identifier
loop?: boolean; // Loop playback (default: false)
volume?: number; // Volume 0-1 (default: 1)
channel?: AudioChannel; // Music or SFX (default: SFX)
}
AudioChannel Enum
enum AudioChannel {
Music = 0,
SFX = 1,
}
Event-Based Sound Triggers
Automatically play sounds when events fire:
import { createEventBus } from 'blecsd';
import { createAudioManager, AudioChannel } from '@blecsd/audio';
const bus = createEventBus();
const audio = createAudioManager();
audio.setAdapter(myAdapter);
// Single trigger
const unsub = audio.onEvent(bus, {
event: 'player:hit',
soundId: 'damage',
options: { channel: AudioChannel.SFX, volume: 0.7 },
when: (data) => data.damage > 10, // Optional condition
});
// Multiple triggers
const unsubAll = audio.onEvents(bus, [
{ event: 'player:jump', soundId: 'jump' },
{ event: 'player:land', soundId: 'land' },
{ event: 'coin:collect', soundId: 'coin', options: { volume: 0.5 } },
{ event: 'enemy:die', soundId: 'explosion' },
]);
// Clean up
unsub(); // Remove single trigger
unsubAll(); // Remove all triggers
SoundTrigger Interface
interface SoundTrigger<T = unknown, K extends string = string> {
event: K; // Event name to listen for
soundId: string; // Sound to play
options?: Partial<PlayOptions>; // Play options
when?: (data: T) => boolean; // Conditional filter
}
Common Patterns
Music + SFX with Volume Control
const audio = createAudioManager();
audio.setAdapter(myAdapter);
// Set initial volumes
audio.setVolume(AudioChannel.Music, 0.5);
audio.setVolume(AudioChannel.SFX, 0.8);
// Play background music (looping)
audio.play({ id: 'bg-music', channel: AudioChannel.Music, loop: true, volume: 0.5 });
// Play SFX
audio.playSound('click');
audio.playSound('explosion');
// Mute/unmute music
audio.toggleMute(AudioChannel.Music);
// Check state
const musicVol = audio.getVolume(AudioChannel.Music); // 0.5
const musicMuted = audio.isMuted(AudioChannel.Music); // true
Adapter Example (Node.js with play-sound)
// This is user code, not part of @blecsd/audio
import playSound from 'play-sound';
const player = playSound();
const activeSounds = new Map();
const adapter: AudioAdapter = {
play(opts) {
const audio = player.play(`sounds/${opts.id}.wav`);
activeSounds.set(opts.id, audio);
},
stop(id) {
activeSounds.get(id)?.kill();
activeSounds.delete(id);
},
stopAll() {
for (const [id, audio] of activeSounds) {
audio.kill();
}
activeSounds.clear();
},
setVolume() { /* implementation depends on backend */ },
setMuted() { /* implementation depends on backend */ },
};
audio.setAdapter(adapter);
Best Practices
- Always provide an adapter. The audio manager does nothing without one. Without an adapter, all play calls are no-ops.
- Use channels for independent control. Music and SFX should use different channels so users can mute/volume each independently.
- Use event triggers for game sounds. Instead of manually calling
playSoundeverywhere, wire up triggers on the event bus. - Clean up triggers. Store unsubscribe functions and call them during cleanup.
- Volume range is 0-1. Clamp values before passing to the manager.
- The adapter is user-provided by design. blECSd is a terminal library and doesn’t bundle audio backends. Users choose their own (play-sound, speaker, SoX, etc.).