@tsparticles/plugin-sounds 4.0.0-beta.0 → 4.0.0-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/{30.min.js → 300.min.js} +2 -2
  2. package/86.min.js +1 -0
  3. package/README.md +22 -0
  4. package/browser/SoundsPluginInstance.js +2 -2
  5. package/browser/index.js +3 -3
  6. package/cjs/SoundsPluginInstance.js +2 -2
  7. package/cjs/index.js +3 -3
  8. package/dist_browser_SoundsPluginInstance_js.js +2 -2
  9. package/dist_browser_SoundsPlugin_js.js +1 -1
  10. package/esm/SoundsPluginInstance.js +2 -2
  11. package/esm/index.js +3 -3
  12. package/package.json +4 -5
  13. package/report.html +84 -29
  14. package/tsparticles.plugin.sounds.js +2 -2
  15. package/tsparticles.plugin.sounds.min.js +2 -2
  16. package/915.min.js +0 -1
  17. package/umd/Options/Classes/Sounds.js +0 -54
  18. package/umd/Options/Classes/SoundsAudio.js +0 -39
  19. package/umd/Options/Classes/SoundsEvent.js +0 -75
  20. package/umd/Options/Classes/SoundsIcon.js +0 -44
  21. package/umd/Options/Classes/SoundsIcons.js +0 -78
  22. package/umd/Options/Classes/SoundsMelody.js +0 -48
  23. package/umd/Options/Classes/SoundsNote.js +0 -34
  24. package/umd/Options/Classes/SoundsVolume.js +0 -49
  25. package/umd/Options/Interfaces/ISounds.js +0 -12
  26. package/umd/Options/Interfaces/ISoundsAudio.js +0 -12
  27. package/umd/Options/Interfaces/ISoundsEvent.js +0 -12
  28. package/umd/Options/Interfaces/ISoundsIcon.js +0 -12
  29. package/umd/Options/Interfaces/ISoundsIcons.js +0 -12
  30. package/umd/Options/Interfaces/ISoundsMelody.js +0 -12
  31. package/umd/Options/Interfaces/ISoundsNote.js +0 -12
  32. package/umd/Options/Interfaces/ISoundsVolume.js +0 -12
  33. package/umd/SoundsPlugin.js +0 -86
  34. package/umd/SoundsPluginInstance.js +0 -451
  35. package/umd/constants.js +0 -14
  36. package/umd/enums.js +0 -23
  37. package/umd/index.js +0 -54
  38. package/umd/types.js +0 -12
  39. package/umd/utils.js +0 -48
