@tsparticles/plugin-emitters 3.0.3 → 3.2.0

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.
@@ -1,2 +1,2 @@
1
1
  /*! For license information please see tsparticles.plugin.emitters.min.js.LICENSE.txt */
2
- !function(t,i){if("object"==typeof exports&&"object"==typeof module)module.exports=i(require("@tsparticles/engine"));else if("function"==typeof define&&define.amd)define(["@tsparticles/engine"],i);else{var e="object"==typeof exports?i(require("@tsparticles/engine")):i(t.window);for(var s in e)("object"==typeof exports?exports:t)[s]=e[s]}}(this,(t=>(()=>{"use strict";var i={533:i=>{i.exports=t}},e={};function s(t){var o=e[t];if(void 0!==o)return o.exports;var n=e[t]={exports:{}};return i[t](n,n.exports,s),n.exports}s.d=(t,i)=>{for(var e in i)s.o(i,e)&&!s.o(t,e)&&Object.defineProperty(t,e,{enumerable:!0,get:i[e]})},s.o=(t,i)=>Object.prototype.hasOwnProperty.call(t,i),s.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})};var o={};return(()=>{s.r(o),s.d(o,{EmitterShapeBase:()=>m,loadEmittersPlugin:()=>_});var t=s(533);class i{constructor(){this.wait=!1}load(i){i&&(void 0!==i.count&&(this.count=i.count),void 0!==i.delay&&(this.delay=(0,t.setRangeValue)(i.delay)),void 0!==i.duration&&(this.duration=(0,t.setRangeValue)(i.duration)),void 0!==i.wait&&(this.wait=i.wait))}}class e{constructor(){this.quantity=1,this.delay=.1}load(i){void 0!==i&&(void 0!==i.quantity&&(this.quantity=(0,t.setRangeValue)(i.quantity)),void 0!==i.delay&&(this.delay=(0,t.setRangeValue)(i.delay)))}}class n{constructor(){this.color=!1,this.opacity=!1}load(t){t&&(void 0!==t.color&&(this.color=t.color),void 0!==t.opacity&&(this.opacity=t.opacity))}}class a{constructor(){this.options={},this.replace=new n,this.type="square"}load(i){i&&(void 0!==i.options&&(this.options=(0,t.deepExtend)({},i.options??{})),this.replace.load(i.replace),void 0!==i.type&&(this.type=i.type))}}class r{constructor(){this.mode="percent",this.height=0,this.width=0}load(t){void 0!==t&&(void 0!==t.mode&&(this.mode=t.mode),void 0!==t.height&&(this.height=t.height),void 0!==t.width&&(this.width=t.width))}}class h{constructor(){this.autoPlay=!0,this.fill=!0,this.life=new i,this.rate=new e,this.shape=new a,this.startCount=0}load(i){i&&(void 0!==i.autoPlay&&(this.autoPlay=i.autoPlay),void 0!==i.size&&(this.size||(this.size=new r),this.size.load(i.size)),void 0!==i.direction&&(this.direction=i.direction),this.domId=i.domId,void 0!==i.fill&&(this.fill=i.fill),this.life.load(i.life),this.name=i.name,this.particles=(0,t.executeOnSingleOrMultiple)(i.particles,(i=>(0,t.deepExtend)({},i))),this.rate.load(i.rate),this.shape.load(i.shape),void 0!==i.position&&(this.position={},void 0!==i.position.x&&(this.position.x=(0,t.setRangeValue)(i.position.x)),void 0!==i.position.y&&(this.position.y=(0,t.setRangeValue)(i.position.y))),void 0!==i.spawnColor&&(void 0===this.spawnColor&&(this.spawnColor=new t.AnimatableColor),this.spawnColor.load(i.spawnColor)),void 0!==i.startCount&&(this.startCount=i.startCount))}}function l(t,i){t.color?t.color.value=i:t.color={value:i}}class c{constructor(i,e,s,o,n){this.emitters=e,this.container=s,this._destroy=()=>{this._mutationObserver?.disconnect(),this._mutationObserver=void 0,this._resizeObserver?.disconnect(),this._resizeObserver=void 0,this.emitters.removeEmitter(this),this._engine.dispatchEvent("emitterDestroyed",{container:this.container,data:{emitter:this}})},this._prepareToDie=()=>{if(this._paused)return;const i=void 0!==this.options.life?.duration?(0,t.getRangeValue)(this.options.life.duration):void 0;this.container.retina.reduceFactor&&(this._lifeCount>0||this._immortal)&&void 0!==i&&i>0&&(this._duration=1e3*i)},this._setColorAnimation=(i,e,s)=>{const o=this.container;if(!i.enable)return e;const n=(0,t.randomInRange)(i.offset),a=1e3*(0,t.getRangeValue)(this.options.rate.delay)/o.retina.reduceFactor;return(e+(0,t.getRangeValue)(i.speed??0)*o.fpsLimit/a+3.6*n)%s},this._engine=i,this._currentDuration=0,this._currentEmitDelay=0,this._currentSpawnDelay=0,this._initialPosition=n,o instanceof h?this.options=o:(this.options=new h,this.options.load(o)),this._spawnDelay=1e3*(0,t.getRangeValue)(this.options.life.delay??0)/this.container.retina.reduceFactor,this.position=this._initialPosition??this._calcPosition(),this.name=this.options.name,this.fill=this.options.fill,this._firstSpawn=!this.options.life.wait,this._startParticlesAdded=!1;let a=(0,t.deepExtend)({},this.options.particles);if(a??={},a.move??={},a.move.direction??=this.options.direction,this.options.spawnColor&&(this.spawnColor=(0,t.rangeColorToHsl)(this.options.spawnColor)),this._paused=!this.options.autoPlay,this._particlesOptions=a,this._size=this._calcSize(),this.size=(0,t.getSize)(this._size,this.container.canvas.size),this._lifeCount=this.options.life.count??-1,this._immortal=this._lifeCount<=0,this.options.domId){const t=document.getElementById(this.options.domId);t&&(this._mutationObserver=new MutationObserver((()=>{this.resize()})),this._resizeObserver=new ResizeObserver((()=>{this.resize()})),this._mutationObserver.observe(t,{attributes:!0,attributeFilter:["style","width","height"]}),this._resizeObserver.observe(t))}const r=this.options.shape,l=this._engine.emitterShapeManager?.getShapeGenerator(r.type);l&&(this._shape=l.generate(this.position,this.size,this.fill,r.options)),this._engine.dispatchEvent("emitterCreated",{container:s,data:{emitter:this}}),this.play()}externalPause(){this._paused=!0,this.pause()}externalPlay(){this._paused=!1,this.play()}async init(){await(this._shape?.init())}pause(){this._paused||delete this._emitDelay}play(){if(!this._paused&&this.container.retina.reduceFactor&&(this._lifeCount>0||this._immortal||!this.options.life.count)&&(this._firstSpawn||this._currentSpawnDelay>=(this._spawnDelay??0))){if(void 0===this._emitDelay){const i=(0,t.getRangeValue)(this.options.rate.delay);this._emitDelay=1e3*i/this.container.retina.reduceFactor}(this._lifeCount>0||this._immortal)&&this._prepareToDie()}}resize(){const i=this._initialPosition;this.position=i&&(0,t.isPointInside)(i,this.container.canvas.size,t.Vector.origin)?i:this._calcPosition(),this._size=this._calcSize(),this.size=(0,t.getSize)(this._size,this.container.canvas.size),this._shape?.resize(this.position,this.size)}async update(i){this._paused||(this._firstSpawn&&(this._firstSpawn=!1,this._currentSpawnDelay=this._spawnDelay??0,this._currentEmitDelay=this._emitDelay??0),this._startParticlesAdded||(this._startParticlesAdded=!0,await this._emitParticles(this.options.startCount)),void 0!==this._duration&&(this._currentDuration+=i.value,this._currentDuration>=this._duration&&(this.pause(),void 0!==this._spawnDelay&&delete this._spawnDelay,this._immortal||this._lifeCount--,this._lifeCount>0||this._immortal?(this.position=this._calcPosition(),this._shape?.resize(this.position,this.size),this._spawnDelay=1e3*(0,t.getRangeValue)(this.options.life.delay??0)/this.container.retina.reduceFactor):this._destroy(),this._currentDuration-=this._duration,delete this._duration)),void 0!==this._spawnDelay&&(this._currentSpawnDelay+=i.value,this._currentSpawnDelay>=this._spawnDelay&&(this._engine.dispatchEvent("emitterPlay",{container:this.container}),this.play(),this._currentSpawnDelay-=this._currentSpawnDelay,delete this._spawnDelay)),void 0!==this._emitDelay&&(this._currentEmitDelay+=i.value,this._currentEmitDelay>=this._emitDelay&&(this._emit(),this._currentEmitDelay-=this._emitDelay)))}_calcPosition(){if(this.options.domId){const t=this.container,i=document.getElementById(this.options.domId);if(i){const e=i.getBoundingClientRect();return{x:(e.x+e.width/2)*t.retina.pixelRatio,y:(e.y+e.height/2)*t.retina.pixelRatio}}}return(0,t.calcPositionOrRandomFromSizeRanged)({size:this.container.canvas.size,position:this.options.position})}_calcSize(){const t=this.container;if(this.options.domId){const i=document.getElementById(this.options.domId);if(i){const e=i.getBoundingClientRect();return{width:e.width*t.retina.pixelRatio,height:e.height*t.retina.pixelRatio,mode:"precise"}}}return this.options.size??(()=>{const t=new r;return t.load({height:0,mode:"percent",width:0}),t})()}async _emit(){if(this._paused)return;const i=(0,t.getRangeValue)(this.options.rate.quantity);await this._emitParticles(i)}async _emitParticles(i){const e=(0,t.itemFromSingleOrMultiple)(this._particlesOptions);for(let s=0;s<i;s++){const i=(0,t.deepExtend)({},e);if(this.spawnColor){const t=this.options.spawnColor?.animation;t&&(this.spawnColor.h=this._setColorAnimation(t.h,this.spawnColor.h,360),this.spawnColor.s=this._setColorAnimation(t.s,this.spawnColor.s,100),this.spawnColor.l=this._setColorAnimation(t.l,this.spawnColor.l,100)),l(i,this.spawnColor)}const s=this.options.shape;let o=this.position;if(this._shape){const t=await this._shape.randomPosition();if(t){o=t.position;const e=s.replace;e.color&&t.color&&l(i,t.color),e.opacity&&(i.opacity?i.opacity.value=t.opacity:i.opacity={value:t.opacity})}else o=null}o&&this.container.particles.addParticle(o,i)}}}class d{constructor(i,e){this.container=e,this._engine=i,this.array=[],this.emitters=[],this.interactivityEmitters={random:{count:1,enable:!1},value:[]},e.getEmitter=i=>void 0===i||(0,t.isNumber)(i)?this.array[i||0]:this.array.find((t=>t.name===i)),e.addEmitter=async(t,i)=>this.addEmitter(t,i),e.removeEmitter=t=>{const i=e.getEmitter(t);i&&this.removeEmitter(i)},e.playEmitter=t=>{const i=e.getEmitter(t);i&&i.externalPlay()},e.pauseEmitter=t=>{const i=e.getEmitter(t);i&&i.externalPause()}}async addEmitter(t,i){const e=new h;e.load(t);const s=new c(this._engine,this,this.container,e,i);return await s.init(),this.array.push(s),s}handleClickMode(i){const e=this.emitters,s=this.interactivityEmitters;if("emitter"!==i)return;let o;if(s&&(0,t.isArray)(s.value))if(s.value.length>0&&s.random.enable){o=[];const i=[];for(let e=0;e<s.random.count;e++){const n=(0,t.arrayRandomIndex)(s.value);i.includes(n)&&i.length<s.value.length?e--:(i.push(n),o.push((0,t.itemFromArray)(s.value,n)))}}else o=s.value;else o=s?.value;const n=o??e,a=this.container.interactivity.mouse.clickPosition;(0,t.executeOnSingleOrMultiple)(n,(t=>{this.addEmitter(t,a)}))}async init(){if(this.emitters=this.container.actualOptions.emitters,this.interactivityEmitters=this.container.actualOptions.interactivity.modes.emitters,this.emitters)if((0,t.isArray)(this.emitters))for(const t of this.emitters)await this.addEmitter(t);else await this.addEmitter(this.emitters)}pause(){for(const t of this.array)t.pause()}play(){for(const t of this.array)t.play()}removeEmitter(t){const i=this.array.indexOf(t);i>=0&&this.array.splice(i,1)}resize(){for(const t of this.array)t.resize()}stop(){this.array=[]}async update(t){for(const i of this.array)await i.update(t)}}const p=new Map;class u{constructor(t){this._engine=t}addShapeGenerator(t,i){this.getShapeGenerator(t)||p.set(t,i)}getShapeGenerator(t){return p.get(t)}getSupportedShapeGenerators(){return p.keys()}}class m{constructor(t,i,e,s){this.position=t,this.size=i,this.fill=e,this.options=s}resize(t,i){this.position=t,this.size=i}}class y{constructor(t){this._engine=t,this.id="emitters"}getPlugin(t){return new d(this._engine,t)}loadOptions(i,e){if(!this.needsPlugin(i)&&!this.needsPlugin(e))return;e?.emitters&&(i.emitters=(0,t.executeOnSingleOrMultiple)(e.emitters,(t=>{const i=new h;return i.load(t),i})));const s=e?.interactivity?.modes?.emitters;if(s)if((0,t.isArray)(s))i.interactivity.modes.emitters={random:{count:1,enable:!0},value:s.map((t=>{const i=new h;return i.load(t),i}))};else{const e=s;if(void 0!==e.value)if((0,t.isArray)(e.value))i.interactivity.modes.emitters={random:{count:e.random.count??1,enable:e.random.enable??!1},value:e.value.map((t=>{const i=new h;return i.load(t),i}))};else{const t=new h;t.load(e.value),i.interactivity.modes.emitters={random:{count:e.random.count??1,enable:e.random.enable??!1},value:t}}else{(i.interactivity.modes.emitters={random:{count:1,enable:!1},value:new h}).value.load(s)}}}needsPlugin(i){if(!i)return!1;const e=i.emitters;return(0,t.isArray)(e)&&!!e.length||void 0!==e||!!i.interactivity?.events?.onClick?.mode&&(0,t.isInArray)("emitter",i.interactivity.events.onClick.mode)}}async function _(t,i=!0){t.emitterShapeManager||(t.emitterShapeManager=new u(t)),t.addEmitterShapeGenerator||(t.addEmitterShapeGenerator=(i,e)=>{t.emitterShapeManager?.addShapeGenerator(i,e)});const e=new y(t);await t.addPlugin(e,i)}})(),o})()));
2
+ !function(e,t){if("object"==typeof exports&&"object"==typeof module)module.exports=t(require("@tsparticles/engine"));else if("function"==typeof define&&define.amd)define(["@tsparticles/engine"],t);else{var r="object"==typeof exports?t(require("@tsparticles/engine")):t(e.window);for(var i in r)("object"==typeof exports?exports:e)[i]=r[i]}}(this,(e=>(()=>{var t,r,i={533:t=>{t.exports=e}},n={};function o(e){var t=n[e];if(void 0!==t)return t.exports;var r=n[e]={exports:{}};return i[e](r,r.exports,o),r.exports}o.m=i,o.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return o.d(t,{a:t}),t},o.d=(e,t)=>{for(var r in t)o.o(t,r)&&!o.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},o.f={},o.e=e=>Promise.all(Object.keys(o.f).reduce(((t,r)=>(o.f[r](e,t),t)),[])),o.u=e=>e+".min.js",o.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),o.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),t={},r="@tsparticles/plugin-emitters:",o.l=(e,i,n,a)=>{if(t[e])t[e].push(i);else{var s,p;if(void 0!==n)for(var l=document.getElementsByTagName("script"),u=0;u<l.length;u++){var c=l[u];if(c.getAttribute("src")==e||c.getAttribute("data-webpack")==r+n){s=c;break}}s||(p=!0,(s=document.createElement("script")).charset="utf-8",s.timeout=120,o.nc&&s.setAttribute("nonce",o.nc),s.setAttribute("data-webpack",r+n),s.src=e),t[e]=[i];var d=(r,i)=>{s.onerror=s.onload=null,clearTimeout(f);var n=t[e];if(delete t[e],s.parentNode&&s.parentNode.removeChild(s),n&&n.forEach((e=>e(i))),r)return r(i)},f=setTimeout(d.bind(null,void 0,{type:"timeout",target:s}),12e4);s.onerror=d.bind(null,s.onerror),s.onload=d.bind(null,s.onload),p&&document.head.appendChild(s)}},o.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{var e;o.g.importScripts&&(e=o.g.location+"");var t=o.g.document;if(!e&&t&&(t.currentScript&&(e=t.currentScript.src),!e)){var r=t.getElementsByTagName("script");if(r.length)for(var i=r.length-1;i>-1&&!e;)e=r[i--].src}if(!e)throw new Error("Automatic publicPath is not supported in this browser");e=e.replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),o.p=e})(),(()=>{var e={606:0};o.f.j=(t,r)=>{var i=o.o(e,t)?e[t]:void 0;if(0!==i)if(i)r.push(i[2]);else{var n=new Promise(((r,n)=>i=e[t]=[r,n]));r.push(i[2]=n);var a=o.p+o.u(t),s=new Error;o.l(a,(r=>{if(o.o(e,t)&&(0!==(i=e[t])&&(e[t]=void 0),i)){var n=r&&("load"===r.type?"missing":r.type),a=r&&r.target&&r.target.src;s.message="Loading chunk "+t+" failed.\n("+n+": "+a+")",s.name="ChunkLoadError",s.type=n,s.request=a,i[1](s)}}),"chunk-"+t,t)}};var t=(t,r)=>{var i,n,a=r[0],s=r[1],p=r[2],l=0;if(a.some((t=>0!==e[t]))){for(i in s)o.o(s,i)&&(o.m[i]=s[i]);if(p)p(o)}for(t&&t(r);l<a.length;l++)n=a[l],o.o(e,n)&&e[n]&&e[n][0](),e[n]=0},r=this.webpackChunk_tsparticles_plugin_emitters=this.webpackChunk_tsparticles_plugin_emitters||[];r.forEach(t.bind(null,0)),r.push=t.bind(null,r.push.bind(r))})();var a={};return(()=>{o.r(a),o.d(a,{EmitterShapeBase:()=>e,loadEmittersPlugin:()=>t});class e{constructor(e,t,r,i){this.position=e,this.size=t,this.fill=r,this.options=i}resize(e,t){this.position=e,this.size=t}}async function t(e,t=!0){if(!e.emitterShapeManager){const{ShapeManager:t}=await o.e(113).then(o.bind(o,113));e.emitterShapeManager=new t(e)}e.addEmitterShapeGenerator||(e.addEmitterShapeGenerator=(t,r)=>{e.emitterShapeManager?.addShapeGenerator(t,r)});const{EmittersPlugin:r}=await o.e(964).then(o.bind(o,964)),i=new r(e);await e.addPlugin(i,t)}})(),a})()));
@@ -1 +1 @@
1
- /*! tsParticles Emitters Plugin v3.0.3 by Matteo Bruni */
1
+ /*! tsParticles Emitters Plugin v3.2.0 by Matteo Bruni */
@@ -30,7 +30,7 @@ export declare class EmitterInstance {
30
30
  private _size;
31
31
  private _spawnDelay?;
32
32
  private _startParticlesAdded;
33
- constructor(engine: EmittersEngine, emitters: Emitters, container: Container, options: RecursivePartial<IEmitter>, position?: ICoordinates);
33
+ constructor(engine: EmittersEngine, emitters: Emitters, container: Container, options: Emitter | RecursivePartial<IEmitter>, position?: ICoordinates);
34
34
  externalPause(): void;
35
35
  externalPlay(): void;
36
36
  init(): Promise<void>;
@@ -1,7 +1,7 @@
1
1
  import { type IContainerPlugin, type ICoordinates, type IDelta, type RecursivePartial, type SingleOrMultiple } from "@tsparticles/engine";
2
- import { Emitter } from "./Options/Classes/Emitter.js";
2
+ import type { Emitter } from "./Options/Classes/Emitter.js";
3
3
  import type { EmitterContainer } from "./EmitterContainer.js";
4
- import { EmitterInstance } from "./EmitterInstance.js";
4
+ import type { EmitterInstance } from "./EmitterInstance.js";
5
5
  import type { EmitterModeOptions } from "./types.js";
6
6
  import type { EmittersEngine } from "./EmittersEngine.js";
7
7
  import type { IEmitter } from "./Options/Interfaces/IEmitter.js";
@@ -0,0 +1,13 @@
1
+ import type { EmitterOptions, IEmitterOptions } from "./types.js";
2
+ import { type IOptions, type IPlugin, type RecursivePartial } from "@tsparticles/engine";
3
+ import type { EmitterContainer } from "./EmitterContainer.js";
4
+ import type { Emitters } from "./Emitters.js";
5
+ import type { EmittersEngine } from "./EmittersEngine.js";
6
+ export declare class EmittersPlugin implements IPlugin {
7
+ readonly id: string;
8
+ private readonly _engine;
9
+ constructor(engine: EmittersEngine);
10
+ getPlugin(container: EmitterContainer): Promise<Emitters>;
11
+ loadOptions(options: EmitterOptions, source?: RecursivePartial<IEmitterOptions>): void;
12
+ needsPlugin(options?: RecursivePartial<IOptions & IEmitterOptions>): boolean;
13
+ }
@@ -13,6 +13,7 @@
13
13
  const engine_1 = require("@tsparticles/engine");
14
14
  const Emitter_js_1 = require("./Options/Classes/Emitter.js");
15
15
  const EmitterSize_js_1 = require("./Options/Classes/EmitterSize.js");
16
+ const half = 0.5, defaultLifeDelay = 0, minLifeCount = 0, defaultSpawnDelay = 0, defaultEmitDelay = 0, defaultLifeCount = -1, defaultColorAnimationFactor = 1;
16
17
  function setParticlesOptionsColor(particlesOptions, color) {
17
18
  if (particlesOptions.color) {
18
19
  particlesOptions.color.value = color;
@@ -44,21 +45,21 @@
44
45
  if (this._paused) {
45
46
  return;
46
47
  }
47
- const duration = this.options.life?.duration !== undefined ? (0, engine_1.getRangeValue)(this.options.life.duration) : undefined;
48
+ const duration = this.options.life?.duration !== undefined ? (0, engine_1.getRangeValue)(this.options.life.duration) : undefined, minDuration = 0, minLifeCount = 0;
48
49
  if (this.container.retina.reduceFactor &&
49
- (this._lifeCount > 0 || this._immortal) &&
50
+ (this._lifeCount > minLifeCount || this._immortal) &&
50
51
  duration !== undefined &&
51
- duration > 0) {
52
- this._duration = duration * 1000;
52
+ duration > minDuration) {
53
+ this._duration = duration * engine_1.millisecondsToSeconds;
53
54
  }
54
55
  };
55
- this._setColorAnimation = (animation, initValue, maxValue) => {
56
+ this._setColorAnimation = (animation, initValue, maxValue, factor = defaultColorAnimationFactor) => {
56
57
  const container = this.container;
57
58
  if (!animation.enable) {
58
59
  return initValue;
59
60
  }
60
- const colorOffset = (0, engine_1.randomInRange)(animation.offset), delay = (0, engine_1.getRangeValue)(this.options.rate.delay), emitFactor = (1000 * delay) / container.retina.reduceFactor, colorSpeed = (0, engine_1.getRangeValue)(animation.speed ?? 0);
61
- return (initValue + (colorSpeed * container.fpsLimit) / emitFactor + colorOffset * 3.6) % maxValue;
61
+ const colorOffset = (0, engine_1.randomInRange)(animation.offset), delay = (0, engine_1.getRangeValue)(this.options.rate.delay), emitFactor = (delay * engine_1.millisecondsToSeconds) / container.retina.reduceFactor, defaultColorSpeed = 0, colorSpeed = (0, engine_1.getRangeValue)(animation.speed ?? defaultColorSpeed);
62
+ return (initValue + (colorSpeed * container.fpsLimit) / emitFactor + colorOffset * factor) % maxValue;
62
63
  };
63
64
  this._engine = engine;
64
65
  this._currentDuration = 0;
@@ -72,7 +73,9 @@
72
73
  this.options = new Emitter_js_1.Emitter();
73
74
  this.options.load(options);
74
75
  }
75
- this._spawnDelay = ((0, engine_1.getRangeValue)(this.options.life.delay ?? 0) * 1000) / this.container.retina.reduceFactor;
76
+ this._spawnDelay =
77
+ ((0, engine_1.getRangeValue)(this.options.life.delay ?? defaultLifeDelay) * engine_1.millisecondsToSeconds) /
78
+ this.container.retina.reduceFactor;
76
79
  this.position = this._initialPosition ?? this._calcPosition();
77
80
  this.name = this.options.name;
78
81
  this.fill = this.options.fill;
@@ -89,8 +92,8 @@
89
92
  this._particlesOptions = particlesOptions;
90
93
  this._size = this._calcSize();
91
94
  this.size = (0, engine_1.getSize)(this._size, this.container.canvas.size);
92
- this._lifeCount = this.options.life.count ?? -1;
93
- this._immortal = this._lifeCount <= 0;
95
+ this._lifeCount = this.options.life.count ?? defaultLifeCount;
96
+ this._immortal = this._lifeCount <= minLifeCount;
94
97
  if (this.options.domId) {
95
98
  const element = document.getElementById(this.options.domId);
96
99
  if (element) {
@@ -141,15 +144,15 @@
141
144
  return;
142
145
  }
143
146
  if (!(this.container.retina.reduceFactor &&
144
- (this._lifeCount > 0 || this._immortal || !this.options.life.count) &&
145
- (this._firstSpawn || this._currentSpawnDelay >= (this._spawnDelay ?? 0)))) {
147
+ (this._lifeCount > minLifeCount || this._immortal || !this.options.life.count) &&
148
+ (this._firstSpawn || this._currentSpawnDelay >= (this._spawnDelay ?? defaultSpawnDelay)))) {
146
149
  return;
147
150
  }
148
151
  if (this._emitDelay === undefined) {
149
152
  const delay = (0, engine_1.getRangeValue)(this.options.rate.delay);
150
- this._emitDelay = (1000 * delay) / this.container.retina.reduceFactor;
153
+ this._emitDelay = (delay * engine_1.millisecondsToSeconds) / this.container.retina.reduceFactor;
151
154
  }
152
- if (this._lifeCount > 0 || this._immortal) {
155
+ if (this._lifeCount > minLifeCount || this._immortal) {
153
156
  this._prepareToDie();
154
157
  }
155
158
  }
@@ -169,8 +172,8 @@
169
172
  }
170
173
  if (this._firstSpawn) {
171
174
  this._firstSpawn = false;
172
- this._currentSpawnDelay = this._spawnDelay ?? 0;
173
- this._currentEmitDelay = this._emitDelay ?? 0;
175
+ this._currentSpawnDelay = this._spawnDelay ?? defaultSpawnDelay;
176
+ this._currentEmitDelay = this._emitDelay ?? defaultEmitDelay;
174
177
  }
175
178
  if (!this._startParticlesAdded) {
176
179
  this._startParticlesAdded = true;
@@ -186,11 +189,12 @@
186
189
  if (!this._immortal) {
187
190
  this._lifeCount--;
188
191
  }
189
- if (this._lifeCount > 0 || this._immortal) {
192
+ if (this._lifeCount > minLifeCount || this._immortal) {
190
193
  this.position = this._calcPosition();
191
194
  this._shape?.resize(this.position, this.size);
192
195
  this._spawnDelay =
193
- ((0, engine_1.getRangeValue)(this.options.life.delay ?? 0) * 1000) / this.container.retina.reduceFactor;
196
+ ((0, engine_1.getRangeValue)(this.options.life.delay ?? defaultLifeDelay) * engine_1.millisecondsToSeconds) /
197
+ this.container.retina.reduceFactor;
194
198
  }
195
199
  else {
196
200
  this._destroy();
@@ -213,19 +217,19 @@
213
217
  if (this._emitDelay !== undefined) {
214
218
  this._currentEmitDelay += delta.value;
215
219
  if (this._currentEmitDelay >= this._emitDelay) {
216
- this._emit();
220
+ await this._emit();
217
221
  this._currentEmitDelay -= this._emitDelay;
218
222
  }
219
223
  }
220
224
  }
221
225
  _calcPosition() {
222
226
  if (this.options.domId) {
223
- const container = this.container, element = document.getElementById(this.options.domId);
227
+ const element = document.getElementById(this.options.domId);
224
228
  if (element) {
225
- const elRect = element.getBoundingClientRect();
229
+ const elRect = element.getBoundingClientRect(), pxRatio = this.container.retina.pixelRatio;
226
230
  return {
227
- x: (elRect.x + elRect.width / 2) * container.retina.pixelRatio,
228
- y: (elRect.y + elRect.height / 2) * container.retina.pixelRatio,
231
+ x: (elRect.x + elRect.width * half) * pxRatio,
232
+ y: (elRect.y + elRect.height * half) * pxRatio,
229
233
  };
230
234
  }
231
235
  }
@@ -272,9 +276,14 @@
272
276
  if (this.spawnColor) {
273
277
  const hslAnimation = this.options.spawnColor?.animation;
274
278
  if (hslAnimation) {
275
- this.spawnColor.h = this._setColorAnimation(hslAnimation.h, this.spawnColor.h, 360);
276
- this.spawnColor.s = this._setColorAnimation(hslAnimation.s, this.spawnColor.s, 100);
277
- this.spawnColor.l = this._setColorAnimation(hslAnimation.l, this.spawnColor.l, 100);
279
+ const maxValues = {
280
+ h: 360,
281
+ s: 100,
282
+ l: 100,
283
+ }, colorFactor = 3.6;
284
+ this.spawnColor.h = this._setColorAnimation(hslAnimation.h, this.spawnColor.h, maxValues.h, colorFactor);
285
+ this.spawnColor.s = this._setColorAnimation(hslAnimation.s, this.spawnColor.s, maxValues.s);
286
+ this.spawnColor.l = this._setColorAnimation(hslAnimation.l, this.spawnColor.l, maxValues.l);
278
287
  }
279
288
  setParticlesOptionsColor(particlesOptions, this.spawnColor);
280
289
  }
@@ -304,7 +313,7 @@
304
313
  }
305
314
  }
306
315
  if (position) {
307
- this.container.particles.addParticle(position, particlesOptions);
316
+ await this.container.particles.addParticle(position, particlesOptions);
308
317
  }
309
318
  }
310
319
  }
