@tsparticles/fireworks
Version:
tsParticles fireworks bundle — easily create spectacular fireworks and fountain particle effects with built-in presets. Ready to use components available for React, Vue.js (2.x and 3.x), Angular, Svelte, jQuery, Preact, Riot.js, Inferno.
1,277 lines (1,243 loc) • 339 kB
JavaScript
(function(g){g.__tsParticlesInternals=g.__tsParticlesInternals||{};g.__tsParticlesInternals.bundles=g.__tsParticlesInternals.bundles||{};g.__tsParticlesInternals.effects=g.__tsParticlesInternals.effects||{};g.__tsParticlesInternals.engine=g.__tsParticlesInternals.engine||{};g.__tsParticlesInternals.interactions=g.__tsParticlesInternals.interactions||{};g.__tsParticlesInternals.palettes=g.__tsParticlesInternals.palettes||{};g.__tsParticlesInternals.paths=g.__tsParticlesInternals.paths||{};g.__tsParticlesInternals.plugins=g.__tsParticlesInternals.plugins||{};g.__tsParticlesInternals.plugins=g.__tsParticlesInternals.plugins||{};g.__tsParticlesInternals.plugins.emittersShapes=g.__tsParticlesInternals.plugins.emittersShapes||{};g.__tsParticlesInternals.presets=g.__tsParticlesInternals.presets||{};g.__tsParticlesInternals.shapes=g.__tsParticlesInternals.shapes||{};g.__tsParticlesInternals.updaters=g.__tsParticlesInternals.updaters||{};g.__tsParticlesInternals.utils=g.__tsParticlesInternals.utils||{};g.__tsParticlesInternals.canvas=g.__tsParticlesInternals.canvas||{};g.__tsParticlesInternals.canvas=g.__tsParticlesInternals.canvas||{};g.__tsParticlesInternals.canvas.utils=g.__tsParticlesInternals.canvas.utils||{};g.__tsParticlesInternals.path=g.__tsParticlesInternals.path||{};g.__tsParticlesInternals.path=g.__tsParticlesInternals.path||{};g.__tsParticlesInternals.path.utils=g.__tsParticlesInternals.path.utils||{};var __tsProxyFactory=typeof Proxy!=="undefined"?function(obj){return new Proxy(obj,{get:function(target,key){if(!(key in target)){target[key]={};}return target[key];}});}:function(obj){return obj;};g.__tsParticlesInternals.bundles=__tsProxyFactory(g.__tsParticlesInternals.bundles);g.__tsParticlesInternals.effects=__tsProxyFactory(g.__tsParticlesInternals.effects);g.__tsParticlesInternals.interactions=__tsProxyFactory(g.__tsParticlesInternals.interactions);g.__tsParticlesInternals.palettes=__tsProxyFactory(g.__tsParticlesInternals.palettes);g.__tsParticlesInternals.paths=__tsProxyFactory(g.__tsParticlesInternals.paths);g.__tsParticlesInternals.plugins=__tsProxyFactory(g.__tsParticlesInternals.plugins);g.__tsParticlesInternals.plugins.emittersShapes=__tsProxyFactory(g.__tsParticlesInternals.plugins.emittersShapes);g.__tsParticlesInternals.presets=__tsProxyFactory(g.__tsParticlesInternals.presets);g.__tsParticlesInternals.shapes=__tsProxyFactory(g.__tsParticlesInternals.shapes);g.__tsParticlesInternals.updaters=__tsProxyFactory(g.__tsParticlesInternals.updaters);g.__tsParticlesInternals.utils=__tsProxyFactory(g.__tsParticlesInternals.utils);g.__tsParticlesInternals.canvas=__tsProxyFactory(g.__tsParticlesInternals.canvas);g.__tsParticlesInternals.path=__tsProxyFactory(g.__tsParticlesInternals.path);g.tsparticlesInternalExports=g.tsparticlesInternalExports||{};})(typeof globalThis!=="undefined"?globalThis:typeof window!=="undefined"?window:this);
/* tsParticles v4.2.0 */
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.__tsParticlesInternals = global.__tsParticlesInternals || {}, global.__tsParticlesInternals.bundles = global.__tsParticlesInternals.bundles || {}, global.__tsParticlesInternals.bundles.fireworks = global.__tsParticlesInternals.bundles.fireworks || {})));
})(this, (function (exports) { 'use strict';
const generatedAttribute = "generated", defaultCompositeValue = "source-over", resizeEvent = "resize", visibilityChangeEvent = "visibilitychange", percentDenominator = 100, half = 0.5, millisecondsToSeconds = 1000, originPoint = {
x: 0,
y: 0,
z: 0,
}, defaultTransform = {
a: 1,
b: 0,
c: 0,
d: 1,
}, randomColorValue = "random", midColorValue = "mid", double = 2, doublePI = Math.PI * double, defaultFps = 60, defaultAlpha$1 = 1, generatedTrue = "true", generatedFalse = "false", canvasTag = "canvas", defaultRetryCount = 0, squareExp = 2, spatialHashGridCellSize = 100, defaultRemoveQuantity = 1, defaultRatio = 1, defaultReduceFactor = 1, inverseFactorNumerator = 1, rgbMax = 255, hMax = 360, sMax = 100, lMax = 100, hMin = 0, sMin = 0, hPhase = 60, empty = 0, quarter = 0.25, threeQuarter = half + quarter, minVelocity = 0, minDistance = 0, minRadius$1 = 0, defaultTransformValue = 1, minimumSize = 0, zIndexFactorOffset = 1, defaultOpacity$1 = 1, removeDeleteCount = 1, removeMinIndex = 0, defaultFpsLimit = 120, minFpsLimit = 0, canvasFirstIndex = 0, loadRandomFactor = 10000, loadMinIndex = 0, one = 1, none = 0, decayOffset = 1, tryCountIncrement = 1, minZ = 0, minLimit = 0, countOffset = 1, minCount = 0, minIndex = 0, lengthOffset = 1, defaultDensityFactor = 1, deleteCount = 1, defaultAngle = 0, identity$1 = 1, minStrokeWidth = 0, lFactor = 1, lMin = 0, maxNits = 400, triple = 3, sextuple = 6, sNormalizedOffset = 1, phaseNumerator = 1, defaultRgbMin = 0, defaultVelocity = 0, defaultLoops = 0, defaultTime = 0, defaultZoom = 1;
exports.MoveDirection = void 0;
(function (MoveDirection) {
MoveDirection["bottom"] = "bottom";
MoveDirection["bottomLeft"] = "bottom-left";
MoveDirection["bottomRight"] = "bottom-right";
MoveDirection["left"] = "left";
MoveDirection["none"] = "none";
MoveDirection["right"] = "right";
MoveDirection["top"] = "top";
MoveDirection["topLeft"] = "top-left";
MoveDirection["topRight"] = "top-right";
MoveDirection["outside"] = "outside";
MoveDirection["inside"] = "inside";
})(exports.MoveDirection || (exports.MoveDirection = {}));
function getZ(source) {
return "z" in source ? source.z : originPoint.z;
}
class Vector3d {
x;
y;
z;
constructor(x = originPoint.x, y = originPoint.y, z = originPoint.z) {
this.x = x;
this.y = y;
this.z = z;
}
static get origin() {
return Vector3d.create(originPoint.x, originPoint.y, originPoint.z);
}
get angle() {
return Math.atan2(this.y, this.x);
}
set angle(angle) {
this.#updateFromAngle(angle, this.length);
}
get length() {
return Math.sqrt(this.getLengthSq());
}
set length(length) {
this.#updateFromAngle(this.angle, length);
}
static clone(source) {
return Vector3d.create(source.x, source.y, getZ(source));
}
static create(x, y, z) {
if (typeof x === "number") {
return new Vector3d(x, y ?? originPoint.y, z ?? originPoint.z);
}
return new Vector3d(x.x, x.y, getZ(x));
}
add(v) {
return Vector3d.create(this.x + v.x, this.y + v.y, this.z + getZ(v));
}
addTo(v) {
this.x += v.x;
this.y += v.y;
this.z += getZ(v);
}
copy() {
return Vector3d.clone(this);
}
div(n) {
return Vector3d.create(this.x / n, this.y / n, this.z / n);
}
getLengthSq() {
return this.x ** squareExp + this.y ** squareExp;
}
mult(n) {
return Vector3d.create(this.x * n, this.y * n, this.z * n);
}
multTo(n) {
this.x *= n;
this.y *= n;
this.z *= n;
}
normalize() {
const length = this.length;
if (length != none) {
this.multTo(inverseFactorNumerator / length);
}
}
rotate(angle) {
return Vector3d.create(this.x * Math.cos(angle) - this.y * Math.sin(angle), this.x * Math.sin(angle) + this.y * Math.cos(angle), originPoint.z);
}
setTo(c) {
this.x = c.x;
this.y = c.y;
this.z = getZ(c);
}
sub(v) {
return Vector3d.create(this.x - v.x, this.y - v.y, this.z - getZ(v));
}
subFrom(v) {
this.x -= v.x;
this.y -= v.y;
this.z -= getZ(v);
}
#updateFromAngle(angle, length) {
this.x = Math.cos(angle) * length;
this.y = Math.sin(angle) * length;
}
}
class Vector extends Vector3d {
constructor(x = originPoint.x, y = originPoint.y) {
super(x, y, originPoint.z);
}
static get origin() {
return Vector.create(originPoint.x, originPoint.y);
}
static clone(source) {
return Vector.create(source.x, source.y);
}
static create(x, y) {
if (typeof x === "number") {
return new Vector(x, y ?? originPoint.y);
}
return new Vector(x.x, x.y);
}
}
function isBoolean(arg) {
return typeof arg === "boolean";
}
function isString(arg) {
return typeof arg === "string";
}
function isNumber(arg) {
return typeof arg === "number";
}
function isFunction(arg) {
return typeof arg === "function";
}
function isObject(arg) {
return typeof arg === "object" && arg !== null;
}
function isArray(arg) {
return Array.isArray(arg);
}
function isNull(arg) {
return arg === null || arg === undefined;
}
const piDeg = 180, degToRadFactor = Math.PI / piDeg;
let _random = Math.random;
const _animationLoop = {
nextFrame: (cb) => requestAnimationFrame(cb),
cancel: (idx) => {
cancelAnimationFrame(idx);
},
};
function setRandom(rnd = Math.random) {
_random = rnd;
}
function getRandomFn() {
return _random;
}
function getRandom() {
const min = 0, max = 1;
return clamp(_random(), min, max - Number.EPSILON);
}
function getRandomInRange(min, max) {
return getRandom() * (max - min) + min;
}
function setAnimationFunctions(nextFrame, cancel) {
_animationLoop.nextFrame = nextFrame;
_animationLoop.cancel = cancel;
}
function animate(fn) {
return _animationLoop.nextFrame(fn);
}
function cancelAnimation(handle) {
_animationLoop.cancel(handle);
}
function clamp(num, min, max) {
return Math.min(Math.max(num, min), max);
}
function mix(comp1, comp2, weight1, weight2) {
return Math.floor((comp1 * weight1 + comp2 * weight2) / (weight1 + weight2));
}
function randomInRangeValue(r) {
const max = getRangeMax(r), minOffset = 0;
let min = getRangeMin(r);
if (max === min) {
min = minOffset;
}
return getRandomInRange(min, max);
}
function getRangeValue(value) {
return isNumber(value) ? value : randomInRangeValue(value);
}
function getRangeMin(value) {
return isNumber(value) ? value : value.min;
}
function getRangeMax(value) {
return isNumber(value) ? value : value.max;
}
function setRangeValue(source, value) {
if (source === value || (value === undefined && isNumber(source))) {
return source;
}
const min = getRangeMin(source), max = getRangeMax(source);
return value !== undefined
? {
min: Math.min(min, value),
max: Math.max(max, value),
}
: setRangeValue(min, max);
}
function getDistances(pointA, pointB) {
const dx = pointA.x - pointB.x, dy = pointA.y - pointB.y;
return { dx: dx, dy: dy, distance: Math.hypot(dx, dy) };
}
function getDistanceSq(pointA, pointB) {
const dx = pointA.x - pointB.x, dy = pointA.y - pointB.y;
return dx * dx + dy * dy;
}
function getDistance(pointA, pointB) {
return Math.sqrt(getDistanceSq(pointA, pointB));
}
function checkDistance(pointA, pointB, distance) {
return getDistanceSq(pointA, pointB) <= distance * distance;
}
function degToRad(degrees) {
return degrees * degToRadFactor;
}
function getParticleDirectionAngle(direction, position, center) {
if (isNumber(direction)) {
return degToRad(direction);
}
switch (direction) {
case exports.MoveDirection.top:
return -Math.PI * half;
case exports.MoveDirection.topRight:
return -Math.PI * quarter;
case exports.MoveDirection.right:
return empty;
case exports.MoveDirection.bottomRight:
return Math.PI * quarter;
case exports.MoveDirection.bottom:
return Math.PI * half;
case exports.MoveDirection.bottomLeft:
return Math.PI * threeQuarter;
case exports.MoveDirection.left:
return Math.PI;
case exports.MoveDirection.topLeft:
return -Math.PI * threeQuarter;
case exports.MoveDirection.inside:
return Math.atan2(center.y - position.y, center.x - position.x);
case exports.MoveDirection.outside:
return Math.atan2(position.y - center.y, position.x - center.x);
default:
return getRandom() * doublePI;
}
}
function getParticleBaseVelocity(direction) {
const baseVelocity = Vector.origin;
baseVelocity.length = 1;
baseVelocity.angle = direction;
return baseVelocity;
}
function collisionVelocity(v1, v2, m1, m2) {
return Vector.create((v1.x * (m1 - m2)) / (m1 + m2) + (v2.x * double * m2) / (m1 + m2), v1.y);
}
function calcPositionFromSize(data) {
return data.position?.x !== undefined && data.position.y !== undefined
? {
x: (data.position.x * data.size.width) / percentDenominator,
y: (data.position.y * data.size.height) / percentDenominator,
}
: undefined;
}
function calcPositionOrRandomFromSize(data) {
return {
x: ((data.position?.x ?? getRandom() * percentDenominator) * data.size.width) / percentDenominator,
y: ((data.position?.y ?? getRandom() * percentDenominator) * data.size.height) / percentDenominator,
};
}
function calcPositionOrRandomFromSizeRanged(data) {
const position = {
x: data.position?.x !== undefined ? getRangeValue(data.position.x) : undefined,
y: data.position?.y !== undefined ? getRangeValue(data.position.y) : undefined,
};
return calcPositionOrRandomFromSize({ size: data.size, position });
}
function calcExactPositionOrRandomFromSize(data) {
const { position, size } = data;
return {
x: position?.x ?? getRandom() * size.width,
y: position?.y ?? getRandom() * size.height,
};
}
function parseAlpha(input) {
const defaultAlpha = 1;
if (!input) {
return defaultAlpha;
}
return input.endsWith("%") ? parseFloat(input) / percentDenominator : parseFloat(input);
}
exports.OutModeDirection = void 0;
(function (OutModeDirection) {
OutModeDirection["bottom"] = "bottom";
OutModeDirection["left"] = "left";
OutModeDirection["right"] = "right";
OutModeDirection["top"] = "top";
})(exports.OutModeDirection || (exports.OutModeDirection = {}));
exports.PixelMode = void 0;
(function (PixelMode) {
PixelMode["precise"] = "precise";
PixelMode["percent"] = "percent";
})(exports.PixelMode || (exports.PixelMode = {}));
const minRadius = 0;
function hasMatchMedia() {
return typeof matchMedia !== "undefined";
}
function safeDocument() {
return globalThis.document;
}
function safeMatchMedia(query) {
if (!hasMatchMedia()) {
return;
}
return matchMedia(query);
}
function safeMutationObserver(callback) {
if (typeof MutationObserver === "undefined") {
return;
}
return new MutationObserver(callback);
}
function isInArray(value, array) {
return value === array || (isArray(array) && array.includes(value));
}
function itemFromArray(array, index, useIndex = true) {
return array[index !== undefined && useIndex ? index % array.length : Math.floor(getRandom() * array.length)];
}
function isPointInside(point, size, offset, radius, direction) {
return areBoundsInside(calculateBounds(point, radius ?? minRadius), size, offset, direction);
}
function areBoundsInside(bounds, size, offset, direction) {
let inside = true;
if (!direction || direction === exports.OutModeDirection.bottom) {
inside = bounds.top < size.height + offset.x;
}
if (inside && (!direction || direction === exports.OutModeDirection.left)) {
inside = bounds.right > offset.x;
}
if (inside && (!direction || direction === exports.OutModeDirection.right)) {
inside = bounds.left < size.width + offset.y;
}
if (inside && (!direction || direction === exports.OutModeDirection.top)) {
inside = bounds.bottom > offset.y;
}
return inside;
}
function calculateBounds(point, radius) {
return {
bottom: point.y + radius,
left: point.x - radius,
right: point.x + radius,
top: point.y - radius,
};
}
function deepExtend(destination, ...sources) {
for (const source of sources) {
if (isNull(source)) {
continue;
}
if (!isObject(source)) {
destination = source;
continue;
}
if (Array.isArray(source)) {
if (!Array.isArray(destination)) {
destination = [];
}
}
else if (!isObject(destination) || Array.isArray(destination)) {
destination = {};
}
const sourceKeys = Object.keys(source), dangerousKeys = new Set(["__proto__", "constructor", "prototype"]), hasNested = sourceKeys.some(k => {
const v = source[k];
return isObject(v) || Array.isArray(v);
});
if (!hasNested) {
const sourceDict = source, destDict = destination;
for (const key of sourceKeys) {
if (dangerousKeys.has(key)) {
continue;
}
if (key in sourceDict) {
const v = sourceDict[key];
if (v !== undefined) {
destDict[key] = v;
}
}
}
continue;
}
for (const key of sourceKeys) {
if (dangerousKeys.has(key)) {
continue;
}
const sourceDict = source, destDict = destination, value = sourceDict[key];
destDict[key] = Array.isArray(value)
? value.map(v => deepExtend(undefined, v))
: deepExtend(destDict[key], value);
}
}
return destination;
}
function circleBounceDataFromParticle(p) {
return {
position: p.getPosition(),
radius: p.getRadius(),
mass: p.getMass(),
velocity: p.velocity,
factor: Vector.create(getRangeValue(p.options.bounce.horizontal.value), getRangeValue(p.options.bounce.vertical.value)),
};
}
function circleBounce(p1, p2) {
const { x: xVelocityDiff, y: yVelocityDiff } = p1.velocity.sub(p2.velocity), [pos1, pos2] = [p1.position, p2.position], { dx: xDist, dy: yDist } = getDistances(pos2, pos1), minimumDistance = 0;
if (xVelocityDiff * xDist + yVelocityDiff * yDist < minimumDistance) {
return;
}
const angle = -Math.atan2(yDist, xDist), m1 = p1.mass, m2 = p2.mass, u1 = p1.velocity.rotate(angle), u2 = p2.velocity.rotate(angle), v1 = collisionVelocity(u1, u2, m1, m2), v2 = collisionVelocity(u2, u1, m1, m2), vFinal1 = v1.rotate(-angle), vFinal2 = v2.rotate(-angle);
p1.velocity.x = vFinal1.x * p1.factor.x;
p1.velocity.y = vFinal1.y * p1.factor.y;
p2.velocity.x = vFinal2.x * p2.factor.x;
p2.velocity.y = vFinal2.y * p2.factor.y;
}
function executeOnSingleOrMultiple(obj, callback) {
const defaultIndex = 0;
return isArray(obj) ? obj.map((item, index) => callback(item, index)) : callback(obj, defaultIndex);
}
function itemFromSingleOrMultiple(obj, index, useIndex) {
return isArray(obj) ? itemFromArray(obj, index, useIndex) : obj;
}
function getPositionOrSize(positionOrSize, canvasSize) {
const isPercent = positionOrSize.mode === exports.PixelMode.percent;
if (!isPercent) {
const { mode: _, ...rest } = positionOrSize;
return rest;
}
const isPosition = "x" in positionOrSize;
if (isPosition) {
return {
x: (positionOrSize.x / percentDenominator) * canvasSize.width,
y: (positionOrSize.y / percentDenominator) * canvasSize.height,
};
}
else {
return {
width: (positionOrSize.width / percentDenominator) * canvasSize.width,
height: (positionOrSize.height / percentDenominator) * canvasSize.height,
};
}
}
function getPosition(position, canvasSize) {
return getPositionOrSize(position, canvasSize);
}
function cloneStyle(style) {
const clonedStyle = safeDocument().createElement("div").style;
for (const key in style) {
const styleKey = style[key];
if (!(key in style) || isNull(styleKey)) {
continue;
}
const styleValue = style.getPropertyValue?.(styleKey);
if (!styleValue) {
continue;
}
const stylePriority = style.getPropertyPriority?.(styleKey);
if (stylePriority) {
clonedStyle.setProperty(styleKey, styleValue, stylePriority);
}
else {
clonedStyle.setProperty(styleKey, styleValue);
}
}
return clonedStyle;
}
let _cachedZIndex, _cachedStyle;
function getFullScreenStyle(zIndex) {
if (_cachedZIndex !== zIndex || !_cachedStyle) {
_cachedZIndex = zIndex;
const fullScreenStyle = safeDocument().createElement("div").style, radix = 10, style = {
width: "100%",
height: "100%",
margin: "0",
padding: "0",
borderWidth: "0",
position: "fixed",
zIndex: zIndex.toString(radix),
"z-index": zIndex.toString(radix),
top: "0",
left: "0",
"pointer-events": "none",
};
for (const key in style) {
const value = style[key];
if (value === undefined) {
continue;
}
fullScreenStyle.setProperty(key, value);
}
_cachedStyle = fullScreenStyle;
}
return _cachedStyle;
}
function manageListener(element, event, handler, add, options) {
if (add) {
let addOptions = { passive: true };
if (isBoolean(options)) {
addOptions.capture = options;
}
else if (options !== undefined) {
addOptions = options;
}
element.addEventListener(event, handler, addOptions);
}
else {
const removeOptions = options;
element.removeEventListener(event, handler, removeOptions);
}
}
async function getItemsFromInitializer(container, map, initializers, force = false) {
let res = map.get(container);
if (!res || force) {
res = await Promise.all([...initializers.values()].map(t => t(container)));
map.set(container, res);
}
return res;
}
async function getItemMapFromInitializer(container, map, initializers, force = false) {
let res = map.get(container);
if (!res || force) {
const entries = await Promise.all([...initializers.entries()].map(([key, initializer]) => initializer(container).then(item => [key, item])));
res = new Map(entries);
map.set(container, res);
}
return res;
}
class EventDispatcher {
#listeners;
constructor() {
this.#listeners = new Map();
}
addEventListener(type, listener) {
this.removeEventListener(type, listener);
let arr = this.#listeners.get(type);
if (!arr) {
arr = [];
this.#listeners.set(type, arr);
}
arr.push(listener);
}
dispatchEvent(type, args) {
const listeners = this.#listeners.get(type);
listeners?.forEach(handler => {
handler(args);
});
}
hasEventListener(type) {
return !!this.#listeners.get(type);
}
removeAllEventListeners(type) {
if (!type) {
this.#listeners = new Map();
}
else {
this.#listeners.delete(type);
}
}
removeEventListener(type, listener) {
const arr = this.#listeners.get(type);
if (!arr) {
return;
}
const length = arr.length, idx = arr.indexOf(listener);
if (idx < minIndex) {
return;
}
if (length === deleteCount) {
this.#listeners.delete(type);
}
else {
arr.splice(idx, deleteCount);
}
}
}
exports.EventType = void 0;
(function (EventType) {
EventType["configAdded"] = "configAdded";
EventType["containerInit"] = "containerInit";
EventType["particlesSetup"] = "particlesSetup";
EventType["containerStarted"] = "containerStarted";
EventType["containerStopped"] = "containerStopped";
EventType["containerDestroyed"] = "containerDestroyed";
EventType["containerPaused"] = "containerPaused";
EventType["containerPlay"] = "containerPlay";
EventType["containerBuilt"] = "containerBuilt";
EventType["particleAdded"] = "particleAdded";
EventType["particleDestroyed"] = "particleDestroyed";
EventType["particleRemoved"] = "particleRemoved";
})(exports.EventType || (exports.EventType = {}));
class PluginManager {
colorManagers = new Map();
easingFunctions = new Map();
effectDrawers = new Map();
initializers = {
effects: new Map(),
shapes: new Map(),
updaters: new Map(),
};
palettes = new Map();
plugins = [];
presets = new Map();
shapeDrawers = new Map();
updaters = new Map();
#allLoadersSet = new Set();
#configs = new Map();
#engine;
#executedSet = new Set();
#initialized = false;
#isRunningLoaders = false;
#loadPromises = new Set();
constructor(engine) {
this.#engine = engine;
}
get configs() {
const res = {};
for (const [name, config] of this.#configs) {
res[name] = config;
}
return res;
}
addColorManager(name, manager) {
this.colorManagers.set(name, manager);
}
addConfig(config) {
const key = config.key ?? config.name ?? "default";
this.#configs.set(key, config);
this.#engine.dispatchEvent(exports.EventType.configAdded, { data: { name: key, config } });
}
addEasing(name, easing) {
if (this.easingFunctions.get(name)) {
return;
}
this.easingFunctions.set(name, easing);
}
addEffect(effect, drawer) {
this.initializers.effects.set(effect, drawer);
}
addPalette(name, palette) {
this.palettes.set(name, palette);
}
addParticleUpdater(name, updaterInitializer) {
this.initializers.updaters.set(name, updaterInitializer);
}
addPlugin(plugin) {
if (this.getPlugin(plugin.id)) {
return;
}
this.plugins.push(plugin);
}
addPreset(preset, options, override = false) {
if (!(override || !this.getPreset(preset))) {
return;
}
this.presets.set(preset, options);
}
addShape(shapes, drawer) {
for (const shape of shapes) {
this.initializers.shapes.set(shape, drawer);
}
}
clearPlugins(container) {
this.effectDrawers.delete(container);
this.shapeDrawers.delete(container);
this.updaters.delete(container);
}
getEasing(name) {
return this.easingFunctions.get(name) ?? ((value) => value);
}
getEffectDrawers(container, force = false) {
return getItemMapFromInitializer(container, this.effectDrawers, this.initializers.effects, force);
}
getPalette(name) {
return this.palettes.get(name);
}
getPlugin(plugin) {
return this.plugins.find(t => t.id === plugin);
}
getPreset(preset) {
return this.presets.get(preset);
}
async getShapeDrawers(container, force = false) {
return getItemMapFromInitializer(container, this.shapeDrawers, this.initializers.shapes, force);
}
async getUpdaters(container, force = false) {
return getItemsFromInitializer(container, this.updaters, this.initializers.updaters, force);
}
async init() {
if (this.#initialized || this.#isRunningLoaders) {
return;
}
this.#isRunningLoaders = true;
this.#executedSet = new Set();
this.#allLoadersSet = new Set(this.#loadPromises);
try {
for (const loader of this.#allLoadersSet) {
await this.#runLoader(loader, this.#executedSet, this.#allLoadersSet);
}
}
finally {
this.#loadPromises.clear();
this.#isRunningLoaders = false;
this.#initialized = true;
}
}
loadParticlesOptions(container, options, ...sourceOptions) {
const updaters = this.updaters.get(container);
if (!updaters) {
return;
}
updaters.forEach(updater => updater.loadOptions?.(options, ...sourceOptions));
}
async register(...loaders) {
if (this.#initialized) {
throw new Error("Register plugins can only be done before calling tsParticles.load()");
}
for (const loader of loaders) {
if (this.#isRunningLoaders) {
await this.#runLoader(loader, this.#executedSet, this.#allLoadersSet);
}
else {
this.#loadPromises.add(loader);
}
}
}
async #runLoader(loader, executed, allLoaders) {
if (executed.has(loader))
return;
executed.add(loader);
allLoaders.add(loader);
await loader(this.#engine);
}
}
const errorPrefix = "tsParticles - Error";
const wrap = (fn) => (...args) => {
fn(...args);
}, _logger = {
debug: wrap(console.debug),
error: (message, ...optionalParams) => {
console.error(`${errorPrefix} - ${message}`, ...optionalParams);
},
info: wrap(console.info),
log: wrap(console.log),
trace: wrap(console.trace),
verbose: wrap(console.log),
warning: wrap(console.warn),
};
function setLogger(logger) {
if (logger.debug) {
_logger.debug = wrap(logger.debug);
}
if (logger.error) {
_logger.error = wrap(logger.error);
}
if (logger.info) {
_logger.info = wrap(logger.info);
}
if (logger.log) {
_logger.log = wrap(logger.log);
}
if (logger.trace) {
_logger.trace = wrap(logger.trace);
}
if (logger.verbose) {
_logger.verbose = wrap(logger.verbose);
}
if (logger.warning) {
_logger.warning = wrap(logger.warning);
}
}
function getLogger() {
return _logger;
}
const fullPercent = "100%";
async function getDataFromUrl(data) {
const url = itemFromSingleOrMultiple(data.url, data.index);
if (!url) {
return data.fallback;
}
const response = await fetch(url);
if (response.ok) {
return (await response.json());
}
getLogger().error(`${response.status.toString()} while retrieving config file`);
return data.fallback;
}
const getCanvasFromContainer = (domContainer) => {
const documentSafe = safeDocument();
let canvasEl;
const isCanvas = domContainer instanceof HTMLCanvasElement || domContainer.tagName.toLowerCase() === canvasTag;
if (isCanvas) {
canvasEl = domContainer;
canvasEl.dataset[generatedAttribute] ??= generatedFalse;
if (canvasEl.dataset[generatedAttribute] === generatedTrue) {
canvasEl.style.width ||= fullPercent;
canvasEl.style.height ||= fullPercent;
canvasEl.style.pointerEvents = "none";
canvasEl.style.setProperty("pointer-events", "none");
}
}
else {
const existingCanvases = domContainer.getElementsByTagName(canvasTag), foundCanvas = existingCanvases.item(canvasFirstIndex);
if (foundCanvas) {
canvasEl = foundCanvas;
canvasEl.dataset[generatedAttribute] = generatedFalse;
}
else {
canvasEl = documentSafe.createElement(canvasTag);
canvasEl.dataset[generatedAttribute] = generatedTrue;
domContainer.appendChild(canvasEl);
}
canvasEl.style.width ||= fullPercent;
canvasEl.style.height ||= fullPercent;
canvasEl.style.pointerEvents = "none";
canvasEl.style.setProperty("pointer-events", "none");
}
return canvasEl;
}, getDomContainer = (id, source) => {
const documentSafe = safeDocument();
let domContainer = source ?? documentSafe.getElementById(id);
if (domContainer) {
return domContainer;
}
domContainer = documentSafe.createElement("canvas");
domContainer.id = id;
domContainer.dataset[generatedAttribute] = generatedTrue;
documentSafe.body.append(domContainer);
return domContainer;
};
class Engine {
pluginManager = new PluginManager(this);
#domArray = [];
#eventDispatcher = new EventDispatcher();
#initialized = false;
get items() {
return this.#domArray;
}
get version() {
return "4.2.0";
}
addEventListener(type, listener) {
this.#eventDispatcher.addEventListener(type, listener);
}
checkVersion(pluginVersion) {
if (this.version === pluginVersion) {
return;
}
throw new Error(`The tsParticles version is different from the loaded plugins version. Engine version: ${this.version}. Plugin version: ${pluginVersion}`);
}
dispatchEvent(type, args) {
this.#eventDispatcher.dispatchEvent(type, args);
}
async init() {
if (this.#initialized) {
return;
}
await this.pluginManager.init();
this.#initialized = true;
}
item(index) {
const items = this.items, item = items[index];
if (item?.destroyed) {
items.splice(index, removeDeleteCount);
return;
}
return item;
}
async load(params) {
await this.init();
let domSourceElement;
if (typeof HTMLElement !== "undefined" && params.element instanceof HTMLElement) {
domSourceElement = params.element;
}
const { Container } = await Promise.resolve().then(function () { return Container$1; }), id = params.id ?? domSourceElement?.id ?? `tsparticles${Math.floor(getRandom() * loadRandomFactor).toString()}`, { index, url } = params, options = url ? await getDataFromUrl({ fallback: params.options, url, index }) : params.options, currentOptions = itemFromSingleOrMultiple(options, index), { items } = this, oldIndex = items.findIndex(v => v.id.description === id), newItem = new Container({
dispatchCallback: (eventType, args) => {
this.dispatchEvent(eventType, args);
},
id,
onDestroy: (remove) => {
if (!remove) {
return;
}
const mainArr = this.items, idx = mainArr.indexOf(newItem);
if (idx >= removeMinIndex) {
mainArr.splice(idx, removeDeleteCount);
}
},
pluginManager: this.pluginManager,
sourceOptions: currentOptions,
});
if (oldIndex >= loadMinIndex) {
const old = this.item(oldIndex), deleteCount = old ? one : none;
if (old && !old.destroyed) {
old.destroy(false);
}
items.splice(oldIndex, deleteCount, newItem);
}
else {
items.push(newItem);
}
const sourceCanvas = typeof OffscreenCanvas !== "undefined" && params.element instanceof OffscreenCanvas
? params.element
: getCanvasFromContainer(getDomContainer(id, domSourceElement));
newItem.canvas.loadCanvas(sourceCanvas);
await newItem.start();
return newItem;
}
async refresh(refresh = true) {
if (!refresh) {
return;
}
await Promise.all(this.items.map(t => t.refresh()));
}
removeEventListener(type, listener) {
this.#eventDispatcher.removeEventListener(type, listener);
}
}
function initEngine() {
return new Engine();
}
var RangeType;
(function (RangeType) {
RangeType["circle"] = "circle";
RangeType["rectangle"] = "rectangle";
})(RangeType || (RangeType = {}));
class BaseRange {
position;
type;
constructor(x, y, type) {
this.position = {
x: x,
y: y,
};
this.type = type;
}
_resetPosition(x, y) {
this.position.x = x;
this.position.y = y;
}
}
class Circle extends BaseRange {
radius;
constructor(x, y, radius) {
super(x, y, RangeType.circle);
this.radius = radius;
}
contains(point) {
return checkDistance(point, this.position, this.radius);
}
intersects(range) {
const pos1 = this.position, pos2 = range.position, r = this.radius, dx = Math.abs(pos2.x - pos1.x), dy = Math.abs(pos2.y - pos1.y);
if (range instanceof Circle || range.type === RangeType.circle) {
const circleRange = range, rSum = r + circleRange.radius, dist = Math.hypot(dx, dy);
return rSum > dist;
}
else if (range instanceof Rectangle || range.type === RangeType.rectangle) {
const rectRange = range, { width, height } = rectRange.size, edges = Math.pow(dx - width, squareExp) + Math.pow(dy - height, squareExp);
return edges <= r ** squareExp || (dx <= r + width && dy <= r + height) || dx <= width || dy <= height;
}
return false;
}
reset(x, y, radius) {
this._resetPosition(x, y);
this.radius = radius;
return this;
}
}
class Rectangle extends BaseRange {
size;
constructor(x, y, width, height) {
super(x, y, RangeType.rectangle);
this.size = {
height: height,
width: width,
};
}
contains(point) {
const w = this.size.width, h = this.size.height, pos = this.position;
return point.x >= pos.x && point.x <= pos.x + w && point.y >= pos.y && point.y <= pos.y + h;
}
intersects(range) {
if (range instanceof Circle) {
return range.intersects(this);
}
if (!(range instanceof Rectangle)) {
return false;
}
const w = this.size.width, h = this.size.height, pos1 = this.position, pos2 = range.position, size2 = range.size, w2 = size2.width, h2 = size2.height;
return pos2.x < pos1.x + w && pos2.x + w2 > pos1.x && pos2.y < pos1.y + h && pos2.y + h2 > pos1.y;
}
reset(x, y, width, height) {
this._resetPosition(x, y);
this.size.width = width;
this.size.height = height;
return this;
}
}
exports.RotateDirection = void 0;
(function (RotateDirection) {
RotateDirection["clockwise"] = "clockwise";
RotateDirection["counterClockwise"] = "counter-clockwise";
RotateDirection["random"] = "random";
})(exports.RotateDirection || (exports.RotateDirection = {}));
exports.AnimationMode = void 0;
(function (AnimationMode) {
AnimationMode["auto"] = "auto";
AnimationMode["increase"] = "increase";
AnimationMode["decrease"] = "decrease";
AnimationMode["random"] = "random";
})(exports.AnimationMode || (exports.AnimationMode = {}));
exports.LimitMode = void 0;
(function (LimitMode) {
LimitMode["delete"] = "delete";
LimitMode["wait"] = "wait";
})(exports.LimitMode || (exports.LimitMode = {}));
exports.OutMode = void 0;
(function (OutMode) {
OutMode["bounce"] = "bounce";
OutMode["none"] = "none";
OutMode["out"] = "out";
OutMode["destroy"] = "destroy";
OutMode["split"] = "split";
})(exports.OutMode || (exports.OutMode = {}));
exports.AlterType = void 0;
(function (AlterType) {
AlterType["darken"] = "darken";
AlterType["enlighten"] = "enlighten";
})(exports.AlterType || (exports.AlterType = {}));
exports.DestroyType = void 0;
(function (DestroyType) {
DestroyType["none"] = "none";
DestroyType["max"] = "max";
DestroyType["min"] = "min";
})(exports.DestroyType || (exports.DestroyType = {}));
exports.GradientType = void 0;
(function (GradientType) {
GradientType["linear"] = "linear";
GradientType["radial"] = "radial";
GradientType["random"] = "random";
})(exports.GradientType || (exports.GradientType = {}));
exports.ParticleOutType = void 0;
(function (ParticleOutType) {
ParticleOutType["normal"] = "normal";
ParticleOutType["inside"] = "inside";
ParticleOutType["outside"] = "outside";
})(exports.ParticleOutType || (exports.ParticleOutType = {}));
exports.StartValueType = void 0;
(function (StartValueType) {
StartValueType["max"] = "max";
StartValueType["min"] = "min";
StartValueType["random"] = "random";
})(exports.StartValueType || (exports.StartValueType = {}));
exports.AnimationStatus = void 0;
(function (AnimationStatus) {
AnimationStatus["increasing"] = "increasing";
AnimationStatus["decreasing"] = "decreasing";
})(exports.AnimationStatus || (exports.AnimationStatus = {}));
class OptionLoader {
load(data) {
if (isNull(data)) {
return;
}
this.doLoad(data);
}
}
function loadOptions(options, ...sourceOptionsArr) {
for (const sourceOptions of sourceOptionsArr) {
options.load(sourceOptions);
}
}
function loadProperty(obj, key, value) {
if (value !== undefined) {
obj[key] = value;
}
}
function loadRangeProperty(obj, key, value) {
if (value !== undefined) {
obj[key] = setRangeValue(value);
}
}
function loadNestedProperty(obj, key, value) {
if (value !== undefined) {
obj[key].load(value);
}
}
function loadLazyProperty(obj, key, value, factory) {
if (value !== undefined) {
const objRecord = obj;
objRecord[key] ??= factory();
objRecord[key].load(value);
}
}
function loadExtendProperty(obj, key, value) {
if (value !== undefined) {
obj[key] = deepExtend(obj[key] ?? {}, value);
}
}
function loadOptionProperty(obj, key, optionClass, ...sources) {
const objRecord = obj;
objRecord[key] ??= new optionClass();
const target = objRecord[key];
for (const source of sources) {
target.load(source?.[key]);
}
}
class AnimationOptions extends OptionLoader {
count = 0;
decay = 0;
delay = 0;
enable = false;
speed = 1;
sync = false;
doLoad(data) {
loadRangeProperty(this, "count", data.count);
loadProperty(this, "enable", data.enable);
loadRangeProperty(this, "speed", data.speed);
loadRangeProperty(this, "decay", data.decay);
loadRangeProperty(this, "delay", data.delay);
loadProperty(this, "sync", data.sync);
}
}
class RangedAnimationOptions extends AnimationOptions {
mode = exports.AnimationMode.auto;
startValue = exports.StartValueType.random;
doLoad(data) {
super.doLoad(data);
loadProperty(this, "mode", data.mode);
loadProperty(this, "startValue", data.startValue);
}
}
class ColorAnimation extends AnimationOptions {
max;
min;
offset = 0;
sync = true;
constructor(min, max) {
super();
this.min = min;
this.max = max;
}
doLoad(data) {
super.doLoad(data);
loadProperty(this, "max", data.max);
loadProperty(this, "min", data.min);
loadRangeProperty(this, "offset", data.offset);
}
}
class HslAnimation extends OptionLoader {
h = new ColorAnimation(hMin, hMax);
l = new ColorAnimation(lMin, lMax);
s = new ColorAnimation(sMin, sMax);
doLoad(data) {
this.h.load(data.h);
this.s.load(data.s);
this.l.load(data.l);
}
}
class OptionsColor extends OptionLoader {
value = "";
static create(source, data) {
const color = new OptionsColor();
color.load(source);
if (data !== undefined) {
if (isString(data) || isArray(data)) {
color.load({ value: data });
}
else {
color.load(data);
}
}
return color;
}
doLoad(data) {
if (!isNull(data.value)) {
this.value = data.value;
}
}
}
class AnimatableColor extends OptionsColor {
animation = new HslAnimation();
static create(source, data) {
const color = new AnimatableColor();
color.load(source);
if (data !== undefined) {
if (isString(data) || isArray(data)) {
color.load({ value: data });
}
else {
color.load(data);
}
}
return color;
}
doLoad(data) {
super.doLoad(data);
const colorAnimation = data.animation;
if (colorAnimation !== undefined) {
if (colorAnimation.enable === undefined) {
this.animation.load(data.animation);
}
else {
this.animation.h.load(colorAnimation);
}
}
}
}
class Background extends OptionLoader {
color;
image = "";
opacity = 1;
position = "";
repeat = "";
size