@@ -1,4 +1,4 @@
1
- "use strict";(this.webpackChunk_tsparticles_plugin_sounds=this.webpackChunk_tsparticles_plugin_sounds||[]).push([[30],{30(e,t,s){s.d(t,{SoundsPlugin:()=>m});var i=s(967),l=s(303);class o{loop;source;constructor(){this.loop=!1,this.source=""}load(e){(0,l.isNull)(e)||((0,l.isObject)(e)?(void 0!==e.loop&&(this.loop=e.loop),void 0!==e.source&&(this.source=e.source)):this.source=e)}}class n{duration;value;constructor(){this.duration=500,this.value=[]}load(e){(0,l.isNull)(e)||(void 0!==e.duration&&(this.duration=e.duration),void 0!==e.value&&(this.value=e.value))}}class a{loop;melodies;notes;constructor(){this.loop=!1,this.melodies=[],this.notes=[]}load(e){(0,l.isNull)(e)||(void 0!==e.loop&&(this.loop=e.loop),void 0!==e.melodies&&(this.melodies=e.melodies.map(e=>{let t=new a;return t.load(e),t})),void 0!==e.notes&&(this.notes=e.notes.map(e=>{let t=new n;return t.load(e),t})))}}class c{audio;event;filter;melodies;notes;constructor(){this.event=[],this.notes=[]}load(e){if(!(0,l.isNull)(e)&&(void 0!==e.event&&(this.event=e.event),void 0!==e.audio&&((0,l.isArray)(e.audio)?this.audio=e.audio.map(e=>{let t=new o;return t.load(e),t}):(this.audio=new o,this.audio.load(e.audio))),void 0!==e.notes&&(this.notes=e.notes.map(e=>{let t=new n;return t.load(e),t})),void 0!==e.melodies&&(this.melodies=e.melodies.map(e=>{let t=new a;return t.load(e),t})),e.filter))if((0,l.isString)(e.filter)){let t=globalThis[e.filter];(0,l.isFunction)(t)&&(this.filter=t)}else this.filter=e.filter}}class h{height;path;style;svg;width;constructor(){this.width=24,this.height=24,this.style=""}load(e){(0,l.isNull)(e)||(void 0!==e.path&&(this.path=e.path),void 0!==e.svg&&(this.svg=e.svg),void 0!==e.width&&(this.width=e.width),void 0!==e.height&&(this.height=e.height))}}class u{enable;mute;unmute;volumeDown;volumeUp;constructor(){this.mute=new h,this.unmute=new h,this.volumeDown=new h,this.volumeUp=new h,this.enable=!1,this.mute.svg=`<?xml version="1.0"?>
1
+ "use strict";(this.webpackChunk_tsparticles_plugin_sounds=this.webpackChunk_tsparticles_plugin_sounds||[]).push([[300],{300(e,t,s){s.d(t,{SoundsPlugin:()=>m});var i=s(886),l=s(303);class o{loop;source;constructor(){this.loop=!1,this.source=""}load(e){(0,l.isNull)(e)||((0,l.isObject)(e)?(void 0!==e.loop&&(this.loop=e.loop),void 0!==e.source&&(this.source=e.source)):this.source=e)}}class n{duration;value;constructor(){this.duration=500,this.value=[]}load(e){(0,l.isNull)(e)||(void 0!==e.duration&&(this.duration=e.duration),void 0!==e.value&&(this.value=e.value))}}class a{loop;melodies;notes;constructor(){this.loop=!1,this.melodies=[],this.notes=[]}load(e){(0,l.isNull)(e)||(void 0!==e.loop&&(this.loop=e.loop),void 0!==e.melodies&&(this.melodies=e.melodies.map(e=>{let t=new a;return t.load(e),t})),void 0!==e.notes&&(this.notes=e.notes.map(e=>{let t=new n;return t.load(e),t})))}}class c{audio;event;filter;melodies;notes;constructor(){this.event=[],this.notes=[]}load(e){if(!(0,l.isNull)(e)&&(void 0!==e.event&&(this.event=e.event),void 0!==e.audio&&((0,l.isArray)(e.audio)?this.audio=e.audio.map(e=>{let t=new o;return t.load(e),t}):(this.audio=new o,this.audio.load(e.audio))),void 0!==e.notes&&(this.notes=e.notes.map(e=>{let t=new n;return t.load(e),t})),void 0!==e.melodies&&(this.melodies=e.melodies.map(e=>{let t=new a;return t.load(e),t})),e.filter))if((0,l.isString)(e.filter)){let t=globalThis[e.filter];(0,l.isFunction)(t)&&(this.filter=t)}else this.filter=e.filter}}class h{height;path;style;svg;width;constructor(){this.width=24,this.height=24,this.style=""}load(e){(0,l.isNull)(e)||(void 0!==e.path&&(this.path=e.path),void 0!==e.svg&&(this.svg=e.svg),void 0!==e.width&&(this.width=e.width),void 0!==e.height&&(this.height=e.height))}}class u{enable;mute;unmute;volumeDown;volumeUp;constructor(){this.mute=new h,this.unmute=new h,this.volumeDown=new h,this.volumeUp=new h,this.enable=!1,this.mute.svg=`<?xml version="1.0"?>
2
2
  <svg baseProfile="tiny" height="24px" version="1.2" viewBox="0 0 24 24" width="24px"
3
3
  xml:space="preserve" xmlns="http://www.w3.org/2000/svg"
4
4
  xmlns:xlink="http://www.w3.org/1999/xlink">
@@ -30,4 +30,4 @@
30
30
  <path fill="#fff" d="M20.706,6.292c-0.391-0.389-1.023-0.39-1.414,0.002c-0.39,0.391-0.39,1.024,0.002,1.414c1.412,1.409,2.191,3.285,2.192,5.284c0.002,2.002-0.777,3.885-2.193,5.301c-0.391,0.391-0.391,1.023,0,1.414C19.488,19.902,19.744,20,20,20s0.512-0.098,0.707-0.293c1.794-1.794,2.781-4.18,2.779-6.717C23.485,10.457,22.497,8.078,20.706,6.292z"/>
31
31
  <path fill="#fff" d="M12.138,5.824c-0.449,0-0.905,0.152-1.356,0.453L8.109,8.059C7.357,8.561,5.904,9,5,9c-1.654,0-3,1.346-3,3v2c0,1.654,1.346,3,3,3c0.904,0,2.357,0.439,3.109,0.941l2.672,1.781c0.451,0.301,0.907,0.453,1.356,0.453C13.035,20.176,14,19.495,14,18V8C14,6.505,13.035,5.824,12.138,5.824z M5,15c-0.552,0-1-0.448-1-1v-2c0-0.552,0.448-1,1-1c1.211,0,2.907-0.495,4-1.146v6.293C7.907,15.495,6.211,15,5,15z M12,18c0,0.046-0.002,0.086-0.006,0.12c-0.03-0.016-0.065-0.036-0.104-0.062L10,16.798V9.202l1.891-1.261c0.038-0.025,0.073-0.046,0.104-0.062C11.998,7.914,12,7.954,12,8V18z"/>
32
32
  </g>
33
- </svg>`}load(e){(0,l.isNull)(e)||(void 0!==e.enable&&(this.enable=e.enable),this.mute.load(e.mute),this.unmute.load(e.unmute),this.volumeDown.load(e.volumeDown),this.volumeUp.load(e.volumeUp))}}class v{max;min;step;value;constructor(){this.value=100,this.max=100,this.min=0,this.step=10}load(e){(0,l.isNull)(e)||((0,l.isObject)(e)?(void 0!==e.max&&(this.max=e.max),void 0!==e.min&&(this.min=e.min),void 0!==e.step&&(this.step=e.step),void 0!==e.value&&(this.value=e.value)):this.value=e)}}class d{autoPlay;enable;events;icons;volume;constructor(){this.autoPlay=!0,this.enable=!1,this.events=[],this.icons=new u,this.volume=new v}load(e){(0,l.isNull)(e)||(void 0!==e.autoPlay&&(this.autoPlay=e.autoPlay),void 0!==e.enable&&(this.enable=e.enable),void 0!==e.events&&(this.events=e.events.map(e=>{let t=new c;return t.load(e),t})),this.icons.load(e.icons),void 0!==e.volume&&this.volume.load(e.volume))}}var r=s(519);let p=()=>{removeEventListener(i.m,p),removeEventListener(i.s,p),(0,r.XK)()};class m{id="sounds";_engine;constructor(e){this._engine=e;const t={capture:!0,once:!0};addEventListener(i.m,p,t),addEventListener(i.s,p,t)}async getPlugin(e){let{SoundsPluginInstance:t}=await s.e(915).then(s.bind(s,915));return new t(e,this._engine)}loadOptions(e,t,s){if(!this.needsPlugin(t)&&!this.needsPlugin(s))return;let i=t.sounds;i?.load===void 0&&(t.sounds=i=new d),i.load(s?.sounds)}needsPlugin(e){return e?.sounds?.enable??!1}}},967(e,t,s){s.d(t,{m:()=>i,s:()=>l});let i="pointerdown",l="touchstart"},519(e,t,s){s.d(t,{E3:()=>n,XK:()=>a,jE:()=>l});let i=new Map;function l(e){let t=/(([A-G]b?)(\d))|pause/i.exec(e);if(!t?.length)return;let s=t[2]??t[0],l=i.get(s);if(l)return l[parseInt(t[3]??"0")]}i.set("C",[16.35,32.7,65.41,130.81,261.63,523.25,1046.5,2093,4186.01]),i.set("Db",[17.32,34.65,69.3,138.59,277.18,554.37,1108.73,2217.46,4434.92]),i.set("D",[18.35,36.71,73.42,146.83,293.66,587.33,1174.66,2349.32,4698.63]),i.set("Eb",[19.45,38.89,77.78,155.56,311.13,622.25,1244.51,2489.02,4978.03]),i.set("E",[20.6,41.2,82.41,164.81,329.63,659.25,1318.51,2637.02,5274.04]),i.set("F",[21.83,43.65,87.31,174.61,349.23,698.46,1396.91,2793.83,5587.65]),i.set("Gb",[23.12,46.25,92.5,185,369.99,739.99,1479.98,2959.96,5919.91]),i.set("G",[24.5,49,98,196,392,783.99,1567.98,3135.96,6271.93]),i.set("Ab",[25.96,51.91,103.83,207.65,415.3,830.61,1661.22,3322.44,6644.88]),i.set("A",[27.5,55,110,220,440,880,1760,3520,7040]),i.set("Bb",[29.14,58.27,116.54,233.08,466.16,932.33,1864.66,3729.31,7458.62]),i.set("B",[30.87,61.74,123.47,246.94,493.88,987.77,1975.53,3951.07,7902.13]),i.set("pause",[0]);let o=!0,n=()=>o,a=()=>{o=!1}}}]);
33
+ </svg>`}load(e){(0,l.isNull)(e)||(void 0!==e.enable&&(this.enable=e.enable),this.mute.load(e.mute),this.unmute.load(e.unmute),this.volumeDown.load(e.volumeDown),this.volumeUp.load(e.volumeUp))}}class v{max;min;step;value;constructor(){this.value=100,this.max=100,this.min=0,this.step=10}load(e){(0,l.isNull)(e)||((0,l.isObject)(e)?(void 0!==e.max&&(this.max=e.max),void 0!==e.min&&(this.min=e.min),void 0!==e.step&&(this.step=e.step),void 0!==e.value&&(this.value=e.value)):this.value=e)}}class d{autoPlay;enable;events;icons;volume;constructor(){this.autoPlay=!0,this.enable=!1,this.events=[],this.icons=new u,this.volume=new v}load(e){(0,l.isNull)(e)||(void 0!==e.autoPlay&&(this.autoPlay=e.autoPlay),void 0!==e.enable&&(this.enable=e.enable),void 0!==e.events&&(this.events=e.events.map(e=>{let t=new c;return t.load(e),t})),this.icons.load(e.icons),void 0!==e.volume&&this.volume.load(e.volume))}}var r=s(238);let p=()=>{removeEventListener(i.m,p),removeEventListener(i.s,p),(0,r.XK)()};class m{id="sounds";_engine;constructor(e){this._engine=e;const t={capture:!0,once:!0};addEventListener(i.m,p,t),addEventListener(i.s,p,t)}async getPlugin(e){let{SoundsPluginInstance:t}=await s.e(86).then(s.bind(s,86));return new t(e,this._engine)}loadOptions(e,t,s){if(!this.needsPlugin(t)&&!this.needsPlugin(s))return;let i=t.sounds;i?.load===void 0&&(t.sounds=i=new d),i.load(s?.sounds)}needsPlugin(e){return e?.sounds?.enable??!1}}},886(e,t,s){s.d(t,{m:()=>i,s:()=>l});let i="pointerdown",l="touchstart"},238(e,t,s){s.d(t,{E3:()=>n,XK:()=>a,jE:()=>l});let i=new Map;function l(e){let t=/(([A-G]b?)(\d))|pause/i.exec(e);if(!t?.length)return;let s=t[2]??t[0],l=i.get(s);if(l)return l[parseInt(t[3]??"0")]}i.set("C",[16.35,32.7,65.41,130.81,261.63,523.25,1046.5,2093,4186.01]),i.set("Db",[17.32,34.65,69.3,138.59,277.18,554.37,1108.73,2217.46,4434.92]),i.set("D",[18.35,36.71,73.42,146.83,293.66,587.33,1174.66,2349.32,4698.63]),i.set("Eb",[19.45,38.89,77.78,155.56,311.13,622.25,1244.51,2489.02,4978.03]),i.set("E",[20.6,41.2,82.41,164.81,329.63,659.25,1318.51,2637.02,5274.04]),i.set("F",[21.83,43.65,87.31,174.61,349.23,698.46,1396.91,2793.83,5587.65]),i.set("Gb",[23.12,46.25,92.5,185,369.99,739.99,1479.98,2959.96,5919.91]),i.set("G",[24.5,49,98,196,392,783.99,1567.98,3135.96,6271.93]),i.set("Ab",[25.96,51.91,103.83,207.65,415.3,830.61,1661.22,3322.44,6644.88]),i.set("A",[27.5,55,110,220,440,880,1760,3520,7040]),i.set("Bb",[29.14,58.27,116.54,233.08,466.16,932.33,1864.66,3729.31,7458.62]),i.set("B",[30.87,61.74,123.47,246.94,493.88,987.77,1975.53,3951.07,7902.13]),i.set("pause",[0]);let o=!0,n=()=>o,a=()=>{o=!1}}}]);
package/86.min.js ADDED
@@ -0,0 +1 @@
1
+ "use strict";(this.webpackChunk_tsparticles_plugin_sounds=this.webpackChunk_tsparticles_plugin_sounds||[]).push([[86],{86(t,e,i){i.d(e,{SoundsPluginInstance:()=>m});var n,s,a,o,u=i(303);(n=a||(a={})).mute="soundsMuted",n.unmute="soundsUnmuted",(s=o||(o={})).Block="block",s.None="none";var l=i(238),r=i(886);function c(t){var e,i,n,s,a,o,l,r;let c=(0,u.safeDocument)().createElement("img"),{clickCb:d,container:m,display:h,iconOptions:_,margin:p,options:g,pos:f,rightOffsets:v}=t,{width:y,path:w,style:O,svg:S}=_;return e=c,i=f.top+p,n=f.right-(p*(v.length+1)+y+v.reduce((t,e)=>t+e,0)),s=h,a=g.fullScreen.zIndex+1,o=y,l=p,r=O,e.style.userSelect="none",e.style.position="absolute",e.style.top=`${(i+l).toString()}px`,e.style.left=`${(n-l-o).toString()}px`,e.style.display=s,e.style.zIndex=(a+1).toString(),e.style.cssText+=r,c.src=w??(S?`data:image/svg+xml;base64,${btoa(S)}`:""),(m.canvas.element?.parentNode??(0,u.safeDocument)().body).append(c),c.addEventListener("click",()=>{d()}),c}function d(t){t&&t.remove()}class m{_audioMap;_audioSources;_container;_engine;_gain;_muteImg;_unmuteImg;_volume;_volumeDownImg;_volumeUpImg;constructor(t,e){this._container=t,this._engine=e,this._volume=0,this._audioSources=[],this._audioMap=new Map}async init(){let t=this._container.actualOptions.sounds;if(!t?.enable)return;if(t.autoPlay&&(0,l.E3)()){let t=()=>{removeEventListener(r.m,t),removeEventListener(r.s,t),(0,l.XK)(),this.unmute()},e={capture:!0,once:!0};addEventListener(r.m,t,e),addEventListener(r.s,t,e)}this._volume=t.volume.value;let e=t.events;for(let t of(this._audioMap=new Map,e)){if(!t.audio)continue;let e=(0,u.executeOnSingleOrMultiple)(t.audio,async t=>{let e=await fetch(t.source);if(!e.ok)return;let i=await e.arrayBuffer(),n=this._getAudioContext(),s=await n.decodeAudioData(i);this._audioMap.set(t.source,s)});e instanceof Promise?await e:await Promise.allSettled(e)}}async mute(){this._container.muted||await this.toggleMute()}async start(){let t=this._container,e=t.actualOptions,i=e.sounds;if(!i?.enable||!t.canvas.element)return;t.muted=!0;let n=t.canvas.element,s={top:n.offsetTop,right:n.offsetLeft+n.offsetWidth},{mute:a,unmute:u,volumeDown:r,volumeUp:d}=i.icons,m=async()=>{await this.toggleMute()},h=i.icons.enable?o.Block:o.None;this._muteImg=c({container:t,options:e,pos:s,display:h,iconOptions:a,margin:10,rightOffsets:[r.width,d.width],clickCb:m}),this._unmuteImg=c({container:t,options:e,pos:s,display:o.None,iconOptions:u,margin:10,rightOffsets:[r.width,d.width],clickCb:m}),this._volumeDownImg=c({container:t,options:e,pos:s,display:h,iconOptions:r,margin:10,rightOffsets:[d.width],clickCb:async()=>{await this.volumeDown()}}),this._volumeUpImg=c({container:t,options:e,pos:s,display:h,iconOptions:d,margin:10,rightOffsets:[],clickCb:async()=>{await this.volumeUp()}}),!(0,l.E3)()&&i.autoPlay&&await this.unmute()}stop(){this._container.muted=!0,(async()=>{await this._mute(),d(this._muteImg),d(this._unmuteImg),d(this._volumeDownImg),d(this._volumeUpImg)})()}async toggleMute(){let t=this._container;t.muted=!t.muted,this._updateMuteIcons(),await this._updateMuteStatus()}async unmute(){this._container.muted&&await this.toggleMute()}async volumeDown(){let t=this._container,e=t.actualOptions.sounds;e?.enable&&(t.muted&&(this._volume=0),this._volume-=e.volume.step,await this._updateVolume())}async volumeUp(){let t=this._container.actualOptions.sounds;t?.enable&&(this._volume+=t.volume.step,await this._updateVolume())}_addBuffer=t=>{let e=t.createBufferSource();return this._audioSources.push(e),e};_addOscillator=t=>{let e=t.createOscillator();return this._audioSources.push(e),e};_getAudioContext(){let t=this._container;return t.audioContext??=new AudioContext,t.audioContext}_initEvents=()=>{let t=this._container,e=t.actualOptions.sounds;if(e?.enable&&t.canvas.element)for(let t of e.events){let e=i=>{i&&(async()=>{let n=t.filter&&!t.filter(i);if(this._container===i.container){if(this._container.muted||this._container.destroyed)return(0,u.executeOnSingleOrMultiple)(t.event,t=>{this._engine.removeEventListener(t,e)});if(!n){if(t.audio){let e=(0,u.itemFromSingleOrMultiple)(t.audio);if(!e)return;this._playBuffer(e)}else if(t.melodies){let e=(0,u.itemFromArray)(t.melodies);if(!e)return;e.melodies.length?await Promise.allSettled(e.melodies.map(t=>this._playNote(t.notes,0,e.loop))):await this._playNote(e.notes,0,e.loop)}else if(t.notes){let e=(0,u.itemFromArray)(t.notes);if(!e)return;await this._playNote([e],0,!1)}}}})()};(0,u.executeOnSingleOrMultiple)(t.event,t=>{this._engine.addEventListener(t,e)})}};_mute=async()=>{let t=this._container,e=this._getAudioContext();for(let t of this._audioSources)this._removeAudioSource(t);this._gain&&this._gain.disconnect(),await e.close(),t.audioContext=void 0,this._container.dispatchEvent(a.mute)};_playBuffer=t=>{let e=this._audioMap.get(t.source);if(!e)return;let i=this._container.audioContext;if(!i)return;let n=this._addBuffer(i);n.loop=t.loop,n.buffer=e,n.connect(this._gain??i.destination),n.start()};_playFrequency=async(t,e)=>{if(!this._gain||this._container.muted)return;let i=this._getAudioContext(),n=this._addOscillator(i);return n.connect(this._gain),n.type="sine",n.frequency.value=t,n.start(),new Promise(t=>{setTimeout(()=>{this._removeAudioSource(n),t()},e)})};_playMuteSound=()=>{if(this._container.muted)return;let t=this._getAudioContext(),e=t.createGain();e.connect(t.destination),e.gain.value=0;let i=t.createOscillator();i.connect(e),i.type="sine",i.frequency.value=1,i.start(),setTimeout(()=>{i.stop(),i.disconnect(),e.disconnect()})};_playNote=async(t,e,i)=>{if(this._container.muted)return;let n=t[e];if(!n)return;let s=n.value,a=(0,u.executeOnSingleOrMultiple)(s,async(i,n)=>this._playNoteValue(t,e,n));await ((0,u.isArray)(a)?Promise.allSettled(a):a);let o=e+1;i&&o>=t.length&&(o%=t.length),await this._playNote(t,o,i)};_playNoteValue=async(t,e,i)=>{let n=t[e];if(!n)return;let s=(0,u.itemFromSingleOrMultiple)(n.value,i,!0);if(s)try{let t=(0,l.jE)(s);if(!(0,u.isNumber)(t))return;await this._playFrequency(t,n.duration)}catch(t){(0,u.getLogger)().error(t)}};_removeAudioSource=t=>{t.stop(),t.disconnect(),this._audioSources.splice(this._audioSources.indexOf(t),1)};_unmute=()=>{let t=this._container.actualOptions.sounds;if(!t)return;let e=this._getAudioContext(),i=e.createGain();i.connect(e.destination),i.gain.value=t.volume.value/u.percentDenominator,this._gain=i,this._initEvents(),this._container.dispatchEvent(a.unmute)};_updateMuteIcons=()=>{let t=this._container,e=t.actualOptions.sounds;if(!e?.enable||!e.icons.enable)return;let i=this._muteImg,n=this._unmuteImg;i&&(i.style.display=t.muted?"block":"none"),n&&(n.style.display=t.muted?"none":"block")};_updateMuteStatus=async()=>{let t=this._container,e=this._getAudioContext();t.muted?(await e.suspend(),await this._mute()):(await e.resume(),this._unmute(),this._playMuteSound())};_updateVolume=async()=>{let t=this._container,e=t.actualOptions.sounds;if(!e?.enable)return;(0,u.clamp)(this._volume,e.volume.min,e.volume.max);let i=!1;this._volume<=0&&!t.muted?(this._volume=0,t.muted=!0,i=!0):this._volume>0&&t.muted&&(t.muted=!1,i=!0),i&&(this._updateMuteIcons(),await this._updateMuteStatus()),this._gain?.gain&&(this._gain.gain.value=this._volume/u.percentDenominator)}}}}]);
package/README.md CHANGED
@@ -8,6 +8,12 @@
8
8
 