package/umd/Emitters.js CHANGED
@@ -1,18 +1,40 @@
1
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
2
+ if (k2 === undefined) k2 = k;
3
+ var desc = Object.getOwnPropertyDescriptor(m, k);
4
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
5
+ desc = { enumerable: true, get: function() { return m[k]; } };
6
+ }
7
+ Object.defineProperty(o, k2, desc);
8
+ }) : (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ o[k2] = m[k];
11
+ }));
12
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
13
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
14
+ }) : function(o, v) {
15
+ o["default"] = v;
16
+ });
17
+ var __importStar = (this && this.__importStar) || function (mod) {
18
+ if (mod && mod.__esModule) return mod;
19
+ var result = {};
20
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
21
+ __setModuleDefault(result, mod);
22
+ return result;
23
+ };
1
24
  (function (factory) {
2
25
  if (typeof module === "object" && typeof module.exports === "object") {
3
26
  var v = factory(require, exports);
4
27
  if (v !== undefined) module.exports = v;
5
28
  }
6
29
  else if (typeof define === "function" && define.amd) {
7
- define(["require", "exports", "@tsparticles/engine", "./Options/Classes/Emitter.js", "./EmitterInstance.js"], factory);
30
+ define(["require", "exports", "@tsparticles/engine"], factory);
8
31
  }
9
32
  })(function (require, exports) {
10
33
  "use strict";
34
+ var __syncRequire = typeof module === "object" && typeof module.exports === "object";
11
35
  Object.defineProperty(exports, "__esModule", { value: true });
12
36
  exports.Emitters = void 0;
13
37
  const engine_1 = require("@tsparticles/engine");
14
- const Emitter_js_1 = require("./Options/Classes/Emitter.js");
15
- const EmitterInstance_js_1 = require("./EmitterInstance.js");
16
38
  class Emitters {
17
39
  constructor(engine, container) {
18
40
  this.container = container;
@@ -26,8 +48,9 @@
26
48
  },
27
49
  value: [],
28
50
  };
51
+ const defaultIndex = 0;
29
52
  container.getEmitter = (idxOrName) => idxOrName === undefined || (0, engine_1.isNumber)(idxOrName)
30
- ? this.array[idxOrName || 0]
53
+ ? this.array[idxOrName ?? defaultIndex]
31
54
  : this.array.find((t) => t.name === idxOrName);
32
55
  container.addEmitter = async (options, position) => this.addEmitter(options, position);
33
56
  container.removeEmitter = (idxOrName) => {
@@ -50,9 +73,9 @@
50
73
  };
51
74
  }
52
75
  async addEmitter(options, position) {
53
- const emitterOptions = new Emitter_js_1.Emitter();
76
+ const { Emitter } = await (__syncRequire ? Promise.resolve().then(() => __importStar(require("./Options/Classes/Emitter.js"))) : new Promise((resolve_1, reject_1) => { require(["./Options/Classes/Emitter.js"], resolve_1, reject_1); }).then(__importStar)), { EmitterInstance } = await (__syncRequire ? Promise.resolve().then(() => __importStar(require("./EmitterInstance.js"))) : new Promise((resolve_2, reject_2) => { require(["./EmitterInstance.js"], resolve_2, reject_2); }).then(__importStar)), emitterOptions = new Emitter();
54
77
  emitterOptions.load(options);
55
- const emitter = new EmitterInstance_js_1.EmitterInstance(this._engine, this, this.container, emitterOptions, position);
78
+ const emitter = new EmitterInstance(this._engine, this, this.container, emitterOptions, position);
56
79
  await emitter.init();
57
80
  this.array.push(emitter);
58
81
  return emitter;
@@ -64,7 +87,8 @@
64
87
  }
65
88
  let emittersModeOptions;
66
89
  if (modeEmitters && (0, engine_1.isArray)(modeEmitters.value)) {
67
- if (modeEmitters.value.length > 0 && modeEmitters.random.enable) {
90
+ const minLength = 0;
91
+ if (modeEmitters.value.length > minLength && modeEmitters.random.enable) {
68
92
  emittersModeOptions = [];
69
93
  const usedIndexes = [];
70
94
  for (let i = 0; i < modeEmitters.random.count; i++) {
@@ -85,8 +109,8 @@
85
109
  emittersModeOptions = modeEmitters?.value;
86
110
  }
87
111
  const emittersOptions = emittersModeOptions ?? emitterOptions, ePosition = this.container.interactivity.mouse.clickPosition;
88
- (0, engine_1.executeOnSingleOrMultiple)(emittersOptions, (emitter) => {
89
- this.addEmitter(emitter, ePosition);
112
+ void (0, engine_1.executeOnSingleOrMultiple)(emittersOptions, async (emitter) => {
113
+ await this.addEmitter(emitter, ePosition);
90
114
  });
91
115
  }
92
116
  async init() {
@@ -115,9 +139,9 @@
115
139
  }
116
140
  }
117
141
  removeEmitter(emitter) {
118
- const index = this.array.indexOf(emitter);
119
- if (index >= 0) {
120
- this.array.splice(index, 1);
142
+ const index = this.array.indexOf(emitter), minIndex = 0, deleteCount = 1;
143
+ if (index >= minIndex) {
144
+ this.array.splice(index, deleteCount);
121
145
  }
122
146
  }
123
147
  resize() {
@@ -0,0 +1,128 @@
1
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
2
+ if (k2 === undefined) k2 = k;
3
+ var desc = Object.getOwnPropertyDescriptor(m, k);
4
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
5
+ desc = { enumerable: true, get: function() { return m[k]; } };
6
+ }
7
+ Object.defineProperty(o, k2, desc);
8
+ }) : (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ o[k2] = m[k];
11
+ }));
12
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
13
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
14
+ }) : function(o, v) {
15
+ o["default"] = v;
16
+ });
17
+ var __importStar = (this && this.__importStar) || function (mod) {
18
+ if (mod && mod.__esModule) return mod;
19
+ var result = {};
20
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
21
+ __setModuleDefault(result, mod);
22
+ return result;
23
+ };
24
+ (function (factory) {
25
+ if (typeof module === "object" && typeof module.exports === "object") {
26
+ var v = factory(require, exports);
27
+ if (v !== undefined) module.exports = v;
28
+ }
29
+ else if (typeof define === "function" && define.amd) {
30
+ define(["require", "exports", "@tsparticles/engine", "./Options/Classes/Emitter.js"], factory);
31
+ }
32
+ })(function (require, exports) {
33
+ "use strict";
34
+ var __syncRequire = typeof module === "object" && typeof module.exports === "object";
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.EmittersPlugin = void 0;
37
+ const engine_1 = require("@tsparticles/engine");
38
+ const Emitter_js_1 = require("./Options/Classes/Emitter.js");
39
+ class EmittersPlugin {
40
+ constructor(engine) {
41
+ this._engine = engine;
42
+ this.id = "emitters";
43
+ }
44
+ async getPlugin(container) {
45
+ const { Emitters } = await (__syncRequire ? Promise.resolve().then(() => __importStar(require("./Emitters.js"))) : new Promise((resolve_1, reject_1) => { require(["./Emitters.js"], resolve_1, reject_1); }).then(__importStar));
46
+ return new Emitters(this._engine, container);
47
+ }
48
+ loadOptions(options, source) {
49
+ if (!this.needsPlugin(options) && !this.needsPlugin(source)) {
50
+ return;
51
+ }
52
+ if (source?.emitters) {
53
+ options.emitters = (0, engine_1.executeOnSingleOrMultiple)(source.emitters, (emitter) => {
54
+ const tmp = new Emitter_js_1.Emitter();
55
+ tmp.load(emitter);
56
+ return tmp;
57
+ });
58
+ }
59
+ const interactivityEmitters = source?.interactivity?.modes?.emitters;
60
+ if (interactivityEmitters) {
61
+ if ((0, engine_1.isArray)(interactivityEmitters)) {
62
+ options.interactivity.modes.emitters = {
63
+ random: {
64
+ count: 1,
65
+ enable: true,
66
+ },
67
+ value: interactivityEmitters.map((s) => {
68
+ const tmp = new Emitter_js_1.Emitter();
69
+ tmp.load(s);
70
+ return tmp;
71
+ }),
72
+ };
73
+ }
74
+ else {
75
+ const emitterMode = interactivityEmitters;
76
+ if (emitterMode.value !== undefined) {
77
+ const defaultCount = 1;
78
+ if ((0, engine_1.isArray)(emitterMode.value)) {
79
+ options.interactivity.modes.emitters = {
80
+ random: {
81
+ count: emitterMode.random.count ?? defaultCount,
82
+ enable: emitterMode.random.enable ?? false,
83
+ },
84
+ value: emitterMode.value.map((s) => {
85
+ const tmp = new Emitter_js_1.Emitter();
86
+ tmp.load(s);
87
+ return tmp;
88
+ }),
89
+ };
90
+ }
91
+ else {
92
+ const tmp = new Emitter_js_1.Emitter();
93
+ tmp.load(emitterMode.value);
94
+ options.interactivity.modes.emitters = {
95
+ random: {
96
+ count: emitterMode.random.count ?? defaultCount,
97
+ enable: emitterMode.random.enable ?? false,
98
+ },
99
+ value: tmp,
100
+ };
101
+ }
102
+ }
103
+ else {
104
+ const emitterOptions = (options.interactivity.modes.emitters = {
105
+ random: {
106
+ count: 1,
107
+ enable: false,
108
+ },
109
+ value: new Emitter_js_1.Emitter(),
110
+ });
111
+ emitterOptions.value.load(interactivityEmitters);
112
+ }
113
+ }
114
+ }
115
+ }
116
+ needsPlugin(options) {
117
+ if (!options) {
118
+ return false;
119
+ }
120
+ const emitters = options.emitters;
121
+ return (((0, engine_1.isArray)(emitters) && !!emitters.length) ||
122
+ emitters !== undefined ||
123
+ (!!options.interactivity?.events?.onClick?.mode &&
124
+ (0, engine_1.isInArray)("emitter", options.interactivity.events.onClick.mode)));
125
+ }
126
+ }
127
+ exports.EmittersPlugin = EmittersPlugin;
128
+ });
package/umd/index.js CHANGED
@@ -9,6 +9,18 @@ var __createBinding = (this && this.__createBinding) || (Object.create ? (functi
9
9
  if (k2 === undefined) k2 = k;
10
10
  o[k2] = m[k];
11
11
  }));
