Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ agent.speak("When all else fails, bind some paper together. My name is Clippy.")
// Speak with text-to-speech (uses Web Speech API)
agent.speak("Hello! I'm here to help.", { tts: true });

// Disable all animation sounds and text-to-speech
agent.mute();

// Re-enable audio later
agent.unmute();

// Keep the balloon open until manually closed
agent.speak("Read this carefully.", { hold: true });

Expand Down
39 changes: 38 additions & 1 deletion src/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export default class Agent {
_pointerDownHandle: (e: MouseEvent | TouchEvent) => void;
_dblClickHandle: () => void;
_tts: { rate: number; pitch: number; voice: string } | undefined;
_muted: boolean;

/**
* @param {string} mapUrl - URL to the agent's sprite sheet
Expand All @@ -53,6 +54,7 @@ export default class Agent {
this._animator = new Animator(this._el, mapUrl, data, sounds);
this._balloon = new Balloon(this._el);
this._tts = data.tts;
this._muted = false;

this._setupEvents();
}
Expand Down Expand Up @@ -335,6 +337,7 @@ export default class Agent {
stop() {
this._queue.clear();
this._animator.exitAnimation();
this._animator.stopAllSounds();
this._balloon.hide();
if (this._tts && "speechSynthesis" in window) {
speechSynthesis.cancel();
Expand All @@ -358,6 +361,40 @@ export default class Agent {
return this._animator.animations();
}

/**
* Mute animation sounds and text-to-speech
*/
mute() {
this.setMuted(true);
}

/**
* Unmute animation sounds and text-to-speech
*/
unmute() {
this.setMuted(false);
}

/**
* Enable or disable audio output
* @param {boolean} muted
*/
setMuted(muted: boolean) {
this._muted = muted;
this._animator.setMuted(muted);
if (muted && this._tts && "speechSynthesis" in window) {
speechSynthesis.cancel();
}
}

/**
* Check if audio output is muted
* @returns {boolean}
*/
isMuted() {
return this._muted;
}

/**
* Play a random non-idle animation
* @returns {boolean}
Expand Down Expand Up @@ -660,7 +697,7 @@ export default class Agent {
}

_speakTTS(text: string) {
if (!this._tts || !("speechSynthesis" in window)) return;
if (this._muted || !this._tts || !("speechSynthesis" in window)) return;
speechSynthesis.cancel();
const utterance = new SpeechSynthesisUtterance(text.replaceAll("\n", " "));
utterance.rate = this._tts.rate;
Expand Down
23 changes: 22 additions & 1 deletion src/animator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export default class Animator {
_endCallback: Function | undefined;
_started: boolean;
_sounds: { [key: string]: HTMLAudioElement };
_muted: boolean;
currentAnimationName: string | undefined;
_overlays: HTMLElement[];
_loop: number | undefined;
Expand All @@ -34,6 +35,7 @@ export default class Animator {
this._endCallback = undefined;
this._started = false;
this._sounds = {};
this._muted = false;
this.currentAnimationName = undefined;
this.preloadSounds(sounds);
this._overlays = [this._el];
Expand Down Expand Up @@ -192,6 +194,7 @@ export default class Animator {
* @private
*/
_playSound() {
if (this._muted) return;
let s = this._currentFrame.sound;
if (!s) return;
let audio = this._sounds[s];
Expand Down Expand Up @@ -253,6 +256,24 @@ export default class Animator {
window.clearTimeout(this._loop);
}

setMuted(muted: boolean) {
this._muted = muted;
if (muted) {
this.stopAllSounds();
}
}

isMuted() {
return this._muted;
}

stopAllSounds() {
for (const key in this._sounds) {
this._sounds[key].pause();
this._sounds[key].currentTime = 0;
}
}

/**
* Resume animation
*/
Expand All @@ -266,8 +287,8 @@ export default class Animator {
this._currentFrame = undefined;
this._endCallback = undefined;
this._started = false;
this.stopAllSounds();
for (const key in this._sounds) {
this._sounds[key].pause();
this._sounds[key].src = "";
}
this._sounds = {};
Expand Down