9
9
  [tsParticles](https://github.com/tsparticles/tsparticles) plugin for particles sounds effect.
10
10
 
11
+ ## Quick checklist
12
+
13
+ 1. Install `@tsparticles/engine` (or use the CDN bundle below)
14
+ 2. Call the package loader function(s) before `tsParticles.load(...)`
15
+ 3. Apply the package options in your `tsParticles.load(...)` config
16
+
11
17
  ## How to use it
12
18
 
13
19
  ### CDN / Vanilla JS / jQuery
@@ -72,3 +78,19 @@ import { loadSoundsPlugin } from "@tsparticles/plugin-sounds";
72
78
  await loadSoundsPlugin(tsParticles);
73
79
  })();
74
80
  ```
81
+
82
+ ## Option mapping
83
+
84
+ - This package primarily extends runtime behavior or rendering and may not expose a single dedicated root options key.
85
+ - Use the usage example in this README and combine with the nearest options section in the docs.
86
+
87
+ ## Common pitfalls
88
+
89
+ - Calling `tsParticles.load(...)` before `loadSoundsPlugin(...)`
90
+ - Verify required peer packages before enabling advanced options
91
+ - Change one option group at a time to isolate regressions quickly
92
+
93
+ ## Related docs
94
+
95
+ - All packages catalog: <https://github.com/tsparticles/tsparticles>
96
+ - Main docs: <https://particles.js.org/docs/>
@@ -277,7 +277,7 @@ export class SoundsPluginInstance {
277
277
  }
278
278
  await audioContext.close();
279
279
  container.audioContext = undefined;
280
- this._engine.dispatchEvent(SoundsEventType.mute, { container: this._container });
280
+ this._container.dispatchEvent(SoundsEventType.mute);
281
281
  };
282
282
  _playBuffer = audio => {
283
283
  const audioBuffer = this._audioMap.get(audio.source);
@@ -383,7 +383,7 @@ export class SoundsPluginInstance {
383
383
  gain.gain.value = soundsOptions.volume.value / percentDenominator;
384
384
  this._gain = gain;
385
385
  this._initEvents();
386
- this._engine.dispatchEvent(SoundsEventType.unmute, { container: this._container });
386
+ this._container.dispatchEvent(SoundsEventType.unmute);
387
387
  };
388
388
  _updateMuteIcons = () => {
389
389
  const container = this._container, soundsOptions = container.actualOptions.sounds;
package/browser/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  export async function loadSoundsPlugin(engine) {
2
- engine.checkVersion("4.0.0-beta.0");
3
- await engine.register(async (e) => {
2
+ engine.checkVersion("4.0.0-beta.10");
3
+ await engine.pluginManager.register(async (e) => {
4
4
  const { SoundsPlugin } = await import("./SoundsPlugin.js");
5
- e.addPlugin(new SoundsPlugin(engine));
5
+ e.pluginManager.addPlugin(new SoundsPlugin(e));
6
6
  });
7
7
  }
@@ -277,7 +277,7 @@ export class SoundsPluginInstance {
277
277
  }
278
278
  await audioContext.close();
279
279
  container.audioContext = undefined;
280
- this._engine.dispatchEvent(SoundsEventType.mute, { container: this._container });
280
+ this._container.dispatchEvent(SoundsEventType.mute);
281
281
  };
282
282
  _playBuffer = audio => {
283
283
  const audioBuffer = this._audioMap.get(audio.source);
@@ -383,7 +383,7 @@ export class SoundsPluginInstance {
383
383
  gain.gain.value = soundsOptions.volume.value / percentDenominator;
384
384
  this._gain = gain;
385
385
  this._initEvents();
386
- this._engine.dispatchEvent(SoundsEventType.unmute, { container: this._container });
386
+ this._container.dispatchEvent(SoundsEventType.unmute);
387
387
  };
388
388
  _updateMuteIcons = () => {
389
389
  const container = this._container, soundsOptions = container.actualOptions.sounds;
package/cjs/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  export async function loadSoundsPlugin(engine) {
2
- engine.checkVersion("4.0.0-beta.0");
3
- await engine.register(async (e) => {
2
+ engine.checkVersion("4.0.0-beta.10");
3
+ await engine.pluginManager.register(async (e) => {
4
4
  const { SoundsPlugin } = await import("./SoundsPlugin.js");
5
- e.addPlugin(new SoundsPlugin(engine));
5
+ e.pluginManager.addPlugin(new SoundsPlugin(e));
6
6
  });
7
7
  }
@@ -4,7 +4,7 @@
4
4
  * Demo / Generator : https://particles.js.org/
5
5
  * GitHub : https://www.github.com/matteobruni/tsparticles
6
6
  * How to use? : Check the GitHub README
7
- * v4.0.0-beta.0
7
+ * v4.0.0-beta.10
8
8
  */
9
9
  "use strict";
10
10
  /*
@@ -23,7 +23,7 @@
23
23
  \**********************************************/
24
24
  (__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
25
25
 
26
- eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ SoundsPluginInstance: () => (/* binding */ SoundsPluginInstance)\n/* harmony export */ });\n/* harmony import */ var _tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tsparticles/engine */ \"@tsparticles/engine\");\n/* harmony import */ var _enums_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./enums.js */ \"./dist/browser/enums.js\");\n/* harmony import */ var _utils_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./utils.js */ \"./dist/browser/utils.js\");\n/* harmony import */ var _constants_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./constants.js */ \"./dist/browser/constants.js\");\n\n\n\n\nconst zIndexOffset = 1, rightOffset = 1, minVolume = 0;\nfunction initImage(data) {\n const img = (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.safeDocument)().createElement(\"img\"), { clickCb, container, display, iconOptions, margin, options, pos, rightOffsets } = data, { width, path, style, svg } = iconOptions, defaultAccumulator = 0;\n setIconStyle(img, pos.top + margin, pos.right - (margin * (rightOffsets.length + rightOffset) + width + rightOffsets.reduce((a, b)=>a + b, defaultAccumulator)), display, options.fullScreen.zIndex + zIndexOffset, width, margin, style);\n img.src = path ?? (svg ? `data:image/svg+xml;base64,${btoa(svg)}` : \"\");\n const parent = container.canvas.element?.parentNode ?? (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.safeDocument)().body;\n parent.append(img);\n img.addEventListener(\"click\", ()=>{\n void clickCb();\n });\n return img;\n}\nfunction removeImage(image) {\n if (!image) {\n return;\n }\n image.remove();\n}\nfunction setIconStyle(icon, top, left, display, zIndex, width, margin, style) {\n icon.style.userSelect = \"none\";\n icon.style.position = \"absolute\";\n icon.style.top = `${(top + margin).toString()}px`;\n icon.style.left = `${(left - margin - width).toString()}px`;\n icon.style.display = display;\n icon.style.zIndex = (zIndex + zIndexOffset).toString();\n icon.style.cssText += style;\n}\nclass SoundsPluginInstance {\n _audioMap;\n _audioSources;\n _container;\n _engine;\n _gain;\n _muteImg;\n _unmuteImg;\n _volume;\n _volumeDownImg;\n _volumeUpImg;\n constructor(container, engine){\n this._container = container;\n this._engine = engine;\n this._volume = 0;\n this._audioSources = [];\n this._audioMap = new Map();\n }\n async init() {\n const container = this._container, options = container.actualOptions, soundsOptions = options.sounds;\n if (!soundsOptions?.enable) {\n return;\n }\n if (soundsOptions.autoPlay && (0,_utils_js__WEBPACK_IMPORTED_MODULE_2__.isWindowMuted)()) {\n const firstClickHandler = ()=>{\n removeEventListener(_constants_js__WEBPACK_IMPORTED_MODULE_3__.mouseDownEvent, firstClickHandler);\n removeEventListener(_constants_js__WEBPACK_IMPORTED_MODULE_3__.touchStartEvent, firstClickHandler);\n (0,_utils_js__WEBPACK_IMPORTED_MODULE_2__.unmuteWindow)();\n void this.unmute();\n }, listenerOptions = {\n capture: true,\n once: true\n };\n addEventListener(_constants_js__WEBPACK_IMPORTED_MODULE_3__.mouseDownEvent, firstClickHandler, listenerOptions);\n addEventListener(_constants_js__WEBPACK_IMPORTED_MODULE_3__.touchStartEvent, firstClickHandler, listenerOptions);\n }\n this._volume = soundsOptions.volume.value;\n const events = soundsOptions.events;\n this._audioMap = new Map();\n for (const event of events){\n if (!event.audio) {\n continue;\n }\n const promises = (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.executeOnSingleOrMultiple)(event.audio, async (audio)=>{\n const response = await fetch(audio.source);\n if (!response.ok) {\n return;\n }\n const arrayBuffer = await response.arrayBuffer(), audioContext = this._getAudioContext(), audioBuffer = await audioContext.decodeAudioData(arrayBuffer);\n this._audioMap.set(audio.source, audioBuffer);\n });\n if (promises instanceof Promise) {\n await promises;\n } else {\n await Promise.allSettled(promises);\n }\n }\n }\n async mute() {\n if (!this._container.muted) {\n await this.toggleMute();\n }\n }\n async start() {\n const container = this._container, options = container.actualOptions, soundsOptions = options.sounds;\n if (!soundsOptions?.enable || !container.canvas.element) {\n return;\n }\n container.muted = true;\n const canvas = container.canvas.element, pos = {\n top: canvas.offsetTop,\n right: canvas.offsetLeft + canvas.offsetWidth\n }, { mute, unmute, volumeDown, volumeUp } = soundsOptions.icons, margin = 10, toggleMute = async ()=>{\n await this.toggleMute();\n }, enableIcons = soundsOptions.icons.enable, display = enableIcons ? _enums_js__WEBPACK_IMPORTED_MODULE_1__.ImageDisplay.Block : _enums_js__WEBPACK_IMPORTED_MODULE_1__.ImageDisplay.None;\n this._muteImg = initImage({\n container,\n options,\n pos,\n display,\n iconOptions: mute,\n margin,\n rightOffsets: [\n volumeDown.width,\n volumeUp.width\n ],\n clickCb: toggleMute\n });\n this._unmuteImg = initImage({\n container,\n options,\n pos,\n display: _enums_js__WEBPACK_IMPORTED_MODULE_1__.ImageDisplay.None,\n iconOptions: unmute,\n margin,\n rightOffsets: [\n volumeDown.width,\n volumeUp.width\n ],\n clickCb: toggleMute\n });\n this._volumeDownImg = initImage({\n container,\n options,\n pos,\n display,\n iconOptions: volumeDown,\n margin,\n rightOffsets: [\n volumeUp.width\n ],\n clickCb: async ()=>{\n await this.volumeDown();\n }\n });\n this._volumeUpImg = initImage({\n container,\n options,\n pos,\n display,\n iconOptions: volumeUp,\n margin,\n rightOffsets: [],\n clickCb: async ()=>{\n await this.volumeUp();\n }\n });\n if (!(0,_utils_js__WEBPACK_IMPORTED_MODULE_2__.isWindowMuted)() && soundsOptions.autoPlay) {\n await this.unmute();\n }\n }\n stop() {\n this._container.muted = true;\n void (async ()=>{\n await this._mute();\n removeImage(this._muteImg);\n removeImage(this._unmuteImg);\n removeImage(this._volumeDownImg);\n removeImage(this._volumeUpImg);\n })();\n }\n async toggleMute() {\n const container = this._container;\n container.muted = !container.muted;\n this._updateMuteIcons();\n await this._updateMuteStatus();\n }\n async unmute() {\n if (this._container.muted) {\n await this.toggleMute();\n }\n }\n async volumeDown() {\n const container = this._container, soundsOptions = container.actualOptions.sounds;\n if (!soundsOptions?.enable) {\n return;\n }\n if (container.muted) {\n this._volume = 0;\n }\n this._volume -= soundsOptions.volume.step;\n await this._updateVolume();\n }\n async volumeUp() {\n const container = this._container, soundsOptions = container.actualOptions.sounds;\n if (!soundsOptions?.enable) {\n return;\n }\n this._volume += soundsOptions.volume.step;\n await this._updateVolume();\n }\n _addBuffer = (audioCtx)=>{\n const buffer = audioCtx.createBufferSource();\n this._audioSources.push(buffer);\n return buffer;\n };\n _addOscillator = (audioCtx)=>{\n const oscillator = audioCtx.createOscillator();\n this._audioSources.push(oscillator);\n return oscillator;\n };\n _getAudioContext() {\n const container = this._container;\n container.audioContext ??= new AudioContext();\n return container.audioContext;\n }\n _initEvents = ()=>{\n const container = this._container, soundsOptions = container.actualOptions.sounds;\n if (!soundsOptions?.enable || !container.canvas.element) {\n return;\n }\n for (const event of soundsOptions.events){\n const cb = (args)=>{\n if (!args) {\n return;\n }\n void (async ()=>{\n const filterNotValid = event.filter && !event.filter(args);\n if (this._container !== args.container) {\n return;\n }\n if (!!this._container.muted || this._container.destroyed) {\n (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.executeOnSingleOrMultiple)(event.event, (item)=>{\n this._engine.removeEventListener(item, cb);\n });\n return;\n }\n if (filterNotValid) {\n return;\n }\n const defaultNoteIndex = 0;\n if (event.audio) {\n const audio = (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.itemFromSingleOrMultiple)(event.audio);\n if (!audio) {\n return;\n }\n this._playBuffer(audio);\n } else if (event.melodies) {\n const melody = (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.itemFromArray)(event.melodies);\n if (!melody) {\n return;\n }\n if (melody.melodies.length) {\n await Promise.allSettled(melody.melodies.map((m)=>this._playNote(m.notes, defaultNoteIndex, melody.loop)));\n } else {\n await this._playNote(melody.notes, defaultNoteIndex, melody.loop);\n }\n } else if (event.notes) {\n const note = (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.itemFromArray)(event.notes);\n if (!note) {\n return;\n }\n await this._playNote([\n note\n ], defaultNoteIndex, false);\n }\n })();\n };\n (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.executeOnSingleOrMultiple)(event.event, (item)=>{\n this._engine.addEventListener(item, cb);\n });\n }\n };\n _mute = async ()=>{\n const container = this._container, audioContext = this._getAudioContext();\n for (const source of this._audioSources){\n this._removeAudioSource(source);\n }\n if (this._gain) {\n this._gain.disconnect();\n }\n await audioContext.close();\n container.audioContext = undefined;\n this._engine.dispatchEvent(_enums_js__WEBPACK_IMPORTED_MODULE_1__.SoundsEventType.mute, {\n container: this._container\n });\n };\n _playBuffer = (audio)=>{\n const audioBuffer = this._audioMap.get(audio.source);\n if (!audioBuffer) {\n return;\n }\n const audioCtx = this._container.audioContext;\n if (!audioCtx) {\n return;\n }\n const source = this._addBuffer(audioCtx);\n source.loop = audio.loop;\n source.buffer = audioBuffer;\n source.connect(this._gain ?? audioCtx.destination);\n source.start();\n };\n _playFrequency = async (frequency, duration)=>{\n if (!this._gain || this._container.muted) {\n return;\n }\n const audioContext = this._getAudioContext(), oscillator = this._addOscillator(audioContext);\n oscillator.connect(this._gain);\n oscillator.type = \"sine\";\n oscillator.frequency.value = frequency;\n oscillator.start();\n return new Promise((resolve)=>{\n setTimeout(()=>{\n this._removeAudioSource(oscillator);\n resolve();\n }, duration);\n });\n };\n _playMuteSound = ()=>{\n if (this._container.muted) {\n return;\n }\n const audioContext = this._getAudioContext(), gain = audioContext.createGain();\n gain.connect(audioContext.destination);\n gain.gain.value = 0;\n const oscillator = audioContext.createOscillator();\n oscillator.connect(gain);\n oscillator.type = \"sine\";\n oscillator.frequency.value = 1;\n oscillator.start();\n setTimeout(()=>{\n oscillator.stop();\n oscillator.disconnect();\n gain.disconnect();\n });\n };\n _playNote = async (notes, noteIdx, loop)=>{\n if (this._container.muted) {\n return;\n }\n const note = notes[noteIdx];\n if (!note) {\n return;\n }\n const value = note.value, promises = (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.executeOnSingleOrMultiple)(value, async (_, idx)=>{\n return this._playNoteValue(notes, noteIdx, idx);\n });\n await ((0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.isArray)(promises) ? Promise.allSettled(promises) : promises);\n const indexOffset = 1;\n let nextNoteIdx = noteIdx + indexOffset;\n if (loop && nextNoteIdx >= notes.length) {\n nextNoteIdx = nextNoteIdx % notes.length;\n }\n await this._playNote(notes, nextNoteIdx, loop);\n };\n _playNoteValue = async (notes, noteIdx, valueIdx)=>{\n const note = notes[noteIdx];\n if (!note) {\n return;\n }\n const value = (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.itemFromSingleOrMultiple)(note.value, valueIdx, true);\n if (!value) {\n return;\n }\n try {\n const freq = (0,_utils_js__WEBPACK_IMPORTED_MODULE_2__.getNoteFrequency)(value);\n if (!(0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.isNumber)(freq)) {\n return;\n }\n await this._playFrequency(freq, note.duration);\n } catch (e) {\n (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.getLogger)().error(e);\n }\n };\n _removeAudioSource = (source)=>{\n source.stop();\n source.disconnect();\n const deleteCount = 1;\n this._audioSources.splice(this._audioSources.indexOf(source), deleteCount);\n };\n _unmute = ()=>{\n const container = this._container, options = container.actualOptions, soundsOptions = options.sounds;\n if (!soundsOptions) {\n return;\n }\n const audioContext = this._getAudioContext(), gain = audioContext.createGain();\n gain.connect(audioContext.destination);\n gain.gain.value = soundsOptions.volume.value / _tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.percentDenominator;\n this._gain = gain;\n this._initEvents();\n this._engine.dispatchEvent(_enums_js__WEBPACK_IMPORTED_MODULE_1__.SoundsEventType.unmute, {\n container: this._container\n });\n };\n _updateMuteIcons = ()=>{\n const container = this._container, soundsOptions = container.actualOptions.sounds;\n if (!soundsOptions?.enable || !soundsOptions.icons.enable) {\n return;\n }\n const muteImg = this._muteImg, unmuteImg = this._unmuteImg;\n if (muteImg) {\n muteImg.style.display = container.muted ? \"block\" : \"none\";\n }\n if (unmuteImg) {\n unmuteImg.style.display = container.muted ? \"none\" : \"block\";\n }\n };\n _updateMuteStatus = async ()=>{\n const container = this._container, audioContext = this._getAudioContext();\n if (container.muted) {\n await audioContext.suspend();\n await this._mute();\n } else {\n await audioContext.resume();\n this._unmute();\n this._playMuteSound();\n }\n };\n _updateVolume = async ()=>{\n const container = this._container, soundsOptions = container.actualOptions.sounds;\n if (!soundsOptions?.enable) {\n return;\n }\n (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.clamp)(this._volume, soundsOptions.volume.min, soundsOptions.volume.max);\n let stateChanged = false;\n if (this._volume <= minVolume && !container.muted) {\n this._volume = 0;\n container.muted = true;\n stateChanged = true;\n } else if (this._volume > minVolume && container.muted) {\n container.muted = false;\n stateChanged = true;\n }\n if (stateChanged) {\n this._updateMuteIcons();\n await this._updateMuteStatus();\n }\n if (this._gain?.gain) {\n this._gain.gain.value = this._volume / _tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.percentDenominator;\n }\n };\n}\n\n\n//# sourceURL=webpack://@tsparticles/plugin-sounds/./dist/browser/SoundsPluginInstance.js?\n}");
26
+ eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ SoundsPluginInstance: () => (/* binding */ SoundsPluginInstance)\n/* harmony export */ });\n/* harmony import */ var _tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tsparticles/engine */ \"@tsparticles/engine\");\n/* harmony import */ var _enums_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./enums.js */ \"./dist/browser/enums.js\");\n/* harmony import */ var _utils_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./utils.js */ \"./dist/browser/utils.js\");\n/* harmony import */ var _constants_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./constants.js */ \"./dist/browser/constants.js\");\n\n\n\n\nconst zIndexOffset = 1, rightOffset = 1, minVolume = 0;\nfunction initImage(data) {\n const img = (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.safeDocument)().createElement(\"img\"), { clickCb, container, display, iconOptions, margin, options, pos, rightOffsets } = data, { width, path, style, svg } = iconOptions, defaultAccumulator = 0;\n setIconStyle(img, pos.top + margin, pos.right - (margin * (rightOffsets.length + rightOffset) + width + rightOffsets.reduce((a, b)=>a + b, defaultAccumulator)), display, options.fullScreen.zIndex + zIndexOffset, width, margin, style);\n img.src = path ?? (svg ? `data:image/svg+xml;base64,${btoa(svg)}` : \"\");\n const parent = container.canvas.element?.parentNode ?? (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.safeDocument)().body;\n parent.append(img);\n img.addEventListener(\"click\", ()=>{\n void clickCb();\n });\n return img;\n}\nfunction removeImage(image) {\n if (!image) {\n return;\n }\n image.remove();\n}\nfunction setIconStyle(icon, top, left, display, zIndex, width, margin, style) {\n icon.style.userSelect = \"none\";\n icon.style.position = \"absolute\";\n icon.style.top = `${(top + margin).toString()}px`;\n icon.style.left = `${(left - margin - width).toString()}px`;\n icon.style.display = display;\n icon.style.zIndex = (zIndex + zIndexOffset).toString();\n icon.style.cssText += style;\n}\nclass SoundsPluginInstance {\n _audioMap;\n _audioSources;\n _container;\n _engine;\n _gain;\n _muteImg;\n _unmuteImg;\n _volume;\n _volumeDownImg;\n _volumeUpImg;\n constructor(container, engine){\n this._container = container;\n this._engine = engine;\n this._volume = 0;\n this._audioSources = [];\n this._audioMap = new Map();\n }\n async init() {\n const container = this._container, options = container.actualOptions, soundsOptions = options.sounds;\n if (!soundsOptions?.enable) {\n return;\n }\n if (soundsOptions.autoPlay && (0,_utils_js__WEBPACK_IMPORTED_MODULE_2__.isWindowMuted)()) {\n const firstClickHandler = ()=>{\n removeEventListener(_constants_js__WEBPACK_IMPORTED_MODULE_3__.mouseDownEvent, firstClickHandler);\n removeEventListener(_constants_js__WEBPACK_IMPORTED_MODULE_3__.touchStartEvent, firstClickHandler);\n (0,_utils_js__WEBPACK_IMPORTED_MODULE_2__.unmuteWindow)();\n void this.unmute();\n }, listenerOptions = {\n capture: true,\n once: true\n };\n addEventListener(_constants_js__WEBPACK_IMPORTED_MODULE_3__.mouseDownEvent, firstClickHandler, listenerOptions);\n addEventListener(_constants_js__WEBPACK_IMPORTED_MODULE_3__.touchStartEvent, firstClickHandler, listenerOptions);\n }\n this._volume = soundsOptions.volume.value;\n const events = soundsOptions.events;\n this._audioMap = new Map();\n for (const event of events){\n if (!event.audio) {\n continue;\n }\n const promises = (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.executeOnSingleOrMultiple)(event.audio, async (audio)=>{\n const response = await fetch(audio.source);\n if (!response.ok) {\n return;\n }\n const arrayBuffer = await response.arrayBuffer(), audioContext = this._getAudioContext(), audioBuffer = await audioContext.decodeAudioData(arrayBuffer);\n this._audioMap.set(audio.source, audioBuffer);\n });\n if (promises instanceof Promise) {\n await promises;\n } else {\n await Promise.allSettled(promises);\n }\n }\n }\n async mute() {\n if (!this._container.muted) {\n await this.toggleMute();\n }\n }\n async start() {\n const container = this._container, options = container.actualOptions, soundsOptions = options.sounds;\n if (!soundsOptions?.enable || !container.canvas.element) {\n return;\n }\n container.muted = true;\n const canvas = container.canvas.element, pos = {\n top: canvas.offsetTop,\n right: canvas.offsetLeft + canvas.offsetWidth\n }, { mute, unmute, volumeDown, volumeUp } = soundsOptions.icons, margin = 10, toggleMute = async ()=>{\n await this.toggleMute();\n }, enableIcons = soundsOptions.icons.enable, display = enableIcons ? _enums_js__WEBPACK_IMPORTED_MODULE_1__.ImageDisplay.Block : _enums_js__WEBPACK_IMPORTED_MODULE_1__.ImageDisplay.None;\n this._muteImg = initImage({\n container,\n options,\n pos,\n display,\n iconOptions: mute,\n margin,\n rightOffsets: [\n volumeDown.width,\n volumeUp.width\n ],\n clickCb: toggleMute\n });\n this._unmuteImg = initImage({\n container,\n options,\n pos,\n display: _enums_js__WEBPACK_IMPORTED_MODULE_1__.ImageDisplay.None,\n iconOptions: unmute,\n margin,\n rightOffsets: [\n volumeDown.width,\n volumeUp.width\n ],\n clickCb: toggleMute\n });\n this._volumeDownImg = initImage({\n container,\n options,\n pos,\n display,\n iconOptions: volumeDown,\n margin,\n rightOffsets: [\n volumeUp.width\n ],\n clickCb: async ()=>{\n await this.volumeDown();\n }\n });\n this._volumeUpImg = initImage({\n container,\n options,\n pos,\n display,\n iconOptions: volumeUp,\n margin,\n rightOffsets: [],\n clickCb: async ()=>{\n await this.volumeUp();\n }\n });\n if (!(0,_utils_js__WEBPACK_IMPORTED_MODULE_2__.isWindowMuted)() && soundsOptions.autoPlay) {\n await this.unmute();\n }\n }\n stop() {\n this._container.muted = true;\n void (async ()=>{\n await this._mute();\n removeImage(this._muteImg);\n removeImage(this._unmuteImg);\n removeImage(this._volumeDownImg);\n removeImage(this._volumeUpImg);\n })();\n }\n async toggleMute() {\n const container = this._container;\n container.muted = !container.muted;\n this._updateMuteIcons();\n await this._updateMuteStatus();\n }\n async unmute() {\n if (this._container.muted) {\n await this.toggleMute();\n }\n }\n async volumeDown() {\n const container = this._container, soundsOptions = container.actualOptions.sounds;\n if (!soundsOptions?.enable) {\n return;\n }\n if (container.muted) {\n this._volume = 0;\n }\n this._volume -= soundsOptions.volume.step;\n await this._updateVolume();\n }\n async volumeUp() {\n const container = this._container, soundsOptions = container.actualOptions.sounds;\n if (!soundsOptions?.enable) {\n return;\n }\n this._volume += soundsOptions.volume.step;\n await this._updateVolume();\n }\n _addBuffer = (audioCtx)=>{\n const buffer = audioCtx.createBufferSource();\n this._audioSources.push(buffer);\n return buffer;\n };\n _addOscillator = (audioCtx)=>{\n const oscillator = audioCtx.createOscillator();\n this._audioSources.push(oscillator);\n return oscillator;\n };\n _getAudioContext() {\n const container = this._container;\n container.audioContext ??= new AudioContext();\n return container.audioContext;\n }\n _initEvents = ()=>{\n const container = this._container, soundsOptions = container.actualOptions.sounds;\n if (!soundsOptions?.enable || !container.canvas.element) {\n return;\n }\n for (const event of soundsOptions.events){\n const cb = (args)=>{\n if (!args) {\n return;\n }\n void (async ()=>{\n const filterNotValid = event.filter && !event.filter(args);\n if (this._container !== args.container) {\n return;\n }\n if (!!this._container.muted || this._container.destroyed) {\n (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.executeOnSingleOrMultiple)(event.event, (item)=>{\n this._engine.removeEventListener(item, cb);\n });\n return;\n }\n if (filterNotValid) {\n return;\n }\n const defaultNoteIndex = 0;\n if (event.audio) {\n const audio = (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.itemFromSingleOrMultiple)(event.audio);\n if (!audio) {\n return;\n }\n this._playBuffer(audio);\n } else if (event.melodies) {\n const melody = (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.itemFromArray)(event.melodies);\n if (!melody) {\n return;\n }\n if (melody.melodies.length) {\n await Promise.allSettled(melody.melodies.map((m)=>this._playNote(m.notes, defaultNoteIndex, melody.loop)));\n } else {\n await this._playNote(melody.notes, defaultNoteIndex, melody.loop);\n }\n } else if (event.notes) {\n const note = (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.itemFromArray)(event.notes);\n if (!note) {\n return;\n }\n await this._playNote([\n note\n ], defaultNoteIndex, false);\n }\n })();\n };\n (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.executeOnSingleOrMultiple)(event.event, (item)=>{\n this._engine.addEventListener(item, cb);\n });\n }\n };\n _mute = async ()=>{\n const container = this._container, audioContext = this._getAudioContext();\n for (const source of this._audioSources){\n this._removeAudioSource(source);\n }\n if (this._gain) {\n this._gain.disconnect();\n }\n await audioContext.close();\n container.audioContext = undefined;\n this._container.dispatchEvent(_enums_js__WEBPACK_IMPORTED_MODULE_1__.SoundsEventType.mute);\n };\n _playBuffer = (audio)=>{\n const audioBuffer = this._audioMap.get(audio.source);\n if (!audioBuffer) {\n return;\n }\n const audioCtx = this._container.audioContext;\n if (!audioCtx) {\n return;\n }\n const source = this._addBuffer(audioCtx);\n source.loop = audio.loop;\n source.buffer = audioBuffer;\n source.connect(this._gain ?? audioCtx.destination);\n source.start();\n };\n _playFrequency = async (frequency, duration)=>{\n if (!this._gain || this._container.muted) {\n return;\n }\n const audioContext = this._getAudioContext(), oscillator = this._addOscillator(audioContext);\n oscillator.connect(this._gain);\n oscillator.type = \"sine\";\n oscillator.frequency.value = frequency;\n oscillator.start();\n return new Promise((resolve)=>{\n setTimeout(()=>{\n this._removeAudioSource(oscillator);\n resolve();\n }, duration);\n });\n };\n _playMuteSound = ()=>{\n if (this._container.muted) {\n return;\n }\n const audioContext = this._getAudioContext(), gain = audioContext.createGain();\n gain.connect(audioContext.destination);\n gain.gain.value = 0;\n const oscillator = audioContext.createOscillator();\n oscillator.connect(gain);\n oscillator.type = \"sine\";\n oscillator.frequency.value = 1;\n oscillator.start();\n setTimeout(()=>{\n oscillator.stop();\n oscillator.disconnect();\n gain.disconnect();\n });\n };\n _playNote = async (notes, noteIdx, loop)=>{\n if (this._container.muted) {\n return;\n }\n const note = notes[noteIdx];\n if (!note) {\n return;\n }\n const value = note.value, promises = (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.executeOnSingleOrMultiple)(value, async (_, idx)=>{\n return this._playNoteValue(notes, noteIdx, idx);\n });\n await ((0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.isArray)(promises) ? Promise.allSettled(promises) : promises);\n const indexOffset = 1;\n let nextNoteIdx = noteIdx + indexOffset;\n if (loop && nextNoteIdx >= notes.length) {\n nextNoteIdx = nextNoteIdx % notes.length;\n }\n await this._playNote(notes, nextNoteIdx, loop);\n };\n _playNoteValue = async (notes, noteIdx, valueIdx)=>{\n const note = notes[noteIdx];\n if (!note) {\n return;\n }\n const value = (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.itemFromSingleOrMultiple)(note.value, valueIdx, true);\n if (!value) {\n return;\n }\n try {\n const freq = (0,_utils_js__WEBPACK_IMPORTED_MODULE_2__.getNoteFrequency)(value);\n if (!(0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.isNumber)(freq)) {\n return;\n }\n await this._playFrequency(freq, note.duration);\n } catch (e) {\n (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.getLogger)().error(e);\n }\n };\n _removeAudioSource = (source)=>{\n source.stop();\n source.disconnect();\n const deleteCount = 1;\n this._audioSources.splice(this._audioSources.indexOf(source), deleteCount);\n };\n _unmute = ()=>{\n const container = this._container, options = container.actualOptions, soundsOptions = options.sounds;\n if (!soundsOptions) {\n return;\n }\n const audioContext = this._getAudioContext(), gain = audioContext.createGain();\n gain.connect(audioContext.destination);\n gain.gain.value = soundsOptions.volume.value / _tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.percentDenominator;\n this._gain = gain;\n this._initEvents();\n this._container.dispatchEvent(_enums_js__WEBPACK_IMPORTED_MODULE_1__.SoundsEventType.unmute);\n };\n _updateMuteIcons = ()=>{\n const container = this._container, soundsOptions = container.actualOptions.sounds;\n if (!soundsOptions?.enable || !soundsOptions.icons.enable) {\n return;\n }\n const muteImg = this._muteImg, unmuteImg = this._unmuteImg;\n if (muteImg) {\n muteImg.style.display = container.muted ? \"block\" : \"none\";\n }\n if (unmuteImg) {\n unmuteImg.style.display = container.muted ? \"none\" : \"block\";\n }\n };\n _updateMuteStatus = async ()=>{\n const container = this._container, audioContext = this._getAudioContext();\n if (container.muted) {\n await audioContext.suspend();\n await this._mute();\n } else {\n await audioContext.resume();\n this._unmute();\n this._playMuteSound();\n }\n };\n _updateVolume = async ()=>{\n const container = this._container, soundsOptions = container.actualOptions.sounds;\n if (!soundsOptions?.enable) {\n return;\n }\n (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.clamp)(this._volume, soundsOptions.volume.min, soundsOptions.volume.max);\n let stateChanged = false;\n if (this._volume <= minVolume && !container.muted) {\n this._volume = 0;\n container.muted = true;\n stateChanged = true;\n } else if (this._volume > minVolume && container.muted) {\n container.muted = false;\n stateChanged = true;\n }\n if (stateChanged) {\n this._updateMuteIcons();\n await this._updateMuteStatus();\n }\n if (this._gain?.gain) {\n this._gain.gain.value = this._volume / _tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.percentDenominator;\n }\n };\n}\n\n\n//# sourceURL=webpack://@tsparticles/plugin-sounds/./dist/browser/SoundsPluginInstance.js?\n}");
27
27
 
28
28
  /***/ },
29
29
 
@@ -4,7 +4,7 @@
4
4
  * Demo / Generator : https://particles.js.org/
5
5
  * GitHub : https://www.github.com/matteobruni/tsparticles
6
6
  * How to use? : Check the GitHub README
7
- * v4.0.0-beta.0
7
+ * v4.0.0-beta.10
8
8
  */
9
9
  "use strict";
10
10
  /*
@@ -277,7 +277,7 @@ export class SoundsPluginInstance {
277
277
  }
278
278
  await audioContext.close();
279
279
  container.audioContext = undefined;
280
- this._engine.dispatchEvent(SoundsEventType.mute, { container: this._container });
280
+ this._container.dispatchEvent(SoundsEventType.mute);
281
281
  };
282
282
  _playBuffer = audio => {
283
283
  const audioBuffer = this._audioMap.get(audio.source);
@@ -383,7 +383,7 @@ export class SoundsPluginInstance {
383
383
  gain.gain.value = soundsOptions.volume.value / percentDenominator;
384
384
  this._gain = gain;
385
385
  this._initEvents();
386
- this._engine.dispatchEvent(SoundsEventType.unmute, { container: this._container });
386
+ this._container.dispatchEvent(SoundsEventType.unmute);
387
387
  };
388
388
  _updateMuteIcons = () => {
389
389
  const container = this._container, soundsOptions = container.actualOptions.sounds;
package/esm/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  export async function loadSoundsPlugin(engine) {
2
- engine.checkVersion("4.0.0-beta.0");
3
- await engine.register(async (e) => {
2
+ engine.checkVersion("4.0.0-beta.10");
3
+ await engine.pluginManager.register(async (e) => {
4
4
  const { SoundsPlugin } = await import("./SoundsPlugin.js");
5
- e.addPlugin(new SoundsPlugin(engine));
5
+ e.pluginManager.addPlugin(new SoundsPlugin(e));
6
6
  });
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tsparticles/plugin-sounds",
3
- "version": "4.0.0-beta.0",
3
+ "version": "4.0.0-beta.10",
4
4
  "description": "tsParticles sounds plugin",
5
5
  "homepage": "https://particles.js.org",
6
6
  "repository": {
@@ -80,13 +80,12 @@
80
80
  "browser": "./browser/index.js",
81
81
  "import": "./esm/index.js",
82
82
  "require": "./cjs/index.js",
83
- "umd": "./umd/index.js",
84
- "default": "./cjs/index.js"
83
+ "default": "./esm/index.js"
85
84
  },
86
85
  "./package.json": "./package.json"
87
86
  },
88
- "dependencies": {
89
- "@tsparticles/engine": "4.0.0-beta.0"
87
+ "peerDependencies": {
88
+ "@tsparticles/engine": "4.0.0-beta.10"
90
89
  },
91
90
  "publishConfig": {
92
91
  "access": "public"