12
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
13
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
14
+ }) : function(o, v) {
15
+ o["default"] = v;
16
+ });
17
+ var __importStar = (this && this.__importStar) || function (mod) {
18
+ if (mod && mod.__esModule) return mod;
19
+ var result = {};
20
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
21
+ __setModuleDefault(result, mod);
22
+ return result;
23
+ };
12
24
  var __exportStar = (this && this.__exportStar) || function(m, exports) {
13
25
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
14
26
  };
@@ -18,112 +30,24 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
18
30
  if (v !== undefined) module.exports = v;
19
31
  }
20
32
  else if (typeof define === "function" && define.amd) {
21
- define(["require", "exports", "@tsparticles/engine", "./Options/Classes/Emitter.js", "./Emitters.js", "./ShapeManager.js", "./EmitterContainer.js", "./EmitterShapeBase.js", "./EmittersEngine.js", "./IEmitterShape.js", "./IEmitterShapeGenerator.js", "./Enums/EmitterClickMode.js", "./IRandomPositionData.js"], factory);
33
+ define(["require", "exports", "./EmitterContainer.js", "./EmitterShapeBase.js", "./EmittersEngine.js", "./IEmitterShape.js", "./IEmitterShapeGenerator.js", "./Enums/EmitterClickMode.js", "./IRandomPositionData.js"], factory);
22
34
  }
