UNPKG

@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
(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