UNPKG

tsparticles-engine

Version:

Easily create highly customizable particle, confetti and fireworks animations and use them as animated backgrounds for your website. Ready to use components available also for React, Vue.js (2.x and 3.x), Angular, Svelte, jQuery, Preact, Riot.js, Inferno.

1,591 lines (1,574 loc) 165 kB
/*! * tsParticles Engine v2.12.0 * Author: Matteo Bruni * MIT license: https://opensource.org/licenses/MIT * Website: https://particles.js.org/ * Confetti Website: https://confetti.js.org * GitHub: https://www.github.com/matteobruni/tsparticles * How to use?: Check the GitHub README * ------------------------------------------------------ */ (function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if(typeof define === 'function' && define.amd) define([], factory); else { var a = factory(); for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i]; } })(this, () => { return /******/ (() => { // webpackBootstrap /******/ "use strict"; /******/ // The require scope /******/ var __webpack_require__ = {}; /******/ /************************************************************************/ /******/ /* webpack/runtime/define property getters */ /******/ (() => { /******/ // define getter functions for harmony exports /******/ __webpack_require__.d = (exports, definition) => { /******/ for(var key in definition) { /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); /******/ } /******/ } /******/ }; /******/ })(); /******/ /******/ /* webpack/runtime/hasOwnProperty shorthand */ /******/ (() => { /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) /******/ })(); /******/ /******/ /* webpack/runtime/make namespace object */ /******/ (() => { /******/ // define __esModule on exports /******/ __webpack_require__.r = (exports) => { /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); /******/ } /******/ Object.defineProperty(exports, '__esModule', { value: true }); /******/ }; /******/ })(); /******/ /************************************************************************/ var __webpack_exports__ = {}; // ESM COMPAT FLAG __webpack_require__.r(__webpack_exports__); // EXPORTS __webpack_require__.d(__webpack_exports__, { AnimatableColor: () => (/* reexport */ AnimatableColor), AnimationOptions: () => (/* reexport */ AnimationOptions), AnimationValueWithRandom: () => (/* reexport */ AnimationValueWithRandom), Background: () => (/* reexport */ Background), BackgroundMask: () => (/* reexport */ BackgroundMask), BackgroundMaskCover: () => (/* reexport */ BackgroundMaskCover), Circle: () => (/* reexport */ Circle), ClickEvent: () => (/* reexport */ ClickEvent), Collisions: () => (/* reexport */ Collisions), CollisionsAbsorb: () => (/* reexport */ CollisionsAbsorb), CollisionsOverlap: () => (/* reexport */ CollisionsOverlap), ColorAnimation: () => (/* reexport */ ColorAnimation), DivEvent: () => (/* reexport */ DivEvent), Events: () => (/* reexport */ Events), ExternalInteractorBase: () => (/* reexport */ ExternalInteractorBase), FullScreen: () => (/* reexport */ FullScreen), HoverEvent: () => (/* reexport */ HoverEvent), HslAnimation: () => (/* reexport */ HslAnimation), HslColorManager: () => (/* reexport */ HslColorManager), Interactivity: () => (/* reexport */ Interactivity), ManualParticle: () => (/* reexport */ ManualParticle), Modes: () => (/* reexport */ Modes), Move: () => (/* reexport */ Move), MoveAngle: () => (/* reexport */ MoveAngle), MoveAttract: () => (/* reexport */ MoveAttract), MoveCenter: () => (/* reexport */ MoveCenter), MoveGravity: () => (/* reexport */ MoveGravity), MovePath: () => (/* reexport */ MovePath), MoveTrail: () => (/* reexport */ MoveTrail), Opacity: () => (/* reexport */ Opacity), OpacityAnimation: () => (/* reexport */ OpacityAnimation), Options: () => (/* reexport */ Options), OptionsColor: () => (/* reexport */ OptionsColor), OutModes: () => (/* reexport */ OutModes), Parallax: () => (/* reexport */ Parallax), ParticlesBounce: () => (/* reexport */ ParticlesBounce), ParticlesBounceFactor: () => (/* reexport */ ParticlesBounceFactor), ParticlesDensity: () => (/* reexport */ ParticlesDensity), ParticlesInteractorBase: () => (/* reexport */ ParticlesInteractorBase), ParticlesNumber: () => (/* reexport */ ParticlesNumber), ParticlesOptions: () => (/* reexport */ ParticlesOptions), Point: () => (/* reexport */ Point), Range: () => (/* reexport */ Range), RangedAnimationOptions: () => (/* reexport */ RangedAnimationOptions), RangedAnimationValueWithRandom: () => (/* reexport */ RangedAnimationValueWithRandom), Rectangle: () => (/* reexport */ Rectangle), ResizeEvent: () => (/* reexport */ ResizeEvent), Responsive: () => (/* reexport */ Responsive), RgbColorManager: () => (/* reexport */ RgbColorManager), Shadow: () => (/* reexport */ Shadow), Shape: () => (/* reexport */ Shape), Size: () => (/* reexport */ Size), SizeAnimation: () => (/* reexport */ SizeAnimation), Spin: () => (/* reexport */ Spin), Stroke: () => (/* reexport */ Stroke), Theme: () => (/* reexport */ Theme), ThemeDefault: () => (/* reexport */ ThemeDefault), ValueWithRandom: () => (/* reexport */ ValueWithRandom), Vector: () => (/* reexport */ Vector), Vector3d: () => (/* reexport */ Vector3d), ZIndex: () => (/* reexport */ ZIndex), addColorManager: () => (/* reexport */ addColorManager), addEasing: () => (/* reexport */ addEasing), alterHsl: () => (/* reexport */ alterHsl), areBoundsInside: () => (/* reexport */ areBoundsInside), arrayRandomIndex: () => (/* reexport */ arrayRandomIndex), calcExactPositionOrRandomFromSize: () => (/* reexport */ calcExactPositionOrRandomFromSize), calcExactPositionOrRandomFromSizeRanged: () => (/* reexport */ calcExactPositionOrRandomFromSizeRanged), calcPositionFromSize: () => (/* reexport */ calcPositionFromSize), calcPositionOrRandomFromSize: () => (/* reexport */ calcPositionOrRandomFromSize), calcPositionOrRandomFromSizeRanged: () => (/* reexport */ calcPositionOrRandomFromSizeRanged), calculateBounds: () => (/* reexport */ calculateBounds), circleBounce: () => (/* reexport */ circleBounce), circleBounceDataFromParticle: () => (/* reexport */ circleBounceDataFromParticle), clamp: () => (/* reexport */ clamp), clear: () => (/* reexport */ clear), collisionVelocity: () => (/* reexport */ collisionVelocity), colorMix: () => (/* reexport */ colorMix), colorToHsl: () => (/* reexport */ colorToHsl), colorToRgb: () => (/* reexport */ colorToRgb), deepExtend: () => (/* reexport */ deepExtend), divMode: () => (/* reexport */ divMode), divModeExecute: () => (/* reexport */ divModeExecute), drawLine: () => (/* reexport */ drawLine), drawParticle: () => (/* reexport */ drawParticle), drawParticlePlugin: () => (/* reexport */ drawParticlePlugin), drawPlugin: () => (/* reexport */ drawPlugin), drawShape: () => (/* reexport */ drawShape), drawShapeAfterEffect: () => (/* reexport */ drawShapeAfterEffect), drawTriangle: () => (/* reexport */ drawTriangle), errorPrefix: () => (/* reexport */ errorPrefix), executeOnSingleOrMultiple: () => (/* reexport */ executeOnSingleOrMultiple), findItemFromSingleOrMultiple: () => (/* reexport */ findItemFromSingleOrMultiple), generatedAttribute: () => (/* reexport */ generatedAttribute), getDistance: () => (/* reexport */ getDistance), getDistances: () => (/* reexport */ getDistances), getEasing: () => (/* reexport */ getEasing), getHslAnimationFromHsl: () => (/* reexport */ getHslAnimationFromHsl), getHslFromAnimation: () => (/* reexport */ getHslFromAnimation), getLinkColor: () => (/* reexport */ getLinkColor), getLinkRandomColor: () => (/* reexport */ getLinkRandomColor), getLogger: () => (/* reexport */ getLogger), getParticleBaseVelocity: () => (/* reexport */ getParticleBaseVelocity), getParticleDirectionAngle: () => (/* reexport */ getParticleDirectionAngle), getPosition: () => (/* reexport */ getPosition), getRandom: () => (/* reexport */ getRandom), getRandomRgbColor: () => (/* reexport */ getRandomRgbColor), getRangeMax: () => (/* reexport */ getRangeMax), getRangeMin: () => (/* reexport */ getRangeMin), getRangeValue: () => (/* reexport */ getRangeValue), getSize: () => (/* reexport */ getSize), getStyleFromHsl: () => (/* reexport */ getStyleFromHsl), getStyleFromRgb: () => (/* reexport */ getStyleFromRgb), getValue: () => (/* reexport */ getValue), hasMatchMedia: () => (/* reexport */ hasMatchMedia), hslToRgb: () => (/* reexport */ hslToRgb), hslaToRgba: () => (/* reexport */ hslaToRgba), initParticleNumericAnimationValue: () => (/* reexport */ initParticleNumericAnimationValue), isArray: () => (/* reexport */ isArray), isBoolean: () => (/* reexport */ isBoolean), isDivModeEnabled: () => (/* reexport */ isDivModeEnabled), isFunction: () => (/* reexport */ isFunction), isInArray: () => (/* reexport */ isInArray), isNumber: () => (/* reexport */ isNumber), isObject: () => (/* reexport */ isObject), isPointInside: () => (/* reexport */ isPointInside), isSsr: () => (/* reexport */ isSsr), isString: () => (/* reexport */ isString), itemFromArray: () => (/* reexport */ itemFromArray), itemFromSingleOrMultiple: () => (/* reexport */ itemFromSingleOrMultiple), loadFont: () => (/* reexport */ loadFont), loadOptions: () => (/* reexport */ loadOptions), loadParticlesOptions: () => (/* reexport */ loadParticlesOptions), mix: () => (/* reexport */ mix), mouseDownEvent: () => (/* reexport */ mouseDownEvent), mouseLeaveEvent: () => (/* reexport */ mouseLeaveEvent), mouseMoveEvent: () => (/* reexport */ mouseMoveEvent), mouseOutEvent: () => (/* reexport */ mouseOutEvent), mouseUpEvent: () => (/* reexport */ mouseUpEvent), paintBase: () => (/* reexport */ paintBase), paintImage: () => (/* reexport */ paintImage), parseAlpha: () => (/* reexport */ parseAlpha), randomInRange: () => (/* reexport */ randomInRange), rangeColorToHsl: () => (/* reexport */ rangeColorToHsl), rangeColorToRgb: () => (/* reexport */ rangeColorToRgb), rectBounce: () => (/* reexport */ rectBounce), resizeEvent: () => (/* reexport */ resizeEvent), rgbToHsl: () => (/* reexport */ rgbToHsl), safeMatchMedia: () => (/* reexport */ safeMatchMedia), safeMutationObserver: () => (/* reexport */ safeMutationObserver), setLogger: () => (/* reexport */ setLogger), setRandom: () => (/* reexport */ setRandom), setRangeValue: () => (/* reexport */ setRangeValue), singleDivModeExecute: () => (/* reexport */ singleDivModeExecute), stringToAlpha: () => (/* reexport */ stringToAlpha), stringToRgb: () => (/* reexport */ stringToRgb), touchCancelEvent: () => (/* reexport */ touchCancelEvent), touchEndEvent: () => (/* reexport */ touchEndEvent), touchMoveEvent: () => (/* reexport */ touchMoveEvent), touchStartEvent: () => (/* reexport */ touchStartEvent), tsParticles: () => (/* binding */ tsParticles), visibilityChangeEvent: () => (/* reexport */ visibilityChangeEvent) }); ;// CONCATENATED MODULE: ./dist/browser/Core/Utils/Constants.js const generatedAttribute = "generated"; const mouseDownEvent = "pointerdown"; const mouseUpEvent = "pointerup"; const mouseLeaveEvent = "pointerleave"; const mouseOutEvent = "pointerout"; const mouseMoveEvent = "pointermove"; const touchStartEvent = "touchstart"; const touchEndEvent = "touchend"; const touchMoveEvent = "touchmove"; const touchCancelEvent = "touchcancel"; const resizeEvent = "resize"; const visibilityChangeEvent = "visibilitychange"; const errorPrefix = "tsParticles - Error"; ;// CONCATENATED MODULE: ./dist/browser/Core/Utils/Vector3d.js class Vector3d { constructor(xOrCoords, y, z) { this._updateFromAngle = (angle, length) => { this.x = Math.cos(angle) * length; this.y = Math.sin(angle) * length; }; if (!isNumber(xOrCoords) && xOrCoords) { this.x = xOrCoords.x; this.y = xOrCoords.y; const coords3d = xOrCoords; this.z = coords3d.z ? coords3d.z : 0; } else if (xOrCoords !== undefined && y !== undefined) { this.x = xOrCoords; this.y = y; this.z = z ?? 0; } else { throw new Error(`${errorPrefix} Vector3d not initialized correctly`); } } static get origin() { return Vector3d.create(0, 0, 0); } 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, source.z); } static create(x, y, z) { return new Vector3d(x, y, z); } add(v) { return Vector3d.create(this.x + v.x, this.y + v.y, this.z + v.z); } addTo(v) { this.x += v.x; this.y += v.y; this.z += v.z; } copy() { return Vector3d.clone(this); } distanceTo(v) { return this.sub(v).length; } distanceToSq(v) { return this.sub(v).getLengthSq(); } div(n) { return Vector3d.create(this.x / n, this.y / n, this.z / n); } divTo(n) { this.x /= n; this.y /= n; this.z /= n; } getLengthSq() { return this.x ** 2 + this.y ** 2; } 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 != 0) { this.multTo(1.0 / 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), 0); } setTo(c) { this.x = c.x; this.y = c.y; const v3d = c; this.z = v3d.z ? v3d.z : 0; } sub(v) { return Vector3d.create(this.x - v.x, this.y - v.y, this.z - v.z); } subFrom(v) { this.x -= v.x; this.y -= v.y; this.z -= v.z; } } ;// CONCATENATED MODULE: ./dist/browser/Core/Utils/Vector.js class Vector extends Vector3d { constructor(xOrCoords, y) { super(xOrCoords, y, 0); } static get origin() { return Vector.create(0, 0); } static clone(source) { return Vector.create(source.x, source.y); } static create(x, y) { return new Vector(x, y); } } ;// CONCATENATED MODULE: ./dist/browser/Utils/NumberUtils.js let _random = Math.random; const easings = new Map(); function addEasing(name, easing) { if (easings.get(name)) { return; } easings.set(name, easing); } function getEasing(name) { return easings.get(name) || (value => value); } function setRandom(rnd = Math.random) { _random = rnd; } function getRandom() { return clamp(_random(), 0, 1 - 1e-16); } 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 randomInRange(r) { const max = getRangeMax(r); let min = getRangeMin(r); if (max === min) { min = 0; } return getRandom() * (max - min) + min; } function getRangeValue(value) { return isNumber(value) ? value : randomInRange(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 getValue(options) { const random = options.random, { enable, minimumValue } = isBoolean(random) ? { enable: random, minimumValue: 0 } : random; return enable ? getRangeValue(setRangeValue(options.value, minimumValue)) : getRangeValue(options.value); } function getDistances(pointA, pointB) { const dx = pointA.x - pointB.x, dy = pointA.y - pointB.y; return { dx: dx, dy: dy, distance: Math.sqrt(dx ** 2 + dy ** 2) }; } function getDistance(pointA, pointB) { return getDistances(pointA, pointB).distance; } function getParticleDirectionAngle(direction, position, center) { if (isNumber(direction)) { return direction * Math.PI / 180; } switch (direction) { case "top": return -Math.PI / 2; case "top-right": return -Math.PI / 4; case "right": return 0; case "bottom-right": return Math.PI / 4; case "bottom": return Math.PI / 2; case "bottom-left": return 3 * Math.PI / 4; case "left": return Math.PI; case "top-left": return -3 * Math.PI / 4; case "inside": return Math.atan2(center.y - position.y, center.x - position.x); case "outside": return Math.atan2(position.y - center.y, position.x - center.x); default: return getRandom() * Math.PI * 2; } } 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 * 2 * m2 / (m1 + m2), v1.y); } function calcPositionFromSize(data) { return data.position && data.position.x !== undefined && data.position.y !== undefined ? { x: data.position.x * data.size.width / 100, y: data.position.y * data.size.height / 100 } : undefined; } function calcPositionOrRandomFromSize(data) { return { x: (data.position?.x ?? getRandom() * 100) * data.size.width / 100, y: (data.position?.y ?? getRandom() * 100) * data.size.height / 100 }; } 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) { return { x: data.position?.x ?? getRandom() * data.size.width, y: data.position?.y ?? getRandom() * data.size.height }; } function calcExactPositionOrRandomFromSizeRanged(data) { const position = { x: data.position?.x !== undefined ? getRangeValue(data.position.x) : undefined, y: data.position?.y !== undefined ? getRangeValue(data.position.y) : undefined }; return calcExactPositionOrRandomFromSize({ size: data.size, position }); } function parseAlpha(input) { return input ? input.endsWith("%") ? parseFloat(input) / 100 : parseFloat(input) : 1; } ;// CONCATENATED MODULE: ./dist/browser/Utils/Utils.js const _logger = { debug: console.debug, error: console.error, info: console.info, log: console.log, verbose: console.log, warning: console.warn }; function setLogger(logger) { _logger.debug = logger.debug || _logger.debug; _logger.error = logger.error || _logger.error; _logger.info = logger.info || _logger.info; _logger.log = logger.log || _logger.log; _logger.verbose = logger.verbose || _logger.verbose; _logger.warning = logger.warning || _logger.warning; } function getLogger() { return _logger; } function rectSideBounce(data) { const res = { bounced: false }, { pSide, pOtherSide, rectSide, rectOtherSide, velocity, factor } = data; if (pOtherSide.min < rectOtherSide.min || pOtherSide.min > rectOtherSide.max || pOtherSide.max < rectOtherSide.min || pOtherSide.max > rectOtherSide.max) { return res; } if (pSide.max >= rectSide.min && pSide.max <= (rectSide.max + rectSide.min) / 2 && velocity > 0 || pSide.min <= rectSide.max && pSide.min > (rectSide.max + rectSide.min) / 2 && velocity < 0) { res.velocity = velocity * -factor; res.bounced = true; } return res; } function checkSelector(element, selectors) { const res = executeOnSingleOrMultiple(selectors, selector => { return element.matches(selector); }); return isArray(res) ? res.some(t => t) : res; } function isSsr() { return typeof window === "undefined" || !window || typeof window.document === "undefined" || !window.document; } function hasMatchMedia() { return !isSsr() && typeof matchMedia !== "undefined"; } function safeMatchMedia(query) { if (!hasMatchMedia()) { return; } return matchMedia(query); } function safeMutationObserver(callback) { if (isSsr() || typeof MutationObserver === "undefined") { return; } return new MutationObserver(callback); } function isInArray(value, array) { return value === array || isArray(array) && array.indexOf(value) > -1; } async function loadFont(font, weight) { try { await document.fonts.load(`${weight ?? "400"} 36px '${font ?? "Verdana"}'`); } catch {} } function arrayRandomIndex(array) { return Math.floor(getRandom() * array.length); } function itemFromArray(array, index, useIndex = true) { return array[index !== undefined && useIndex ? index % array.length : arrayRandomIndex(array)]; } function isPointInside(point, size, offset, radius, direction) { return areBoundsInside(calculateBounds(point, radius ?? 0), size, offset, direction); } function areBoundsInside(bounds, size, offset, direction) { let inside = true; if (!direction || direction === "bottom") { inside = bounds.top < size.height + offset.x; } if (inside && (!direction || direction === "left")) { inside = bounds.right > offset.x; } if (inside && (!direction || direction === "right")) { inside = bounds.left < size.width + offset.y; } if (inside && (!direction || direction === "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 (source === undefined || source === null) { continue; } if (!isObject(source)) { destination = source; continue; } const sourceIsArray = Array.isArray(source); if (sourceIsArray && (isObject(destination) || !destination || !Array.isArray(destination))) { destination = []; } else if (!sourceIsArray && (isObject(destination) || !destination || Array.isArray(destination))) { destination = {}; } for (const key in source) { if (key === "__proto__") { continue; } const sourceDict = source, value = sourceDict[key], destDict = destination; destDict[key] = isObject(value) && Array.isArray(value) ? value.map(v => deepExtend(destDict[key], v)) : deepExtend(destDict[key], value); } } return destination; } function isDivModeEnabled(mode, divs) { return !!findItemFromSingleOrMultiple(divs, t => t.enable && isInArray(mode, t.mode)); } function divModeExecute(mode, divs, callback) { executeOnSingleOrMultiple(divs, div => { const divMode = div.mode, divEnabled = div.enable; if (divEnabled && isInArray(mode, divMode)) { singleDivModeExecute(div, callback); } }); } function singleDivModeExecute(div, callback) { const selectors = div.selectors; executeOnSingleOrMultiple(selectors, selector => { callback(selector, div); }); } function divMode(divs, element) { if (!element || !divs) { return; } return findItemFromSingleOrMultiple(divs, div => { return checkSelector(element, div.selectors); }); } function circleBounceDataFromParticle(p) { return { position: p.getPosition(), radius: p.getRadius(), mass: p.getMass(), velocity: p.velocity, factor: Vector.create(getValue(p.options.bounce.horizontal), getValue(p.options.bounce.vertical)) }; } 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); if (xVelocityDiff * xDist + yVelocityDiff * yDist < 0) { 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 rectBounce(particle, divBounds) { const pPos = particle.getPosition(), size = particle.getRadius(), bounds = calculateBounds(pPos, size), resH = rectSideBounce({ pSide: { min: bounds.left, max: bounds.right }, pOtherSide: { min: bounds.top, max: bounds.bottom }, rectSide: { min: divBounds.left, max: divBounds.right }, rectOtherSide: { min: divBounds.top, max: divBounds.bottom }, velocity: particle.velocity.x, factor: getValue(particle.options.bounce.horizontal) }); if (resH.bounced) { if (resH.velocity !== undefined) { particle.velocity.x = resH.velocity; } if (resH.position !== undefined) { particle.position.x = resH.position; } } const resV = rectSideBounce({ pSide: { min: bounds.top, max: bounds.bottom }, pOtherSide: { min: bounds.left, max: bounds.right }, rectSide: { min: divBounds.top, max: divBounds.bottom }, rectOtherSide: { min: divBounds.left, max: divBounds.right }, velocity: particle.velocity.y, factor: getValue(particle.options.bounce.vertical) }); if (resV.bounced) { if (resV.velocity !== undefined) { particle.velocity.y = resV.velocity; } if (resV.position !== undefined) { particle.position.y = resV.position; } } } function executeOnSingleOrMultiple(obj, callback) { return isArray(obj) ? obj.map((item, index) => callback(item, index)) : callback(obj, 0); } function itemFromSingleOrMultiple(obj, index, useIndex) { return isArray(obj) ? itemFromArray(obj, index, useIndex) : obj; } function findItemFromSingleOrMultiple(obj, callback) { return isArray(obj) ? obj.find((t, index) => callback(t, index)) : callback(obj, 0) ? obj : undefined; } function initParticleNumericAnimationValue(options, pxRatio) { const valueRange = options.value, animationOptions = options.animation, res = { delayTime: getRangeValue(animationOptions.delay) * 1000, enable: animationOptions.enable, value: getRangeValue(options.value) * pxRatio, max: getRangeMax(valueRange) * pxRatio, min: getRangeMin(valueRange) * pxRatio, loops: 0, maxLoops: getRangeValue(animationOptions.count), time: 0 }; if (animationOptions.enable) { res.decay = 1 - getRangeValue(animationOptions.decay); switch (animationOptions.mode) { case "increase": res.status = "increasing"; break; case "decrease": res.status = "decreasing"; break; case "random": res.status = getRandom() >= 0.5 ? "increasing" : "decreasing"; break; } const autoStatus = animationOptions.mode === "auto"; switch (animationOptions.startValue) { case "min": res.value = res.min; if (autoStatus) { res.status = "increasing"; } break; case "max": res.value = res.max; if (autoStatus) { res.status = "decreasing"; } break; case "random": default: res.value = randomInRange(res); if (autoStatus) { res.status = getRandom() >= 0.5 ? "increasing" : "decreasing"; } break; } } res.initialValue = res.value; return res; } function getPositionOrSize(positionOrSize, canvasSize) { const isPercent = positionOrSize.mode === "percent"; if (!isPercent) { const { mode: _, ...rest } = positionOrSize; return rest; } const isPosition = ("x" in positionOrSize); if (isPosition) { return { x: positionOrSize.x / 100 * canvasSize.width, y: positionOrSize.y / 100 * canvasSize.height }; } else { return { width: positionOrSize.width / 100 * canvasSize.width, height: positionOrSize.height / 100 * canvasSize.height }; } } function getPosition(position, canvasSize) { return getPositionOrSize(position, canvasSize); } function getSize(size, canvasSize) { return getPositionOrSize(size, canvasSize); } 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); } ;// CONCATENATED MODULE: ./dist/browser/Utils/ColorUtils.js const randomColorValue = "random", midColorValue = "mid", colorManagers = new Map(); function addColorManager(manager) { colorManagers.set(manager.key, manager); } function hue2rgb(p, q, t) { if (t < 0) { t += 1; } if (t > 1) { t -= 1; } if (t < 1 / 6) { return p + (q - p) * 6 * t; } if (t < 1 / 2) { return q; } if (t < 2 / 3) { return p + (q - p) * (2 / 3 - t) * 6; } return p; } function stringToRgba(input) { for (const [, manager] of colorManagers) { if (input.startsWith(manager.stringPrefix)) { return manager.parseString(input); } } const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])([a-f\d])?$/i, hexFixed = input.replace(shorthandRegex, (_, r, g, b, a) => { return r + r + g + g + b + b + (a !== undefined ? a + a : ""); }), regex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i, result = regex.exec(hexFixed); return result ? { a: result[4] !== undefined ? parseInt(result[4], 16) / 0xff : 1, b: parseInt(result[3], 16), g: parseInt(result[2], 16), r: parseInt(result[1], 16) } : undefined; } function rangeColorToRgb(input, index, useIndex = true) { if (!input) { return; } const color = isString(input) ? { value: input } : input; if (isString(color.value)) { return colorToRgb(color.value, index, useIndex); } if (isArray(color.value)) { return rangeColorToRgb({ value: itemFromArray(color.value, index, useIndex) }); } for (const [, manager] of colorManagers) { const res = manager.handleRangeColor(color); if (res) { return res; } } } function colorToRgb(input, index, useIndex = true) { if (!input) { return; } const color = isString(input) ? { value: input } : input; if (isString(color.value)) { return color.value === randomColorValue ? getRandomRgbColor() : stringToRgb(color.value); } if (isArray(color.value)) { return colorToRgb({ value: itemFromArray(color.value, index, useIndex) }); } for (const [, manager] of colorManagers) { const res = manager.handleColor(color); if (res) { return res; } } } function colorToHsl(color, index, useIndex = true) { const rgb = colorToRgb(color, index, useIndex); return rgb ? rgbToHsl(rgb) : undefined; } function rangeColorToHsl(color, index, useIndex = true) { const rgb = rangeColorToRgb(color, index, useIndex); return rgb ? rgbToHsl(rgb) : undefined; } function rgbToHsl(color) { const r1 = color.r / 255, g1 = color.g / 255, b1 = color.b / 255, max = Math.max(r1, g1, b1), min = Math.min(r1, g1, b1), res = { h: 0, l: (max + min) / 2, s: 0 }; if (max !== min) { res.s = res.l < 0.5 ? (max - min) / (max + min) : (max - min) / (2.0 - max - min); res.h = r1 === max ? (g1 - b1) / (max - min) : res.h = g1 === max ? 2.0 + (b1 - r1) / (max - min) : 4.0 + (r1 - g1) / (max - min); } res.l *= 100; res.s *= 100; res.h *= 60; if (res.h < 0) { res.h += 360; } if (res.h >= 360) { res.h -= 360; } return res; } function stringToAlpha(input) { return stringToRgba(input)?.a; } function stringToRgb(input) { return stringToRgba(input); } function hslToRgb(hsl) { const result = { b: 0, g: 0, r: 0 }, hslPercent = { h: hsl.h / 360, l: hsl.l / 100, s: hsl.s / 100 }; if (!hslPercent.s) { result.r = result.g = result.b = hslPercent.l; } else { const q = hslPercent.l < 0.5 ? hslPercent.l * (1 + hslPercent.s) : hslPercent.l + hslPercent.s - hslPercent.l * hslPercent.s, p = 2 * hslPercent.l - q; result.r = hue2rgb(p, q, hslPercent.h + 1 / 3); result.g = hue2rgb(p, q, hslPercent.h); result.b = hue2rgb(p, q, hslPercent.h - 1 / 3); } result.r = Math.floor(result.r * 255); result.g = Math.floor(result.g * 255); result.b = Math.floor(result.b * 255); return result; } function hslaToRgba(hsla) { const rgbResult = hslToRgb(hsla); return { a: hsla.a, b: rgbResult.b, g: rgbResult.g, r: rgbResult.r }; } function getRandomRgbColor(min) { const fixedMin = min ?? 0; return { b: Math.floor(randomInRange(setRangeValue(fixedMin, 256))), g: Math.floor(randomInRange(setRangeValue(fixedMin, 256))), r: Math.floor(randomInRange(setRangeValue(fixedMin, 256))) }; } function getStyleFromRgb(color, opacity) { return `rgba(${color.r}, ${color.g}, ${color.b}, ${opacity ?? 1})`; } function getStyleFromHsl(color, opacity) { return `hsla(${color.h}, ${color.s}%, ${color.l}%, ${opacity ?? 1})`; } function colorMix(color1, color2, size1, size2) { let rgb1 = color1, rgb2 = color2; if (rgb1.r === undefined) { rgb1 = hslToRgb(color1); } if (rgb2.r === undefined) { rgb2 = hslToRgb(color2); } return { b: mix(rgb1.b, rgb2.b, size1, size2), g: mix(rgb1.g, rgb2.g, size1, size2), r: mix(rgb1.r, rgb2.r, size1, size2) }; } function getLinkColor(p1, p2, linkColor) { if (linkColor === randomColorValue) { return getRandomRgbColor(); } else if (linkColor === midColorValue) { const sourceColor = p1.getFillColor() ?? p1.getStrokeColor(), destColor = p2?.getFillColor() ?? p2?.getStrokeColor(); if (sourceColor && destColor && p2) { return colorMix(sourceColor, destColor, p1.getRadius(), p2.getRadius()); } else { const hslColor = sourceColor ?? destColor; if (hslColor) { return hslToRgb(hslColor); } } } else { return linkColor; } } function getLinkRandomColor(optColor, blink, consent) { const color = isString(optColor) ? optColor : optColor.value; if (color === randomColorValue) { if (consent) { return rangeColorToRgb({ value: color }); } if (blink) { return randomColorValue; } return midColorValue; } else if (color === midColorValue) { return midColorValue; } else { return rangeColorToRgb({ value: color }); } } function getHslFromAnimation(animation) { return animation !== undefined ? { h: animation.h.value, s: animation.s.value, l: animation.l.value } : undefined; } function getHslAnimationFromHsl(hsl, animationOptions, reduceFactor) { const resColor = { h: { enable: false, value: hsl.h }, s: { enable: false, value: hsl.s }, l: { enable: false, value: hsl.l } }; if (animationOptions) { setColorAnimation(resColor.h, animationOptions.h, reduceFactor); setColorAnimation(resColor.s, animationOptions.s, reduceFactor); setColorAnimation(resColor.l, animationOptions.l, reduceFactor); } return resColor; } function setColorAnimation(colorValue, colorAnimation, reduceFactor) { colorValue.enable = colorAnimation.enable; if (colorValue.enable) { colorValue.velocity = getRangeValue(colorAnimation.speed) / 100 * reduceFactor; colorValue.decay = 1 - getRangeValue(colorAnimation.decay); colorValue.status = "increasing"; colorValue.loops = 0; colorValue.maxLoops = getRangeValue(colorAnimation.count); colorValue.time = 0; colorValue.delayTime = getRangeValue(colorAnimation.delay) * 1000; if (!colorAnimation.sync) { colorValue.velocity *= getRandom(); colorValue.value *= getRandom(); } colorValue.initialValue = colorValue.value; } else { colorValue.velocity = 0; } } ;// CONCATENATED MODULE: ./dist/browser/Utils/CanvasUtils.js function drawLine(context, begin, end) { context.beginPath(); context.moveTo(begin.x, begin.y); context.lineTo(end.x, end.y); context.closePath(); } function drawTriangle(context, p1, p2, p3) { context.beginPath(); context.moveTo(p1.x, p1.y); context.lineTo(p2.x, p2.y); context.lineTo(p3.x, p3.y); context.closePath(); } function paintBase(context, dimension, baseColor) { context.fillStyle = baseColor ?? "rgba(0,0,0,0)"; context.fillRect(0, 0, dimension.width, dimension.height); } function paintImage(context, dimension, image, opacity) { if (!image) { return; } context.globalAlpha = opacity; context.drawImage(image, 0, 0, dimension.width, dimension.height); context.globalAlpha = 1; } function clear(context, dimension) { context.clearRect(0, 0, dimension.width, dimension.height); } function drawParticle(data) { const { container, context, particle, delta, colorStyles, backgroundMask, composite, radius, opacity, shadow, transform } = data; const pos = particle.getPosition(), angle = particle.rotation + (particle.pathRotation ? particle.velocity.angle : 0), rotateData = { sin: Math.sin(angle), cos: Math.cos(angle) }, transformData = { a: rotateData.cos * (transform.a ?? 1), b: rotateData.sin * (transform.b ?? 1), c: -rotateData.sin * (transform.c ?? 1), d: rotateData.cos * (transform.d ?? 1) }; context.setTransform(transformData.a, transformData.b, transformData.c, transformData.d, pos.x, pos.y); context.beginPath(); if (backgroundMask) { context.globalCompositeOperation = composite; } const shadowColor = particle.shadowColor; if (shadow.enable && shadowColor) { context.shadowBlur = shadow.blur; context.shadowColor = getStyleFromRgb(shadowColor); context.shadowOffsetX = shadow.offset.x; context.shadowOffsetY = shadow.offset.y; } if (colorStyles.fill) { context.fillStyle = colorStyles.fill; } const strokeWidth = particle.strokeWidth ?? 0; context.lineWidth = strokeWidth; if (colorStyles.stroke) { context.strokeStyle = colorStyles.stroke; } drawShape(container, context, particle, radius, opacity, delta); if (strokeWidth > 0) { context.stroke(); } if (particle.close) { context.closePath(); } if (particle.fill) { context.fill(); } drawShapeAfterEffect(container, context, particle, radius, opacity, delta); context.globalCompositeOperation = "source-over"; context.setTransform(1, 0, 0, 1, 0, 0); } function drawShape(container, context, particle, radius, opacity, delta) { if (!particle.shape) { return; } const drawer = container.drawers.get(particle.shape); if (!drawer) { return; } drawer.draw(context, particle, radius, opacity, delta, container.retina.pixelRatio); } function drawShapeAfterEffect(container, context, particle, radius, opacity, delta) { if (!particle.shape) { return; } const drawer = container.drawers.get(particle.shape); if (!drawer || !drawer.afterEffect) { return; } drawer.afterEffect(context, particle, radius, opacity, delta, container.retina.pixelRatio); } function drawPlugin(context, plugin, delta) { if (!plugin.draw) { return; } plugin.draw(context, delta); } function drawParticlePlugin(context, plugin, particle, delta) { if (!plugin.drawParticle) { return; } plugin.drawParticle(context, particle, delta); } function alterHsl(color, type, value) { return { h: color.h, s: color.s, l: color.l + (type === "darken" ? -1 : 1) * value }; } ;// CONCATENATED MODULE: ./dist/browser/Core/Canvas.js function setTransformValue(factor, newFactor, key) { const newValue = newFactor[key]; if (newValue !== undefined) { factor[key] = (factor[key] ?? 1) * newValue; } } class Canvas { constructor(container) { this.container = container; this._applyPostDrawUpdaters = particle => { for (const updater of this._postDrawUpdaters) { updater.afterDraw && updater.afterDraw(particle); } }; this._applyPreDrawUpdaters = (ctx, particle, radius, zOpacity, colorStyles, transform) => { for (const updater of this._preDrawUpdaters) { if (updater.getColorStyles) { const { fill, stroke } = updater.getColorStyles(particle, ctx, radius, zOpacity); if (fill) { colorStyles.fill = fill; } if (stroke) { colorStyles.stroke = stroke; } } if (updater.getTransformValues) { const updaterTransform = updater.getTransformValues(particle); for (const key in updaterTransform) { setTransformValue(transform, updaterTransform, key); } } updater.beforeDraw && updater.beforeDraw(particle); } }; this._applyResizePlugins = () => { for (const plugin of this._resizePlugins) { plugin.resize && plugin.resize(); } }; this._getPluginParticleColors = particle => { let fColor, sColor; for (const plugin of this._colorPlugins) { if (!fColor && plugin.particleFillColor) { fColor = rangeColorToHsl(plugin.particleFillColor(particle)); } if (!sColor && plugin.particleStrokeColor) { sColor = rangeColorToHsl(plugin.particleStrokeColor(particle)); } if (fColor && sColor) { break; } } return [fColor, sColor]; }; this._initCover = () => { const options = this.container.actualOptions, cover = options.backgroundMask.cover, color = cover.color, coverRgb = rangeColorToRgb(color); if (coverRgb) { const coverColor = { ...coverRgb, a: cover.opacity }; this._coverColorStyle = getStyleFromRgb(coverColor, coverColor.a); } }; this._initStyle = () => { const element = this.element, options = this.container.actualOptions; if (!element) { return; } if (this._fullScreen) { this._originalStyle = deepExtend({}, element.style); this._setFullScreenStyle(); } else { this._resetOriginalStyle(); } for (const key in options.style) { if (!key || !options.style) { continue; } const value = options.style[key]; if (!value) { continue; } element.style.setProperty(key, value, "important"); } }; this._initTrail = async () => { const options = this.container.actualOptions, trail = options.particles.move.trail, trailFill = trail.fill; if (!trail.enable) { return; } if (trailFill.color) { const fillColor = rangeColorToRgb(trailFill.color); if (!fillColor) { return; } const trail = options.particles.move.trail; this._trailFill = { color: { ...fillColor }, opacity: 1 / trail.length }; } else { await new Promise((resolve, reject) => { if (!trailFill.image) { return; } const img = document.createElement("img"); img.addEventListener("load", () => { this._trailFill = { image: img, opacity: 1 / trail.length }; resolve(); }); img.addEventListener("error", evt => { reject(evt.error); }); img.src = trailFill.image; }); } }; this._paintBase = baseColor => { this.draw(ctx => paintBase(ctx, this.size, baseColor)); }; this._paintImage = (image, opacity) => { this.draw(ctx => paintImage(ctx, this.size, image, opacity)); }; this._repairStyle = () => { const element = this.element; if (!element) { return; } this._safeMutationObserver(observer => observer.disconnect()); this._initStyle(); this.initBackground(); this._safeMutationObserver(observer => observer.observe(element, { attributes: true })); }; this._resetOriginalStyle = () => { const element = this.element, originalStyle = this._originalStyle; if (!(element && originalStyle)) { return; } const style = element.style; style.position = originalStyle.position; style.zIndex = originalStyle.zIndex; style.top = originalStyle.top; style.left = originalStyle.left; style.width = originalStyle.width; style.height = originalStyle.height; }; this._safeMutationObserver = callback => { if (!this._mutationObserver) { return; } callback(this._mutationObserver); }; this._setFullScreenStyle = () => { const element = this.element; if (!element) { return; } const priority = "important", style = element.style; style.setProperty("position", "fixed", priority); style.setProperty("z-index", this.container.actualOptions.fullScreen.zIndex.toString(10), priority); style.setProperty("top", "0", priority); style.setProperty("left", "0", priority); style.setProperty("width", "100%", priority); style.setProperty("height", "100%", priority); }; this.size = { height: 0, width: 0 }; this._context = null; this._generated = false; this._preDrawUpdaters = []; this._postDrawUpdaters = []; this._resizePlugins = []; this._colorPlugins = []; } get _fullScreen() { return this.container.actualOptions.fullScreen.enable; } clear() { const options = this.container.actualOptions, trail = options.particles.move.trail, trailFill = this._trailFill; if (options.backgroundMask.enable) { this.paint(); } else if (trail.enable && trail.length > 0 && trailFill) { if (trailFill.color) { this._paintBase(getStyleFromRgb(trailFill.color, trailFill.opacity)); } else if (trailFill.image) { this._paintImage(trailFill.image, trailFill.opacity); } } else { this.draw(ctx => { clear(ctx, this.size); }); } } destroy() { this.stop(); if (this._generated) { const element = this.element; element && element.remove(); } else { this._resetOriginalStyle(); } this._preDrawUpdaters = []; this._postDrawUpdaters = []; this._resizePlugins = []; this._colorPlugins = []; } draw(cb) { const ctx = this._context; if (!ctx) { return; } return cb(ctx); } drawParticle(particle, delta) { if (particle.spawning || particle.destroyed) { return; } const radius = particle.getRadius(); if (radius <= 0) { return; } const pfColor = particle.getFillColor(), psColor = particle.getStrokeColor() ?? pfColor; let [fColor, sColor] = this._getPluginParticleColors(particle); if (!fColor) { fColor = pfColor; } if (!sColor) { sColor = psColor; } if (!fColor && !sColor) { return; } this.draw(ctx => { const container = this.container, options = container.actualOptions, zIndexOptions = particle.options.zIndex, zOpacityFactor = (1 - particle.zIndexFactor) ** zIndexOptions.opacityRate, opacity = particle.bubble.opacity ?? particle.opacity?.value ?? 1, strokeOpacity = particle.strokeOpacity ?? opacity, zOpacity = opacity * zOpacityFactor, zStrokeOpacity = strokeOpacity * zOpacityFactor, transform = {}, colorStyles = { fill: fColor ? getStyleFromHsl(fColor, zOpacity) : undefined }; colorStyles.stroke = sColor ? getStyleFromHsl(sColor, zStrokeOpacity) : colorStyles.fill; this._applyPreDrawUpdaters(ctx, particle, radius, zOpacity, colorStyles, transform); drawParticle({ container, context: ctx, particle, delta, colorStyles, backgroundMask: options.backgroundMask.enable, composite: options.backgroundMask.composite, radius: radius * (1 - particle.zIndexFactor) ** zIndexOptions.sizeRate, opacity: zOpacity, shadow: particle.options.shadow, transform }); this._applyPostDrawUpdaters(particle); }); } drawParticlePlugin(plugin, particle, delta) { this.draw(ctx => drawParticlePlugin(ctx, plugin, particle, delta)); } drawPlugin(plugin, delta) { this.draw(ctx => drawPlugin(ctx, plugin, delta)); } async init() { this._safeMutationObserver(obs => obs.disconnect()); this._mutationObserver = safeMutationObserver(records => { for (const record of records) { if (record.type === "attributes" && record.attributeName === "style") {