23
35
  })(function (require, exports) {
24
36
  "use strict";
37
+ var __syncRequire = typeof module === "object" && typeof module.exports === "object";
25
38
  Object.defineProperty(exports, "__esModule", { value: true });
26
39
  exports.loadEmittersPlugin = void 0;
27
- const engine_1 = require("@tsparticles/engine");
28
- const Emitter_js_1 = require("./Options/Classes/Emitter.js");
29
- const Emitters_js_1 = require("./Emitters.js");
30
- const ShapeManager_js_1 = require("./ShapeManager.js");
31
- class EmittersPlugin {
32
- constructor(engine) {
33
- this._engine = engine;
34
- this.id = "emitters";
35
- }
36
- getPlugin(container) {
37
- return new Emitters_js_1.Emitters(this._engine, container);
38
- }
39
- loadOptions(options, source) {
40
- if (!this.needsPlugin(options) && !this.needsPlugin(source)) {
41
- return;
42
- }
43
- if (source?.emitters) {
44
- options.emitters = (0, engine_1.executeOnSingleOrMultiple)(source.emitters, (emitter) => {
45
- const tmp = new Emitter_js_1.Emitter();
46
- tmp.load(emitter);
47
- return tmp;
48
- });
49
- }
50
- const interactivityEmitters = source?.interactivity?.modes?.emitters;
51
- if (interactivityEmitters) {
52
- if ((0, engine_1.isArray)(interactivityEmitters)) {
53
- options.interactivity.modes.emitters = {
54
- random: {
55
- count: 1,
56
- enable: true,
57
- },
58
- value: interactivityEmitters.map((s) => {
59
- const tmp = new Emitter_js_1.Emitter();
60
- tmp.load(s);
61
- return tmp;
62
- }),
63
- };
64
- }
65
- else {
66
- const emitterMode = interactivityEmitters;
67
- if (emitterMode.value !== undefined) {
68
- if ((0, engine_1.isArray)(emitterMode.value)) {
69
- options.interactivity.modes.emitters = {
70
- random: {
71
- count: emitterMode.random.count ?? 1,
72
- enable: emitterMode.random.enable ?? false,
73
- },
74
- value: emitterMode.value.map((s) => {
75
- const tmp = new Emitter_js_1.Emitter();
76
- tmp.load(s);
77
- return tmp;
78
- }),
79
- };
80
- }
81
- else {
82
- const tmp = new Emitter_js_1.Emitter();
83
- tmp.load(emitterMode.value);
84
- options.interactivity.modes.emitters = {
85
- random: {
86
- count: emitterMode.random.count ?? 1,
87
- enable: emitterMode.random.enable ?? false,
88
- },
89
- value: tmp,
90
- };
91
- }
92
- }
93
- else {
94
- const emitterOptions = (options.interactivity.modes.emitters = {
95
- random: {
96
- count: 1,
97
- enable: false,
98
- },
99
- value: new Emitter_js_1.Emitter(),
100
- });
101
- emitterOptions.value.load(interactivityEmitters);
102
- }
103
- }
104
- }
105
- }
106
- needsPlugin(options) {
107
- if (!options) {
108
- return false;
109
- }
110
- const emitters = options.emitters;
111
- return (((0, engine_1.isArray)(emitters) && !!emitters.length) ||
112
- emitters !== undefined ||
113
- (!!options.interactivity?.events?.onClick?.mode &&
114
- (0, engine_1.isInArray)("emitter", options.interactivity.events.onClick.mode)));
115
- }
116
- }
117
40
  async function loadEmittersPlugin(engine, refresh = true) {
118
41
  if (!engine.emitterShapeManager) {
119
- engine.emitterShapeManager = new ShapeManager_js_1.ShapeManager(engine);
42
+ const { ShapeManager } = await (__syncRequire ? Promise.resolve().then(() => __importStar(require("./ShapeManager.js"))) : new Promise((resolve_1, reject_1) => { require(["./ShapeManager.js"], resolve_1, reject_1); }).then(__importStar));
43
+ engine.emitterShapeManager = new ShapeManager(engine);
120
44
  }
121
45
  if (!engine.addEmitterShapeGenerator) {
122
46
  engine.addEmitterShapeGenerator = (name, generator) => {
123
47
  engine.emitterShapeManager?.addShapeGenerator(name, generator);
124
48
  };
125
49
  }
126
- const plugin = new EmittersPlugin(engine);
50
+ const { EmittersPlugin } = await (__syncRequire ? Promise.resolve().then(() => __importStar(require("./EmittersPlugin.js"))) : new Promise((resolve_2, reject_2) => { require(["./EmittersPlugin.js"], resolve_2, reject_2); }).then(__importStar)), plugin = new EmittersPlugin(engine);
127
51
  await engine.addPlugin(plugin, refresh);
128
52
  }
129
53
  exports.loadEmittersPlugin = loadEmittersPlugin;