UNPKG

tsparticles

Version:

Full-featured tsParticles bundle — create stunning particle, confetti and fireworks animations with all official plugins and presets included. Ready to use components available for React, Vue.js (2.x and 3.x), Angular, Svelte, jQuery, Preact, Riot.js, Inf

13,372 lines 545 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.4.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.full = global.__tsParticlesInternals.bundles.full || {})));
})(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 = 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$6 = 0, minRadius$5 = 0, defaultTransformValue = 1, minimumSize = 0, zIndexFactorOffset = 1, defaultOpacity$3 = 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$2 = 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$4 = 0;
    function isForbiddenKey(key) {
        return key === "__proto__" || key === "constructor" || key === "prototype";
    }
    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$4), 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 = Object.create(null);
            }
            const sourceKeys = Object.keys(source), 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 (isForbiddenKey(key)) {
                        continue;
                    }
                    const v = sourceDict[key];
                    if (v !== undefined) {
                        destDict[key] = v;
                    }
                }
                continue;
            }
            for (const key of sourceKeys) {
                if (isForbiddenKey(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.4.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() {
        const existing = globalThis.tsParticles;
        if (existing?.pluginManager) {
            return existing;
        }
        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.HdrMode = void 0;
    (function (HdrMode) {
        HdrMode["standard"] = "standard";
        HdrMode["natural"] = "natural";
        HdrMode["vivid"] = "vivid";
        HdrMode["cinematic"] = "cinematic";
        HdrMode["dynamic"] = "dynamic";
    })(exports.HdrMode || (exports.HdrMode = {}));

    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 = {}));

    exports.DrawLayer = void 0;
    (function (DrawLayer) {
        DrawLayer[DrawLayer["BackgroundElement"] = 0] = "BackgroundElement";
        DrawLayer[DrawLayer["BackgroundDraw"] = 1] = "BackgroundDraw";
        DrawLayer[DrawLayer["BackgroundMask"] = 2] = "BackgroundMask";
        DrawLayer[DrawLayer["CanvasSetup"] = 3] = "CanvasSetup";
        DrawLayer[DrawLayer["PluginContent"] = 4] = "PluginContent";
        DrawLayer[DrawLayer["Particles"] = 5] = "Particles";
        DrawLayer[DrawLayer["CanvasCleanup"] = 6] = "CanvasCleanup";
        DrawLayer[DrawLayer["Foreground"] = 7] = "Foreground";
    })(exports.DrawLayer || (exports.DrawLayer = {}));

    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) {
            const keyStr = key;
            if (keyStr === "__proto__" || keyStr === "constructor" || keyStr === "prototype") {
                return;
            }
            const objRecord = obj, currentValue = Object.prototype.hasOwnProperty.call(objRecord, keyStr) ? objRecord[keyStr] : {};
            objRecord[keyStr] = deepExtend(currentValue, 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;
        draw;
        element;
        image = "";
        opacity = 1;
        position = "";
        repeat = "";
        size = "";
        constructor() {
            super();
            this.color = new OptionsColor();
            this.color.value = "";
        }
        doLoad(data) {
            if (data.color !== undefined) {
                this.color = OptionsColor.create(this.color, data.color);
            }
            loadProperty(this, "element", data.element);
            loadProperty(this, "draw", data.draw);
            loadProperty(this, "image", data.image);
            loadProperty(this, "position", data.position);
            loadProperty(this, "repeat", data.repeat);
            loadProperty(this, "size", data.size);
            loadProperty(this, "opacity", data.opacity);
        }
    }

    class FullScreen extends OptionLoader {
        enable = true;
        zIndex = 0;
        doLoad(data) {
            loadProperty(this, "enable", data.enable);
            loadProperty(this, "zIndex", data.zIndex);
        }
    }

    const defaultPeakNits = 400, minPeakNits = 0, toStringValue = (value) => String(value);
    class HDROptions extends OptionLoader {
        enable = true;
        mode = exports.HdrMode.standard;
        peakNits = defaultPeakNits;
        doLoad(data) {
            if (data.enable !== undefined && !isBoolean(data.enable)) {
                throw new Error(`Invalid HDR "enable" value: expected a boolean, got "${String(data.enable)}"`);
            }
            if (data.mode !== undefined &&
                (typeof data.mode !== "string" || !Object.values(exports.HdrMode).includes(data.mode))) {
                throw new Error(`Invalid HDR "mode" value: expected one of ${Object.values(exports.HdrMode).join(", ")}, got "${toStringValue(data.mode)}"`);
            }
            if (data.peakNits !== undefined &&
                (!isNumber(data.peakNits) || !Number.isFinite(data.peakNits) || data.peakNits <= minPeakNits)) {
                throw new Error(`Invalid HDR "peakNits" value: expected a positive number, got "${String(data.peakNits)}"`);
            }
            loadProperty(this, "enable", data.enable);
            loadProperty(this, "mode", data.mode);
            loadProperty(this, "peakNits", data.peakNits);
        }
    }

    class ResizeEvent extends OptionLoader {
        delay = 0.5;
        enable = true;
        doLoad(data) {
            loadProperty(this, "delay", data.delay);
            loadProperty(this, "enable", data.enable);
        }
    }

    class Effect extends OptionLoader {
        close = true;
        options = {};
        type = [];
        doLoad(data) {
            const options = data.options;
            if (options !== undefined) {
                for (const effect in options) {
                    const item = options[effect];
                    if (item) {
                        this.options[effect] = deepExtend(this.options[effect] ?? {}, item);
                    }
                }
            }
            loadProperty(this, "close", data.close);
            loadProperty(this, "type", data.type);
        }
    }

    class Fill extends OptionLoader {
        color;
        enable = true;
        opacity = 1;
        doLoad(data) {
            if (data.color !== undefined) {
                this.color = AnimatableColor.create(this.color, data.color);
            }
            loadProperty(this, "enable", data.enable);
            loadRangeProperty(this, "opacity", data.opacity);
        }
    }

    class MoveAngle extends OptionLoader {
        offset = 0;
        value = 90;
        doLoad(data) {
            loadRangeProperty(this, "offset", data.offset);
            loadRangeProperty(this, "value", data.value);
        }
    }

    class MoveCenter extends OptionLoader {
        mode = exports.PixelMode.percent;
        radius = 0;
        x = 50;
        y = 50;
        doLoad(data) {
            loadProperty(this, "x", data.x);
            loadProperty(this, "y", data.y);
            loadProperty(this, "mode", data.mode);
            loadProperty(this, "radius", data.radius);
        }
    }

    class MoveGravity extends OptionLoader {
        acceleration = 9.81;
        enable = false;
        inverse = false;
        maxSpeed = 50;
        doLoad(data) {
            loadRangeProperty(this, "acceleration", data.acceleration);
            loadProperty(this, "enable", data.enable);
            loadProperty(this, "inverse", data.inverse);
            loadRangeProperty(this, "maxSpeed", data.maxSpeed);
        }
    }

    class ValueWithRandom extends OptionLoader {
        value = 0;
        doLoad(data) {
            if (!isNull(data.value)) {
                this.value = setRangeValue(data.value);
            }
        }
    }
    class AnimationValueWithRandom extends ValueWithRandom {
        animation = new AnimationOptions();
        doLoad(data) {
            super.doLoad(data);
            loadNestedProperty(this, "animation", data.animation);
        }
    }
    class RangedAnimationValueWithRandom extends AnimationValueWithRandom {
        animation = new RangedAnimationOptions();
    }

    class MovePath extends OptionLoader {
        clamp = true;
        delay = new ValueWithRandom();
        enable = false;
        generator;
        options = {};
        doLoad(data) {
            loadProperty(this, "clamp", data.clamp);
            this.delay.load(data.delay);
            loadProperty(this, "enable", data.enable);
            this.generator = data.generator;
            if (data.options) {
                this.options = deepExtend(this.options, data.options);
            }
        }
    }

    class OutModes extends OptionLoader {
        bottom;
        default = exports.OutMode.out;
        left;
        right;
        top;
        doLoad(data) {
            if (data.default !== undefined) {
                this.default = data.default;
            }
            this.bottom = data.bottom ?? data.default;
            this.left = data.left ?? data.default;
            this.right = data.right ?? data.default;
            this.top = data.top ?? data.default;
        }
    }

    class Spin extends OptionLoader {
        acceleration = 0;
        enable = false;
        position;
        doLoad(data) {
            loadRangeProperty(this, "acceleration", data.acceleration);
            loadProperty(this, "enable", data.enable);
            if (data.position) {
                this.position = deepExtend({}, data.position);
            }
        }
    }

    class Move extends OptionLoader {
        angle = new MoveAngle();
        center = new MoveCenter();
        decay = 0;
        direction = exports.MoveDirection.none;
        distance = {};
        drift = 0;
        enable = false;
        gravity = new MoveGravity();
        outModes = new OutModes();
        path = new MovePath();
        random = false;
        size = false;
        speed = 2;
        spin = new Spin();
        straight = false;
        vibrate = false;
        warp = false;
        doLoad(data) {
            this.angle.load(isNumber(data.angle) ? { value: data.angle } : data.angle);
            this.center.load(data.center);
            loadRangeProperty(this, "decay", data.decay);
            loadProperty(this, "direction", data.direction);
            if (data.distance !== undefined) {
                this.distance = isNumber(data.distance)
                    ? {
                        horizontal: data.distance,
                        vertical: data.distance,
                    }
                    : { ...data.distance };
            }
            loadRangeProperty(this, "drift", data.drift);
            loadProperty(this, "enable", data.enable);
            this.gravity.load(data.gravity);
            const outModes = data.outModes;
            if (outModes !== undefined) {
                if (isObject(outModes)) {
                    this.outModes.load(outModes);
                }
                else {
                    this.outModes.load({
                        default: outModes,
                    });
                }
            }
            this.path.load(data.path);
            loadProperty(this, "random", data.random);
            loadProperty(this, "size", data.size);
            loadRangeProperty(this, "speed", data.speed);
            this.spin.load(data.spin);
            loadProperty(this, "straight", data.straight);
            loadProperty(this, "vibrate", data.vibrate);
            loadProperty(this, "warp", data.warp);
        }
    }

    class Stroke extends OptionLoader {
        color;
        opacity;
        width = 0;
        doLoad(data) {
            if (data.color !== undefined) {
                this.color = AnimatableColor.create(this.color, data.color);
            }
            loadRangeProperty(this, "width", data.width);
            loadRangeProperty(this, "opacity", data.opacity);
        }
    }

    class Paint extends OptionLoader {
        color;
        fill;
        stroke;
        doLoad(data) {
            if (data.color !== undefined) {
                this.color = AnimatableColor.create(this.color, data.color);
            }
            loadLazyProperty(this, "fill", data.fill, () => new Fill());
            loadLazyProperty(this, "stroke", data.stroke, () => new Stroke());
        }
    }

    class ParticlesBounceFactor extends ValueWithRandom {
        value = 1;
    }

    class ParticlesBounce extends OptionLoader {
        horizontal = new ParticlesBounceFactor();
        vertical = new ParticlesBounceFactor();
        doLoad(data) {
            this.horizontal.load(data.horizontal);
            this.vertical.load(data.vertical);
        }
    }

    class ParticlesDensity extends OptionLoader {
        enable = false;
        height = 1080;
        width = 1920;
        doLoad(data) {
            loadProperty(this, "enable", data.enable);
            loadProperty(this, "width", data.width);
            loadProperty(this, "height", data.height);
        }
    }

    class ParticlesNumberLimit extends OptionLoader {
        mode = exports.LimitMode.delete;
        value = 0;
        doLoad(data) {
            loadProperty(this, "mode", data.mode);
            loadProperty(this, "value", data.value);
        }
    }

    class ParticlesNumber extends OptionLoader {
        density = new ParticlesDensity();
        limit = new ParticlesNumberLimit();
        value = 0;
        doLoad(data) {
            this.density.load(data.density);
            this.limit.load(data.limit);
            loadProperty(this, "value", data.value);
        }
    }

    class Shape extends OptionLoader {
        close = true;
        options = {};
        type = "circle";
        doLoad(data) {
            const options = data.options;
            if (options !== undefined) {
                for (const shape in options) {
                    const item = options[shape];
                    if (item) {
                        this.options[shape] = deepExtend(this.options[shape] ?? {}, item);
                    }
                }
            }
            loadProperty(this, "close", data.close);
            loadProperty(this, "type", data.type);
        }
    }

    class ZIndex extends ValueWithRandom {
        opacityRate = 1;
        sizeRate = 1;
        velocityRate = 1;
        doLoad(data) {
            super.doLoad(data);
            loadProperty(this, "opacityRate", data.opacityRate);
            loadProperty(this, "sizeRate", data.sizeRate);
            loadProperty(this, "velocityRate", data.velocityRate);
        }
    }

    class ParticlesOptions extends OptionLoader {
        bounce = new ParticlesBounce();
        effect = new Effect();
        groups = {};
        move = new Move();
        number = new ParticlesNumber();
        paint;
        palette;
        reduceDuplicates = false;
        shape = new Shape();
        zIndex = new ZIndex();
        #container;
        #pluginManager;
        constructor(pluginManager, container) {
            super();
            this.#pluginManager = pluginManager;
            this.#container = container;
            this.paint = new Paint();
            this.paint.color = new AnimatableColor();
            this.paint.color.value = "#fff";
            this.paint.fill = new Fill();
            this.paint.fill.enable = true;
        }
        doLoad(data) {
            if (data.palette) {
                this.palette = data.palette;
                this.#importPalette(this.palette);
            }
            if (data.groups !== undefined) {
                for (const group of Object.keys(data.groups)) {
                    if (!(group in data.groups)) {
                        continue;
                    }
                    const item = data.groups[group];
                    if (item !== undefined) {
                        this.groups[group] = deepExtend(this.groups[group] ?? {}, item);
                    }
                }
            }
            if (data.reduceDuplicates !== undefined) {
                this.reduceDuplicates = data.reduceDuplicates;
            }
            this.bounce.load(data.bounce);
            this.effect.load(data.effect);
            this.move.load(data.move);
            this.number.load(data.number);
            const paintToLoad = data.paint;
            if (paintToLoad) {
                if (isArray(paintToLoad)) {
                    this.paint = executeOnSingleOrMultiple(paintToLoad, t => {
                        const tmp = new Paint();
                        tmp.load(t);
                        return tmp;
                    });
                }
                else if (isArray(this.paint)) {
                    this.paint = new Paint();
                    this.paint.load(paintToLoad);
                }
                else {
                    this.paint.load(paintToLoad);
                }
            }
            this.shape.load(data.shape);
            this.zIndex.load(data.zIndex);
            if (this.#container) {
                for (const plugin of this.#pluginManager.plugins) {
                    if (plugin.loadParticlesOptions) {
                        plugin.loadParticlesOptions(this.#container, this, data);
                    }
                }
                const updaters = this.#pluginManager.updaters.get(this.#container);
                if (updaters) {
                    for (const updater of updaters) {
                        if (updater.loadOptions) {
                            updater.loadOptions(this, data);
                        }
                    }
                }
            }
        }
        #importPalette(palette) {
            const paletteData = this.#pluginManager.getPalette(palette);
            if (!paletteData) {
                return;
            }
            const paletteColors = paletteData.colors, defaultPaintStrokeWidth = 0, defaultPaintVariantsLength = 1, firstPaintVariantIndex = 0, defaultPalettePaintVariant = {}, colorVariants = isArray(paletteColors) ? paletteColors : [paletteColors], palettePaintVariants = colorVariants.flatMap(variant => {
                const paletteFill = variant.fill, paletteStroke = variant.stroke, fillPart = paletteFill
                    ? {
                        color: {
                            value: paletteFill.value,
                        },
                        enable: paletteFill.enable,
                        opacity: paletteFill.opacity,
                    }
                    : undefined;
                if (!paletteStroke) {
                    return [
                        {
                            fill: fillPart,
                        },
                    ];
                }
                return [
                    {
                        fill: fillPart,
                        stroke: {
                            color: {
                                value: paletteStroke.value,
                            },
                            opacity: paletteStroke.opacity,
                            width: paletteStroke.width || defaultPaintStrokeWidth,
                        },
                    },
                ];
            }), palettePaint = palettePaintVariants.length > defaultPaintVariantsLength
                ? palettePaintVariants
                : (palettePaintVariants[firstPaintVariantIndex] ?? defaultPalettePaintVariant);
            this.load({
                paint: palettePaint,
                blend: {
                    enable: true,
                    mode: paletteData.blendMode,
                },
            });
        }
    }

    function loadParticlesOptions(pluginManager, container, ...sourceOptionsArr) {
        const options = new ParticlesOptions(pluginManager, container);
        loadOptions(options, ...sourceOptionsArr);
        return options;
    }

    class Options extends OptionLoader {
        autoPlay = true;
        background;
        clear = true;
        defaultThemes = {};
        delay = 0;
        detectRetina = true;
        duration = 0;
        fpsLimit = 120;
        fullScreen;
        hdr;
        key;
        name;
        palette;
        particles;
        pauseOnBlur = true;
        pauseOnOutsideViewport = true;
        preset;
        resize;
        smooth = false;
        style = {};
        zLayers = 100;
        #container;
        #pluginManager;
        constructor(pluginManager, container) {
            super();
            this.#pluginManager = pluginManager;
            this.#container = container;
            this.background = new Background();
            this.fullScreen = new FullScreen();
            this.hdr = new HDROptions();
            this.particles = loadParticlesOptions(this.#pluginManager, this.#container);
            this.resize = new ResizeEvent();
        }
        doLoad(data) {
            if (data.preset !== undefined) {
                this.preset = data.preset;
                executeOnSingleOrMultiple(this.preset, preset => {
                    this.#importPreset(preset);
                });
            }
            if (data.palette !== undefined) {
                this.palette = data.palette;
                this.#importPalette(this.palette);
            }
            loadProperty(this, "autoPlay", data.autoPlay);
            loadProperty(this, "clear", data.clear);
            loadProperty(this, "key", data.key);
            loadProperty(this, "name", data.name);
            loadRangeProperty(this, "delay", data.delay);
            loadProperty(this, "detectRetina", data.detectRetina);
            loadRangeProperty(this, "duration", data.duration);
            loadProperty(this, "fpsLimit", data.fpsLimit);
            const hdrData = data.hdr;
            if (isBoolean(hdrData)) {
                this.hdr.enable = hdrData;
                this.hdr.mode = exports.HdrMode.standard;
                this.hdr.peakNits = 400;
            }
            else {
                this.hdr.load(hdrData);
            }
            loadProperty(this, "pauseOnBlur", data.pauseOnBlur);
            loadProperty(this, "pauseOnOutsideViewport", data.pauseOnOutsideViewport);
            loadProperty(this, "zLayers", data.zLayers);
            this.background.load(data.background);
            const fullScreen = data.fullScreen;
            if (isBoolean(fullScreen)) {
                this.fullScreen.enable = fullScreen;
            }
            else {
                this.fullScreen.load(fullScreen);
            }
            this.particles.load(data.particles);
            this.resize.load(data.resize);
            this.style = deepExtend(this.style, data.style);
            loadProperty(this, "smooth", data.smooth);
            this.#pluginManager.plugins.forEach(plugin => {
                plugin.loadOptions(this.#container, this, data);
            });
        }
        #importPalette(palette) {
            const paletteData = this.#pluginManager.getPalette(palette);
            if (!paletteData) {
                return;
            }
            this.load({
                background: {
                    color: paletteData.background,
                },
                blend: {
                    enable: true,
                    mode: paletteData.blendMode,
                },
                particles: {
                    palette,
                },
            });
        }
        #importPreset(preset) {
            this.load(this.#pluginManager.getPreset(preset));
        }
    }

    const styleCache = new Map(), maxStyleCacheSize = 2000, rgbFixedPrecision = 2, hslFixedPrecision = 2, hdrRgbFixedPrecision = 4, hdrHslFixedPrecision = 4, sdrReferenceWhiteNits = 203, acesA = 2.51, acesB = 0.03, acesC = 2.43, acesD = 0.59, acesE = 0.14, saturationBoost = 1.15, lightnessBoost = 1.05, temperatureR = 1.05, temperatureB = 0.95, contrastFactor = 1.1, luminanceR = 0.2126, luminanceG = 0.7152, luminanceB = 0.0722, dynamicLuminanceFactor = 2, channelCount = 3, srgbThreshold = 0.04045, srgbDivisor = 12.92, srgbOffset = 0.055, srgbScale = 1.055, srgbExponent = 2.4, linearThreshold = 0.0031308, linearScale = 12.92;
    function getCachedStyle(key, generator) {
        let cached = styleCache.get(key);
        if (!cached) {
            cached = generator();
            if (styleCache.size > maxStyleCacheSize) {
                styleCache.clear();
            }
            styleCache.set(key, cached);
        }
        return cached;
    }
    function acesFilmic(x) {
        return clamp((x * (acesA * x + acesB)) / (x * (acesC * x + acesD) + acesE), none, one);
    }
    function srgbToLinear(c) {
        return c <= srgbThreshold ? c / srgbDivisor : Math.pow((c + srgbOffset) / srgbScale, srgbExponent);
    }
    function linearToSrgb(c) {
        return c <= linearThreshold ? c * linearScale : srgbScale * Math.pow(c, one / srgbExponent) - srgbOffset;
    }
    function applyHdrModeAdjustments(r, g, b, mode, maxChannel) {
        switch (mode) {
            case exports.HdrMode.vivid: {
                const avg = (r + g + b) / channelCount;
                return {
                    b: clamp(clamp(avg + (b - avg) * saturationBoost, none, maxChannel) * lightnessBoost, none, maxChannel),
                    g: clamp(clamp(avg + (g - avg) * saturationBoost, none, maxChannel) * lightnessBoost, none, maxChannel),
                    r: clamp(clamp(avg + (r - avg) * saturationBoost, none, maxChannel) * lightnessBoost, none, maxChannel),
                };
            }
            case exports.HdrMode.cinematic: {
                const tempR = r * temperatureR, tempB = b * temperatureB, avg = (tempR + g + tempB) / channelCount;
                return {
                    b: clamp(avg + (tempB - avg) * contrastFactor, none, maxChannel),
                    g: clamp(avg + (g - avg) * contrastFactor, none, maxChannel),
                    r: clamp(avg + (tempR - avg) * contrastFactor, none, maxChannel),
                };
            }
            case exports.HdrMode.dynamic: {
                const luminance = luminanceR * r + luminanceG * g + luminanceB * b, vividWeight = Math.min(one, luminance * dynamicLuminanceFactor), naturalWeight = one - vividWeight, avg = (r + g + b) / channelCount, vividR = clamp(avg + (r - avg) * saturationBoost, none, maxChannel) * lightnessBoost, vividG = clamp(avg + (g - avg) * saturationBoost, none, maxChannel) * lightnessBoost, vividB = clamp(avg + (b - avg) * saturationBoost, none, maxChannel) * lightnessBoost;
                return {
                    b: clamp(b * naturalWeight + vividB * vividWeight, none, maxChannel),
                    g: clamp(g * naturalWeight + vividG * vividWeight, none, maxChannel),
                    r: clamp(r * naturalWeight + vividR * vividWeight, none, maxChannel),
                };
            }
            case exports.HdrMode.standard:
                return { b, g, r };
            case exports.HdrMode.natural:
            default:
                return { b, g, r };
        }
    }
    function stringToRgba(pluginManager, input) {
        if (!input) {
            return;
        }
        for (const manager of pluginManager.colorManagers.values()) {
            if (manager.accepts(input)) {
                return manager.parseString(input);
            }
        }
        return undefined;
    }
    function rangeColorToRgb(pluginManager, input, index, useIndex = true) {
        if (!input) {
            return;
        }
        const color = isString(input) ? { value: input } : input;
        if (isString(color.value)) {
            return colorToRgb(pluginManager, color.value, index, useIndex);
        }
        if (isArray(color.value)) {
            const value = itemFromArray(color.value, index, useIndex);
            if (!value) {
                return;
            }
            return rangeColorToRgb(pluginManager, {
                value,
            });
        }
        for (const manager of pluginManager.colorManagers.values()) {
            const res = manager.handleRangeColor(color);
            if (res) {
                return res;
            }
        }
        return undefined;
    }
    function colorToRgb(pluginManager, input, index, useIndex = true) {
        if (!input) {
            return;
        }
        const color = isString(input) ? { value: input } : input;
        if (isString(color.value)) {
            return color.value === randomColorValue ? getRandomRgbColor() : stringToRgb(pluginManager, color.value);
        }
        if (isArray(color.value)) {
            const value = itemFromArray(color.value, index, useIndex);
            if (!value) {
                return;
            }
            return colorToRgb(pluginManager, {
                value,
            });
        }
        for (const manager of pluginManager.colorManagers.values()) {
            const res = manager.handleColor(color);
            if (res) {
                return res;
            }
        }
        return undefined;
    }
    function rangeColorToHsl(pluginManager, color, index, useIndex = true) {
        const rgb = rangeColorToRgb(pluginManager, color, index, useIndex);
        return rgb ? rgbToHsl(rgb) : undefined;
    }
    function rgbToHsl(color) {
        const r1 = color.r / rgbMax, g1 = color.g / rgbMax, b1 = color.b / rgbMax, max = Math.max(r1, g1, b1), min = Math.min(r1, g1, b1), res = {
            h: hMin,
            l: (max + min) * half,
            s: sMin,
        };
        if (max !== min) {
            res.s = res.l < half ? (max - min) / (max + min) : (max - min) / (double - max - min);
            if (r1 === max) {
                res.h = (g1 - b1) / (max - min);
            }
            else if (g1 === max) {
                res.h = double + (b1 - r1) / (max - min);
            }
            else {
                res.h = double * double + (r1 - g1) / (max - min);
            }
        }
        res.l *= lMax;
        res.s *= sMax;
        res.h *= hPhase;
        if (res.h < hMin) {
            res.h += hMax;
        }
        if (res.h >= hMax) {
            res.h -= hMax;
        }
        return res;
    }
    function stringToAlpha(pluginManager, input) {
        return stringToRgba(pluginManager, input)?.a;
    }
    function stringToRgb(pluginManager, input) {
        return stringToRgba(pluginManager, input);
    }
    function hslChannel(temp1, temp2, temp3) {
        const temp3Min = 0, temp3Max = 1;
        if (temp3 < temp3Min) {
            temp3++;
        }
        if (temp3 > temp3Max) {
            temp3--;
        }
        if (temp3 * sextuple < temp3Max) {
            return temp1 + (temp2 - temp1) * sextuple * temp3;
        }
        if (temp3 * double < temp3Max) {
            return temp2;
        }
        if (temp3 * triple < temp3Max * double) {
            const temp3Offset = double / triple;
            return temp1 + (temp2 - temp1) * (temp3Offset - temp3) * sextuple;
        }
        return temp1;
    }
    function hslToRgb(hsl) {
        const h = ((hsl.h % hMax) + hMax) % hMax, s = Math.max(sMin, Math.min(sMax, hsl.s)), l = Math.max(lMin, Math.min(lMax, hsl.l)), hNormalized = h / hMax, sNormalized = s / sMax, lNormalized = l / lMax;
        if (s === sMin) {
            const grayscaleValue = Math.round(lNormalized * rgbMax);
            return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
        }
        const temp1 = lNormalized < half
            ? lNormalized * (sNormalizedOffset + sNormalized)
            : lNormalized + sNormalized - lNormalized * sNormalized, temp2 = double * lNormalized - temp1, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized)), blue = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized - phaseThird));
        return { r: Math.round(red), g: Math.round(green), b: Math.round(blue) };
    }
    function hslToRgbFloat(hsl) {
        const h = ((hsl.h % hMax) + hMax) % hMax, s = Math.max(sMin, Math.min(sMax, hsl.s)), l = Math.max(lMin, Math.min(lMax, hsl.l)), hNormalized = h / hMax, sNormalized = s / sMax, lNormalized = l / lMax;
        if (s === sMin) {
            const grayscaleValue = lNormalized * rgbMax;
            return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
        }
        const temp1 = lNormalized < half
            ? lNormalized * (sNormalizedOffset + sNormalized)
            : lNormalized + sNormalized - lNormalized * sNormalized, temp2 = double * lNormalized - temp1, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized)), blue = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized - phaseThird));
        return { r: red, g: green, b: blue };
    }
    function hslaToRgba(hsla) {
        const rgbResult = hslToRgb(hsla);
        return {
            a: hsla.a,
            b: rgbResult.b,
            g: rgbResult.g,
            r: rgbResult.r,
        };
    }
    function getRandomRgbColor(min, hdr) {
        const fixedMin = min ?? defaultRgbMin;
        if (hdr) {
            return {
                r: getRandomInRange(fixedMin, rgbMax),
                g: getRandomInRange(fixedMin, rgbMax),
                b: getRandomInRange(fixedMin, rgbMax),
            };
        }
        const fixedMax = rgbMax + identity$2, getRgbInRangeValue = () => Math.floor(getRandomInRange(fixedMin, fixedMax));
        return {
            b: getRgbInRangeValue(),
            g: getRgbInRangeValue(),
            r: getRgbInRangeValue(),
        };
    }
    function getStyleFromRgb(color, hdr, opacity, peakNits, mode) {
        const rgbPrecision = hdr ? hdrRgbFixedPrecision : rgbFixedPrecision, op = opacity ?? defaultOpacity$3, key = hdr
            ? `rgb-${color.r.toFixed(rgbPrecision)}-${color.g.toFixed(rgbPrecision)}-${color.b.toFixed(rgbPrecision)}-hdr-${op.toString()}-${(peakNits ?? maxNits).toString()}-${mode ?? exports.HdrMode.standard}`
            : `rgb-${color.r.toFixed(rgbPrecision)}-${color.g.toFixed(rgbPrecision)}-${color.b.toFixed(rgbPrecision)}-sdr-${op.toString()}`;
        return getCachedStyle(key, () => hdr ? getHdrStyleFromRgb(color, opacity, peakNits, mode) : getSdrStyleFromRgb(color, opacity));
    }
    function getHdrStyleFromRgb(color, opacity, peakNits = maxNits, mode = exports.HdrMode.standard) {
        const headroom = peakNits / sdrReferenceWhiteNits, middleGray = 0.18, mapped = hdrToneMapColor(color, headroom, middleGray, mode);
        return `color(display-p3 ${mapped.r.toString()} ${mapped.g.toString()} ${mapped.b.toString()} / ${(opacity ?? defaultOpacity$3).toString()})`;
    }
    function hdrToneMapColor(color, headroom, middleGray, mode) {
        const rNorm = color.r / rgbMax, gNorm = color.g / rgbMax, bNorm = color.b / rgbMax;
        if (mode !== exports.HdrMode.natural && mode !== exports.HdrMode.vivid && mode !== exports.HdrMode.cinematic && mode !== exports.HdrMode.dynamic) {
            return { b: bNorm, g: gNorm, r: rNorm };
        }
        const maxChannel = Math.max(one, headroom), luminance = luminanceR * rNorm + luminanceG * gNorm + luminanceB * bNorm, mappedLuminance = hdrToneMap(luminance, headroom, middleGray), scale = luminance > none ? mappedLuminance / luminance : one;
        return applyHdrModeAdjustments(clamp(rNorm * scale, none, maxChannel), clamp(gNorm * scale, none, maxChannel), clamp(bNorm * scale, none, maxChannel), mode, maxChannel);
    }
    function hdrToneMap(normalized, headroom, middleGray) {
        if (normalized <= middleGray) {
            return acesFilmic(normalized);
        }
        const expanded = normalized + (normalized - middleGray) * (headroom - one);
        return acesFilmic(expanded);
    }
    function getSdrStyleFromRgb(color, opacity) {
        return `rgba(${color.r.toString()}, ${color.g.toString()}, ${color.b.toString()}, ${(opacity ?? defaultOpacity$3).toString()})`;
    }
    function getStyleFromHsl(color, hdr, opacity, peakNits, mode) {
        const hslPrecision = hdr ? hdrHslFixedPrecision : hslFixedPrecision, op = opacity ?? defaultOpacity$3, key = hdr
            ? `hsl-${color.h.toFixed(hslPrecision)}-${color.s.toFixed(hslPrecision)}-${color.l.toFixed(hslPrecision)}-hdr-${op.toString()}-${(peakNits ?? maxNits).toString()}-${mode ?? exports.HdrMode.standard}`
            : `hsl-${color.h.toFixed(hslPrecision)}-${color.s.toFixed(hslPrecision)}-${color.l.toFixed(hslPrecision)}-sdr-${op.toString()}`;
        return getCachedStyle(key, () => hdr
            ? getStyleFromRgb(hslToRgbFloat(color), true, opacity, peakNits, mode)
            : `hsla(${color.h.toString()}, ${color.s.toString()}%, ${color.l.toString()}%, ${op.toString()})`);
    }
    function colorMix(color1, color2, size1, size2, hdr) {
        let rgb1 = color1, rgb2 = color2;
        if (!("r" in rgb1)) {
            rgb1 = hdr ? hslToRgbFloat(color1) : hslToRgb(color1);
        }
        if (!("r" in rgb2)) {
            rgb2 = hdr ? hslToRgbFloat(color2) : hslToRgb(color2);
        }
        if (hdr) {
            const lin1 = {
                b: srgbToLinear(rgb1.b / rgbMax),
                g: srgbToLinear(rgb1.g / rgbMax),
                r: srgbToLinear(rgb1.r / rgbMax),
            }, lin2 = {
                b: srgbToLinear(rgb2.b / rgbMax),
                g: srgbToLinear(rgb2.g / rgbMax),
                r: srgbToLinear(rgb2.r / rgbMax),
            }, totalWeight = size1 + size2;
            return {
                b: linearToSrgb((lin1.b * size1 + lin2.b * size2) / totalWeight) * rgbMax,
                g: linearToSrgb((lin1.g * size1 + lin2.g * size2) / totalWeight) * rgbMax,
                r: linearToSrgb((lin1.r * size1 + lin2.r * size2) / totalWeight) * rgbMax,
            };
        }
        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, hdr) {
        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(), hdr);
            }
            else {
                const hslColor = sourceColor ?? destColor;
                if (hslColor) {
                    return hslToRgb(hslColor);
                }
            }
        }
        else {
            return linkColor;
        }
        return undefined;
    }
    function getLinkRandomColor(pluginManager, optColor, blink, consent) {
        const color = isString(optColor) ? optColor : optColor.value;
        if (color === randomColorValue) {
            if (consent) {
                return rangeColorToRgb(pluginManager, {
                    value: color,
                });
            }
            if (blink) {
                return randomColorValue;
            }
            return midColorValue;
        }
        else if (color === midColorValue) {
            return midColorValue;
        }
        else {
            return rangeColorToRgb(pluginManager, {
                value: color,
            });
        }
    }
    function getHslFromAnimation(animation) {
        return animation === undefined
            ? undefined
            : {
                h: animation.h.value,
                s: animation.s.value,
                l: animation.l.value,
            };
    }
    function getHslAnimationFromHsl(hsl, animationOptions, reduceFactor) {
        const resColor = {
            h: {
                enable: false,
                value: hsl.h,
                min: hMin,
                max: hMax,
            },
            s: {
                enable: false,
                value: hsl.s,
                min: sMin,
                max: sMax,
            },
            l: {
                enable: false,
                value: hsl.l,
                min: lMin,
                max: lMax,
            },
        };
        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;
        colorValue.min = colorAnimation.min;
        colorValue.max = colorAnimation.max;
        if (colorValue.enable) {
            colorValue.velocity = (getRangeValue(colorAnimation.speed) / percentDenominator) * reduceFactor;
            colorValue.decay = decayOffset - getRangeValue(colorAnimation.decay);
            colorValue.status = exports.AnimationStatus.increasing;
            colorValue.loops = defaultLoops;
            colorValue.maxLoops = getRangeValue(colorAnimation.count);
            colorValue.time = defaultTime;
            colorValue.delayTime = getRangeValue(colorAnimation.delay) * millisecondsToSeconds;
            if (!colorAnimation.sync) {
                colorValue.velocity *= getRandom();
                colorValue.value *= getRandom();
            }
            colorValue.initialValue = colorValue.value;
            colorValue.offset = setRangeValue(colorAnimation.offset);
        }
        else {
            colorValue.velocity = defaultVelocity;
        }
    }
    function updateColorValue(data, decrease, delta, _hdr) {
        const minLoops = 0, minDelay = 0, identity = 1, minVelocity = 0, minOffset = 0, velocityFactor = 3.6;
        if (!data.enable ||
            ((data.maxLoops ?? minLoops) > minLoops && (data.loops ?? minLoops) > (data.maxLoops ?? minLoops))) {
            return;
        }
        data.time ??= 0;
        if ((data.delayTime ?? minDelay) > minDelay && data.time < (data.delayTime ?? minDelay)) {
            data.time += delta.value;
        }
        if ((data.delayTime ?? minDelay) > minDelay && data.time < (data.delayTime ?? minDelay)) {
            return;
        }
        const offset = data.offset ? randomInRangeValue(data.offset) : minOffset, velocity = (data.velocity ?? minVelocity) * delta.factor + offset * velocityFactor, decay = data.decay ?? identity, max = data.max, min = data.min;
        if (!decrease || data.status === exports.AnimationStatus.increasing) {
            data.value += velocity;
            if (data.value > max) {
                data.loops ??= 0;
                data.loops++;
                if (decrease) {
                    data.status = exports.AnimationStatus.decreasing;
                }
                else {
                    data.value -= max;
                }
            }
        }
        else {
            data.value -= velocity;
            if (data.value < min) {
                data.loops ??= 0;
                data.loops++;
                data.status = exports.AnimationStatus.increasing;
            }
        }
        if (data.velocity && decay !== identity) {
            data.velocity *= decay;
        }
        data.value = clamp(data.value, min, max);
    }
    function updateColor(color, delta, hdr) {
        if (!color) {
            return;
        }
        const { h, s, l } = color;
        updateColorValue(h, false, delta);
        updateColorValue(s, true, delta);
        updateColorValue(l, true, delta);
    }
    function alterHsl(color, type, value) {
        return {
            h: color.h,
            s: color.s,
            l: color.l + (type === exports.AlterType.darken ? -lFactor : lFactor) * value,
        };
    }

    const tsParticles = initEngine();

    class ClickEvent {
        enable = false;
        mode = [];
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadProperty(this, "enable", data.enable);
            loadProperty(this, "mode", data.mode);
        }
    }

    var DivType;
    (function (DivType) {
        DivType["circle"] = "circle";
        DivType["rectangle"] = "rectangle";
    })(DivType || (DivType = {}));

    class DivEvent {
        enable = false;
        mode = [];
        selectors = [];
        type = DivType.circle;
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadProperty(this, "selectors", data.selectors);
            loadProperty(this, "enable", data.enable);
            loadProperty(this, "mode", data.mode);
            loadProperty(this, "type", data.type);
        }
    }

    class HoverEvent {
        enable = false;
        mode = [];
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadProperty(this, "enable", data.enable);
            loadProperty(this, "mode", data.mode);
        }
    }

    class Events {
        onClick = new ClickEvent();
        onDiv = new DivEvent();
        onHover = new HoverEvent();
        load(data) {
            if (isNull(data)) {
                return;
            }
            this.onClick.load(data.onClick);
            const onDiv = data.onDiv;
            if (onDiv !== undefined) {
                this.onDiv = executeOnSingleOrMultiple(onDiv, t => {
                    const tmp = new DivEvent();
                    tmp.load(t);
                    return tmp;
                });
            }
            this.onHover.load(data.onHover);
        }
    }

    var InteractivityDetect;
    (function (InteractivityDetect) {
        InteractivityDetect["canvas"] = "canvas";
        InteractivityDetect["parent"] = "parent";
        InteractivityDetect["window"] = "window";
    })(InteractivityDetect || (InteractivityDetect = {}));

    class Modes {
        #container;
        #pluginManager;
        constructor(pluginManager, container) {
            this.#pluginManager = pluginManager;
            this.#container = container;
        }
        load(data) {
            if (isNull(data)) {
                return;
            }
            if (!this.#container) {
                return;
            }
            const interactors = this.#pluginManager.interactors?.get(this.#container);
            if (!interactors) {
                return;
            }
            for (const interactor of interactors) {
                if (!interactor.loadModeOptions) {
                    continue;
                }
                interactor.loadModeOptions(this, data);
            }
        }
    }

    class Interactivity {
        detectsOn = InteractivityDetect.window;
        events = new Events();
        modes;
        constructor(pluginManager, container) {
            this.modes = new Modes(pluginManager, container);
        }
        load(data) {
            if (isNull(data)) {
                return;
            }
            const detectsOn = data.detectsOn;
            if (detectsOn !== undefined) {
                this.detectsOn = detectsOn;
            }
            this.events.load(data.events);
            this.modes.load(data.modes);
        }
    }

    class InteractivityPlugin {
        id = "interactivity";
        #pluginManager;
        constructor(pluginManager) {
            this.#pluginManager = pluginManager;
        }
        async getPlugin(container) {
            const { InteractivityPluginInstance } = await Promise.resolve().then(function () { return InteractivityPluginInstance$1; });
            return new InteractivityPluginInstance(this.#pluginManager, container);
        }
        loadOptions(container, options, source) {
            if (!this.needsPlugin()) {
                return;
            }
            let interactivityOptions = options.interactivity;
            if (!interactivityOptions?.load) {
                options.interactivity = interactivityOptions = new Interactivity(this.#pluginManager, container);
            }
            interactivityOptions.load(source?.interactivity);
            const interactors = this.#pluginManager.interactors?.get(container);
            if (!interactors) {
                return;
            }
            for (const interactor of interactors) {
                if (interactor.loadOptions) {
                    interactor.loadOptions(options, source);
                }
            }
        }
        loadParticlesOptions(container, options, source) {
            if (source?.interactivity) {
                options.interactivity = deepExtend({}, source.interactivity);
            }
            const interactors = this.#pluginManager.interactors?.get(container);
            if (!interactors) {
                return;
            }
            for (const interactor of interactors) {
                interactor.loadParticlesOptions?.(options, source);
            }
        }
        needsPlugin() {
            return true;
        }
    }

    var InteractorType;
    (function (InteractorType) {
        InteractorType["external"] = "external";
        InteractorType["particles"] = "particles";
    })(InteractorType || (InteractorType = {}));

    class ExternalInteractorBase {
        type = InteractorType.external;
        container;
        constructor(container) {
            this.container = container;
        }
    }

    class ParticlesInteractorBase {
        type = InteractorType.particles;
        container;
        constructor(container) {
            this.container = container;
        }
    }

    const clickEvent = "click", mouseDownEvent = "pointerdown", mouseUpEvent = "pointerup", mouseLeaveEvent = "pointerleave", mouseMoveEvent = "pointermove", touchStartEvent = "touchstart", touchEndEvent = "touchend", touchMoveEvent = "touchmove", touchCancelEvent = "touchcancel";

    function findItemFromSingleOrMultiple(obj, callback) {
        if (isArray(obj)) {
            return obj.find((t, index) => callback(t, index));
        }
        const defaultIndex = 0;
        return callback(obj, defaultIndex) ? obj : undefined;
    }
    function checkSelector(element, selectors) {
        const res = executeOnSingleOrMultiple(selectors, selector => {
            return element.matches(selector);
        });
        return isArray(res) ? res.some(t => t) : res;
    }
    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);
        });
    }

    async function loadInteractivityPlugin(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register(e => {
            const interactivityEngine = e, interactivityPluginManager = interactivityEngine.pluginManager;
            interactivityPluginManager.addPlugin(new InteractivityPlugin(interactivityPluginManager));
            interactivityPluginManager.initializers.interactors ??= new Map();
            interactivityPluginManager.interactors ??= new Map();
            interactivityPluginManager.addInteractor = (name, interactorInitializer) => {
                interactivityPluginManager.initializers.interactors ??= new Map();
                interactivityPluginManager.initializers.interactors.set(name, interactorInitializer);
            };
            interactivityPluginManager.getInteractors = async (container, force = false) => {
                interactivityPluginManager.interactors ??= new Map();
                interactivityPluginManager.initializers.interactors ??= new Map();
                return getItemsFromInitializer(container, interactivityPluginManager.interactors, interactivityPluginManager.initializers.interactors, force);
            };
            interactivityPluginManager.setOnClickHandler = (callback) => {
                const { items } = interactivityEngine;
                if (!items.length) {
                    throw new Error("Click handlers can only be set after calling tsParticles.load()");
                }
                items.forEach(item => {
                    const interactivityContainer = item;
                    interactivityContainer.addClickHandler?.(callback);
                });
            };
        });
    }
    function ensureInteractivityPluginLoaded(e) {
        if (!e.pluginManager.addInteractor) {
            throw new Error("tsParticles Interactivity Plugin is not loaded");
        }
    }

    class AbsorberLife {
        count;
        delay;
        duration;
        wait = false;
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadProperty(this, "count", data.count);
            loadRangeProperty(this, "delay", data.delay);
            loadRangeProperty(this, "duration", data.duration);
            loadProperty(this, "wait", data.wait);
        }
    }

    class AbsorberSizeLimit {
        mass = 0;
        radius = 0;
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadProperty(this, "mass", data.mass);
            loadProperty(this, "radius", data.radius);
        }
    }

    class AbsorberSize extends ValueWithRandom {
        density = 5;
        limit = new AbsorberSizeLimit();
        value = 50;
        load(data) {
            if (isNull(data)) {
                return;
            }
            super.load(data);
            loadProperty(this, "density", data.density);
            if (isNumber(data.limit)) {
                this.limit.radius = data.limit;
            }
            else {
                this.limit.load(data.limit);
            }
        }
    }

    class Absorber {
        color;
        destroy;
        draggable;
        life;
        name;
        opacity;
        orbits;
        position;
        size;
        constructor() {
            this.color = new OptionsColor();
            this.color.value = "#000000";
            this.draggable = false;
            this.opacity = 1;
            this.destroy = true;
            this.orbits = false;
            this.life = new AbsorberLife();
            this.size = new AbsorberSize();
        }
        load(data) {
            if (isNull(data)) {
                return;
            }
            if (data.color !== undefined) {
                this.color = OptionsColor.create(this.color, data.color);
            }
            loadProperty(this, "draggable", data.draggable);
            if (data.life !== undefined) {
                this.life.load(data.life);
            }
            this.name = data.name;
            loadProperty(this, "opacity", data.opacity);
            if (data.position !== undefined) {
                this.position = {};
                if (data.position.x !== undefined) {
                    this.position.x = setRangeValue(data.position.x);
                }
                if (data.position.y !== undefined) {
                    this.position.y = setRangeValue(data.position.y);
                }
            }
            if (data.size !== undefined) {
                this.size.load(data.size);
            }
            loadProperty(this, "destroy", data.destroy);
            loadProperty(this, "orbits", data.orbits);
        }
    }

    const absorbersMode = "absorbers";
    class AbsorbersInteractor extends ExternalInteractorBase {
        handleClickMode;
        maxDistance;
        #dragging = false;
        #draggingAbsorber;
        #instancesManager;
        constructor(container, instancesManager) {
            super(container);
            this.maxDistance = 0;
            this.#instancesManager = instancesManager;
            this.#instancesManager.initContainer(container);
            this.handleClickMode = (mode, interactivityData) => {
                const container = this.container, options = container.actualOptions, absorbers = options.interactivity.modes.absorbers;
                if (!absorbers || mode !== absorbersMode) {
                    return;
                }
                const { clickPosition } = interactivityData.mouse;
                if (clickPosition) {
                    const existingAbsorber = instancesManager
                        .getArray(this.container)
                        .some(t => getDistance(t.position, clickPosition) < t.size);
                    if (existingAbsorber) {
                        return;
                    }
                }
                const absorbersModeOptions = itemFromArray(absorbers) ?? new Absorber();
                void this.#instancesManager.addAbsorber(container, absorbersModeOptions, clickPosition);
            };
        }
        clear() {
        }
        init() {
        }
        interact(interactivityData, delta) {
            for (const particle of this.container.particles.filter(p => this.isEnabled(interactivityData, p))) {
                for (const absorber of this.#instancesManager.getArray(this.container)) {
                    if (absorber.options.draggable) {
                        const mouse = interactivityData.mouse;
                        if (mouse.clicking && mouse.downPosition) {
                            const mouseDist = getDistance(absorber.position, mouse.downPosition);
                            if (mouseDist <= absorber.size) {
                                this.#dragging = true;
                                this.#draggingAbsorber = absorber;
                            }
                        }
                        else {
                            this.#dragging = false;
                            this.#draggingAbsorber = undefined;
                        }
                        if (this.#dragging && this.#draggingAbsorber == absorber && mouse.position) {
                            absorber.position.x = mouse.position.x;
                            absorber.position.y = mouse.position.y;
                        }
                    }
                    absorber.attract(particle, delta);
                    if (particle.destroyed) {
                        break;
                    }
                }
            }
        }
        isEnabled(interactivityData, particle) {
            const container = this.container, options = container.actualOptions, mouse = interactivityData.mouse, events = (particle?.interactivity ?? options.interactivity).events;
            if (!mouse.clickPosition || !events.onClick.enable) {
                return false;
            }
            return isInArray(absorbersMode, events.onClick.mode);
        }
        loadModeOptions(options, ...sources) {
            options.absorbers ??= [];
            for (const source of sources) {
                if (!source) {
                    continue;
                }
                if (isArray(source.absorbers)) {
                    for (const absorber of source.absorbers) {
                        const tmp = new Absorber();
                        tmp.load(absorber);
                        options.absorbers.push(tmp);
                    }
                }
                else {
                    const tmp = new Absorber();
                    tmp.load(source.absorbers);
                    options.absorbers.push(tmp);
                }
            }
        }
        reset() {
        }
    }

    const instancesManagers$1 = new WeakMap();
    function getAbsorbersInstancesManager(e) {
        const pluginManager = e.pluginManager;
        let manager = instancesManagers$1.get(pluginManager);
        if (!manager) {
            manager = Promise.resolve().then(function () { return AbsorbersInstancesManager$1; })
                .then(({ AbsorbersInstancesManager }) => new AbsorbersInstancesManager(pluginManager))
                .catch((error) => {
                instancesManagers$1.delete(pluginManager);
                throw error;
            });
            instancesManagers$1.set(pluginManager, manager);
        }
        return manager;
    }

    async function loadAbsorbersInteraction(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register(async (e) => {
            const pluginManager = e.pluginManager, instancesManager = await getAbsorbersInstancesManager(e);
            ensureInteractivityPluginLoaded(e);
            pluginManager.addInteractor?.("externalAbsorbers", container => {
                return Promise.resolve(new AbsorbersInteractor(container, instancesManager));
            });
        });
    }

    class AbsorbersPlugin {
        id = "absorbers";
        #instancesManager;
        constructor(instancesManager) {
            this.#instancesManager = instancesManager;
        }
        async getPlugin(container) {
            const { AbsorbersPluginInstance } = await Promise.resolve().then(function () { return AbsorbersPluginInstance$1; });
            return new AbsorbersPluginInstance(container, this.#instancesManager);
        }
        loadOptions(_container, options, source) {
            if (!this.needsPlugin(options) && !this.needsPlugin(source)) {
                return;
            }
            if (source?.absorbers) {
                options.absorbers = executeOnSingleOrMultiple(source.absorbers, absorber => {
                    const tmp = new Absorber();
                    tmp.load(absorber);
                    return tmp;
                });
            }
        }
        needsPlugin(options) {
            if (!options) {
                return false;
            }
            const absorbers = options.absorbers;
            if (isArray(absorbers)) {
                return !!absorbers.length;
            }
            else if (absorbers) {
                return true;
            }
            return false;
        }
    }

    async function loadAbsorbersPluginSimple(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register(async (e) => {
            const pluginManager = e.pluginManager, instancesManager = await getAbsorbersInstancesManager(e);
            pluginManager.addPlugin(new AbsorbersPlugin(instancesManager));
        });
    }

    async function loadAbsorbersPlugin(engine) {
        await loadAbsorbersPluginSimple(engine);
        await loadAbsorbersInteraction(engine);
    }

    class DestroyBounds {
        bottom;
        left;
        right;
        top;
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadRangeProperty(this, "bottom", data.bottom);
            loadRangeProperty(this, "left", data.left);
            loadRangeProperty(this, "right", data.right);
            loadRangeProperty(this, "top", data.top);
        }
    }

    var DestroyMode;
    (function (DestroyMode) {
        DestroyMode["explode"] = "explode";
        DestroyMode["none"] = "none";
        DestroyMode["split"] = "split";
    })(DestroyMode || (DestroyMode = {}));

    class Explode {
        maxSizeFactor = 3;
        speed = 2;
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadProperty(this, "maxSizeFactor", data.maxSizeFactor);
            loadProperty(this, "speed", data.speed);
        }
    }

    class SplitFactor extends ValueWithRandom {
        value = 3;
    }

    class SplitRate extends ValueWithRandom {
        value = { min: 4, max: 9 };
    }

    class Split {
        count = 1;
        factor = new SplitFactor();
        fillColor;
        fillColorOffset;
        particles;
        rate = new SplitRate();
        sizeOffset = true;
        strokeColor;
        strokeColorOffset;
        load(data) {
            if (isNull(data)) {
                return;
            }
            if (data.fillColor !== undefined) {
                this.fillColor = OptionsColor.create(this.fillColor, data.fillColor);
            }
            if (data.strokeColor !== undefined) {
                this.strokeColor = OptionsColor.create(this.strokeColor, data.strokeColor);
            }
            loadProperty(this, "count", data.count);
            this.factor.load(data.factor);
            this.rate.load(data.rate);
            this.particles = executeOnSingleOrMultiple(data.particles, particles => {
                return deepExtend({}, particles);
            });
            loadProperty(this, "sizeOffset", data.sizeOffset);
            if (data.fillColorOffset) {
                this.fillColorOffset = this.fillColorOffset ?? {};
                if (data.fillColorOffset.h !== undefined) {
                    this.fillColorOffset.h = data.fillColorOffset.h;
                }
                if (data.fillColorOffset.s !== undefined) {
                    this.fillColorOffset.s = data.fillColorOffset.s;
                }
                if (data.fillColorOffset.l !== undefined) {
                    this.fillColorOffset.l = data.fillColorOffset.l;
                }
            }
            if (data.strokeColorOffset) {
                this.strokeColorOffset = this.strokeColorOffset ?? {};
                if (data.strokeColorOffset.h !== undefined) {
                    this.strokeColorOffset.h = data.strokeColorOffset.h;
                }
                if (data.strokeColorOffset.s !== undefined) {
                    this.strokeColorOffset.s = data.strokeColorOffset.s;
                }
                if (data.strokeColorOffset.l !== undefined) {
                    this.strokeColorOffset.l = data.strokeColorOffset.l;
                }
            }
        }
    }

    let Destroy$1 = class Destroy {
        bounds = new DestroyBounds();
        explode = new Explode();
        mode = DestroyMode.none;
        split = new Split();
        load(data) {
            if (isNull(data)) {
                return;
            }
            if (data.mode) {
                this.mode = data.mode;
            }
            if (data.bounds) {
                this.bounds.load(data.bounds);
            }
            this.explode.load(data.explode);
            this.split.load(data.split);
        }
    };

    const defaultOffset = 0, minDestroySize = 0.5, defaultSplitCount = 0, increment = 1, unbreakableTime = 500, minSplitCount = 0, minHue = 0, hueRange = 360, minSaturation = 0, maxSaturation = 100, minLightness = 0, maxLightness = 100;
    function createParentColor(parentColor) {
        return AnimatableColor.create(undefined, {
            value: {
                hsl: parentColor,
            },
        });
    }
    function createOffsetColor(parentColor, offset) {
        const offsetH = getRangeValue(offset.h ?? defaultOffset), offsetS = getRangeValue(offset.s ?? defaultOffset), offsetL = getRangeValue(offset.l ?? defaultOffset), h = (parentColor.h + offsetH) % hueRange, s = Math.max(minSaturation, Math.min(maxSaturation, parentColor.s + offsetS)), l = Math.max(minLightness, Math.min(maxLightness, parentColor.l + offsetL));
        return AnimatableColor.create(undefined, {
            value: {
                hsl: {
                    h: h < minHue ? h + hueRange : h,
                    s,
                    l,
                },
            },
        });
    }
    function resolveSplitColor(offset, splitColor, splitParticlesColor, parentColor) {
        if (offset && parentColor) {
            return createOffsetColor(parentColor, offset);
        }
        if (splitColor) {
            return AnimatableColor.create(undefined, splitColor);
        }
        if (splitParticlesColor) {
            return AnimatableColor.create(undefined, splitParticlesColor);
        }
        return parentColor ? createParentColor(parentColor) : undefined;
    }
    function addSplitParticle(pluginManager, container, parent, splitParticlesOptions) {
        const destroyOptions = parent.options.destroy;
        if (!destroyOptions) {
            return;
        }
        const splitOptions = destroyOptions.split, splitParticleOptions = loadParticlesOptions(pluginManager, container, parent.options), splitFillColor = itemFromSingleOrMultiple(splitOptions.fillColor), splitStrokeColor = itemFromSingleOrMultiple(splitOptions.strokeColor), parentFillColor = parent.getFillColor(), parentStrokeColor = parent.getStrokeColor();
        splitParticleOptions.move.load({
            center: {
                x: parent.position.x,
                y: parent.position.y,
                mode: exports.PixelMode.precise,
            },
        });
        const factor = identity$2 / getRangeValue(splitOptions.factor.value), sizeOptions = splitParticleOptions["size"];
        if (sizeOptions) {
            if (isNumber(sizeOptions.value)) {
                sizeOptions.value *= factor;
            }
            else {
                sizeOptions.value.min *= factor;
                sizeOptions.value.max *= factor;
            }
        }
        splitParticleOptions.load(splitParticlesOptions);
        const splitParticlePaintOptions = itemFromSingleOrMultiple(splitParticleOptions.paint), splitParticleFillOptions = splitParticlePaintOptions?.fill, splitParticleStrokeOptions = splitParticlePaintOptions?.stroke, fillColor = resolveSplitColor(splitOptions.fillColorOffset, splitFillColor, splitParticleFillOptions?.color, parentFillColor), strokeColor = resolveSplitColor(splitOptions.strokeColorOffset, splitStrokeColor, splitParticleStrokeOptions?.color, parentStrokeColor);
        if (fillColor && splitParticleFillOptions) {
            splitParticleFillOptions.color = fillColor;
        }
        if (strokeColor && splitParticleStrokeOptions) {
            splitParticleStrokeOptions.color = strokeColor;
        }
        const offset = splitOptions.sizeOffset ? setRangeValue(-parent.size.value, parent.size.value) : defaultOffset, position = {
            x: parent.position.x + randomInRangeValue(offset),
            y: parent.position.y + randomInRangeValue(offset),
        };
        return container.particles.addParticle(position, splitParticleOptions, parent.group, (particle) => {
            if (particle.size.value < minDestroySize) {
                return false;
            }
            particle.velocity.length = randomInRangeValue(setRangeValue(parent.velocity.length, particle.velocity.length));
            particle.splitCount = (parent.splitCount ?? defaultSplitCount) + increment;
            particle.unbreakable = true;
            particle.unbreakableUntil = performance.now() + unbreakableTime;
            return true;
        });
    }
    function split(pluginManager, container, particle) {
        const destroyOptions = particle.options.destroy;
        if (!destroyOptions) {
            return;
        }
        const splitOptions = destroyOptions.split;
        if (splitOptions.count >= minSplitCount) {
            if (particle.splitCount === undefined || particle.splitCount > splitOptions.count) {
                return;
            }
            particle.splitCount++;
        }
        const rate = getRangeValue(splitOptions.rate.value), particlesSplitOptions = itemFromSingleOrMultiple(splitOptions.particles);
        for (let i = 0; i < rate; i++) {
            addSplitParticle(pluginManager, container, particle, particlesSplitOptions);
        }
    }

    const defaultDeltaFactor$1 = 1, fpsFactor = 60, minExplodeSpeed = 0.01, maxExplodeProgress = 1;
    class DestroyUpdater {
        #container;
        #pluginManager;
        constructor(pluginManager, container) {
            this.#container = container;
            this.#pluginManager = pluginManager;
        }
        init(particle) {
            const container = this.#container, particlesOptions = particle.options, destroyOptions = particlesOptions.destroy;
            if (!destroyOptions) {
                return;
            }
            particle.exploding = undefined;
            particle.splitCount = 0;
            const destroyBoundsOptions = destroyOptions.bounds;
            particle.destroyBounds ??= {};
            const { bottom, left, right, top } = destroyBoundsOptions, { destroyBounds } = particle, canvasSize = container.canvas.size;
            if (bottom) {
                destroyBounds.bottom = (getRangeValue(bottom) * canvasSize.height) / percentDenominator;
            }
            if (left) {
                destroyBounds.left = (getRangeValue(left) * canvasSize.width) / percentDenominator;
            }
            if (right) {
                destroyBounds.right = (getRangeValue(right) * canvasSize.width) / percentDenominator;
            }
            if (top) {
                destroyBounds.top = (getRangeValue(top) * canvasSize.height) / percentDenominator;
            }
        }
        isEnabled(particle) {
            const destroyParticle = particle;
            return !destroyParticle.destroyed || !!destroyParticle.exploding;
        }
        loadOptions(options, ...sources) {
            loadOptionProperty(options, "destroy", Destroy$1, ...sources);
        }
        particleDestroyed(particle, override) {
            if (override) {
                return;
            }
            const destroyOptions = particle.options.destroy;
            switch (destroyOptions?.mode) {
                case DestroyMode.split:
                    split(this.#pluginManager, this.#container, particle);
                    break;
                case DestroyMode.explode: {
                    if (particle.exploding) {
                        particle.destroyed = false;
                        break;
                    }
                    const { explode } = destroyOptions, initialSize = particle.size.value, maxSize = initialSize * explode.maxSizeFactor, opacity = particle.getOpacity();
                    particle.exploding = {
                        initialFillOpacity: opacity.fillOpacity,
                        initialSize,
                        initialStrokeOpacity: opacity.strokeOpacity,
                        maxSize,
                        progress: 0,
                        speed: Math.max(explode.speed, minExplodeSpeed),
                    };
                    particle.fillOpacity = opacity.fillOpacity;
                    particle.strokeOpacity = opacity.strokeOpacity;
                    particle.destroyed = false;
                    break;
                }
            }
        }
        update(particle, delta) {
            if (particle.exploding) {
                const explosionState = particle.exploding, deltaFactor = delta.factor || defaultDeltaFactor$1;
                explosionState.progress = Math.min(maxExplodeProgress, explosionState.progress + (explosionState.speed * deltaFactor) / fpsFactor);
                const progress = explosionState.progress;
                particle.size.value =
                    explosionState.initialSize + (explosionState.maxSize - explosionState.initialSize) * progress;
                particle.fillOpacity = explosionState.initialFillOpacity * (maxExplodeProgress - progress);
                particle.strokeOpacity = explosionState.initialStrokeOpacity * (maxExplodeProgress - progress);
                if (progress >= maxExplodeProgress) {
                    particle.exploding = undefined;
                    particle.destroy(true);
                }
                return;
            }
            if (particle.unbreakableUntil !== undefined && performance.now() >= particle.unbreakableUntil) {
                particle.unbreakable = false;
                particle.unbreakableUntil = undefined;
            }
            const position = particle.getPosition(), bounds = particle.destroyBounds;
            if (!bounds) {
                return;
            }
            if ((bounds.bottom !== undefined && position.y >= bounds.bottom) ||
                (bounds.left !== undefined && position.x <= bounds.left) ||
                (bounds.right !== undefined && position.x >= bounds.right) ||
                (bounds.top !== undefined && position.y <= bounds.top)) {
                particle.destroy();
            }
        }
    }

    async function loadDestroyUpdater(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register(e => {
            e.pluginManager.addParticleUpdater("destroy", container => {
                return Promise.resolve(new DestroyUpdater(e.pluginManager, container));
            });
        });
    }

    class EmitterLife {
        count;
        delay;
        duration;
        wait = false;
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadProperty(this, "count", data.count);
            loadRangeProperty(this, "delay", data.delay);
            loadRangeProperty(this, "duration", data.duration);
            loadProperty(this, "wait", data.wait);
        }
    }

    class EmitterRate {
        delay = 0.1;
        quantity = 1;
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadRangeProperty(this, "quantity", data.quantity);
            loadRangeProperty(this, "delay", data.delay);
        }
    }

    class EmitterShapeReplace {
        color = false;
        opacity = false;
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadProperty(this, "color", data.color);
            loadProperty(this, "opacity", data.opacity);
        }
    }

    class EmitterShape {
        options = {};
        replace = new EmitterShapeReplace();
        type = "square";
        load(data) {
            if (isNull(data)) {
                return;
            }
            if (data.options !== undefined) {
                this.options = deepExtend({}, data.options ?? {});
            }
            this.replace.load(data.replace);
            loadProperty(this, "type", data.type);
        }
    }

    class EmitterSize {
        height = 0;
        mode = exports.PixelMode.percent;
        width = 0;
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadProperty(this, "mode", data.mode);
            loadProperty(this, "height", data.height);
            loadProperty(this, "width", data.width);
        }
    }

    class EmitterSpawn {
        fill;
        stroke;
        load(data) {
            if (isNull(data)) {
                return;
            }
            if (data.fill) {
                this.fill ??= new Fill();
                this.fill.load(data.fill);
            }
            if (data.stroke) {
                this.stroke ??= new Stroke();
                this.stroke.load(data.stroke);
            }
        }
    }

    class Emitter {
        autoPlay = true;
        direction;
        domId;
        fill = true;
        life = new EmitterLife();
        name;
        particles;
        position;
        rate = new EmitterRate();
        shape = new EmitterShape();
        size;
        spawn = new EmitterSpawn();
        spawnFillColor;
        spawnStrokeColor;
        startCount = 0;
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadProperty(this, "autoPlay", data.autoPlay);
            if (data.size !== undefined) {
                this.size ??= new EmitterSize();
                this.size.load(data.size);
            }
            loadProperty(this, "direction", data.direction);
            loadProperty(this, "domId", data.domId);
            loadProperty(this, "fill", data.fill);
            this.life.load(data.life);
            loadProperty(this, "name", data.name);
            this.particles = executeOnSingleOrMultiple(data.particles, particles => {
                return deepExtend({}, particles);
            });
            this.rate.load(data.rate);
            this.shape.load(data.shape);
            this.spawn.load(data.spawn);
            if (data.position !== undefined) {
                this.position = {};
                if (data.position.x !== undefined) {
                    this.position.x = setRangeValue(data.position.x);
                }
                if (data.position.y !== undefined) {
                    this.position.y = setRangeValue(data.position.y);
                }
            }
            if (data.spawnFillColor !== undefined) {
                this.spawnFillColor ??= new AnimatableColor();
                this.spawnFillColor.load(data.spawnFillColor);
            }
            if (data.spawnStrokeColor !== undefined) {
                this.spawnStrokeColor ??= new AnimatableColor();
                this.spawnStrokeColor.load(data.spawnStrokeColor);
            }
            loadProperty(this, "startCount", data.startCount);
        }
    }

    const defaultRandomOptions = {
        count: 1,
        enable: true,
    };

    const emittersMode = "emitters";
    class EmittersInteractor extends ExternalInteractorBase {
        handleClickMode;
        maxDistance;
        #instancesManager;
        constructor(instancesManager, container) {
            super(container);
            this.#instancesManager = instancesManager;
            this.maxDistance = 0;
            this.handleClickMode = (mode, interactivityData) => {
                const container = this.container, options = container.actualOptions, modeEmitters = options.interactivity.modes.emitters;
                if (!modeEmitters || mode !== emittersMode) {
                    return;
                }
                let emittersModeOptions;
                if (isArray(modeEmitters.value)) {
                    const minLength = 0, modeEmittersCount = modeEmitters.value.length;
                    if (modeEmittersCount > minLength && modeEmitters.random.enable) {
                        emittersModeOptions = [];
                        const usedIndexes = new Set();
                        for (let i = 0; i < modeEmitters.random.count; i++) {
                            const idx = Math.floor(getRandom() * modeEmitters.value.length);
                            if (usedIndexes.has(idx) && usedIndexes.size < modeEmittersCount) {
                                i--;
                                continue;
                            }
                            usedIndexes.add(idx);
                            const selectedOptions = itemFromArray(modeEmitters.value, idx);
                            if (!selectedOptions) {
                                continue;
                            }
                            emittersModeOptions.push(selectedOptions);
                        }
                    }
                    else {
                        emittersModeOptions = modeEmitters.value;
                    }
                }
                else {
                    emittersModeOptions = modeEmitters.value;
                }
                const emittersOptions = emittersModeOptions, ePosition = interactivityData.mouse.clickPosition;
                void executeOnSingleOrMultiple(emittersOptions, async (emitter) => {
                    await this.#instancesManager.addEmitter(this.container, emitter, ePosition);
                });
            };
        }
        clear() {
        }
        init() {
        }
        interact(_interactivityData, delta) {
            for (const emitter of this.#instancesManager.getArray(this.container)) {
                emitter.update(delta);
            }
        }
        isEnabled(interactivityData, particle) {
            const container = this.container, options = container.actualOptions, mouse = interactivityData.mouse, events = (particle?.interactivity ?? options.interactivity).events;
            if (!mouse.clickPosition || !events.onClick.enable) {
                return false;
            }
            return isInArray(emittersMode, events.onClick.mode);
        }
        loadModeOptions(options, ...sources) {
            options.emitters = {
                random: defaultRandomOptions,
                value: [],
            };
            for (const source of sources) {
                if (!source?.emitters) {
                    continue;
                }
                if (isArray(source.emitters)) {
                    for (const emitter of source.emitters) {
                        const tmp = new Emitter();
                        tmp.load(emitter);
                        options.emitters.value.push(tmp);
                    }
                }
                else if ("value" in source.emitters) {
                    const emitterModeOptions = source.emitters;
                    options.emitters.random.enable = emitterModeOptions.random?.enable ?? options.emitters.random.enable;
                    options.emitters.random.count = emitterModeOptions.random?.count ?? options.emitters.random.count;
                    if (isArray(emitterModeOptions.value)) {
                        for (const emitter of emitterModeOptions.value) {
                            const tmp = new Emitter();
                            tmp.load(emitter);
                            options.emitters.value.push(tmp);
                        }
                    }
                    else {
                        const tmp = new Emitter();
                        tmp.load(emitterModeOptions.value);
                        options.emitters.value.push(tmp);
                    }
                }
                else {
                    const tmp = new Emitter();
                    tmp.load(source.emitters);
                    options.emitters.value.push(tmp);
                }
            }
        }
        removeEmitter(emitter) {
            const index = this.#instancesManager.getArray(this.container).indexOf(emitter), minIndex = 0, deleteCount = 1;
            if (index >= minIndex) {
                this.#instancesManager.getArray(this.container).splice(index, deleteCount);
            }
        }
        reset() {
        }
    }

    async function addEmittersShapesManager(e) {
        const { ShapeManager } = await Promise.resolve().then(function () { return ShapeManager$1; }), pluginManager = e.pluginManager;
        pluginManager.emitterShapeManager ??= new ShapeManager();
        pluginManager.addEmitterShapeGenerator ??= (name, generator) => {
            pluginManager.emitterShapeManager?.addShapeGenerator(name, generator);
        };
    }

    const instancesManagers = new WeakMap();
    function getEmittersInstancesManager(e) {
        const pluginManager = e.pluginManager;
        let manager = instancesManagers.get(pluginManager);
        if (!manager) {
            manager = Promise.resolve().then(function () { return EmittersInstancesManager$1; })
                .then(({ EmittersInstancesManager }) => new EmittersInstancesManager(pluginManager))
                .catch((error) => {
                instancesManagers.delete(pluginManager);
                throw error;
            });
            instancesManagers.set(pluginManager, manager);
        }
        return manager;
    }

    class EmitterShapeBase {
        fill;
        options;
        position;
        size;
        constructor(position, size, fill, options) {
            this.position = position;
            this.size = size;
            this.fill = fill;
            this.options = options;
        }
        resize(position, size) {
            this.position = position;
            this.size = size;
        }
    }

    var EmitterClickMode;
    (function (EmitterClickMode) {
        EmitterClickMode["emitter"] = "emitter";
    })(EmitterClickMode || (EmitterClickMode = {}));

    async function loadEmittersInteraction(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register(async (e) => {
            const instancesManager = await getEmittersInstancesManager(e);
            ensureInteractivityPluginLoaded(e);
            await addEmittersShapesManager(e);
            e.pluginManager.addInteractor?.("externalEmitters", container => {
                return Promise.resolve(new EmittersInteractor(instancesManager, container));
            });
        });
    }

    class EmittersPlugin {
        id = "emitters";
        #instancesManager;
        constructor(instancesManager) {
            this.#instancesManager = instancesManager;
        }
        async getPlugin(container) {
            const { EmittersPluginInstance } = await Promise.resolve().then(function () { return EmittersPluginInstance$1; });
            return new EmittersPluginInstance(this.#instancesManager, container);
        }
        loadOptions(_container, options, source) {
            if (!this.needsPlugin(options) && !this.needsPlugin(source)) {
                return;
            }
            if (source?.emitters) {
                options.emitters = executeOnSingleOrMultiple(source.emitters, emitter => {
                    const tmp = new Emitter();
                    tmp.load(emitter);
                    return tmp;
                });
            }
        }
        needsPlugin(options) {
            if (!options) {
                return false;
            }
            const emitters = options.emitters;
            return (isArray(emitters) && !!emitters.length) || emitters !== undefined;
        }
    }

    async function loadEmittersPluginSimple(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register(async (e) => {
            const instancesManager = await getEmittersInstancesManager(e);
            await addEmittersShapesManager(e);
            e.pluginManager.addPlugin(new EmittersPlugin(instancesManager));
        });
    }

    function ensureEmittersPluginLoaded(e) {
        if (!e.pluginManager.addEmitterShapeGenerator) {
            throw new Error("tsParticles Emitters Plugin is not loaded");
        }
    }

    async function loadEmittersPlugin(engine) {
        await loadEmittersPluginSimple(engine);
        await loadEmittersInteraction(engine);
    }

    class EmittersCircleShape extends EmitterShapeBase {
        constructor(position, size, fill, options) {
            super(position, size, fill, options);
        }
        async init() {
        }
        randomPosition() {
            const size = this.size, fill = this.fill, position = this.position, generateTheta = (x, y) => {
                const u = getRandom() * quarter, theta = Math.atan((y / x) * Math.tan(doublePI * u)), v = getRandom();
                if (v < quarter) {
                    return theta;
                }
                else if (v < double * quarter) {
                    return Math.PI - theta;
                }
                else if (v < double * quarter + quarter) {
                    return Math.PI + theta;
                }
                else {
                    return -theta;
                }
            }, radius = (x, y, theta) => (x * y) / Math.sqrt((y * Math.cos(theta)) ** squareExp + (x * Math.sin(theta)) ** squareExp), [a, b] = [size.width * half, size.height * half], randomTheta = generateTheta(a, b), maxRadius = radius(a, b, randomTheta), randomRadius = fill ? maxRadius * Math.sqrt(getRandom()) : maxRadius;
            return {
                position: {
                    x: position.x + randomRadius * Math.cos(randomTheta),
                    y: position.y + randomRadius * Math.sin(randomTheta),
                },
            };
        }
    }

    class EmittersCircleShapeGenerator {
        generate(_container, position, size, fill, options) {
            return new EmittersCircleShape(position, size, fill, options);
        }
    }

    async function loadEmittersShapeCircle(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register((e) => {
            ensureEmittersPluginLoaded(e);
            e.pluginManager.addEmitterShapeGenerator?.("circle", new EmittersCircleShapeGenerator());
        });
    }

    const sides$5 = 4;
    var Sides;
    (function (Sides) {
        Sides[Sides["TopLeft"] = 0] = "TopLeft";
        Sides[Sides["TopRight"] = 1] = "TopRight";
        Sides[Sides["BottomRight"] = 2] = "BottomRight";
        Sides[Sides["BottomLeft"] = 3] = "BottomLeft";
    })(Sides || (Sides = {}));
    function randomSquareCoordinate(position, offset) {
        return position + offset * (getRandom() - half);
    }
    function getRandomSize(sides) {
        return Math.floor(getRandom() * sides);
    }
    class EmittersSquareShape extends EmitterShapeBase {
        constructor(position, size, fill, options) {
            super(position, size, fill, options);
        }
        async init() {
        }
        randomPosition() {
            const fill = this.fill, position = this.position, size = this.size;
            if (fill) {
                return {
                    position: {
                        x: randomSquareCoordinate(position.x, size.width),
                        y: randomSquareCoordinate(position.y, size.height),
                    },
                };
            }
            else {
                const halfW = size.width * half, halfH = size.height * half, side = getRandomSize(sides$5), v = (getRandom() - half) * double;
                switch (side) {
                    case Sides.TopLeft:
                        return {
                            position: {
                                x: position.x + v * halfW,
                                y: position.y - halfH,
                            },
                        };
                    case Sides.TopRight:
                        return {
                            position: {
                                x: position.x - halfW,
                                y: position.y + v * halfH,
                            },
                        };
                    case Sides.BottomRight:
                        return {
                            position: {
                                x: position.x + v * halfW,
                                y: position.y + halfH,
                            },
                        };
                    case Sides.BottomLeft:
                    default:
                        return {
                            position: {
                                x: position.x + halfW,
                                y: position.y + v * halfH,
                            },
                        };
                }
            }
        }
    }

    class EmittersSquareShapeGenerator {
        generate(_container, position, size, fill, options) {
            return new EmittersSquareShape(position, size, fill, options);
        }
    }

    async function loadEmittersShapeSquare(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register((e) => {
            ensureEmittersPluginLoaded(e);
            e.pluginManager.addEmitterShapeGenerator?.("square", new EmittersSquareShapeGenerator());
        });
    }

    const defaultMomentumFactor$1 = 0.03, defaultPreserveMomentum = false;
    class Drag {
        momentumFactor = defaultMomentumFactor$1;
        preserveMomentum = defaultPreserveMomentum;
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadProperty(this, "momentumFactor", data.momentumFactor);
            loadProperty(this, "preserveMomentum", data.preserveMomentum);
        }
    }

    const clickReleaseDelayMs = 50, defaultMomentumFactor = 0.03, dragMode = "drag", firstSampleIndex = 0, lastSampleOffset = 1, maxMomentumSamples = 5, minSamplesForMomentum = 2, momentumToVelocityFactor = millisecondsToSeconds / defaultFps, zeroValue = 0;
    class Dragger extends ExternalInteractorBase {
        maxDistance = 0;
        #dragStartClickTime;
        #dragStartClickingFalseTime;
        #draggedParticle;
        #grabOffset;
        #lastMousePosition;
        #momentumSamples = [];
        #mouseDownHandled = false;
        #savedVelocity;
        constructor(container) {
            super(container);
        }
        clear(_particle, _delta) {
        }
        init() {
        }
        interact(interactivityData, _delta) {
            const mouse = interactivityData.mouse, mousePos = mouse.position;
            if (mousePos) {
                this.#lastMousePosition = mousePos;
            }
            if (this.#draggedParticle) {
                const now = performance.now();
                if (!mouse.clicking) {
                    this.#dragStartClickingFalseTime ??= now;
                }
                else {
                    this.#dragStartClickingFalseTime = undefined;
                }
                const hasStableClickEndWithoutClickTime = this.#dragStartClickTime === undefined &&
                    this.#dragStartClickingFalseTime !== undefined &&
                    now - this.#dragStartClickingFalseTime >= clickReleaseDelayMs;
                if (!mouse.inside || this.#hasClickEnded(mouse) || hasStableClickEndWithoutClickTime) {
                    this.#releaseDragged();
                    this.#mouseDownHandled = false;
                    return;
                }
                const pointerPos = mousePos ?? this.#lastMousePosition;
                if (!pointerPos) {
                    return;
                }
                this.#momentumSamples.push({ x: pointerPos.x, y: pointerPos.y, t: now });
                if (this.#momentumSamples.length > maxMomentumSamples) {
                    this.#momentumSamples.shift();
                }
                const targetX = pointerPos.x + (this.#grabOffset?.x ?? zeroValue), targetY = pointerPos.y + (this.#grabOffset?.y ?? zeroValue);
                this.#draggedParticle.position.x = targetX - this.#draggedParticle.offset.x;
                this.#draggedParticle.position.y = targetY - this.#draggedParticle.offset.y;
                this.#draggedParticle.velocity.x = zeroValue;
                this.#draggedParticle.velocity.y = zeroValue;
                this.#draggedParticle.initialPosition.x = this.#draggedParticle.position.x;
                this.#draggedParticle.initialPosition.y = this.#draggedParticle.position.y;
                this.#draggedParticle.misplaced = false;
                return;
            }
            if (!mouse.clicking) {
                this.#releaseDragged();
                this.#mouseDownHandled = false;
                return;
            }
            if (this.#mouseDownHandled) {
                return;
            }
            this.#mouseDownHandled = true;
            const downPos = mouse.downPosition ?? mousePos ?? this.#lastMousePosition, closest = this.#findParticleUnderCursor(interactivityData, downPos);
            if (!closest || !mousePos) {
                if (!closest) {
                    this.#mouseDownHandled = false;
                }
                return;
            }
            const renderedPos = closest.getPosition();
            this.#draggedParticle = closest;
            this.#dragStartClickTime = mouse.clickTime;
            this.#grabOffset = {
                x: renderedPos.x - mousePos.x,
                y: renderedPos.y - mousePos.y,
            };
            this.#savedVelocity = { x: closest.velocity.x, y: closest.velocity.y };
            this.#dragStartClickingFalseTime = undefined;
            this.#momentumSamples = [{ x: mousePos.x, y: mousePos.y, t: performance.now() }];
            closest.velocity.x = zeroValue;
            closest.velocity.y = zeroValue;
            closest.position.x = renderedPos.x - closest.offset.x;
            closest.position.y = renderedPos.y - closest.offset.y;
            closest.initialPosition.x = closest.position.x;
            closest.initialPosition.y = closest.position.y;
            closest.misplaced = false;
        }
        isEnabled(interactivityData, particle) {
            const container = this.container, mouse = interactivityData.mouse, events = (particle?.interactivity ?? container.actualOptions.interactivity)?.events;
            if (this.#draggedParticle || this.#mouseDownHandled) {
                return true;
            }
            return !!events?.onClick.enable && mouse.clicking && !!mouse.position && isInArray(dragMode, events.onClick.mode);
        }
        loadModeOptions(options, ...sources) {
            loadOptionProperty(options, "drag", Drag, ...sources);
        }
        reset(_interactivityData, _particle) {
        }
        #findParticleUnderCursor(interactivityData, mousePos) {
            if (!mousePos) {
                return;
            }
            const candidates = this.container.particles.filter(p => this.isEnabled(interactivityData, p));
            let closest, closestDist = Infinity;
            for (const candidate of candidates) {
                const dist = getDistance(candidate.getPosition(), mousePos), radius = candidate.getRadius();
                if (!Number.isFinite(dist) || !Number.isFinite(radius) || dist > radius || dist >= closestDist) {
                    continue;
                }
                closest = candidate;
                closestDist = dist;
            }
            return closest;
        }
        #hasClickEnded(mouse) {
            return (this.#dragStartClickTime !== undefined &&
                mouse.clickTime !== undefined &&
                mouse.clickTime !== this.#dragStartClickTime);
        }
        #releaseDragged() {
            if (this.#draggedParticle) {
                const dragOptions = this.container.actualOptions.interactivity?.modes.drag, preserveMomentum = dragOptions?.preserveMomentum ?? false;
                if (preserveMomentum && this.#momentumSamples.length >= minSamplesForMomentum) {
                    const first = this.#momentumSamples[firstSampleIndex], last = this.#momentumSamples[this.#momentumSamples.length - lastSampleOffset];
                    if (first && last) {
                        const dt = last.t - first.t;
                        if (dt > zeroValue) {
                            const factor = dragOptions?.momentumFactor ?? defaultMomentumFactor;
                            this.#draggedParticle.velocity.x = ((last.x - first.x) / dt) * momentumToVelocityFactor * factor;
                            this.#draggedParticle.velocity.y = ((last.y - first.y) / dt) * momentumToVelocityFactor * factor;
                        }
                        else if (this.#savedVelocity) {
                            this.#draggedParticle.velocity.x = this.#savedVelocity.x;
                            this.#draggedParticle.velocity.y = this.#savedVelocity.y;
                        }
                    }
                    else if (this.#savedVelocity) {
                        this.#draggedParticle.velocity.x = this.#savedVelocity.x;
                        this.#draggedParticle.velocity.y = this.#savedVelocity.y;
                    }
                }
                else if (this.#savedVelocity) {
                    this.#draggedParticle.velocity.x = this.#savedVelocity.x;
                    this.#draggedParticle.velocity.y = this.#savedVelocity.y;
                }
            }
            this.#draggedParticle = undefined;
            this.#dragStartClickTime = undefined;
            this.#dragStartClickingFalseTime = undefined;
            this.#grabOffset = undefined;
            this.#lastMousePosition = undefined;
            this.#momentumSamples = [];
            this.#savedVelocity = undefined;
        }
    }

    async function loadExternalDragInteraction(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register((e) => {
            ensureInteractivityPluginLoaded(e);
            e.pluginManager.addInteractor?.("externalDrag", container => {
                return Promise.resolve(new Dragger(container));
            });
        });
    }

    class TrailColorWeight {
        x = 0;
        y = 0;
        load(data) {
            if (!data) {
                return;
            }
            loadProperty(this, "x", data.x);
            loadProperty(this, "y", data.y);
        }
    }

    class TrailColorComponent {
        value;
        weights = new TrailColorWeight();
        load(data) {
            if (!data) {
                return;
            }
            if (data.weights) {
                this.weights ??= new TrailColorWeight();
                this.weights.load(data.weights);
            }
            if (!isNull(data.value)) {
                this.value = setRangeValue(data.value);
            }
        }
    }

    class TrailColorCoords {
        h = new TrailColorComponent();
        l = new TrailColorComponent();
        s = new TrailColorComponent();
        load(data) {
            if (!data) {
                return;
            }
            if (data.h) {
                this.h ??= new TrailColorComponent();
                this.h.load(data.h);
            }
            if (data.s) {
                this.s ??= new TrailColorComponent();
                this.s.load(data.s);
            }
            if (data.l) {
                this.l ??= new TrailColorComponent();
                this.l.load(data.l);
            }
        }
    }

    class Trail {
        colorCoords = new TrailColorCoords();
        delay = 1;
        particles;
        pauseOnStop = false;
        quantity = 1;
        load(data) {
            if (isNull(data))
                return;
            loadProperty(this, "delay", data.delay);
            loadProperty(this, "quantity", data.quantity);
            loadProperty(this, "pauseOnStop", data.pauseOnStop);
            if (data.particles !== undefined) {
                this.particles = deepExtend({}, data.particles);
            }
            if (data.colorCoords) {
                this.colorCoords ??= new TrailColorCoords();
                this.colorCoords.load(data.colorCoords);
            }
        }
    }

    const trailMode = "trail", defaultMin = 0, defaultWeight = 0;
    class TrailMaker extends ExternalInteractorBase {
        maxDistance = 0;
        #delay;
        #lastPosition;
        #pluginManager;
        constructor(pluginManager, container) {
            super(container);
            this.#pluginManager = pluginManager;
            this.#delay = 0;
        }
        clear() {
        }
        init() {
        }
        interact(interactivityData, delta) {
            const container = this.container;
            if (!container.retina.reduceFactor)
                return;
            const options = container.actualOptions, trailOptions = options.interactivity?.modes.trail;
            if (!trailOptions)
                return;
            const optDelay = (trailOptions.delay * millisecondsToSeconds) / this.container.retina.reduceFactor;
            if (this.#delay < optDelay) {
                this.#delay += delta.value;
            }
            if (this.#delay < optDelay)
                return;
            const mousePos = interactivityData.mouse.position, canEmit = !(trailOptions.pauseOnStop &&
                (mousePos === this.#lastPosition ||
                    (mousePos?.x === this.#lastPosition?.x && mousePos?.y === this.#lastPosition?.y)));
            if (mousePos) {
                this.#lastPosition = { ...mousePos };
            }
            else {
                this.#lastPosition = undefined;
            }
            if (canEmit && mousePos) {
                let particleOptions = trailOptions.particles;
                const colorCoords = trailOptions.colorCoords;
                if (colorCoords) {
                    const { width, height } = container.canvas.size, norm = {
                        x: mousePos.x / width,
                        y: mousePos.y / height,
                    }, hasWeights = (comp) => {
                        return !!(comp?.weights?.x ?? comp?.weights?.y);
                    }, calculateValue = (comp, originalValue, defaultMax) => {
                        if (!hasWeights(comp))
                            return undefined;
                        const w = comp?.weights, factor = norm.x * (w?.x ?? defaultWeight) + norm.y * (w?.y ?? defaultWeight), rangeSource = comp?.value ?? originalValue, min = getRangeMin(rangeSource ?? defaultMin), max = getRangeMax(rangeSource ?? defaultMax), result = min + factor * (max - min);
                        return Math.min(max, Math.max(min, result));
                    }, trailPaintOptions = trailOptions.particles?.paint
                        ? itemFromSingleOrMultiple(trailOptions.particles.paint)
                        : undefined, fillData = trailPaintOptions?.fill, baseHsl = fillData
                        ? rangeColorToHsl(this.#pluginManager, AnimatableColor.create(undefined, fillData.color))
                        : undefined, h = calculateValue(colorCoords.h, baseHsl?.h, hMax), s = calculateValue(colorCoords.s, baseHsl?.s, sMax), l = calculateValue(colorCoords.l, baseHsl?.l, lMax);
                    if (h !== undefined || s !== undefined || l !== undefined) {
                        particleOptions = deepExtend({}, trailOptions.particles, {
                            paint: {
                                fill: {
                                    color: {
                                        value: {
                                            h: h ?? baseHsl?.h,
                                            s: s ?? baseHsl?.s,
                                            l: l ?? baseHsl?.l,
                                        },
                                    },
                                },
                            },
                        });
                    }
                }
                container.particles.push(trailOptions.quantity, mousePos, particleOptions);
            }
            this.#delay -= optDelay;
        }
        isEnabled(interactivityData, particle) {
            const container = this.container, options = container.actualOptions, mouse = interactivityData.mouse, events = (particle?.interactivity ?? options.interactivity)?.events;
            return (!!events &&
                ((mouse.clicking && mouse.inside && !!mouse.position && isInArray(trailMode, events.onClick.mode)) ||
                    (mouse.inside && !!mouse.position && isInArray(trailMode, events.onHover.mode))));
        }
        loadModeOptions(options, ...sources) {
            loadOptionProperty(options, "trail", Trail, ...sources);
        }
        reset() {
        }
    }

    async function loadExternalTrailInteraction(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register((e) => {
            ensureInteractivityPluginLoaded(e);
            e.pluginManager.addInteractor?.("externalTrail", container => {
                return Promise.resolve(new TrailMaker(e.pluginManager, container));
            });
        });
    }

    var RollMode;
    (function (RollMode) {
        RollMode["both"] = "both";
        RollMode["horizontal"] = "horizontal";
        RollMode["vertical"] = "vertical";
    })(RollMode || (RollMode = {}));

    const maxAngle$4 = 360;
    function initParticle(pluginManager, particle) {
        const rollOpt = particle.options.roll;
        if (!rollOpt?.enable) {
            particle.roll = {
                enable: false,
                horizontal: false,
                vertical: false,
                angle: 0,
                speed: 0,
            };
            return;
        }
        particle.roll = {
            enable: rollOpt.enable,
            horizontal: rollOpt.mode === RollMode.horizontal || rollOpt.mode === RollMode.both,
            vertical: rollOpt.mode === RollMode.vertical || rollOpt.mode === RollMode.both,
            angle: getRandom() * doublePI,
            speed: getRangeValue(rollOpt.speed) / maxAngle$4,
        };
        if (rollOpt.backColor) {
            particle.backColor = rangeColorToHsl(pluginManager, rollOpt.backColor);
        }
        else if (rollOpt.darken.enable && rollOpt.enlighten.enable) {
            const alterType = getRandom() >= half ? exports.AlterType.darken : exports.AlterType.enlighten;
            particle.roll.alter = {
                type: alterType,
                value: getRangeValue(alterType === exports.AlterType.darken ? rollOpt.darken.value : rollOpt.enlighten.value),
            };
        }
        else if (rollOpt.darken.enable) {
            particle.roll.alter = {
                type: exports.AlterType.darken,
                value: getRangeValue(rollOpt.darken.value),
            };
        }
        else if (rollOpt.enlighten.enable) {
            particle.roll.alter = {
                type: exports.AlterType.enlighten,
                value: getRangeValue(rollOpt.enlighten.value),
            };
        }
    }
    function updateRoll(particle, delta) {
        const roll = particle.options.roll, data = particle.roll;
        if (!data || !roll?.enable) {
            return;
        }
        const speed = data.speed * delta.factor, max = doublePI;
        data.angle += speed;
        if (data.angle > max) {
            data.angle -= max;
        }
    }

    class RollLight {
        enable = false;
        value = 0;
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadProperty(this, "enable", data.enable);
            loadRangeProperty(this, "value", data.value);
        }
    }

    class Roll {
        backColor;
        darken = new RollLight();
        enable = false;
        enlighten = new RollLight();
        mode = RollMode.vertical;
        speed = 25;
        load(data) {
            if (isNull(data)) {
                return;
            }
            if (data.backColor !== undefined) {
                this.backColor = OptionsColor.create(this.backColor, data.backColor);
            }
            this.darken.load(data.darken);
            loadProperty(this, "enable", data.enable);
            this.enlighten.load(data.enlighten);
            loadProperty(this, "mode", data.mode);
            loadRangeProperty(this, "speed", data.speed);
        }
    }

    class RollUpdater {
        #pluginManager;
        constructor(pluginManager) {
            this.#pluginManager = pluginManager;
        }
        getTransformValues(particle) {
            const roll = particle.roll?.enable && particle.roll, rollHorizontal = roll && roll.horizontal, rollVertical = roll && roll.vertical;
            return {
                a: rollHorizontal ? Math.cos(roll.angle) : undefined,
                d: rollVertical ? Math.sin(roll.angle) : undefined,
            };
        }
        init(particle) {
            initParticle(this.#pluginManager, particle);
        }
        isEnabled(particle) {
            const roll = particle.options.roll;
            return !particle.destroyed && !particle.spawning && !!roll?.enable;
        }
        loadOptions(options, ...sources) {
            loadOptionProperty(options, "roll", Roll, ...sources);
        }
        update(particle, delta) {
            if (!this.isEnabled(particle)) {
                return;
            }
            updateRoll(particle, delta);
        }
    }

    async function loadRollUpdater(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register(e => {
            e.pluginManager.addParticleUpdater("roll", () => {
                return Promise.resolve(new RollUpdater(e.pluginManager));
            });
        });
    }

    class Blend {
        enable = false;
        mode = "destination-out";
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadProperty(this, "mode", data.mode);
            loadProperty(this, "enable", data.enable);
        }
    }

    class BlendPlugin {
        id = "blend";
        async getPlugin(container) {
            const { BlendPluginInstance } = await Promise.resolve().then(function () { return BlendPluginInstance$1; });
            return new BlendPluginInstance(container);
        }
        loadOptions(_container, options, source) {
            if (!this.needsPlugin(options) && !this.needsPlugin(source)) {
                return;
            }
            let blendOptions = options.blend;
            if (!blendOptions?.load) {
                options.blend = blendOptions = new Blend();
            }
            blendOptions.load(source?.blend);
        }
        loadParticlesOptions(_container, options, source) {
            options.blend ??= new Blend();
            options.blend.load(source?.blend);
        }
        needsPlugin(options) {
            return !!options?.blend?.enable || !!options?.particles?.blend?.enable;
        }
    }

    async function loadBlendPlugin(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register(e => {
            e.pluginManager.addPlugin(new BlendPlugin());
        });
    }

    const minAngle$2 = 0;
    function drawCircle(data) {
        const { context, particle, radius } = data;
        particle.circleRange ??= { min: minAngle$2, max: doublePI };
        const circleRange = particle.circleRange;
        context.arc(originPoint.x, originPoint.y, radius, circleRange.min, circleRange.max, false);
    }

    const sides$4 = 12, maxAngle$3 = 360, minAngle$1 = 0;
    class CircleDrawer {
        draw(data) {
            drawCircle(data);
        }
        getSidesCount() {
            return sides$4;
        }
        particleInit(_container, particle) {
            const shapeData = particle.shapeData, angle = shapeData?.angle ?? {
                max: maxAngle$3,
                min: minAngle$1,
            };
            particle.circleRange = isObject(angle)
                ? { min: degToRad(angle.min), max: degToRad(angle.max) }
                : {
                    min: minAngle$1,
                    max: degToRad(angle),
                };
        }
    }

    async function loadCircleShape(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register(e => {
            e.pluginManager.addShape(["circle"], () => {
                return Promise.resolve(new CircleDrawer());
            });
        });
    }

    var RgbIndexes$1;
    (function (RgbIndexes) {
        RgbIndexes[RgbIndexes["r"] = 1] = "r";
        RgbIndexes[RgbIndexes["g"] = 2] = "g";
        RgbIndexes[RgbIndexes["b"] = 3] = "b";
        RgbIndexes[RgbIndexes["a"] = 4] = "a";
    })(RgbIndexes$1 || (RgbIndexes$1 = {}));
    const shorthandHexRegex = /^#?([a-f\d])([a-f\d])([a-f\d])([a-f\d])?$/i, hexRegex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i, hexRadix = 16, defaultAlpha = 1, alphaFactor = 0xff;
    class HexColorManager {
        accepts(input) {
            return input.startsWith("#");
        }
        handleColor(color) {
            return this.#parseString(color.value);
        }
        handleRangeColor(color) {
            return this.#parseString(color.value);
        }
        parseString(input) {
            return this.#parseString(input);
        }
        #parseString(hexColor) {
            if (typeof hexColor !== "string" || !this.accepts(hexColor)) {
                return;
            }
            const hexFixed = hexColor.replace(shorthandHexRegex, (_, r, g, b, a) => {
                return r + r + g + g + b + b + (a === undefined ? "" : a + a);
            }), result = hexRegex.exec(hexFixed);
            return result
                ? {
                    a: result[RgbIndexes$1.a] ? Number.parseInt(result[RgbIndexes$1.a], hexRadix) / alphaFactor : defaultAlpha,
                    b: Number.parseInt(result[RgbIndexes$1.b] ?? "0", hexRadix),
                    g: Number.parseInt(result[RgbIndexes$1.g] ?? "0", hexRadix),
                    r: Number.parseInt(result[RgbIndexes$1.r] ?? "0", hexRadix),
                }
                : undefined;
        }
    }

    async function loadHexColorPlugin(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register(e => {
            e.pluginManager.addColorManager("hex", new HexColorManager());
        });
    }

    var HslIndexes;
    (function (HslIndexes) {
        HslIndexes[HslIndexes["h"] = 1] = "h";
        HslIndexes[HslIndexes["s"] = 2] = "s";
        HslIndexes[HslIndexes["l"] = 3] = "l";
        HslIndexes[HslIndexes["a"] = 5] = "a";
    })(HslIndexes || (HslIndexes = {}));
    const hslRegex = /hsla?\(\s*(\d+)\s*[\s,]\s*(\d+)%\s*[\s,]\s*(\d+)%\s*([\s,]\s*(0|1|0?\.\d+|(\d{1,3})%)\s*)?\)/i;
    class HslColorManager {
        accepts(input) {
            return input.startsWith("hsl");
        }
        handleColor(color) {
            const colorValue = color.value, hslColor = colorValue.hsl ?? color.value;
            if (!("h" in hslColor) || !("s" in hslColor) || !("l" in hslColor)) {
                return;
            }
            return hslToRgb(hslColor);
        }
        handleRangeColor(color) {
            const colorValue = color.value, hslColor = colorValue.hsl ?? color.value;
            if (!("h" in hslColor) || !("s" in hslColor) || !("l" in hslColor)) {
                return;
            }
            return hslToRgb({
                h: getRangeValue(hslColor.h),
                l: getRangeValue(hslColor.l),
                s: getRangeValue(hslColor.s),
            });
        }
        parseString(input) {
            if (!this.accepts(input)) {
                return;
            }
            const result = hslRegex.exec(input), minLength = 4, defaultAlpha = 1, radix = 10;
            return result
                ? hslaToRgba({
                    a: result.length > minLength ? parseAlpha(result[HslIndexes.a]) : defaultAlpha,
                    h: Number.parseInt(result[HslIndexes.h] ?? "0", radix),
                    l: Number.parseInt(result[HslIndexes.l] ?? "0", radix),
                    s: Number.parseInt(result[HslIndexes.s] ?? "0", radix),
                })
                : undefined;
        }
    }

    async function loadHslColorPlugin(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register(e => {
            e.pluginManager.addColorManager("hsl", new HslColorManager());
        });
    }

    class MovePlugin {
        id = "move";
        #pluginManager;
        constructor(pluginManager) {
            this.#pluginManager = pluginManager;
        }
        async getPlugin(container) {
            const { MovePluginInstance } = await Promise.resolve().then(function () { return MovePluginInstance$1; });
            return new MovePluginInstance(this.#pluginManager, container);
        }
        loadOptions() {
        }
        needsPlugin() {
            return true;
        }
    }

    async function loadMovePlugin(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register(e => {
            const moveEngine = e, movePluginManager = moveEngine.pluginManager;
            movePluginManager.initializers.pathGenerators ??= new Map();
            movePluginManager.pathGenerators ??= new Map();
            movePluginManager.addPathGenerator = (name, generator) => {
                movePluginManager.initializers.pathGenerators ??= new Map();
                movePluginManager.initializers.pathGenerators.set(name, generator);
            };
            movePluginManager.getPathGenerators = async (container, force = false) => {
                movePluginManager.initializers.pathGenerators ??= new Map();
                movePluginManager.pathGenerators ??= new Map();
                return getItemMapFromInitializer(container, movePluginManager.pathGenerators, movePluginManager.initializers.pathGenerators, force);
            };
            e.pluginManager.addPlugin(new MovePlugin(e.pluginManager));
        });
    }

    function checkDestroy(particle, destroyType, value, minValue, maxValue) {
        switch (destroyType) {
            case exports.DestroyType.max:
                if (value >= maxValue) {
                    particle.destroy();
                }
                break;
            case exports.DestroyType.min:
                if (value <= minValue) {
                    particle.destroy();
                }
                break;
        }
    }
    function initParticleNumericAnimationValue(options, pxRatio) {
        const valueRange = options.value, animationOptions = options.animation, res = {
            delayTime: getRangeValue(animationOptions.delay) * millisecondsToSeconds,
            enable: animationOptions.enable,
            value: getRangeValue(options.value) * pxRatio,
            max: getRangeMax(valueRange) * pxRatio,
            min: getRangeMin(valueRange) * pxRatio,
            loops: 0,
            maxLoops: getRangeValue(animationOptions.count),
            time: 0,
        }, decayOffset = 1;
        if (animationOptions.enable) {
            res.decay = decayOffset - getRangeValue(animationOptions.decay);
            switch (animationOptions.mode) {
                case exports.AnimationMode.increase:
                    res.status = exports.AnimationStatus.increasing;
                    break;
                case exports.AnimationMode.decrease:
                    res.status = exports.AnimationStatus.decreasing;
                    break;
                case exports.AnimationMode.random:
                    res.status = getRandom() >= half ? exports.AnimationStatus.increasing : exports.AnimationStatus.decreasing;
                    break;
            }
            const autoStatus = animationOptions.mode === exports.AnimationMode.auto;
            switch (animationOptions.startValue) {
                case exports.StartValueType.min:
                    res.value = res.min;
                    if (autoStatus) {
                        res.status = exports.AnimationStatus.increasing;
                    }
                    break;
                case exports.StartValueType.max:
                    res.value = res.max;
                    if (autoStatus) {
                        res.status = exports.AnimationStatus.decreasing;
                    }
                    break;
                case exports.StartValueType.random:
                default:
                    res.value = randomInRangeValue(res);
                    if (autoStatus) {
                        res.status = getRandom() >= half ? exports.AnimationStatus.increasing : exports.AnimationStatus.decreasing;
                    }
                    break;
            }
        }
        res.initialValue = res.value;
        return res;
    }
    function updateAnimation(particle, data, changeDirection, destroyType, delta) {
        const minLoops = 0, minDelay = 0, identity = 1, minVelocity = 0, minDecay = 1;
        if (particle.destroyed ||
            !data.enable ||
            ((data.maxLoops ?? minLoops) > minLoops && (data.loops ?? minLoops) > (data.maxLoops ?? minLoops))) {
            return;
        }
        const velocity = (data.velocity ?? minVelocity) * delta.factor, minValue = data.min, maxValue = data.max, decay = data.decay ?? minDecay;
        data.time ??= 0;
        const delayTime = data.delayTime ?? minDelay;
        if (delayTime > minDelay && data.time < delayTime) {
            data.time += delta.value;
            if (data.time < delayTime) {
                return;
            }
        }
        switch (data.status) {
            case exports.AnimationStatus.increasing:
                data.value += velocity;
                break;
            case exports.AnimationStatus.decreasing:
                data.value -= velocity;
                break;
        }
        if (data.velocity && decay !== identity) {
            data.velocity *= decay;
        }
        switch (data.status) {
            case exports.AnimationStatus.increasing:
                if (data.value >= maxValue) {
                    if (changeDirection) {
                        data.status = exports.AnimationStatus.decreasing;
                    }
                    else {
                        data.value -= maxValue;
                    }
                    data.loops ??= minLoops;
                    data.loops++;
                }
                break;
            case exports.AnimationStatus.decreasing:
                if (data.value <= minValue) {
                    if (changeDirection) {
                        data.status = exports.AnimationStatus.increasing;
                    }
                    else {
                        data.value += maxValue;
                    }
                    data.loops ??= minLoops;
                    data.loops++;
                }
                break;
        }
        checkDestroy(particle, destroyType, data.value, minValue, maxValue);
        if (!particle.destroyed) {
            data.value = clamp(data.value, minValue, maxValue);
        }
    }

    class OpacityAnimation extends RangedAnimationOptions {
        destroy = exports.DestroyType.none;
        load(data) {
            super.load(data);
            if (isNull(data)) {
                return;
            }
            loadProperty(this, "destroy", data.destroy);
        }
    }

    class Opacity extends RangedAnimationValueWithRandom {
        animation = new OpacityAnimation();
        value = 1;
        load(data) {
            if (isNull(data)) {
                return;
            }
            super.load(data);
            const animation = data.animation;
            if (animation !== undefined) {
                this.animation.load(animation);
            }
        }
    }

    class OpacityUpdater {
        #container;
        constructor(container) {
            this.#container = container;
        }
        init(particle) {
            const opacityOptions = particle.options.opacity, pxRatio = 1;
            if (!opacityOptions) {
                return;
            }
            particle.opacity = initParticleNumericAnimationValue(opacityOptions, pxRatio);
            const opacityAnimation = opacityOptions.animation;
            if (opacityAnimation.enable) {
                particle.opacity.velocity =
                    (getRangeValue(opacityAnimation.speed) / percentDenominator) * this.#container.retina.reduceFactor;
                if (!opacityAnimation.sync) {
                    particle.opacity.velocity *= getRandom();
                }
            }
        }
        isEnabled(particle) {
            const none = 0;
            return (!particle.destroyed &&
                !particle.spawning &&
                !!particle.opacity &&
                particle.opacity.enable &&
                ((particle.opacity.maxLoops ?? none) <= none ||
                    ((particle.opacity.maxLoops ?? none) > none &&
                        (particle.opacity.loops ?? none) < (particle.opacity.maxLoops ?? none))));
        }
        loadOptions(options, ...sources) {
            loadOptionProperty(options, "opacity", Opacity, ...sources);
        }
        reset(particle) {
            if (!particle.opacity) {
                return;
            }
            particle.opacity.time = 0;
            particle.opacity.loops = 0;
        }
        update(particle, delta) {
            if (!this.isEnabled(particle) || !particle.opacity || !particle.options.opacity) {
                return;
            }
            updateAnimation(particle, particle.opacity, true, particle.options.opacity.animation.destroy, delta);
        }
    }

    async function loadOpacityUpdater(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register(e => {
            e.pluginManager.addParticleUpdater("opacity", container => {
                return Promise.resolve(new OpacityUpdater(container));
            });
        });
    }

    const boundsMin = 0;
    function bounceHorizontal(data) {
        if ((data.outMode !== exports.OutMode.bounce && data.outMode !== exports.OutMode.split) ||
            (data.direction !== exports.OutModeDirection.left && data.direction !== exports.OutModeDirection.right)) {
            return;
        }
        if (data.bounds.right < boundsMin && data.direction === exports.OutModeDirection.left) {
            data.particle.position.x = data.size + data.offset.x;
        }
        else if (data.bounds.left > data.canvasSize.width && data.direction === exports.OutModeDirection.right) {
            data.particle.position.x = data.canvasSize.width - data.size - data.offset.x;
        }
        const velocity = data.particle.velocity.x;
        let bounced = false;
        if (data.outOfCanvas &&
            ((data.direction === exports.OutModeDirection.right && velocity > minVelocity) ||
                (data.direction === exports.OutModeDirection.left && velocity < minVelocity))) {
            const newVelocity = getRangeValue(data.particle.options.bounce.horizontal.value);
            data.particle.velocity.x *= -newVelocity;
            bounced = true;
        }
        if (!bounced) {
            return;
        }
        const minPos = data.offset.x + data.size;
        if (data.outOfCanvas && data.direction === exports.OutModeDirection.right) {
            data.particle.position.x = data.canvasSize.width - minPos;
        }
        else if (data.outOfCanvas && data.direction === exports.OutModeDirection.left) {
            data.particle.position.x = minPos;
        }
        if (data.outMode === exports.OutMode.split) {
            data.particle.destroy();
        }
    }
    function bounceVertical(data) {
        if ((data.outMode !== exports.OutMode.bounce && data.outMode !== exports.OutMode.split) ||
            (data.direction !== exports.OutModeDirection.bottom && data.direction !== exports.OutModeDirection.top)) {
            return;
        }
        if (data.bounds.bottom < boundsMin && data.direction === exports.OutModeDirection.top) {
            data.particle.position.y = data.size + data.offset.y;
        }
        else if (data.bounds.top > data.canvasSize.height && data.direction === exports.OutModeDirection.bottom) {
            data.particle.position.y = data.canvasSize.height - data.size - data.offset.y;
        }
        const velocity = data.particle.velocity.y;
        let bounced = false;
        if (data.outOfCanvas &&
            ((data.direction === exports.OutModeDirection.bottom && velocity > minVelocity) ||
                (data.direction === exports.OutModeDirection.top && velocity < minVelocity))) {
            const newVelocity = getRangeValue(data.particle.options.bounce.vertical.value);
            data.particle.velocity.y *= -newVelocity;
            bounced = true;
        }
        if (!bounced) {
            return;
        }
        const minPos = data.offset.y + data.size;
        if (data.outOfCanvas && data.direction === exports.OutModeDirection.bottom) {
            data.particle.position.y = data.canvasSize.height - minPos;
        }
        else if (data.outOfCanvas && data.direction === exports.OutModeDirection.top) {
            data.particle.position.y = minPos;
        }
        if (data.outMode === exports.OutMode.split) {
            data.particle.destroy();
        }
    }

    class BounceOutMode {
        modes;
        #container;
        #particleBouncePlugins;
        constructor(container) {
            this.#container = container;
            this.modes = [
                exports.OutMode.bounce,
                exports.OutMode.split,
            ];
            this.#particleBouncePlugins = container.plugins.filter(p => p.particleBounce !== undefined);
        }
        update(particle, direction, delta, outMode) {
            if (!this.modes.includes(outMode)) {
                return;
            }
            const container = this.#container;
            let handled = false;
            for (const plugin of this.#particleBouncePlugins) {
                handled = plugin.particleBounce?.(particle, delta, direction) ?? false;
                if (handled) {
                    break;
                }
            }
            if (handled) {
                return;
            }
            const pos = particle.getPosition(), offset = particle.offset, size = particle.getRadius(), bounds = calculateBounds(pos, size), canvasSize = container.canvas.size, outOfCanvas = !particle.isInsideCanvasForOutMode(outMode, direction);
            bounceHorizontal({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
            bounceVertical({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
        }
    }

    class DestroyOutMode {
        modes;
        constructor(_container) {
            this.modes = [exports.OutMode.destroy];
        }
        update(particle, direction, _delta, outMode) {
            if (!this.modes.includes(outMode)) {
                return;
            }
            switch (particle.outType) {
                case exports.ParticleOutType.normal:
                case exports.ParticleOutType.outside:
                    if (particle.isInsideCanvasForOutMode(outMode, direction)) {
                        return;
                    }
                    break;
                case exports.ParticleOutType.inside: {
                    const { dx, dy } = getDistances(particle.position, particle.moveCenter), { x: vx, y: vy } = particle.velocity;
                    if ((vx < minVelocity && dx > particle.moveCenter.radius) ||
                        (vy < minVelocity && dy > particle.moveCenter.radius) ||
                        (vx >= minVelocity && dx < -particle.moveCenter.radius) ||
                        (vy >= minVelocity && dy < -particle.moveCenter.radius)) {
                        return;
                    }
                    break;
                }
            }
            particle.destroy(true);
        }
    }

    class NoneOutMode {
        modes;
        #container;
        constructor(container) {
            this.#container = container;
            this.modes = [exports.OutMode.none];
        }
        update(particle, direction, _delta, outMode) {
            if (!this.modes.includes(outMode)) {
                return;
            }
            if ((particle.options.move.distance.horizontal &&
                (direction === exports.OutModeDirection.left || direction === exports.OutModeDirection.right)) ??
                (particle.options.move.distance.vertical &&
                    (direction === exports.OutModeDirection.top || direction === exports.OutModeDirection.bottom))) {
                return;
            }
            const gravityOptions = particle.options.move.gravity, container = this.#container, canvasSize = container.canvas.size, pRadius = particle.getRadius();
            if (!gravityOptions.enable) {
                if ((particle.velocity.y > minVelocity && particle.position.y <= canvasSize.height + pRadius) ||
                    (particle.velocity.y < minVelocity && particle.position.y >= -pRadius) ||
                    (particle.velocity.x > minVelocity && particle.position.x <= canvasSize.width + pRadius) ||
                    (particle.velocity.x < minVelocity && particle.position.x >= -pRadius)) {
                    return;
                }
                if (!isPointInside(particle.position, container.canvas.size, originPoint, pRadius, direction)) {
                    particle.destroy();
                }
            }
            else {
                const position = particle.position;
                if ((!gravityOptions.inverse &&
                    position.y > canvasSize.height + pRadius &&
                    direction === exports.OutModeDirection.bottom) ||
                    (gravityOptions.inverse && position.y < -pRadius && direction === exports.OutModeDirection.top)) {
                    particle.destroy();
                }
            }
        }
    }

    const updateVector$1 = Vector.origin;
    class OutOutMode {
        modes;
        #container;
        constructor(container) {
            this.#container = container;
            this.modes = [exports.OutMode.out];
        }
        update(particle, direction, _delta, outMode) {
            if (!this.modes.includes(outMode)) {
                return;
            }
            const container = this.#container;
            switch (particle.outType) {
                case exports.ParticleOutType.inside: {
                    const { x: vx, y: vy } = particle.velocity;
                    updateVector$1.setTo(originPoint);
                    updateVector$1.length = particle.moveCenter.radius;
                    updateVector$1.angle = particle.velocity.angle + Math.PI;
                    updateVector$1.addTo(particle.moveCenter);
                    const { dx, dy } = getDistances(particle.position, updateVector$1);
                    if ((vx <= minVelocity && dx >= minDistance$6) ||
                        (vy <= minVelocity && dy >= minDistance$6) ||
                        (vx >= minVelocity && dx <= minDistance$6) ||
                        (vy >= minVelocity && dy <= minDistance$6)) {
                        return;
                    }
                    particle.position.x = Math.floor(randomInRangeValue({
                        min: 0,
                        max: container.canvas.size.width,
                    }));
                    particle.position.y = Math.floor(randomInRangeValue({
                        min: 0,
                        max: container.canvas.size.height,
                    }));
                    const { dx: newDx, dy: newDy } = getDistances(particle.position, particle.moveCenter);
                    particle.direction = Math.atan2(-newDy, -newDx);
                    particle.velocity.angle = particle.direction;
                    particle.justWarped = true;
                    break;
                }
                default: {
                    if (particle.isInsideCanvasForOutMode(outMode, direction)) {
                        return;
                    }
                    switch (particle.outType) {
                        case exports.ParticleOutType.outside: {
                            particle.position.x =
                                Math.floor(randomInRangeValue({
                                    min: -particle.moveCenter.radius,
                                    max: particle.moveCenter.radius,
                                })) + particle.moveCenter.x;
                            particle.position.y =
                                Math.floor(randomInRangeValue({
                                    min: -particle.moveCenter.radius,
                                    max: particle.moveCenter.radius,
                                })) + particle.moveCenter.y;
                            const { dx, dy } = getDistances(particle.position, particle.moveCenter);
                            if (particle.moveCenter.radius) {
                                particle.direction = Math.atan2(dy, dx);
                                particle.velocity.angle = particle.direction;
                            }
                            particle.justWarped = true;
                            break;
                        }
                        case exports.ParticleOutType.normal: {
                            const warp = particle.options.move.warp, canvasSize = container.canvas.size, newPos = {
                                bottom: canvasSize.height + particle.getRadius() + particle.offset.y,
                                left: -particle.getRadius() - particle.offset.x,
                                right: canvasSize.width + particle.getRadius() + particle.offset.x,
                                top: -particle.getRadius() - particle.offset.y,
                            }, sizeValue = particle.getRadius(), nextBounds = calculateBounds(particle.position, sizeValue);
                            if (direction === exports.OutModeDirection.right && nextBounds.left > canvasSize.width + particle.offset.x) {
                                particle.position.x = newPos.left;
                                particle.initialPosition.x = particle.position.x;
                                if (!warp) {
                                    particle.position.y = getRandom() * canvasSize.height;
                                    particle.initialPosition.y = particle.position.y;
                                }
                                particle.justWarped = true;
                            }
                            else if (direction === exports.OutModeDirection.left && nextBounds.right < -particle.offset.x) {
                                particle.position.x = newPos.right;
                                particle.initialPosition.x = particle.position.x;
                                if (!warp) {
                                    particle.position.y = getRandom() * canvasSize.height;
                                    particle.initialPosition.y = particle.position.y;
                                }
                                particle.justWarped = true;
                            }
                            if (direction === exports.OutModeDirection.bottom && nextBounds.top > canvasSize.height + particle.offset.y) {
                                if (!warp) {
                                    particle.position.x = getRandom() * canvasSize.width;
                                    particle.initialPosition.x = particle.position.x;
                                }
                                particle.position.y = newPos.top;
                                particle.initialPosition.y = particle.position.y;
                                particle.justWarped = true;
                            }
                            else if (direction === exports.OutModeDirection.top && nextBounds.bottom < -particle.offset.y) {
                                if (!warp) {
                                    particle.position.x = getRandom() * canvasSize.width;
                                    particle.initialPosition.x = particle.position.x;
                                }
                                particle.position.y = newPos.bottom;
                                particle.initialPosition.y = particle.position.y;
                                particle.justWarped = true;
                            }
                            break;
                        }
                    }
                    break;
                }
            }
        }
    }

    const checkOutMode = (outModes, outMode) => {
        return (outModes.default === outMode ||
            outModes.bottom === outMode ||
            outModes.left === outMode ||
            outModes.right === outMode ||
            outModes.top === outMode);
    };
    class OutOfCanvasUpdater {
        updaters;
        #container;
        constructor(container) {
            this.#container = container;
            this.updaters = new Map();
        }
        init(particle) {
            this.#addUpdaterIfMissing(particle, exports.OutMode.bounce, container => new BounceOutMode(container));
            this.#addUpdaterIfMissing(particle, exports.OutMode.out, container => new OutOutMode(container));
            this.#addUpdaterIfMissing(particle, exports.OutMode.destroy, container => new DestroyOutMode(container));
            this.#addUpdaterIfMissing(particle, exports.OutMode.none, container => new NoneOutMode(container));
        }
        isEnabled(particle) {
            return !particle.destroyed && !particle.spawning;
        }
        update(particle, delta) {
            const outModes = particle.options.move.outModes;
            particle.justWarped = false;
            this.#updateOutMode(particle, delta, outModes.bottom ?? outModes.default, exports.OutModeDirection.bottom);
            this.#updateOutMode(particle, delta, outModes.left ?? outModes.default, exports.OutModeDirection.left);
            this.#updateOutMode(particle, delta, outModes.right ?? outModes.default, exports.OutModeDirection.right);
            this.#updateOutMode(particle, delta, outModes.top ?? outModes.default, exports.OutModeDirection.top);
        }
        #addUpdaterIfMissing(particle, outMode, getUpdater) {
            const outModes = particle.options.move.outModes;
            if (!this.updaters.has(outMode) && checkOutMode(outModes, outMode)) {
                this.updaters.set(outMode, getUpdater(this.#container));
            }
        }
        #updateOutMode(particle, delta, outMode, direction) {
            for (const updater of this.updaters.values()) {
                updater.update(particle, direction, delta, outMode);
            }
        }
    }

    async function loadOutModesUpdater(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register(e => {
            e.pluginManager.addParticleUpdater("outModes", container => {
                return Promise.resolve(new OutOfCanvasUpdater(container));
            });
        });
    }

    const defaultOpacity$2 = 1;
    class PaintUpdater {
        #container;
        #pluginManager;
        constructor(pluginManager, container) {
            this.#container = container;
            this.#pluginManager = pluginManager;
        }
        init(particle) {
            const container = this.#container, options = particle.options, paint = itemFromSingleOrMultiple(options.paint, particle.id, options.reduceDuplicates), color = paint?.color, paintColor = color ?? undefined, fill = paint?.fill, stroke = paint?.stroke;
            if (fill) {
                const fillColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), fill.color);
                particle.fillEnabled = fill.enable;
                particle.fillOpacity = getRangeValue(fill.opacity);
                particle.fillAnimation = fillColor.animation;
                const fillHslColor = rangeColorToHsl(this.#pluginManager, fillColor);
                if (fillHslColor) {
                    particle.fillColor = getHslAnimationFromHsl(fillHslColor, particle.fillAnimation, container.retina.reduceFactor);
                }
            }
            else {
                particle.fillEnabled = false;
                particle.fillAnimation = undefined;
                particle.fillColor = undefined;
                particle.fillOpacity = defaultOpacity$2;
            }
            if (stroke) {
                const strokeColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), stroke.color);
                particle.strokeWidth = getRangeValue(stroke.width) * container.retina.pixelRatio;
                particle.strokeOpacity = getRangeValue(stroke.opacity ?? defaultOpacity$2);
                particle.strokeAnimation = strokeColor.animation;
                const strokeHslColor = rangeColorToHsl(this.#pluginManager, strokeColor) ?? particle.getFillColor();
                if (strokeHslColor) {
                    particle.strokeColor = getHslAnimationFromHsl(strokeHslColor, particle.strokeAnimation, container.retina.reduceFactor);
                }
            }
            else {
                particle.strokeAnimation = undefined;
                particle.strokeColor = undefined;
                particle.strokeOpacity = defaultOpacity$2;
                particle.strokeWidth = 0;
            }
        }
        isEnabled(particle) {
            const { fillAnimation, fillColor, strokeAnimation, strokeColor } = particle, fillEnabled = !!fillAnimation &&
                ((fillColor?.h.value !== undefined && fillColor.h.enable) ||
                    (fillColor?.s.value !== undefined && fillColor.s.enable) ||
                    (fillColor?.l.value !== undefined && fillColor.l.enable)), strokeEnabled = !!strokeAnimation &&
                ((strokeColor?.h.value !== undefined && strokeColor.h.enable) ||
                    (strokeColor?.s.value !== undefined && strokeColor.s.enable) ||
                    (strokeColor?.l.value !== undefined && strokeColor.l.enable));
            return !particle.destroyed && !particle.spawning && (fillEnabled || strokeEnabled);
        }
        update(particle, delta) {
            if (!this.isEnabled(particle)) {
                return;
            }
            updateColor(particle.fillColor, delta, this.#container.hdr);
            updateColor(particle.strokeColor, delta, this.#container.hdr);
        }
    }

    async function loadPaintUpdater(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register(e => {
            e.pluginManager.addParticleUpdater("paint", container => {
                return Promise.resolve(new PaintUpdater(e.pluginManager, container));
            });
        });
    }

    var RgbIndexes;
    (function (RgbIndexes) {
        RgbIndexes[RgbIndexes["r"] = 1] = "r";
        RgbIndexes[RgbIndexes["g"] = 2] = "g";
        RgbIndexes[RgbIndexes["b"] = 3] = "b";
        RgbIndexes[RgbIndexes["a"] = 5] = "a";
    })(RgbIndexes || (RgbIndexes = {}));
    const rgbRegex = /rgba?\(\s*(\d{1,3})\s*[\s,]\s*(\d{1,3})\s*[\s,]\s*(\d{1,3})\s*([\s,]\s*(0|1|0?\.\d+|(\d{1,3})%)\s*)?\)/i;
    class RgbColorManager {
        accepts(input) {
            return input.startsWith("rgb");
        }
        handleColor(color) {
            const colorValue = color.value, rgbColor = colorValue.rgb ?? color.value;
            if (!("r" in rgbColor) || !("g" in rgbColor) || !("b" in rgbColor)) {
                return;
            }
            return rgbColor;
        }
        handleRangeColor(color) {
            const colorValue = color.value, rgbColor = colorValue.rgb ?? color.value;
            if (!("r" in rgbColor) || !("g" in rgbColor) || !("b" in rgbColor)) {
                return;
            }
            return {
                r: getRangeValue(rgbColor.r),
                g: getRangeValue(rgbColor.g),
                b: getRangeValue(rgbColor.b),
            };
        }
        parseString(input) {
            if (!this.accepts(input)) {
                return;
            }
            const result = rgbRegex.exec(input), radix = 10, minLength = 4, defaultAlpha = 1;
            return result
                ? {
                    a: result.length > minLength ? parseAlpha(result[RgbIndexes.a]) : defaultAlpha,
                    b: parseInt(result[RgbIndexes.b] ?? "0", radix),
                    g: parseInt(result[RgbIndexes.g] ?? "0", radix),
                    r: parseInt(result[RgbIndexes.r] ?? "0", radix),
                }
                : undefined;
        }
    }

    async function loadRgbColorPlugin(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register(e => {
            e.pluginManager.addColorManager("rgb", new RgbColorManager());
        });
    }

    class SizeAnimation extends RangedAnimationOptions {
        destroy = exports.DestroyType.none;
        load(data) {
            super.load(data);
            if (isNull(data)) {
                return;
            }
            loadProperty(this, "destroy", data.destroy);
        }
    }

    class Size extends RangedAnimationValueWithRandom {
        animation = new SizeAnimation();
        value = 3;
        load(data) {
            super.load(data);
            if (isNull(data)) {
                return;
            }
            const animation = data.animation;
            if (animation !== undefined) {
                this.animation.load(animation);
            }
        }
    }

    const minLoops = 0;
    class SizeUpdater {
        #container;
        constructor(container) {
            this.#container = container;
        }
        init(particle) {
            const container = this.#container, sizeOptions = particle.options.size;
            if (!sizeOptions) {
                return;
            }
            const sizeAnimation = sizeOptions.animation;
            if (!sizeAnimation.enable) {
                return;
            }
            particle.size.velocity = (particle.retina.sizeAnimationSpeed / percentDenominator) * container.retina.reduceFactor;
            if (sizeAnimation.sync) {
                return;
            }
            particle.size.velocity *= getRandom();
        }
        isEnabled(particle) {
            return (!particle.destroyed &&
                !particle.spawning &&
                particle.size.enable &&
                ((particle.size.maxLoops ?? minLoops) <= minLoops ||
                    ((particle.size.maxLoops ?? minLoops) > minLoops &&
                        (particle.size.loops ?? minLoops) < (particle.size.maxLoops ?? minLoops))));
        }
        loadOptions(options, ...sources) {
            loadOptionProperty(options, "size", Size, ...sources);
        }
        preInit(particle) {
            const pxRatio = this.#container.retina.pixelRatio, options = particle.options, sizeOptions = options.size;
            if (!sizeOptions) {
                return;
            }
            particle.size = initParticleNumericAnimationValue(sizeOptions, pxRatio);
            particle.retina.sizeAnimationSpeed = getRangeValue(sizeOptions.animation.speed) * pxRatio;
        }
        reset(particle) {
            particle.size.time = 0;
            particle.size.loops = 0;
        }
        update(particle, delta) {
            if (!this.isEnabled(particle) || !particle.options.size) {
                return;
            }
            updateAnimation(particle, particle.size, true, particle.options.size.animation.destroy, delta);
        }
    }

    async function loadSizeUpdater(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register(e => {
            e.pluginManager.addParticleUpdater("size", container => {
                return Promise.resolve(new SizeUpdater(container));
            });
        });
    }

    async function loadBasic(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register(async (e) => {
            await Promise.all([
                loadBlendPlugin(e),
                loadHexColorPlugin(e),
                loadHslColorPlugin(e),
                loadRgbColorPlugin(e),
                loadMovePlugin(e),
                loadCircleShape(e),
                loadPaintUpdater(e),
                loadOpacityUpdater(e),
                loadOutModesUpdater(e),
                loadSizeUpdater(e),
            ]);
        });
    }

    const easingsFunctions = new Map();
    easingsFunctions.set("ease-in-quad", value => value ** 2);
    easingsFunctions.set("ease-out-quad", value => 1 - (1 - value) ** 2);
    easingsFunctions.set("ease-in-out-quad", value => (value < 0.5 ? 2 * value ** 2 : 1 - (-2 * value + 2) ** 2 / 2));

    async function loadEasingQuadPlugin(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register(e => {
            for (const [easing, easingFn] of easingsFunctions) {
                e.pluginManager.addEasing(easing, easingFn);
            }
        });
    }

    const validTypes$1 = ["emoji"];
    function drawEmoji(data, image) {
        const { context, opacity } = data, previousAlpha = context.globalAlpha, diameter = image.width, radius = diameter * half;
        context.globalAlpha = opacity;
        context.drawImage(image, -radius, -radius, diameter, diameter);
        context.globalAlpha = previousAlpha;
    }

    function drawLine$1(context, begin, end) {
        context.beginPath();
        context.moveTo(begin.x, begin.y);
        context.lineTo(end.x, end.y);
        context.closePath();
    }
    async function loadFont(font, weight) {
        try {
            await safeDocument().fonts.load(`${weight ?? "400"} 36px '${font ?? "Verdana"}'`);
        }
        catch {
        }
    }

    const defaultFont = '"Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", sans-serif', noPadding = 0, firstItem = 0;
    class EmojiDrawer {
        #emojiShapeDict = new Map();
        destroy() {
            for (const [key, data] of this.#emojiShapeDict) {
                if (data instanceof ImageBitmap) {
                    data.close();
                }
                this.#emojiShapeDict.delete(key);
            }
        }
        draw(data) {
            const key = data.particle.emojiDataKey;
            if (!key) {
                return;
            }
            const image = this.#emojiShapeDict.get(key);
            if (!image) {
                return;
            }
            drawEmoji(data, image);
        }
        async init(container) {
            const options = container.actualOptions, shapeData = options.particles.shape;
            if (!validTypes$1.some(t => isInArray(t, shapeData.type))) {
                return;
            }
            const promises = [loadFont(defaultFont)], shapeOptions = validTypes$1.map(t => shapeData.options[t])[firstItem];
            executeOnSingleOrMultiple(shapeOptions, shape => {
                if (shape.font) {
                    promises.push(loadFont(shape.font));
                }
            });
            await Promise.all(promises);
        }
        particleDestroy(particle) {
            particle.emojiDataKey = undefined;
        }
        particleInit(container, particle) {
            const shapeData = particle.shapeData;
            if (!shapeData.value) {
                return;
            }
            const emoji = itemFromSingleOrMultiple(shapeData.value, particle.randomIndexData);
            if (!emoji) {
                return;
            }
            const emojiOptions = typeof emoji === "string"
                ? {
                    font: shapeData.font ?? defaultFont,
                    padding: shapeData.padding ?? noPadding,
                    value: emoji,
                }
                : {
                    font: defaultFont,
                    padding: noPadding,
                    ...shapeData,
                    ...emoji,
                }, font = emojiOptions.font, value = emojiOptions.value, cacheKey = `${value}_${font}`;
            if (this.#emojiShapeDict.has(cacheKey)) {
                particle.emojiDataKey = cacheKey;
                return;
            }
            const padding = emojiOptions.padding * double, maxSize = getRangeMax(particle.size.value), fullSize = maxSize + padding, canvasSize = fullSize * double, cacheCanvas = new OffscreenCanvas(canvasSize, canvasSize), context = cacheCanvas.getContext("2d", container.canvas.render.settings);
            if (!context) {
                return;
            }
            context.font = `400 ${(maxSize * double).toString()}px ${font}`;
            context.textBaseline = "middle";
            context.textAlign = "center";
            context.fillText(value, fullSize, fullSize);
            const image = cacheCanvas instanceof HTMLCanvasElement ? cacheCanvas : cacheCanvas.transferToImageBitmap();
            this.#emojiShapeDict.set(cacheKey, image);
            particle.emojiDataKey = cacheKey;
        }
    }

    async function loadEmojiShape(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register(e => {
            e.pluginManager.addShape(validTypes$1, () => Promise.resolve(new EmojiDrawer()));
        });
    }

    const minFactor = 1, minRadius$3 = 0, updateVector = Vector.origin;
    function processAttract(pluginManager, container, position, attractRadius, area, queryCb, onAttractParticle) {
        const attractOptions = container.actualOptions.interactivity?.modes.attract;
        if (!attractOptions) {
            return;
        }
        const query = container.particles.grid.query(area, queryCb);
        for (const particle of query) {
            const { dx, dy, distance } = getDistances(particle.position, position), velocity = attractOptions.speed * attractOptions.factor, attractFactor = clamp(pluginManager.getEasing(attractOptions.easing)(identity$2 - distance / attractRadius) * velocity, minFactor, attractOptions.maxSpeed);
            updateVector.x = !distance ? velocity : (dx / distance) * attractFactor;
            updateVector.y = !distance ? velocity : (dy / distance) * attractFactor;
            onAttractParticle?.(particle);
            particle.position.subFrom(updateVector);
        }
    }
    function clickAttract(pluginManager, container, interactivityData, enabledCb, onAttractParticle) {
        container.attract ??= { particles: [] };
        const { attract } = container;
        if (!attract.finish) {
            attract.count ??= 0;
            attract.count++;
            if (attract.count === container.particles.count) {
                attract.finish = true;
            }
        }
        if (attract.clicking) {
            const mousePos = interactivityData.mouse.clickPosition, attractRadius = container.retina.attractModeDistance;
            if (!attractRadius || attractRadius < minRadius$3 || !mousePos) {
                return;
            }
            processAttract(pluginManager, container, mousePos, attractRadius, new Circle(mousePos.x, mousePos.y, attractRadius), (p) => enabledCb(p), onAttractParticle);
        }
        else if (attract.clicking === false) {
            attract.particles = [];
        }
    }
    function hoverAttract(pluginManager, container, interactivityData, enabledCb, onAttractParticle) {
        const mousePos = interactivityData.mouse.position, attractRadius = container.retina.attractModeDistance;
        if (!attractRadius || attractRadius < minRadius$3 || !mousePos) {
            return;
        }
        processAttract(pluginManager, container, mousePos, attractRadius, new Circle(mousePos.x, mousePos.y, attractRadius), (p) => enabledCb(p), onAttractParticle);
    }

    let Attract$1 = class Attract {
        distance = 200;
        duration = 0.4;
        easing = "ease-out-quad";
        factor = 1;
        maxSpeed = 50;
        restore;
        speed = 1;
        constructor() {
            this.restore = {
                enable: false,
                delay: 0,
                speed: 0.08,
                follow: true,
            };
        }
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadProperty(this, "distance", data.distance);
            loadProperty(this, "duration", data.duration);
            if (data.easing !== undefined) {
                this.easing = data.easing;
            }
            loadProperty(this, "factor", data.factor);
            if (data.maxSpeed !== undefined) {
                this.maxSpeed = data.maxSpeed;
            }
            loadProperty(this, "speed", data.speed);
            if (data.restore !== undefined) {
                this.restore.enable = data.restore.enable ?? this.restore.enable;
                this.restore.delay = data.restore.delay ?? this.restore.delay;
                this.restore.speed = data.restore.speed ?? this.restore.speed;
                this.restore.follow = data.restore.follow ?? this.restore.follow;
            }
        }
    };

    const attractMode = "attract", minVelocityLengthSq = 0, minRestoreSpeed$1 = 0.001, maxRestoreSpeed$1 = 1, restoreEpsilon$1 = 0.5;
    let Attractor$1 = class Attractor extends ExternalInteractorBase {
        handleClickMode;
        #interactedThisFrame;
        #maxDistance;
        #pluginManager;
        #restoreData;
        constructor(pluginManager, container) {
            super(container);
            this.#pluginManager = pluginManager;
            this.#maxDistance = 0;
            this.#interactedThisFrame = new Set();
            this.#restoreData = new Map();
            container.attract ??= { particles: [] };
            this.handleClickMode = (mode, interactivityData) => {
                const options = this.container.actualOptions, attract = options.interactivity?.modes.attract;
                if (!attract || mode !== attractMode) {
                    return;
                }
                container.attract ??= { particles: [] };
                container.attract.clicking = true;
                container.attract.count = 0;
                for (const particle of container.attract.particles) {
                    if (!this.isEnabled(interactivityData, particle)) {
                        continue;
                    }
                    particle.velocity.setTo(particle.initialVelocity);
                }
                container.attract.particles = [];
                container.attract.finish = false;
                setTimeout(() => {
                    if (container.destroyed) {
                        return;
                    }
                    container.attract ??= { particles: [] };
                    container.attract.clicking = false;
                }, attract.duration * millisecondsToSeconds);
            };
        }
        get maxDistance() {
            return this.#maxDistance;
        }
        clear() {
        }
        init() {
            const container = this.container, attract = container.actualOptions.interactivity?.modes.attract;
            if (!attract) {
                return;
            }
            this.#maxDistance = attract.distance;
            container.retina.attractModeDistance = attract.distance * container.retina.pixelRatio;
        }
        interact(interactivityData) {
            this.#interactedThisFrame.clear();
            const container = this.container, options = container.actualOptions, mouseMoveStatus = interactivityData.status === mouseMoveEvent, events = options.interactivity?.events;
            if (!events) {
                return;
            }
            const { enable: hoverEnabled, mode: hoverMode } = events.onHover, { enable: clickEnabled, mode: clickMode } = events.onClick;
            if (mouseMoveStatus && hoverEnabled && isInArray(attractMode, hoverMode)) {
                hoverAttract(this.#pluginManager, this.container, interactivityData, p => this.isEnabled(interactivityData, p), p => {
                    this.#trackInteractedParticle(p);
                });
            }
            else if (clickEnabled && isInArray(attractMode, clickMode)) {
                clickAttract(this.#pluginManager, this.container, interactivityData, p => this.isEnabled(interactivityData, p), p => {
                    this.#trackInteractedParticle(p);
                });
            }
            this.#restoreParticles();
        }
        isEnabled(interactivityData, particle) {
            const container = this.container, options = container.actualOptions, mouse = interactivityData.mouse, events = (particle?.interactivity ?? options.interactivity)?.events;
            if ((!mouse.position || !events?.onHover.enable) && (!mouse.clickPosition || !events?.onClick.enable)) {
                return false;
            }
            const hoverMode = events.onHover.mode, clickMode = events.onClick.mode;
            return isInArray(attractMode, hoverMode) || isInArray(attractMode, clickMode);
        }
        loadModeOptions(options, ...sources) {
            loadOptionProperty(options, "attract", Attract$1, ...sources);
        }
        reset() {
        }
        #restoreParticles() {
            const restore = this.container.actualOptions.interactivity?.modes.attract?.restore;
            if (!restore?.enable || !this.#restoreData.size) {
                return;
            }
            const now = Date.now(), restoreDelay = restore.delay * millisecondsToSeconds, restoreSpeed = Math.max(minRestoreSpeed$1, Math.min(maxRestoreSpeed$1, restore.speed));
            for (const [particle, restoreData] of this.#restoreData) {
                if (this.#interactedThisFrame.has(particle)) {
                    continue;
                }
                if (particle.destroyed) {
                    this.#restoreData.delete(particle);
                    continue;
                }
                const target = restoreData.target;
                if (now - restoreData.lastInteractionTime < restoreDelay) {
                    continue;
                }
                let dx = target.x - particle.position.x, dy = target.y - particle.position.y, dz = target.z - particle.position.z;
                if (restore.follow && particle.options.move.enable) {
                    const { x: vx, y: vy, z: vz } = particle.velocity, velocityLengthSq = vx * vx + vy * vy + vz * vz;
                    if (velocityLengthSq > minVelocityLengthSq) {
                        const parallelScale = (dx * vx + dy * vy + dz * vz) / velocityLengthSq;
                        dx -= vx * parallelScale;
                        dy -= vy * parallelScale;
                        dz -= vz * parallelScale;
                    }
                }
                particle.position.x += dx * restoreSpeed;
                particle.position.y += dy * restoreSpeed;
                particle.position.z += dz * restoreSpeed;
                if (Math.abs(dx) <= restoreEpsilon$1 && Math.abs(dy) <= restoreEpsilon$1) {
                    particle.position.x = target.x;
                    particle.position.y = target.y;
                    particle.position.z = target.z;
                    this.#restoreData.delete(particle);
                    continue;
                }
            }
        }
        #trackInteractedParticle(particle) {
            this.#interactedThisFrame.add(particle);
            const restore = this.container.actualOptions.interactivity?.modes.attract?.restore;
            if (!restore?.enable) {
                return;
            }
            const now = Date.now();
            let restoreData = this.#restoreData.get(particle);
            if (!restoreData) {
                restoreData = {
                    target: particle.position.copy(),
                    lastInteractionTime: now,
                };
                this.#restoreData.set(particle, restoreData);
            }
            restoreData.lastInteractionTime = now;
        }
    };

    async function loadExternalAttractInteraction(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register((e) => {
            ensureInteractivityPluginLoaded(e);
            e.pluginManager.addInteractor?.("externalAttract", container => {
                return Promise.resolve(new Attractor$1(e.pluginManager, container));
            });
        });
    }

    const halfPI = Math.PI * half, toleranceFactor$1 = 10;
    function processBounce(container, position, radius, area, enabledCb) {
        const query = container.particles.grid.query(area, enabledCb);
        for (const particle of query) {
            if (area instanceof Circle) {
                circleBounce(circleBounceDataFromParticle(particle), {
                    position,
                    mass: radius ** squareExp * halfPI,
                    velocity: Vector.origin,
                    factor: Vector.origin,
                });
            }
            else if (area instanceof Rectangle) {
                rectBounce(particle, calculateBounds(position, radius));
            }
        }
    }
    function singleSelectorBounce(container, selector, div, bounceCb) {
        const query = safeDocument().querySelectorAll(selector);
        if (!query.length) {
            return;
        }
        query.forEach(item => {
            const elem = item, pxRatio = container.retina.pixelRatio, pos = {
                x: (elem.offsetLeft + elem.offsetWidth * half) * pxRatio,
                y: (elem.offsetTop + elem.offsetHeight * half) * pxRatio,
            }, radius = elem.offsetWidth * half * pxRatio, tolerance = toleranceFactor$1 * pxRatio, area = div.type === DivType.circle
                ? new Circle(pos.x, pos.y, radius + tolerance)
                : new Rectangle(elem.offsetLeft * pxRatio - tolerance, elem.offsetTop * pxRatio - tolerance, elem.offsetWidth * pxRatio + tolerance * double, elem.offsetHeight * pxRatio + tolerance * double);
            bounceCb(pos, radius, area);
        });
    }
    function divBounce(container, divs, bounceMode, enabledCb) {
        divModeExecute(bounceMode, divs, (selector, div) => {
            singleSelectorBounce(container, selector, div, (pos, radius, area) => {
                processBounce(container, pos, radius, area, enabledCb);
            });
        });
    }
    function mouseBounce(container, interactivityData, enabledCb) {
        const pxRatio = container.retina.pixelRatio, tolerance = toleranceFactor$1 * pxRatio, mousePos = interactivityData.mouse.position, radius = container.retina.bounceModeDistance;
        if (!radius || radius < minRadius$5 || !mousePos) {
            return;
        }
        processBounce(container, mousePos, radius, new Circle(mousePos.x, mousePos.y, radius + tolerance), enabledCb);
    }
    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) * half && velocity > minVelocity) ||
            (pSide.min <= rectSide.max && pSide.min > (rectSide.max + rectSide.min) * half && velocity < minVelocity)) {
            res.velocity = velocity * -factor;
            res.bounced = true;
        }
        return res;
    }
    function rectBounce(particle, divBounds) {
        const pPos = particle.getPosition(), size = particle.getRadius(), bounds = calculateBounds(pPos, size), bounceOptions = particle.options.bounce, 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: getRangeValue(bounceOptions.horizontal.value),
        });
        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: getRangeValue(bounceOptions.vertical.value),
        });
        if (resV.bounced) {
            if (resV.velocity !== undefined) {
                particle.velocity.y = resV.velocity;
            }
            if (resV.position !== undefined) {
                particle.position.y = resV.position;
            }
        }
    }

    class Bounce {
        distance = 200;
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadProperty(this, "distance", data.distance);
        }
    }

    const bounceMode = "bounce";
    class Bouncer extends ExternalInteractorBase {
        #maxDistance;
        constructor(container) {
            super(container);
            this.#maxDistance = 0;
        }
        get maxDistance() {
            return this.#maxDistance;
        }
        clear() {
        }
        init() {
            const container = this.container, bounce = container.actualOptions.interactivity?.modes.bounce;
            if (!bounce) {
                return;
            }
            this.#maxDistance = bounce.distance;
            container.retina.bounceModeDistance = bounce.distance * container.retina.pixelRatio;
        }
        interact(interactivityData) {
            const container = this.container, options = container.actualOptions, events = options.interactivity?.events, mouseMoveStatus = interactivityData.status === mouseMoveEvent;
            if (!events) {
                return;
            }
            const hoverEnabled = events.onHover.enable, hoverMode = events.onHover.mode, divs = events.onDiv;
            if (mouseMoveStatus && hoverEnabled && isInArray(bounceMode, hoverMode)) {
                mouseBounce(this.container, interactivityData, p => this.isEnabled(interactivityData, p));
            }
            else {
                divBounce(this.container, divs, bounceMode, p => this.isEnabled(interactivityData, p));
            }
        }
        isEnabled(interactivityData, particle) {
            const container = this.container, options = container.actualOptions, mouse = interactivityData.mouse, events = (particle?.interactivity ?? options.interactivity)?.events;
            if (!events) {
                return false;
            }
            const divs = events.onDiv;
            return ((!!mouse.position && events.onHover.enable && isInArray(bounceMode, events.onHover.mode)) ||
                isDivModeEnabled(bounceMode, divs));
        }
        loadModeOptions(options, ...sources) {
            loadOptionProperty(options, "bounce", Bounce, ...sources);
        }
        reset() {
        }
    }

    async function loadExternalBounceInteraction(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register((e) => {
            ensureInteractivityPluginLoaded(e);
            e.pluginManager.addInteractor?.("externalBounce", container => {
                return Promise.resolve(new Bouncer(container));
            });
        });
    }

    class BubbleBase {
        color;
        distance = 200;
        duration = 0.4;
        mix = false;
        opacity;
        size;
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadProperty(this, "distance", data.distance);
            loadProperty(this, "duration", data.duration);
            loadProperty(this, "mix", data.mix);
            loadRangeProperty(this, "opacity", data.opacity);
            if (data.color !== undefined) {
                const sourceColor = isArray(this.color) ? undefined : this.color;
                this.color = executeOnSingleOrMultiple(data.color, color => {
                    return OptionsColor.create(sourceColor, color);
                });
            }
            loadProperty(this, "size", data.size);
        }
    }

    class BubbleDiv extends BubbleBase {
        selectors = [];
        load(data) {
            super.load(data);
            if (isNull(data)) {
                return;
            }
            loadProperty(this, "selectors", data.selectors);
        }
    }

    class Bubble extends BubbleBase {
        divs;
        load(data) {
            super.load(data);
            if (isNull(data)) {
                return;
            }
            this.divs = executeOnSingleOrMultiple(data.divs, div => {
                const tmp = new BubbleDiv();
                tmp.load(div);
                return tmp;
            });
        }
    }

    class BubbleModifier {
        div;
        enabled = false;
        fillColor;
        finalColor;
        id = "bubble";
        inRange = false;
        opacity;
        priority = 100;
        radius;
        strokeColor;
    }

    var ProcessBubbleType;
    (function (ProcessBubbleType) {
        ProcessBubbleType["color"] = "color";
        ProcessBubbleType["opacity"] = "opacity";
        ProcessBubbleType["size"] = "size";
    })(ProcessBubbleType || (ProcessBubbleType = {}));

    function calculateBubbleValue(particleValue, modeValue, optionsValue, ratio) {
        if (modeValue >= optionsValue) {
            const value = particleValue + (modeValue - optionsValue) * ratio;
            return clamp(value, particleValue, modeValue);
        }
        else if (modeValue < optionsValue) {
            const value = particleValue - (optionsValue - modeValue) * ratio;
            return clamp(value, modeValue, particleValue);
        }
        return undefined;
    }

    const bubbleMode = "bubble", minDistance$5 = 0, defaultClickTime = 0, defaultOpacity$1 = 1, ratioOffset = 1, defaultBubbleValue = 0, minRatio = 0, defaultRatio = 1;
    class Bubbler extends ExternalInteractorBase {
        handleClickMode;
        #maxDistance;
        #modifiers = new WeakMap();
        #pluginManager;
        constructor(pluginManager, container) {
            super(container);
            this.#pluginManager = pluginManager;
            this.#maxDistance = 0;
            container.bubble ??= {};
            this.handleClickMode = (mode) => {
                if (mode !== bubbleMode) {
                    return;
                }
                container.bubble ??= {};
                container.bubble.clicking = true;
            };
        }
        get maxDistance() {
            return this.#maxDistance;
        }
        clear(particle, _delta, force) {
            const mod = this.#modifiers.get(particle);
            if (mod?.inRange && !force) {
                return;
            }
            particle.removeModifier(bubbleMode);
            this.#modifiers.delete(particle);
        }
        getOrCreateModifier(particle) {
            let mod = this.#modifiers.get(particle);
            if (!mod) {
                mod = new BubbleModifier();
                this.#modifiers.set(particle, mod);
                particle.addModifier(mod);
            }
            return mod;
        }
        init() {
            const container = this.container, bubble = container.actualOptions.interactivity?.modes.bubble;
            if (!bubble) {
                return;
            }
            this.#maxDistance = bubble.distance;
            container.retina.bubbleModeDistance = bubble.distance * container.retina.pixelRatio;
            if (bubble.size !== undefined) {
                container.retina.bubbleModeSize = bubble.size * container.retina.pixelRatio;
            }
        }
        interact(interactivityData, delta) {
            const options = this.container.actualOptions, events = options.interactivity?.events;
            if (!events) {
                return;
            }
            const onHover = events.onHover, onClick = events.onClick, hoverEnabled = onHover.enable, hoverMode = onHover.mode, clickEnabled = onClick.enable, clickMode = onClick.mode, divs = events.onDiv;
            if (hoverEnabled && isInArray(bubbleMode, hoverMode)) {
                this.#hoverBubble(interactivityData);
            }
            else if (clickEnabled && isInArray(bubbleMode, clickMode)) {
                this.#clickBubble(interactivityData);
            }
            else {
                divModeExecute(bubbleMode, divs, (selector, div) => {
                    this.#singleSelectorHover(interactivityData, delta, selector, div);
                });
            }
        }
        isEnabled(interactivityData, particle) {
            const container = this.container, options = container.actualOptions, mouse = interactivityData.mouse, events = (particle?.interactivity ?? options.interactivity)?.events;
            if (!events) {
                return false;
            }
            const { onClick, onDiv, onHover } = events, divBubble = isDivModeEnabled(bubbleMode, onDiv);
            if (!(divBubble || (onHover.enable && !!mouse.position) || (onClick.enable && mouse.clickPosition))) {
                return false;
            }
            return isInArray(bubbleMode, onHover.mode) || isInArray(bubbleMode, onClick.mode) || divBubble;
        }
        loadModeOptions(options, ...sources) {
            loadOptionProperty(options, "bubble", Bubble, ...sources);
        }
        reset(_interactivityData, particle) {
            const mod = this.#modifiers.get(particle);
            if (mod) {
                mod.enabled = false;
                mod.inRange = false;
            }
        }
        #clickBubble(interactivityData) {
            const container = this.container, options = container.actualOptions, mouseClickPos = interactivityData.mouse.clickPosition, bubbleOptions = options.interactivity?.modes.bubble;
            if (!bubbleOptions || !mouseClickPos) {
                return;
            }
            container.bubble ??= {};
            const distance = container.retina.bubbleModeDistance;
            if (!distance || distance < minDistance$5) {
                return;
            }
            const query = container.particles.grid.queryCircle(mouseClickPos, distance, p => this.isEnabled(interactivityData, p)), { bubble } = container;
            for (const particle of query) {
                if (!bubble.clicking) {
                    continue;
                }
                const mod = this.getOrCreateModifier(particle);
                mod.enabled = !bubble.durationEnd;
                mod.inRange = !bubble.durationEnd;
                const pos = particle.getPosition(), distMouse = getDistance(pos, mouseClickPos), timeSpent = (performance.now() - (interactivityData.mouse.clickTime ?? defaultClickTime)) / millisecondsToSeconds;
                if (timeSpent > bubbleOptions.duration) {
                    bubble.durationEnd = true;
                }
                if (timeSpent > bubbleOptions.duration * double) {
                    bubble.clicking = false;
                    bubble.durationEnd = false;
                }
                const sizeData = {
                    bubbleObj: {
                        optValue: container.retina.bubbleModeSize,
                        value: mod.radius,
                    },
                    particlesObj: {
                        optValue: particle.size.max,
                        value: particle.size.value,
                    },
                    type: ProcessBubbleType.size,
                };
                this.#process(particle, distMouse, timeSpent, sizeData);
                const opacityData = {
                    bubbleObj: {
                        optValue: bubbleOptions.opacity,
                        value: mod.opacity,
                    },
                    particlesObj: {
                        optValue: particle.opacity?.max ?? defaultOpacity$1,
                        value: particle.opacity?.value ?? defaultOpacity$1,
                    },
                    type: ProcessBubbleType.opacity,
                };
                this.#process(particle, distMouse, timeSpent, opacityData);
                if (!bubble.durationEnd && distMouse <= distance) {
                    this.#hoverBubbleColor(particle, distMouse);
                }
                else {
                    mod.fillColor = undefined;
                    mod.strokeColor = undefined;
                }
            }
        }
        #hoverBubble(interactivityData) {
            const container = this.container, mousePos = interactivityData.mouse.position, distance = container.retina.bubbleModeDistance;
            if (!distance || distance < minDistance$5 || !mousePos) {
                return;
            }
            const query = container.particles.grid.queryCircle(mousePos, distance, p => this.isEnabled(interactivityData, p));
            for (const particle of query) {
                const mod = this.getOrCreateModifier(particle);
                mod.enabled = true;
                mod.inRange = true;
                const pos = particle.getPosition(), pointDistance = getDistance(pos, mousePos), ratio = ratioOffset - pointDistance / distance;
                if (pointDistance <= distance) {
                    if (ratio >= minRatio && interactivityData.status === mouseMoveEvent) {
                        this.#hoverBubbleSize(particle, ratio);
                        this.#hoverBubbleOpacity(particle, ratio);
                        this.#hoverBubbleColor(particle, ratio);
                    }
                }
                else {
                    this.reset(interactivityData, particle);
                }
                if (interactivityData.status === mouseLeaveEvent) {
                    this.reset(interactivityData, particle);
                }
            }
        }
        #hoverBubbleColor(particle, ratio, divBubble) {
            const options = this.container.actualOptions, bubbleOptions = divBubble ?? options.interactivity?.modes.bubble, mod = this.getOrCreateModifier(particle);
            if (!bubbleOptions) {
                return;
            }
            if (!mod.finalColor) {
                const modeColor = bubbleOptions.color;
                if (!modeColor) {
                    return;
                }
                const bubbleColor = itemFromSingleOrMultiple(modeColor);
                mod.finalColor = rangeColorToHsl(this.#pluginManager, bubbleColor);
            }
            if (!mod.finalColor) {
                return;
            }
            if (bubbleOptions.mix) {
                mod.fillColor = undefined;
                mod.strokeColor = undefined;
                const pColor = particle.getFillColor();
                if (pColor) {
                    const mixedColor = rgbToHsl(colorMix(pColor, mod.finalColor, ratioOffset - ratio, ratio, this.container.hdr));
                    mod.fillColor = mixedColor;
                    mod.strokeColor = mixedColor;
                }
                else {
                    mod.fillColor = mod.finalColor;
                    mod.strokeColor = mod.finalColor;
                }
            }
            else {
                mod.fillColor = mod.finalColor;
                mod.strokeColor = mod.finalColor;
            }
        }
        #hoverBubbleOpacity(particle, ratio, divBubble) {
            const container = this.container, options = container.actualOptions, modeOpacity = divBubble?.opacity ?? options.interactivity?.modes.bubble?.opacity;
            if (!modeOpacity) {
                return;
            }
            const pOpacity = particle.opacity?.value ?? defaultOpacity$1, opacity = calculateBubbleValue(pOpacity, modeOpacity, particle.opacity?.max ?? defaultOpacity$1, ratio);
            if (opacity !== undefined) {
                const mod = this.getOrCreateModifier(particle);
                mod.opacity = opacity;
            }
        }
        #hoverBubbleSize(particle, ratio, divBubble) {
            const container = this.container, modeSize = divBubble?.size ? divBubble.size * container.retina.pixelRatio : container.retina.bubbleModeSize;
            if (modeSize === undefined) {
                return;
            }
            const pSize = particle.size.value, size = calculateBubbleValue(pSize, modeSize, particle.size.max, ratio);
            if (size !== undefined) {
                const mod = this.getOrCreateModifier(particle);
                mod.radius = size;
            }
        }
        #process(particle, distMouse, timeSpent, data) {
            const container = this.container, bubbleParam = data.bubbleObj.optValue, options = container.actualOptions, bubbleOptions = options.interactivity?.modes.bubble;
            if (!bubbleOptions || bubbleParam === undefined) {
                return;
            }
            const bubbleDuration = bubbleOptions.duration, bubbleDistance = container.retina.bubbleModeDistance, particlesParam = data.particlesObj.optValue, pObjBubble = data.bubbleObj.value, pObj = data.particlesObj.value ?? defaultBubbleValue, type = data.type;
            if (!bubbleDistance || bubbleDistance < minDistance$5 || bubbleParam === particlesParam) {
                return;
            }
            container.bubble ??= {};
            const mod = this.getOrCreateModifier(particle);
            if (container.bubble.durationEnd) {
                if (pObjBubble) {
                    if (type === ProcessBubbleType.size) {
                        mod.radius = undefined;
                    }
                    if (type === ProcessBubbleType.opacity) {
                        mod.opacity = undefined;
                    }
                }
            }
            else {
                if (distMouse <= bubbleDistance) {
                    const obj = pObjBubble ?? pObj;
                    if (obj !== bubbleParam) {
                        const value = pObj - (timeSpent * (pObj - bubbleParam)) / bubbleDuration;
                        if (type === ProcessBubbleType.size) {
                            mod.radius = value;
                        }
                        if (type === ProcessBubbleType.opacity) {
                            mod.opacity = value;
                        }
                    }
                }
                else {
                    if (type === ProcessBubbleType.size) {
                        mod.radius = undefined;
                    }
                    if (type === ProcessBubbleType.opacity) {
                        mod.opacity = undefined;
                    }
                }
            }
        }
        #singleSelectorHover(interactivityData, delta, selector, div) {
            const container = this.container, selectors = safeDocument().querySelectorAll(selector), bubble = container.actualOptions.interactivity?.modes.bubble;
            if (!bubble || !selectors.length) {
                return;
            }
            selectors.forEach(item => {
                const elem = item, pxRatio = container.retina.pixelRatio, pos = {
                    x: (elem.offsetLeft + elem.offsetWidth * half) * pxRatio,
                    y: (elem.offsetTop + elem.offsetHeight * half) * pxRatio,
                }, repulseRadius = elem.offsetWidth * half * pxRatio, area = div.type === DivType.circle
                    ? new Circle(pos.x, pos.y, repulseRadius)
                    : new Rectangle(elem.offsetLeft * pxRatio, elem.offsetTop * pxRatio, elem.offsetWidth * pxRatio, elem.offsetHeight * pxRatio), query = container.particles.grid.query(area, p => this.isEnabled(interactivityData, p));
                for (const particle of query) {
                    if (!area.contains(particle.getPosition())) {
                        continue;
                    }
                    const mod = this.getOrCreateModifier(particle);
                    mod.enabled = true;
                    mod.inRange = true;
                    const divs = bubble.divs, divBubble = divMode(divs, elem);
                    if (!mod.div || mod.div !== elem) {
                        this.clear(particle, delta, true);
                        mod.div = elem;
                    }
                    this.#hoverBubbleSize(particle, defaultRatio, divBubble);
                    this.#hoverBubbleOpacity(particle, defaultRatio, divBubble);
                    this.#hoverBubbleColor(particle, defaultRatio, divBubble);
                }
            });
        }
    }

    async function loadExternalBubbleInteraction(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register((e) => {
            ensureInteractivityPluginLoaded(e);
            e.pluginManager.addInteractor?.("externalBubble", container => {
                return Promise.resolve(new Bubbler(e.pluginManager, container));
            });
        });
    }

    class ConnectLinks {
        opacity = 0.5;
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadRangeProperty(this, "opacity", data.opacity);
        }
    }

    class Connect {
        distance = 80;
        links = new ConnectLinks();
        radius = 60;
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadProperty(this, "distance", data.distance);
            this.links.load(data.links);
            loadProperty(this, "radius", data.radius);
        }
    }

    const gradientMin = 0, gradientMax = 1, defaultLinksWidth = 0;
    function gradient(container, context, p1, p2, opacity) {
        const gradStop = Math.floor(p2.getRadius() / p1.getRadius()), color1 = p1.getFillColor(), color2 = p2.getFillColor();
        if (!color1 || !color2) {
            return;
        }
        const sourcePos = p1.getPosition(), destPos = p2.getPosition(), midRgb = colorMix(color1, color2, p1.getRadius(), p2.getRadius(), container.hdr), grad = context.createLinearGradient(sourcePos.x, sourcePos.y, destPos.x, destPos.y);
        grad.addColorStop(gradientMin, getStyleFromHsl(color1, container.hdr, opacity, container.peakNits, container.hdrMode));
        grad.addColorStop(clamp(gradStop, gradientMin, gradientMax), getStyleFromRgb(midRgb, container.hdr, opacity, container.peakNits, container.hdrMode));
        grad.addColorStop(gradientMax, getStyleFromHsl(color2, container.hdr, opacity, container.peakNits, container.hdrMode));
        return grad;
    }
    function drawConnectLine(context, width, lineStyle, begin, end) {
        drawLine$1(context, begin, end);
        context.lineWidth = width;
        context.strokeStyle = lineStyle;
        context.stroke();
    }
    function lineStyle(container, ctx, p1, p2) {
        const options = container.actualOptions, connectOptions = options.interactivity?.modes.connect;
        if (!connectOptions) {
            return;
        }
        return gradient(container, ctx, p1, p2, connectOptions.links.opacity);
    }
    function drawConnection(container, p1, p2) {
        container.canvas.render.draw(ctx => {
            const ls = lineStyle(container, ctx, p1, p2);
            if (!ls) {
                return;
            }
            const pos1 = p1.getPosition(), pos2 = p2.getPosition();
            drawConnectLine(ctx, p1.retina.linksWidth ?? defaultLinksWidth, ls, pos1, pos2);
        });
    }

    const connectMode = "connect", minDistance$4 = 0;
    class Connector extends ExternalInteractorBase {
        #maxDistance;
        constructor(container) {
            super(container);
            this.#maxDistance = 0;
        }
        get maxDistance() {
            return this.#maxDistance;
        }
        clear() {
        }
        init() {
            const container = this.container, connect = container.actualOptions.interactivity?.modes.connect;
            if (!connect) {
                return;
            }
            this.#maxDistance = connect.distance;
            container.retina.connectModeDistance = connect.distance * container.retina.pixelRatio;
            container.retina.connectModeRadius = connect.radius * container.retina.pixelRatio;
        }
        interact(interactivityData) {
            const container = this.container, options = container.actualOptions;
            if (options.interactivity?.events.onHover.enable && interactivityData.status === "pointermove") {
                const mousePos = interactivityData.mouse.position, { connectModeDistance, connectModeRadius } = container.retina;
                if (!connectModeDistance ||
                    connectModeDistance < minDistance$4 ||
                    !connectModeRadius ||
                    connectModeRadius < minDistance$4 ||
                    !mousePos) {
                    return;
                }
                const distance = Math.abs(connectModeRadius), query = container.particles.grid.queryCircle(mousePos, distance, p => this.isEnabled(interactivityData, p));
                query.forEach((p1, i) => {
                    const pos1 = p1.getPosition(), indexOffset = 1;
                    for (const p2 of query.slice(i + indexOffset)) {
                        const pos2 = p2.getPosition(), distMax = Math.abs(connectModeDistance), xDiff = Math.abs(pos1.x - pos2.x), yDiff = Math.abs(pos1.y - pos2.y);
                        if (xDiff < distMax && yDiff < distMax) {
                            drawConnection(container, p1, p2);
                        }
                    }
                });
            }
        }
        isEnabled(interactivityData, particle) {
            const container = this.container, mouse = interactivityData.mouse, events = (particle?.interactivity ?? container.actualOptions.interactivity)?.events;
            if (!(events?.onHover.enable && mouse.position)) {
                return false;
            }
            return isInArray(connectMode, events.onHover.mode);
        }
        loadModeOptions(options, ...sources) {
            loadOptionProperty(options, "connect", Connect, ...sources);
        }
        reset() {
        }
    }

    async function loadExternalConnectInteraction(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register((e) => {
            ensureInteractivityPluginLoaded(e);
            e.pluginManager.addInteractor?.("externalConnect", container => {
                return Promise.resolve(new Connector(container));
            });
        });
    }

    const toleranceFactor = 10;
    function processDestroy(container, area) {
        const query = container.particles.grid.query(area);
        for (const particle of query) {
            particle.destroy();
        }
    }
    function singleSelectorDestroy(container, selector, div) {
        const query = safeDocument().querySelectorAll(selector);
        if (!query.length) {
            return;
        }
        query.forEach(item => {
            const elem = item, pxRatio = container.retina.pixelRatio, pos = {
                x: (elem.offsetLeft + elem.offsetWidth * half) * pxRatio,
                y: (elem.offsetTop + elem.offsetHeight * half) * pxRatio,
            }, radius = elem.offsetWidth * half * pxRatio, tolerance = toleranceFactor * pxRatio, area = div.type === DivType.circle
                ? new Circle(pos.x, pos.y, radius + tolerance)
                : new Rectangle(elem.offsetLeft * pxRatio - tolerance, elem.offsetTop * pxRatio - tolerance, elem.offsetWidth * pxRatio + tolerance * double, elem.offsetHeight * pxRatio + tolerance * double);
            processDestroy(container, area);
        });
    }
    function divDestroy(container, divs, destroyMode) {
        divModeExecute(destroyMode, divs, (selector, div) => {
            singleSelectorDestroy(container, selector, div);
        });
    }
    function mouseDestroy(container, interactivityData) {
        const pxRatio = container.retina.pixelRatio, tolerance = toleranceFactor * pxRatio, mousePos = interactivityData.mouse.position, radius = container.retina.destroyModeDistance;
        if (!radius || radius < minRadius$5 || !mousePos) {
            return;
        }
        processDestroy(container, new Circle(mousePos.x, mousePos.y, radius + tolerance));
    }

    class Destroy {
        distance = 200;
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadProperty(this, "distance", data.distance);
        }
    }

    const destroyMode = "destroy";
    class Destroyer extends ExternalInteractorBase {
        #maxDistance;
        constructor(container) {
            super(container);
            this.#maxDistance = 0;
        }
        get maxDistance() {
            return this.#maxDistance;
        }
        clear() {
        }
        init() {
            const container = this.container, destroy = container.actualOptions.interactivity?.modes.destroy;
            if (!destroy) {
                return;
            }
            this.#maxDistance = destroy.distance;
            container.retina.destroyModeDistance = destroy.distance * container.retina.pixelRatio;
        }
        interact(interactivityData) {
            const container = this.container, options = container.actualOptions, events = options.interactivity?.events, mouseMoveStatus = interactivityData.status === mouseMoveEvent;
            if (!events) {
                return;
            }
            const hoverEnabled = events.onHover.enable, hoverMode = events.onHover.mode, divs = events.onDiv;
            if (mouseMoveStatus && hoverEnabled && isInArray(destroyMode, hoverMode)) {
                mouseDestroy(this.container, interactivityData);
            }
            else {
                divDestroy(this.container, divs, destroyMode);
            }
        }
        isEnabled(interactivityData, particle) {
            const container = this.container, options = container.actualOptions, mouse = interactivityData.mouse, events = (particle?.interactivity ?? options.interactivity)?.events;
            if (!events) {
                return false;
            }
            const divs = events.onDiv;
            return ((!!mouse.position && events.onHover.enable && isInArray(destroyMode, events.onHover.mode)) ||
                isDivModeEnabled(destroyMode, divs));
        }
        loadModeOptions(options, ...sources) {
            loadOptionProperty(options, "destroy", Destroy, ...sources);
        }
        reset() {
        }
    }

    async function loadExternalDestroyInteraction(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register((e) => {
            ensureInteractivityPluginLoaded(e);
            e.pluginManager.addInteractor?.("externalDestroy", async (container) => {
                return Promise.resolve(new Destroyer(container));
            });
        });
    }

    class GrabLinks {
        blink = false;
        color;
        consent = false;
        opacity = 1;
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadProperty(this, "blink", data.blink);
            if (data.color !== undefined) {
                this.color = OptionsColor.create(this.color, data.color);
            }
            loadProperty(this, "consent", data.consent);
            loadRangeProperty(this, "opacity", data.opacity);
        }
    }

    class Grab {
        distance = 100;
        links = new GrabLinks();
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadProperty(this, "distance", data.distance);
            this.links.load(data.links);
        }
    }

    const defaultWidth = 0;
    function drawGrabLine(context, width, begin, end, colorLine, opacity, hdr = false, peakNits, mode) {
        drawLine$1(context, begin, end);
        context.strokeStyle = getStyleFromRgb(colorLine, hdr, opacity, peakNits, mode);
        context.lineWidth = width;
        context.stroke();
    }
    function drawGrab(container, particle, lineColor, opacity, mousePos) {
        container.canvas.render.draw(ctx => {
            const beginPos = particle.getPosition();
            drawGrabLine(ctx, particle.retina.linksWidth ?? defaultWidth, beginPos, mousePos, lineColor, opacity, container.hdr, container.peakNits, container.hdrMode);
        });
    }

    const grabMode = "grab", minDistance$3 = 0, minOpacity$1 = 0;
    class Grabber extends ExternalInteractorBase {
        #maxDistance;
        #pluginManager;
        constructor(pluginManager, container) {
            super(container);
            this.#pluginManager = pluginManager;
            this.#maxDistance = 0;
        }
        get maxDistance() {
            return this.#maxDistance;
        }
        clear() {
        }
        init() {
            const container = this.container, grab = container.actualOptions.interactivity?.modes.grab;
            if (!grab) {
                return;
            }
            this.#maxDistance = grab.distance;
            container.retina.grabModeDistance = grab.distance * container.retina.pixelRatio;
        }
        interact(interactivityData) {
            const container = this.container, options = container.actualOptions, interactivity = options.interactivity;
            if (!interactivity?.modes.grab ||
                !interactivity.events.onHover.enable ||
                interactivityData.status !== mouseMoveEvent) {
                return;
            }
            const mousePos = interactivityData.mouse.position;
            if (!mousePos) {
                return;
            }
            const distance = container.retina.grabModeDistance;
            if (!distance || distance < minDistance$3) {
                return;
            }
            const query = container.particles.grid.queryCircle(mousePos, distance, p => this.isEnabled(interactivityData, p));
            for (const particle of query) {
                const pos = particle.getPosition(), pointDistance = getDistance(pos, mousePos);
                if (pointDistance > distance) {
                    continue;
                }
                const grabLineOptions = interactivity.modes.grab.links, lineOpacity = grabLineOptions.opacity, opacityLine = lineOpacity - (pointDistance * lineOpacity) / distance;
                if (opacityLine <= minOpacity$1) {
                    continue;
                }
                const optColor = grabLineOptions.color ?? particle.options.links?.color;
                if (!container.particles.grabLineColor && optColor) {
                    const linksOptions = interactivity.modes.grab.links;
                    container.particles.grabLineColor = getLinkRandomColor(this.#pluginManager, optColor, linksOptions.blink, linksOptions.consent);
                }
                const colorLine = getLinkColor(particle, undefined, container.particles.grabLineColor, container.hdr);
                if (!colorLine) {
                    continue;
                }
                drawGrab(container, particle, colorLine, opacityLine, mousePos);
            }
        }
        isEnabled(interactivityData, particle) {
            const container = this.container, mouse = interactivityData.mouse, events = (particle?.interactivity ?? container.actualOptions.interactivity)?.events;
            return !!events?.onHover.enable && !!mouse.position && isInArray(grabMode, events.onHover.mode);
        }
        loadModeOptions(options, ...sources) {
            loadOptionProperty(options, "grab", Grab, ...sources);
        }
        reset() {
        }
    }

    async function loadExternalGrabInteraction(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register((e) => {
            ensureInteractivityPluginLoaded(e);
            e.pluginManager.addInteractor?.("externalGrab", container => {
                return Promise.resolve(new Grabber(e.pluginManager, container));
            });
        });
    }

    class Parallax {
        force = 2;
        smooth = 10;
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadProperty(this, "force", data.force);
            loadProperty(this, "smooth", data.smooth);
        }
    }

    const parallaxMode = "parallax";
    class Parallaxer extends ExternalInteractorBase {
        maxDistance = 0;
        constructor(container) {
            super(container);
        }
        clear() {
        }
        init() {
        }
        interact(interactivityData) {
            for (const particle of this.container.particles.filter(p => this.isEnabled(interactivityData, p))) {
                this.#parallaxInteract(interactivityData, particle);
            }
        }
        isEnabled(interactivityData, particle) {
            const container = this.container, mouse = interactivityData.mouse, events = (particle?.interactivity ?? container.actualOptions.interactivity)?.events;
            return !!events?.onHover.enable && !!mouse.position && isInArray(parallaxMode, events.onHover.mode);
        }
        loadModeOptions(options, ...sources) {
            loadOptionProperty(options, "parallax", Parallax, ...sources);
        }
        reset() {
        }
        #parallaxInteract(interactivityData, particle) {
            if (!this.isEnabled(interactivityData, particle)) {
                return;
            }
            const container = this.container, options = container.actualOptions, parallaxOptions = options.interactivity?.modes.parallax;
            if (!parallaxOptions) {
                return;
            }
            const parallaxForce = parallaxOptions.force, mousePos = interactivityData.mouse.position;
            if (!mousePos) {
                return;
            }
            const canvasSize = container.canvas.size, canvasCenter = {
                x: canvasSize.width * half,
                y: canvasSize.height * half,
            }, parallaxSmooth = parallaxOptions.smooth, factor = particle.getRadius() / parallaxForce, centerDistance = {
                x: (mousePos.x - canvasCenter.x) * factor,
                y: (mousePos.y - canvasCenter.y) * factor,
            }, { offset } = particle;
            offset.x += (centerDistance.x - offset.x) / parallaxSmooth;
            offset.y += (centerDistance.y - offset.y) / parallaxSmooth;
        }
    }

    async function loadExternalParallaxInteraction(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register((e) => {
            ensureInteractivityPluginLoaded(e);
            e.pluginManager.addInteractor?.("externalParallax", container => {
                return Promise.resolve(new Parallaxer(container));
            });
        });
    }

    const pauseMode = "pause";
    class Pauser extends ExternalInteractorBase {
        handleClickMode;
        maxDistance = 0;
        constructor(container) {
            super(container);
            this.handleClickMode = (mode) => {
                if (mode !== pauseMode) {
                    return;
                }
                const container = this.container;
                if (container.animationStatus) {
                    container.pause();
                }
                else {
                    container.play();
                }
            };
        }
        clear() {
        }
        init() {
        }
        interact() {
        }
        isEnabled(_interactivityData, particle) {
            const container = this.container, options = container.actualOptions, events = (particle?.interactivity ?? options.interactivity)?.events;
            return !!events && isInArray(pauseMode, events.onClick.mode);
        }
        reset() {
        }
    }

    async function loadExternalPauseInteraction(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register((e) => {
            ensureInteractivityPluginLoaded(e);
            e.pluginManager.addInteractor?.("externalPause", container => {
                return Promise.resolve(new Pauser(container));
            });
        });
    }

    class Push {
        default = true;
        groups = [];
        particles;
        quantity = 4;
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadProperty(this, "default", data.default);
            if (data.groups !== undefined) {
                this.groups = data.groups.map(t => t);
            }
            if (!this.groups.length) {
                this.default = true;
            }
            loadRangeProperty(this, "quantity", data.quantity);
            this.particles = executeOnSingleOrMultiple(data.particles, particles => {
                return deepExtend({}, particles);
            });
        }
    }

    const pushMode = "push", minQuantity = 0;
    class Pusher extends ExternalInteractorBase {
        handleClickMode;
        maxDistance = 0;
        constructor(container) {
            super(container);
            this.handleClickMode = (mode, interactivityData) => {
                if (mode !== pushMode) {
                    return;
                }
                const container = this.container, options = container.actualOptions, pushOptions = options.interactivity?.modes.push;
                if (!pushOptions) {
                    return;
                }
                const quantity = getRangeValue(pushOptions.quantity);
                if (quantity <= minQuantity) {
                    return;
                }
                const group = itemFromArray([undefined, ...pushOptions.groups]), groupOptions = group !== undefined ? container.actualOptions.particles.groups[group] : undefined, particlesOptions = itemFromSingleOrMultiple(pushOptions.particles), overrideOptions = deepExtend(groupOptions, particlesOptions);
                container.particles.push(quantity, interactivityData.mouse.position, overrideOptions, group);
            };
        }
        clear() {
        }
        init() {
        }
        interact() {
        }
        isEnabled(interactivityData, particle) {
            const container = this.container, options = container.actualOptions, mouse = interactivityData.mouse, events = (particle?.interactivity ?? options.interactivity)?.events;
            return !!events && mouse.clicking && mouse.inside && !!mouse.position && isInArray(pushMode, events.onClick.mode);
        }
        loadModeOptions(options, ...sources) {
            loadOptionProperty(options, "push", Push, ...sources);
        }
        reset() {
        }
    }

    async function loadExternalPushInteraction(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register((e) => {
            ensureInteractivityPluginLoaded(e);
            e.pluginManager.addInteractor?.("externalPush", container => {
                return Promise.resolve(new Pusher(container));
            });
        });
    }

    class Remove {
        quantity = 2;
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadRangeProperty(this, "quantity", data.quantity);
        }
    }

    const removeMode = "remove";
    class Remover extends ExternalInteractorBase {
        handleClickMode;
        maxDistance = 0;
        constructor(container) {
            super(container);
            this.handleClickMode = (mode) => {
                const container = this.container, options = container.actualOptions;
                if (!options.interactivity?.modes.remove || mode !== removeMode) {
                    return;
                }
                const removeNb = getRangeValue(options.interactivity.modes.remove.quantity);
                for (let i = 0; i < removeNb; i++) {
                    container.particles.get(i)?.destroy();
                }
            };
        }
        clear() {
        }
        init() {
        }
        interact() {
        }
        isEnabled(interactivityData, particle) {
            const container = this.container, options = container.actualOptions, mouse = interactivityData.mouse, events = (particle?.interactivity ?? options.interactivity)?.events;
            return !!events && mouse.clicking && mouse.inside && !!mouse.position && isInArray(removeMode, events.onClick.mode);
        }
        loadModeOptions(options, ...sources) {
            loadOptionProperty(options, "remove", Remove, ...sources);
        }
        reset() {
        }
    }

    async function loadExternalRemoveInteraction(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register((e) => {
            ensureInteractivityPluginLoaded(e);
            e.pluginManager.addInteractor?.("externalRemove", container => {
                return Promise.resolve(new Remover(container));
            });
        });
    }

    class RepulseBase {
        distance = 200;
        duration = 0.4;
        easing = "ease-out-quad";
        factor = 100;
        maxSpeed = 50;
        restore;
        speed = 1;
        constructor() {
            this.restore = {
                enable: false,
                delay: 0,
                speed: 0.08,
                follow: true,
            };
        }
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadProperty(this, "distance", data.distance);
            loadProperty(this, "duration", data.duration);
            loadProperty(this, "easing", data.easing);
            loadProperty(this, "factor", data.factor);
            loadProperty(this, "speed", data.speed);
            loadProperty(this, "maxSpeed", data.maxSpeed);
            if (data.restore !== undefined) {
                this.restore.enable = data.restore.enable ?? this.restore.enable;
                this.restore.delay = data.restore.delay ?? this.restore.delay;
                this.restore.speed = data.restore.speed ?? this.restore.speed;
                this.restore.follow = data.restore.follow ?? this.restore.follow;
            }
        }
    }

    class RepulseDiv extends RepulseBase {
        selectors = [];
        load(data) {
            super.load(data);
            if (isNull(data)) {
                return;
            }
            loadProperty(this, "selectors", data.selectors);
        }
    }

    class Repulse extends RepulseBase {
        divs;
        load(data) {
            super.load(data);
            if (isNull(data)) {
                return;
            }
            this.divs = executeOnSingleOrMultiple(data.divs, div => {
                const tmp = new RepulseDiv();
                tmp.load(div);
                return tmp;
            });
        }
    }

    const repulseMode = "repulse", minDistance$2 = 0, repulseRadiusFactor = 6, repulseRadiusPower = 3, squarePower = 2, minRadius$2 = 0, minSpeed = 0, easingOffset = 1, minRestoreSpeed = 0.001, maxRestoreSpeed = 1, restoreEpsilon = 0.5;
    class Repulser extends ExternalInteractorBase {
        handleClickMode;
        #clickVec;
        #interactedThisFrame;
        #maxDistance;
        #normVec;
        #pluginManager;
        #restoreData;
        constructor(pluginManager, container) {
            super(container);
            this.#pluginManager = pluginManager;
            this.#maxDistance = 0;
            this.#normVec = Vector.origin;
            this.#interactedThisFrame = new Set();
            this.#clickVec = Vector.origin;
            this.#restoreData = new Map();
            container.repulse ??= { particles: [] };
            this.handleClickMode = (mode, interactivityData) => {
                const options = this.container.actualOptions, repulseOpts = options.interactivity?.modes.repulse;
                if (!repulseOpts || mode !== repulseMode) {
                    return;
                }
                container.repulse ??= { particles: [] };
                const repulse = container.repulse;
                repulse.clicking = true;
                repulse.count = 0;
                for (const particle of container.repulse.particles) {
                    if (!this.isEnabled(interactivityData, particle)) {
                        continue;
                    }
                    particle.velocity.setTo(particle.initialVelocity);
                }
                repulse.particles = [];
                repulse.finish = false;
                setTimeout(() => {
                    if (container.destroyed) {
                        return;
                    }
                    repulse.clicking = false;
                }, repulseOpts.duration * millisecondsToSeconds);
            };
        }
        get maxDistance() {
            return this.#maxDistance;
        }
        clear() {
        }
        init() {
            const container = this.container, repulse = container.actualOptions.interactivity?.modes.repulse;
            if (!repulse) {
                return;
            }
            this.#maxDistance = repulse.distance;
            container.retina.repulseModeDistance = repulse.distance * container.retina.pixelRatio;
        }
        interact(interactivityData) {
            this.#interactedThisFrame.clear();
            const container = this.container, options = container.actualOptions, mouseMoveStatus = interactivityData.status === mouseMoveEvent, events = options.interactivity?.events;
            if (!events) {
                return;
            }
            const hover = events.onHover, hoverEnabled = hover.enable, hoverMode = hover.mode, click = events.onClick, clickEnabled = click.enable, clickMode = click.mode, divs = events.onDiv;
            if (mouseMoveStatus && hoverEnabled && isInArray(repulseMode, hoverMode)) {
                this.#hoverRepulse(interactivityData);
            }
            else if (clickEnabled && isInArray(repulseMode, clickMode)) {
                this.#clickRepulse(interactivityData);
            }
            else {
                divModeExecute(repulseMode, divs, (selector, div) => {
                    this.#singleSelectorRepulse(interactivityData, selector, div);
                });
            }
            this.#restoreParticles();
        }
        isEnabled(interactivityData, particle) {
            const container = this.container, options = container.actualOptions, mouse = interactivityData.mouse, events = (particle?.interactivity ?? options.interactivity)?.events;
            if (!events) {
                return false;
            }
            const divs = events.onDiv, hover = events.onHover, click = events.onClick, divRepulse = isDivModeEnabled(repulseMode, divs);
            if (!(divRepulse || (hover.enable && !!mouse.position) || (click.enable && mouse.clickPosition))) {
                return false;
            }
            const hoverMode = hover.mode, clickMode = click.mode;
            return isInArray(repulseMode, hoverMode) || isInArray(repulseMode, clickMode) || divRepulse;
        }
        loadModeOptions(options, ...sources) {
            loadOptionProperty(options, "repulse", Repulse, ...sources);
        }
        reset() {
        }
        #clickRepulse(interactivityData) {
            const container = this.container, repulseOptions = container.actualOptions.interactivity?.modes.repulse;
            if (!repulseOptions) {
                return;
            }
            const repulse = container.repulse ?? { particles: [] };
            if (!repulse.finish) {
                repulse.count ??= 0;
                repulse.count++;
                if (repulse.count === container.particles.count) {
                    repulse.finish = true;
                }
            }
            if (repulse.clicking) {
                const repulseDistance = container.retina.repulseModeDistance;
                if (!repulseDistance || repulseDistance < minDistance$2) {
                    return;
                }
                const repulseRadius = Math.pow(repulseDistance / repulseRadiusFactor, repulseRadiusPower), mouseClickPos = interactivityData.mouse.clickPosition;
                if (mouseClickPos === undefined) {
                    return;
                }
                const range = new Circle(mouseClickPos.x, mouseClickPos.y, repulseRadius), query = container.particles.grid.query(range, p => this.isEnabled(interactivityData, p));
                for (const particle of query) {
                    const { dx, dy, distance } = getDistances(mouseClickPos, particle.position), d = distance ** squarePower, velocity = repulseOptions.speed, force = (-repulseRadius * velocity) / d;
                    if (d <= repulseRadius) {
                        this.#trackInteractedParticle(particle);
                        repulse.particles.push(particle);
                        this.#clickVec.x = dx;
                        this.#clickVec.y = dy;
                        this.#clickVec.length = force;
                        particle.velocity.setTo(this.#clickVec);
                    }
                }
            }
            else if (repulse.clicking === false) {
                for (const particle of repulse.particles) {
                    particle.velocity.setTo(particle.initialVelocity);
                }
                repulse.particles = [];
            }
        }
        #hoverRepulse(interactivityData) {
            const container = this.container, mousePos = interactivityData.mouse.position, repulseRadius = container.retina.repulseModeDistance;
            if (!repulseRadius || repulseRadius < minRadius$2 || !mousePos) {
                return;
            }
            this.#processRepulse(interactivityData, mousePos, repulseRadius, new Circle(mousePos.x, mousePos.y, repulseRadius));
        }
        #processRepulse(interactivityData, position, repulseRadius, area, divRepulse) {
            const container = this.container, query = container.particles.grid.query(area, p => this.isEnabled(interactivityData, p)), repulseOptions = container.actualOptions.interactivity?.modes.repulse;
            if (!repulseOptions) {
                return;
            }
            const { easing, speed, factor, maxSpeed } = repulseOptions, easingFunc = this.#pluginManager.getEasing(easing), velocity = (divRepulse?.speed ?? speed) * factor;
            for (const particle of query) {
                const { dx, dy, distance } = getDistances(particle.position, position), repulseFactor = clamp(easingFunc(easingOffset - distance / repulseRadius) * velocity, minSpeed, maxSpeed);
                this.#normVec.x = !distance ? velocity : (dx / distance) * repulseFactor;
                this.#normVec.y = !distance ? velocity : (dy / distance) * repulseFactor;
                this.#trackInteractedParticle(particle);
                particle.position.addTo(this.#normVec);
            }
        }
        #restoreParticles() {
            const restore = this.container.actualOptions.interactivity?.modes.repulse?.restore;
            if (!restore?.enable || !this.#restoreData.size) {
                return;
            }
            const now = Date.now(), restoreDelay = restore.delay * millisecondsToSeconds, restoreSpeed = Math.max(minRestoreSpeed, Math.min(maxRestoreSpeed, restore.speed));
            for (const [particle, restoreData] of this.#restoreData) {
                if (this.#interactedThisFrame.has(particle)) {
                    continue;
                }
                if (particle.destroyed) {
                    this.#restoreData.delete(particle);
                    continue;
                }
                const target = restoreData.target;
                if (now - restoreData.lastInteractionTime < restoreDelay) {
                    continue;
                }
                if (restore.follow && particle.options.move.enable) {
                    target.x += particle.velocity.x;
                    target.y += particle.velocity.y;
                    target.z += particle.velocity.z;
                }
                const dx = target.x - particle.position.x, dy = target.y - particle.position.y, dz = target.z - particle.position.z;
                particle.position.x += dx * restoreSpeed;
                particle.position.y += dy * restoreSpeed;
                particle.position.z += dz * restoreSpeed;
                if (Math.abs(dx) <= restoreEpsilon && Math.abs(dy) <= restoreEpsilon) {
                    particle.position.x = target.x;
                    particle.position.y = target.y;
                    particle.position.z = target.z;
                    this.#restoreData.delete(particle);
                    continue;
                }
            }
        }
        #singleSelectorRepulse(interactivityData, selector, div) {
            const container = this.container, repulse = container.actualOptions.interactivity?.modes.repulse;
            if (!repulse) {
                return;
            }
            const query = safeDocument().querySelectorAll(selector);
            if (!query.length) {
                return;
            }
            query.forEach(item => {
                const elem = item, pxRatio = container.retina.pixelRatio, pos = {
                    x: (elem.offsetLeft + elem.offsetWidth * half) * pxRatio,
                    y: (elem.offsetTop + elem.offsetHeight * half) * pxRatio,
                }, repulseRadius = elem.offsetWidth * half * pxRatio, area = div.type === DivType.circle
                    ? new Circle(pos.x, pos.y, repulseRadius)
                    : new Rectangle(elem.offsetLeft * pxRatio, elem.offsetTop * pxRatio, elem.offsetWidth * pxRatio, elem.offsetHeight * pxRatio), divs = repulse.divs, divRepulse = divMode(divs, elem);
                this.#processRepulse(interactivityData, pos, repulseRadius, area, divRepulse);
            });
        }
        #trackInteractedParticle(particle) {
            this.#interactedThisFrame.add(particle);
            const restore = this.container.actualOptions.interactivity?.modes.repulse?.restore;
            if (!restore?.enable) {
                return;
            }
            const now = Date.now();
            let restoreData = this.#restoreData.get(particle);
            if (!restoreData) {
                restoreData = {
                    target: particle.position.copy(),
                    lastInteractionTime: now,
                };
                this.#restoreData.set(particle, restoreData);
            }
            restoreData.lastInteractionTime = now;
            if (restore.follow && particle.options.move.enable) {
                restoreData.target.x += particle.velocity.x;
                restoreData.target.y += particle.velocity.y;
                restoreData.target.z += particle.velocity.z;
            }
        }
    }

    async function loadExternalRepulseInteraction(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register((e) => {
            ensureInteractivityPluginLoaded(e);
            const pluginManager = e.pluginManager;
            pluginManager.addInteractor?.("externalRepulse", container => {
                return Promise.resolve(new Repulser(pluginManager, container));
            });
        });
    }

    class Slow {
        factor = 3;
        radius = 200;
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadProperty(this, "factor", data.factor);
            loadProperty(this, "radius", data.radius);
        }
    }

    class SlowModifier {
        enabled = false;
        id = "slow";
        priority = 100;
        speedFactor = 1;
    }

    const slowMode = "slow", minRadius$1 = 0;
    class Slower extends ExternalInteractorBase {
        #maxDistance;
        #modifiers = new WeakMap();
        constructor(container) {
            super(container);
            this.#maxDistance = 0;
        }
        get maxDistance() {
            return this.#maxDistance;
        }
        clear(particle, _delta, force) {
            const mod = this.#modifiers.get(particle);
            if (mod?.enabled && !force) {
                return;
            }
            particle.removeModifier(slowMode);
            this.#modifiers.delete(particle);
        }
        getOrCreateModifier(particle) {
            let mod = this.#modifiers.get(particle);
            if (!mod) {
                mod = new SlowModifier();
                this.#modifiers.set(particle, mod);
                particle.addModifier(mod);
            }
            return mod;
        }
        init() {
            const container = this.container, slow = container.actualOptions.interactivity?.modes.slow;
            if (!slow) {
                return;
            }
            this.#maxDistance = slow.radius;
            container.retina.slowModeRadius = slow.radius * container.retina.pixelRatio;
        }
        interact() {
        }
        isEnabled(interactivityData, particle) {
            const container = this.container, mouse = interactivityData.mouse, events = (particle?.interactivity ?? container.actualOptions.interactivity)?.events;
            return !!events?.onHover.enable && !!mouse.position && isInArray(slowMode, events.onHover.mode);
        }
        loadModeOptions(options, ...sources) {
            loadOptionProperty(options, "slow", Slow, ...sources);
        }
        reset(interactivityData, particle) {
            const mod = this.#modifiers.get(particle);
            if (mod) {
                mod.enabled = false;
            }
            const container = this.container, options = container.actualOptions, mousePos = interactivityData.mouse.position, radius = container.retina.slowModeRadius, slowOptions = options.interactivity?.modes.slow;
            if (!slowOptions || !radius || radius < minRadius$1 || !mousePos) {
                return;
            }
            const particlePos = particle.getPosition(), dist = getDistance(mousePos, particlePos), proximityFactor = dist / radius, slowFactor = slowOptions.factor;
            if (dist > radius) {
                return;
            }
            const activeMod = this.getOrCreateModifier(particle);
            activeMod.enabled = true;
            activeMod.speedFactor = proximityFactor / slowFactor;
        }
    }

    async function loadExternalSlowInteraction(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register((e) => {
            ensureInteractivityPluginLoaded(e);
            e.pluginManager.addInteractor?.("externalSlow", container => {
                return Promise.resolve(new Slower(container));
            });
        });
    }

    const shapeTypes = ["image", "images"];
    const stringStart = 0, defaultOpacity = 1;
    const currentColorRegex = /(#(?:[0-9a-f]{2}){2,4}|(#[0-9a-f]{3})|(rgb|hsl)a?\((-?\d+%?[,\s]+){2,3}\s*[\d.]+%?\))|currentcolor/gi;
    function replaceColorSvg(imageShape, color, opacity, hdr = false, peakNits, mode) {
        const { svgData } = imageShape;
        if (!svgData) {
            return "";
        }
        const colorStyle = getStyleFromHsl(color, hdr, opacity, peakNits, mode);
        if (svgData.includes("fill")) {
            return svgData.replaceAll(currentColorRegex, () => colorStyle);
        }
        const preFillIndex = svgData.indexOf(">");
        return `${svgData.substring(stringStart, preFillIndex)} fill="${colorStyle}"${svgData.substring(preFillIndex)}`;
    }
    async function loadImage(image) {
        return new Promise(resolve => {
            image.loading = true;
            const img = new Image();
            image.element = img;
            img.addEventListener("load", () => {
                image.loading = false;
                resolve();
            });
            img.addEventListener("error", () => {
                image.element = undefined;
                image.error = true;
                image.loading = false;
                getLogger().error(`Error loading image: ${image.source}`);
                resolve();
            });
            img.src = image.source;
        });
    }
    async function downloadSvgImage(image) {
        if (image.type !== "svg") {
            await loadImage(image);
            return;
        }
        image.loading = true;
        const response = await fetch(image.source);
        if (response.ok) {
            image.svgData = await response.text();
        }
        else {
            getLogger().error("Image not found");
            image.error = true;
        }
        image.loading = false;
    }
    function replaceImageColor(image, imageData, color, particle, hdr = false, peakNits, mode) {
        const svgColoredData = replaceColorSvg(image, color, particle.opacity?.value ?? defaultOpacity, hdr, peakNits, mode), imageRes = {
            color,
            data: {
                ...image,
                svgData: svgColoredData,
            },
            loaded: false,
            ratio: imageData.width / imageData.height,
            replaceColor: imageData.replaceColor,
            source: imageData.src,
        };
        return new Promise(resolve => {
            const svg = new Blob([svgColoredData], { type: "image/svg+xml" }), url = URL.createObjectURL(svg), img = new Image();
            img.addEventListener("load", () => {
                imageRes.loaded = true;
                imageRes.element = img;
                resolve(imageRes);
                URL.revokeObjectURL(url);
            });
            const errorHandler = async () => {
                URL.revokeObjectURL(url);
                const img2 = {
                    ...image,
                    error: false,
                    loading: true,
                };
                await loadImage(img2);
                imageRes.loaded = true;
                imageRes.element = img2.element;
                resolve(imageRes);
            };
            img.addEventListener("error", () => void errorHandler());
            img.src = url;
        });
    }

    const sides$3 = 12;
    class ImageDrawer {
        #container;
        #engine;
        constructor(engine, container) {
            this.#engine = engine;
            this.#container = container;
        }
        draw(data) {
            const { context, radius, particle, opacity } = data, image = particle.image, element = image?.element;
            if (!image) {
                return;
            }
            context.globalAlpha = opacity;
            if (element) {
                const ratio = image.ratio, pos = {
                    x: -radius,
                    y: -radius,
                }, diameter = radius * double;
                context.drawImage(element, pos.x, pos.y, diameter, diameter / ratio);
            }
            context.globalAlpha = defaultAlpha$1;
        }
        getSidesCount() {
            return sides$3;
        }
        async init(container) {
            const options = container.actualOptions;
            if (!options.preload || !this.#engine.loadImage) {
                return;
            }
            const promises = [];
            for (const imageData of options.preload) {
                promises.push(this.#engine.loadImage(container, imageData));
            }
            await Promise.all(promises);
        }
        loadShape(particle) {
            const container = this.#container;
            if (!particle.shape || !shapeTypes.includes(particle.shape)) {
                return;
            }
            const imageData = particle.shapeData;
            if (!imageData) {
                return;
            }
            const images = this.#engine.getImages?.(container), image = images?.find((t) => t.name === imageData.name || t.source === imageData.src);
            if (image) {
                return;
            }
            void this.#loadImageShape(container, imageData).then(() => {
                this.loadShape(particle);
            });
        }
        particleInit(container, particle) {
            if (particle.shape !== "image" && particle.shape !== "images") {
                return;
            }
            const images = this.#engine.getImages?.(container), imageData = particle.shapeData;
            if (!imageData) {
                return;
            }
            const color = particle.getFillColor(), image = images?.find((t) => t.name === imageData.name || t.source === imageData.src);
            if (!image) {
                return;
            }
            const replaceColor = imageData.replaceColor;
            if (image.loading) {
                setTimeout(() => {
                    this.particleInit(container, particle);
                });
                return;
            }
            void (async () => {
                let imageRes;
                if (image.svgData && color) {
                    imageRes = await replaceImageColor(image, imageData, color, particle, container.hdr, container.peakNits, container.hdrMode);
                }
                else {
                    imageRes = {
                        color,
                        data: image,
                        element: image.element,
                        loaded: true,
                        ratio: imageData.width && imageData.height ? imageData.width / imageData.height : (image.ratio ?? defaultRatio$1),
                        replaceColor: replaceColor,
                        source: imageData.src,
                    };
                }
                if (!imageRes.ratio) {
                    imageRes.ratio = 1;
                }
                const close = imageData.close ?? particle.shapeClose, imageShape = {
                    image: imageRes,
                    close,
                };
                particle.image = imageShape.image;
                particle.shapeClose = imageShape.close;
            })();
        }
        #loadImageShape = async (container, imageShape) => {
            if (!this.#engine.loadImage) {
                throw new Error(`Image shape not initialized`);
            }
            await this.#engine.loadImage(container, {
                name: imageShape.name,
                replaceColor: imageShape.replaceColor,
                src: imageShape.src,
            });
        };
    }

    class Preload {
        height;
        name;
        replaceColor;
        src = "";
        width;
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadProperty(this, "height", data.height);
            loadProperty(this, "name", data.name);
            loadProperty(this, "replaceColor", data.replaceColor);
            loadProperty(this, "src", data.src);
            loadProperty(this, "width", data.width);
        }
    }

    class ImagePreloaderPlugin {
        id = "image-preloader";
        #engine;
        constructor(engine) {
            this.#engine = engine;
        }
        async getPlugin(container) {
            const { ImagePreloaderInstance } = await Promise.resolve().then(function () { return ImagePreloaderInstance$1; });
            return new ImagePreloaderInstance(this.#engine, container);
        }
        loadOptions(_container, options, source) {
            if (!source?.preload) {
                return;
            }
            options.preload ??= [];
            const preloadOptions = options.preload;
            for (const item of source.preload) {
                const existing = preloadOptions.find(t => t.name === item.name || t.src === item.src);
                if (existing) {
                    existing.load(item);
                }
                else {
                    const preload = new Preload();
                    preload.load(item);
                    preloadOptions.push(preload);
                }
            }
        }
        needsPlugin() {
            return true;
        }
    }

    const extLength = 3;
    function addLoadImageToEngine(engine) {
        engine.getImages ??= (container) => {
            engine.images ??= new Map();
            let images = engine.images.get(container);
            if (!images) {
                images = [];
                engine.images.set(container, images);
            }
            return images;
        };
        engine.loadImage ??= async (container, data) => {
            if (!engine.getImages) {
                throw new Error("No images collection found");
            }
            if (!data.name && !data.src) {
                throw new Error("No image source provided");
            }
            engine.images ??= new Map();
            const containerImages = engine.getImages(container);
            if (containerImages.some((t) => t.name === data.name || t.source === data.src)) {
                return;
            }
            try {
                const image = {
                    name: data.name ?? data.src,
                    source: data.src,
                    type: data.src.substring(data.src.length - extLength),
                    error: false,
                    loading: true,
                    replaceColor: data.replaceColor,
                    ratio: data.width && data.height ? data.width / data.height : undefined,
                };
                containerImages.push(image);
                engine.images.set(container, containerImages);
                let imageFunc;
                if (data.replaceColor) {
                    imageFunc = downloadSvgImage;
                }
                else {
                    imageFunc = loadImage;
                }
                await imageFunc(image);
            }
            catch {
                throw new Error(`${data.name ?? data.src} not found`);
            }
        };
    }
    async function loadImageShape(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register(e => {
            addLoadImageToEngine(e);
            e.pluginManager.addPlugin(new ImagePreloaderPlugin(e));
            e.pluginManager.addShape(shapeTypes, container => Promise.resolve(new ImageDrawer(e, container)));
        });
    }

    class LifeDelay extends ValueWithRandom {
        sync = false;
        load(data) {
            if (isNull(data)) {
                return;
            }
            super.load(data);
            loadProperty(this, "sync", data.sync);
        }
    }

    class LifeDuration extends ValueWithRandom {
        sync = false;
        load(data) {
            if (isNull(data)) {
                return;
            }
            super.load(data);
            loadProperty(this, "sync", data.sync);
        }
    }

    class Life {
        count = 0;
        delay = new LifeDelay();
        duration = new LifeDuration();
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadProperty(this, "count", data.count);
            this.delay.load(data.delay);
            this.duration.load(data.duration);
        }
    }

    const noTime$1 = 0, infiniteValue$1 = -1, noLife = 0, minCanvasSize = 0;
    function updateLife(particle, delta, canvasSize) {
        if (!particle.life) {
            return;
        }
        const life = particle.life;
        let justSpawned = false;
        if (particle.spawning) {
            life.delayTime += delta.value;
            if (life.delayTime >= particle.life.delay) {
                justSpawned = true;
                particle.spawning = false;
                life.delayTime = noTime$1;
                life.time = noTime$1;
            }
            else {
                return;
            }
        }
        if (life.duration === infiniteValue$1) {
            return;
        }
        if (justSpawned) {
            life.time = noTime$1;
        }
        else {
            life.time += delta.value;
        }
        if (life.time < life.duration) {
            return;
        }
        life.time = noTime$1;
        if (particle.life.count > noLife) {
            particle.life.count--;
        }
        if (particle.life.count === noLife) {
            particle.destroy();
            return;
        }
        const widthRange = setRangeValue(minCanvasSize, canvasSize.width), heightRange = setRangeValue(minCanvasSize, canvasSize.width);
        particle.position.x = randomInRangeValue(widthRange);
        particle.position.y = randomInRangeValue(heightRange);
        particle.spawning = true;
        life.delayTime = noTime$1;
        life.time = noTime$1;
        particle.reset();
        const lifeOptions = particle.options.life;
        if (lifeOptions) {
            life.delay = getRangeValue(lifeOptions.delay.value) * millisecondsToSeconds;
            life.duration = getRangeValue(lifeOptions.duration.value) * millisecondsToSeconds;
        }
    }

    const noTime = 0, identity$1 = 1, infiniteValue = -1;
    class LifeUpdater {
        #container;
        constructor(container) {
            this.#container = container;
        }
        init(particle) {
            const container = this.#container, particlesOptions = particle.options, lifeOptions = particlesOptions.life;
            if (!lifeOptions) {
                return;
            }
            const delayFactor = lifeOptions.delay.sync ? identity$1 : getRandom(), durationFactor = lifeOptions.duration.sync ? identity$1 : getRandom();
            particle.life = {
                delay: container.retina.reduceFactor
                    ? ((getRangeValue(lifeOptions.delay.value) * delayFactor) / container.retina.reduceFactor) *
                        millisecondsToSeconds
                    : noTime,
                delayTime: noTime,
                duration: container.retina.reduceFactor
                    ? ((getRangeValue(lifeOptions.duration.value) * durationFactor) / container.retina.reduceFactor) *
                        millisecondsToSeconds
                    : noTime,
                time: noTime,
                count: lifeOptions.count,
            };
            if (particle.life.duration <= noTime) {
                particle.life.duration = infiniteValue;
            }
            if (particle.life.count <= noTime) {
                particle.life.count = infiniteValue;
            }
            particle.spawning = particle.life.delay > noTime;
        }
        isEnabled(particle) {
            return !particle.destroyed;
        }
        loadOptions(options, ...sources) {
            loadOptionProperty(options, "life", Life, ...sources);
        }
        update(particle, delta) {
            if (!this.isEnabled(particle) || !particle.life) {
                return;
            }
            updateLife(particle, delta, this.#container.canvas.size);
        }
    }

    async function loadLifeUpdater(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register(e => {
            e.pluginManager.addParticleUpdater("life", container => {
                return Promise.resolve(new LifeUpdater(container));
            });
        });
    }

    function drawLine(data) {
        const { context, particle, radius } = data, shapeData = particle.shapeData, centerY = 0;
        context.moveTo(-radius, centerY);
        context.lineTo(radius, centerY);
        context.lineCap = shapeData?.cap ?? "butt";
    }

    const sides$2 = 1;
    class LineDrawer {
        draw(data) {
            drawLine(data);
        }
        getSidesCount() {
            return sides$2;
        }
    }

    async function loadLineShape(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register(e => {
            e.pluginManager.addShape(["line"], () => Promise.resolve(new LineDrawer()));
        });
    }

    class Attract {
        distance = 200;
        enable = false;
        rotate;
        constructor() {
            this.rotate = {
                x: 3000,
                y: 3000,
            };
        }
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadRangeProperty(this, "distance", data.distance);
            loadProperty(this, "enable", data.enable);
            if (data.rotate) {
                const rotateX = data.rotate.x;
                if (rotateX !== undefined) {
                    this.rotate.x = rotateX;
                }
                const rotateY = data.rotate.y;
                if (rotateY !== undefined) {
                    this.rotate.y = rotateY;
                }
            }
        }
    }

    const attractFactor = 1000, identity = 1;
    class Attractor extends ParticlesInteractorBase {
        #maxDistance;
        constructor(container) {
            super(container);
            this.#maxDistance = 0;
        }
        get maxDistance() {
            return this.#maxDistance;
        }
        clear() {
        }
        init() {
        }
        interact(p1) {
            if (!p1.options.attract?.enable) {
                return;
            }
            const container = this.container;
            if (isNull(p1.attractDistance)) {
                const attractDistance = getRangeValue(p1.options.attract.distance);
                if (attractDistance > this.#maxDistance) {
                    this.#maxDistance = attractDistance;
                }
                p1.attractDistance = attractDistance * container.retina.pixelRatio;
            }
            const distance = p1.attractDistance, pos1 = p1.getPosition(), query = container.particles.grid.queryCircle(pos1, distance);
            for (const p2 of query) {
                if (p1 === p2 || !p2.options.attract?.enable || p2.destroyed || p2.spawning) {
                    continue;
                }
                const pos2 = p2.getPosition(), { dx, dy } = getDistances(pos1, pos2), rotate = p1.options.attract.rotate, ax = dx / (rotate.x * attractFactor), ay = dy / (rotate.y * attractFactor), p1Factor = p2.size.value / p1.size.value, p2Factor = identity / p1Factor;
                p1.velocity.x -= ax * p1Factor;
                p1.velocity.y -= ay * p1Factor;
                p2.velocity.x += ax * p2Factor;
                p2.velocity.y += ay * p2Factor;
            }
        }
        isEnabled(particle) {
            return particle.options.attract?.enable ?? false;
        }
        loadParticlesOptions(options, ...sources) {
            loadOptionProperty(options, "attract", Attract, ...sources);
        }
        reset() {
        }
    }

    async function loadParticlesAttractInteraction(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register((e) => {
            ensureInteractivityPluginLoaded(e);
            e.pluginManager.addInteractor?.("particlesAttract", container => {
                return Promise.resolve(new Attractor(container));
            });
        });
    }

    var CollisionMode;
    (function (CollisionMode) {
        CollisionMode["absorb"] = "absorb";
        CollisionMode["bounce"] = "bounce";
        CollisionMode["destroy"] = "destroy";
    })(CollisionMode || (CollisionMode = {}));

    class CollisionsAbsorb {
        speed = 2;
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadProperty(this, "speed", data.speed);
        }
    }

    class CollisionsOverlap {
        enable = true;
        retries = 0;
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadProperty(this, "enable", data.enable);
            loadProperty(this, "retries", data.retries);
        }
    }

    class Collisions {
        absorb = new CollisionsAbsorb();
        bounce = new ParticlesBounce();
        enable = false;
        maxSpeed = 50;
        mode = CollisionMode.bounce;
        overlap = new CollisionsOverlap();
        load(data) {
            if (isNull(data)) {
                return;
            }
            this.absorb.load(data.absorb);
            this.bounce.load(data.bounce);
            loadProperty(this, "enable", data.enable);
            loadRangeProperty(this, "maxSpeed", data.maxSpeed);
            loadProperty(this, "mode", data.mode);
            this.overlap.load(data.overlap);
        }
    }

    const minAbsorbAmount = 0;
    function updateAbsorb(p1, r1, p2, r2, delta, pixelRatio) {
        if (!p1.options.collisions || !p2.options.collisions) {
            return;
        }
        const absorbSpeed = p1.options.collisions.absorb.speed, shrinkAmount = clamp(absorbSpeed * delta.factor, minAbsorbAmount, r2);
        p1.size.value = Math.sqrt(r1 * r1 + shrinkAmount * shrinkAmount);
        p2.size.value -= shrinkAmount;
        if (p2.size.value <= pixelRatio) {
            p2.size.value = 0;
            p2.destroy();
        }
    }
    function absorb(p1, p2, delta, pixelRatio) {
        const r1 = p1.getRadius(), r2 = p2.getRadius();
        if (!r1 && r2) {
            p1.destroy();
        }
        else if (r1 && !r2) {
            p2.destroy();
        }
        else if (r1 && r2) {
            if (r1 >= r2) {
                updateAbsorb(p1, r1, p2, r2, delta, pixelRatio);
            }
            else {
                updateAbsorb(p2, r2, p1, r1, delta, pixelRatio);
            }
        }
    }

    const energyCorrectionMinRatio = 1e-6, energyDriftThreshold = 1e-4, correctionFactorNeutral = 1, fixBounceSpeed = (p) => {
        if (!p.options.collisions) {
            return;
        }
        p.collisionMaxSpeed ??= getRangeValue(p.options.collisions.maxSpeed);
        if (p.velocity.length > p.collisionMaxSpeed) {
            p.velocity.length = p.collisionMaxSpeed;
        }
    };
    function bounce(p1, p2) {
        const m1 = p1.getMass(), m2 = p2.getMass(), speed1Before = p1.velocity.length, speed2Before = p2.velocity.length, keBefore = m1 * speed1Before * speed1Before + m2 * speed2Before * speed2Before;
        circleBounce(circleBounceDataFromParticle(p1), circleBounceDataFromParticle(p2));
        const speed1After = p1.velocity.length, speed2After = p2.velocity.length, keAfter = m1 * speed1After * speed1After + m2 * speed2After * speed2After;
        if (keAfter > keBefore * energyCorrectionMinRatio) {
            const correctionFactor = Math.sqrt(keBefore / keAfter);
            if (Math.abs(correctionFactor - correctionFactorNeutral) > energyDriftThreshold) {
                p1.velocity.length = speed1After * correctionFactor;
                p2.velocity.length = speed2After * correctionFactor;
            }
        }
        fixBounceSpeed(p1);
        fixBounceSpeed(p2);
    }

    function destroy(p1, p2) {
        if (!p1.unbreakable && !p2.unbreakable) {
            bounce(p1, p2);
        }
        const p1Radius = p1.getRadius(), p2Radius = p2.getRadius();
        if (!p1Radius && p2Radius) {
            p1.destroy();
        }
        else if (p1Radius && !p2Radius) {
            p2.destroy();
        }
        else if (p1Radius && p2Radius) {
            const deleteP = p1.getRadius() >= p2.getRadius() ? p2 : p1;
            deleteP.destroy();
        }
    }

    function resolveCollision(p1, p2, delta, pixelRatio) {
        if (!p1.options.collisions || !p2.options.collisions) {
            return;
        }
        switch (p1.options.collisions.mode) {
            case CollisionMode.absorb: {
                absorb(p1, p2, delta, pixelRatio);
                break;
            }
            case CollisionMode.bounce: {
                bounce(p1, p2);
                break;
            }
            case CollisionMode.destroy: {
                destroy(p1, p2);
                break;
            }
        }
    }

    class Collider extends ParticlesInteractorBase {
        maxDistance;
        constructor(container) {
            super(container);
            this.maxDistance = 0;
        }
        clear() {
        }
        init() {
        }
        interact(p1, _interactivityData, delta) {
            if (p1.destroyed || p1.spawning) {
                return;
            }
            const container = this.container, pos1 = p1.getPosition(), radius1 = p1.getRadius(), query = container.particles.grid.queryCircle(pos1, radius1 * double);
            for (const p2 of query) {
                if (p1 === p2 ||
                    p1.id >= p2.id ||
                    !p1.options.collisions?.enable ||
                    !p2.options.collisions?.enable ||
                    p1.options.collisions.mode !== p2.options.collisions.mode ||
                    p2.destroyed ||
                    p2.spawning) {
                    continue;
                }
                const pos2 = p2.getPosition(), radius2 = p2.getRadius();
                if (Math.abs(Math.round(pos1.z) - Math.round(pos2.z)) > radius1 + radius2) {
                    continue;
                }
                const dist = getDistance(pos1, pos2), distP = radius1 + radius2;
                if (dist > distP) {
                    continue;
                }
                resolveCollision(p1, p2, delta, container.retina.pixelRatio);
            }
        }
        isEnabled(particle) {
            return !!particle.options.collisions?.enable;
        }
        loadParticlesOptions(options, ...sources) {
            loadOptionProperty(options, "collisions", Collisions, ...sources);
        }
        reset() {
        }
    }

    class OverlapPlugin {
        id = "overlap";
        async getPlugin(container) {
            const { OverlapPluginInstance } = await Promise.resolve().then(function () { return OverlapPluginInstance$1; });
            return new OverlapPluginInstance(container);
        }
        loadOptions() {
        }
        needsPlugin() {
            return true;
        }
    }

    async function loadParticlesCollisionsInteraction(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register((e) => {
            ensureInteractivityPluginLoaded(e);
            e.pluginManager.addPlugin(new OverlapPlugin());
            e.pluginManager.addInteractor?.("particlesCollisions", container => {
                return Promise.resolve(new Collider(container));
            });
        });
    }

    class CircleWarp extends Circle {
        #canvasSize;
        constructor(x, y, radius, canvasSize) {
            super(x, y, radius);
            this.#canvasSize = canvasSize;
        }
        contains(point) {
            if (super.contains(point))
                return true;
            const { width, height } = this.#canvasSize, { x, y } = point;
            return (super.contains({ x: x - width, y }) ||
                super.contains({ x: x + width, y }) ||
                super.contains({ x, y: y - height }) ||
                super.contains({ x, y: y + height }) ||
                super.contains({ x: x - width, y: y - height }) ||
                super.contains({ x: x + width, y: y + height }) ||
                super.contains({ x: x - width, y: y + height }) ||
                super.contains({ x: x + width, y: y - height }));
        }
        intersects(range) {
            if (super.intersects(range))
                return true;
            const { width, height } = this.#canvasSize, pos = range.position, shifts = [
                { x: -width, y: 0 },
                { x: width, y: 0 },
                { x: 0, y: -height },
                { x: 0, y: height },
                { x: -width, y: -height },
                { x: width, y: height },
                { x: -width, y: height },
                { x: width, y: -height },
            ];
            for (const shift of shifts) {
                const shiftedPos = { x: pos.x + shift.x, y: pos.y + shift.y };
                let shiftedRange;
                if (range instanceof Circle) {
                    shiftedRange = new Circle(shiftedPos.x, shiftedPos.y, range.radius);
                }
                else {
                    const rect = range;
                    shiftedRange = new Rectangle(shiftedPos.x, shiftedPos.y, rect.size.width, rect.size.height);
                }
                if (super.intersects(shiftedRange))
                    return true;
            }
            return false;
        }
    }

    class LinksShadow {
        blur = 5;
        color = new OptionsColor();
        enable = false;
        constructor() {
            this.color.value = "#000";
        }
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadProperty(this, "blur", data.blur);
            this.color = OptionsColor.create(this.color, data.color);
            loadProperty(this, "enable", data.enable);
        }
    }

    class LinksTriangle {
        color;
        enable = false;
        frequency = 1;
        opacity;
        load(data) {
            if (isNull(data)) {
                return;
            }
            if (data.color !== undefined) {
                this.color = OptionsColor.create(this.color, data.color);
            }
            loadProperty(this, "enable", data.enable);
            loadProperty(this, "frequency", data.frequency);
            loadProperty(this, "opacity", data.opacity);
        }
    }

    class Links {
        blink = false;
        color = new OptionsColor();
        consent = false;
        distance = 100;
        enable = false;
        frequency = 1;
        id;
        opacity = 1;
        shadow = new LinksShadow();
        triangles = new LinksTriangle();
        warp = false;
        width = 1;
        constructor() {
            this.color.value = "#fff";
        }
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadProperty(this, "id", data.id);
            loadProperty(this, "blink", data.blink);
            this.color = OptionsColor.create(this.color, data.color);
            loadProperty(this, "consent", data.consent);
            loadProperty(this, "distance", data.distance);
            loadProperty(this, "enable", data.enable);
            loadProperty(this, "frequency", data.frequency);
            loadProperty(this, "opacity", data.opacity);
            this.shadow.load(data.shadow);
            this.triangles.load(data.triangles);
            loadProperty(this, "width", data.width);
            loadProperty(this, "warp", data.warp);
        }
    }

    const opacityOffset = 1, minDistance$1 = 0;
    function getWarpDistance(pos1, pos2, canvasSize) {
        const { dx, dy } = getDistances(pos1, pos2), absDiffs = { x: Math.abs(dx), y: Math.abs(dy) }, warpDistances = {
            x: Math.min(absDiffs.x, canvasSize.width - absDiffs.x),
            y: Math.min(absDiffs.y, canvasSize.height - absDiffs.y),
        };
        return Math.hypot(warpDistances.x, warpDistances.y);
    }
    class Linker extends ParticlesInteractorBase {
        #maxDistance;
        #pluginManager;
        constructor(pluginManager, container) {
            super(container);
            this.#pluginManager = pluginManager;
            this.#maxDistance = 0;
        }
        get maxDistance() {
            return this.#maxDistance;
        }
        clear() {
        }
        init() {
            this.container.particles.linksColor = undefined;
            this.container.particles.linksColors = new Map();
        }
        interact(p1) {
            if (!p1.options.links) {
                return;
            }
            p1.links = [];
            if (p1.linksDistance && p1.linksDistance > this.#maxDistance) {
                this.#maxDistance = p1.linksDistance;
            }
            const pos1 = p1.getPosition(), container = this.container, canvasSize = container.canvas.size;
            if (pos1.x < originPoint.x || pos1.y < originPoint.y || pos1.x > canvasSize.width || pos1.y > canvasSize.height) {
                return;
            }
            const linkOpt1 = p1.options.links, optOpacity = linkOpt1.opacity, optDistance = p1.retina.linksDistance ?? minDistance$1, warp = linkOpt1.warp, range = warp ? new CircleWarp(pos1.x, pos1.y, optDistance, canvasSize) : new Circle(pos1.x, pos1.y, optDistance), query = container.particles.grid.query(range);
            for (const p2 of query) {
                const linkOpt2 = p2.options.links;
                if (p1 === p2 ||
                    !linkOpt2?.enable ||
                    linkOpt1.id !== linkOpt2.id ||
                    p2.spawning ||
                    p2.destroyed ||
                    !p2.links ||
                    p1.links.some(t => t.destination === p2) ||
                    p2.links.some(t => t.destination === p1)) {
                    continue;
                }
                const pos2 = p2.getPosition();
                if (pos2.x < originPoint.x || pos2.y < originPoint.y || pos2.x > canvasSize.width || pos2.y > canvasSize.height) {
                    continue;
                }
                const distDirect = getDistances(pos1, pos2).distance, distWarp = warp && linkOpt2.warp ? getWarpDistance(pos1, pos2, canvasSize) : distDirect, distance = Math.min(distDirect, distWarp);
                if (distance > optDistance) {
                    continue;
                }
                const opacityLine = (opacityOffset - distance / optDistance) * optOpacity;
                this.#setColor(p1);
                p1.links.push({
                    destination: p2,
                    opacity: opacityLine,
                    color: this.#getLinkColor(p1, p2),
                    isWarped: distWarp < distDirect,
                });
            }
        }
        isEnabled(particle) {
            return !!particle.options.links?.enable;
        }
        loadParticlesOptions(options, ...sources) {
            loadOptionProperty(options, "links", Links, ...sources);
        }
        reset() {
        }
        #getLinkColor(p1, p2) {
            const container = this.container, linksOptions = p1.options.links;
            if (!linksOptions) {
                return;
            }
            const linkColor = linksOptions.id !== undefined
                ? container.particles.linksColors.get(linksOptions.id)
                : container.particles.linksColor;
            return getLinkColor(p1, p2, linkColor, container.hdr);
        }
        #setColor(p1) {
            if (!p1.options.links) {
                return;
            }
            const container = this.container, linksOptions = p1.options.links;
            let linkColor = linksOptions.id === undefined
                ? container.particles.linksColor
                : container.particles.linksColors.get(linksOptions.id);
            if (linkColor) {
                return;
            }
            linkColor = getLinkRandomColor(this.#pluginManager, linksOptions.color, linksOptions.blink, linksOptions.consent);
            if (linksOptions.id === undefined) {
                container.particles.linksColor = linkColor;
            }
            else {
                container.particles.linksColors.set(linksOptions.id, linkColor);
            }
        }
    }

    class LinksPlugin {
        id = "links";
        #pluginManager;
        constructor(pluginManager) {
            this.#pluginManager = pluginManager;
        }
        async getPlugin(container) {
            const { LinkInstance } = await Promise.resolve().then(function () { return LinkInstance$1; });
            return new LinkInstance(this.#pluginManager, container);
        }
        loadOptions() {
        }
        needsPlugin() {
            return true;
        }
    }

    async function loadParticlesLinksInteraction(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register((e) => {
            const pluginManager = e.pluginManager;
            ensureInteractivityPluginLoaded(e);
            pluginManager.addPlugin(new LinksPlugin(pluginManager));
            pluginManager.addInteractor?.("particlesLinks", container => {
                return Promise.resolve(new Linker(pluginManager, container));
            });
        });
    }

    const polygonCache = new Map(), noOffset = 0;
    function getUnitPolygon(sides) {
        const cached = polygonCache.get(sides);
        if (cached) {
            return cached;
        }
        const step = doublePI / sides, isOdd = !!(sides % double), baseAngle = (-Math.PI + (isOdd ? noOffset : step)) * half, verts = [];
        for (let i = 0; i < sides; i++) {
            const angle = baseAngle + i * step;
            verts[i] = {
                x: Math.cos(angle),
                y: Math.sin(angle),
            };
        }
        polygonCache.set(sides, verts);
        return verts;
    }
    function drawPolygon(data, side) {
        const { context, radius } = data, sides = side.count.numerator / side.count.denominator, verts = getUnitPolygon(sides);
        context.beginPath();
        for (let i = 0; i < verts.length; i++) {
            const vert = verts[i];
            if (!vert) {
                continue;
            }
            const x = vert.x * radius, y = vert.y * radius;
            if (i) {
                context.lineTo(x, y);
            }
            else {
                context.moveTo(x, y);
            }
        }
        context.closePath();
    }

    const defaultSides$1 = 5;
    class PolygonDrawerBase {
        draw(data) {
            const { particle, radius } = data, side = this.getSidesData(particle, radius);
            drawPolygon(data, side);
        }
        getSidesCount(particle) {
            const polygon = particle.shapeData;
            return Math.round(getRangeValue(polygon?.sides ?? defaultSides$1));
        }
    }

    const yFactor$1 = 2.66, sidesFactor$1 = 3;
    class PolygonDrawer extends PolygonDrawerBase {
        getSidesData(particle, radius) {
            const { sides } = particle;
            return {
                count: {
                    denominator: 1,
                    numerator: sides,
                },
                length: (radius * yFactor$1) / (sides / sidesFactor$1),
            };
        }
    }

    const sides$1 = 3, yFactor = 2.66, sidesFactor = 3;
    class TriangleDrawer extends PolygonDrawerBase {
        getSidesCount() {
            return sides$1;
        }
        getSidesData(_particle, radius) {
            return {
                count: {
                    denominator: 1,
                    numerator: sides$1,
                },
                length: (radius * yFactor) / (sides$1 / sidesFactor),
            };
        }
    }

    async function loadGenericPolygonShape(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register(e => {
            e.pluginManager.addShape(["polygon"], () => Promise.resolve(new PolygonDrawer()));
        });
    }
    async function loadTriangleShape(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register(e => {
            e.pluginManager.addShape(["triangle"], () => Promise.resolve(new TriangleDrawer()));
        });
    }
    async function loadPolygonShape(engine) {
        engine.checkVersion("4.4.0");
        await Promise.all([
            loadGenericPolygonShape(engine),
            loadTriangleShape(engine),
        ]);
    }

    class RotateAnimation {
        decay = 0;
        enable = false;
        speed = 0;
        sync = false;
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadProperty(this, "enable", data.enable);
            loadRangeProperty(this, "speed", data.speed);
            loadRangeProperty(this, "decay", data.decay);
            loadProperty(this, "sync", data.sync);
        }
    }

    class Rotate extends ValueWithRandom {
        animation = new RotateAnimation();
        direction = exports.RotateDirection.clockwise;
        path = false;
        load(data) {
            if (isNull(data)) {
                return;
            }
            super.load(data);
            loadProperty(this, "direction", data.direction);
            this.animation.load(data.animation);
            loadProperty(this, "path", data.path);
        }
    }

    const doublePIDeg = 360;
    class RotateUpdater {
        #container;
        constructor(container) {
            this.#container = container;
        }
        init(particle) {
            const rotateOptions = particle.options.rotate;
            if (!rotateOptions) {
                return;
            }
            particle.rotate = {
                enable: rotateOptions.animation.enable,
                value: degToRad(getRangeValue(rotateOptions.value)),
                min: 0,
                max: doublePI,
            };
            particle.pathRotation = rotateOptions.path;
            let rotateDirection = rotateOptions.direction;
            if (rotateDirection === exports.RotateDirection.random) {
                const index = Math.floor(getRandom() * double), minIndex = 0;
                rotateDirection = index > minIndex ? exports.RotateDirection.counterClockwise : exports.RotateDirection.clockwise;
            }
            switch (rotateDirection) {
                case exports.RotateDirection.counterClockwise:
                case "counterClockwise":
                    particle.rotate.status = exports.AnimationStatus.decreasing;
                    break;
                case exports.RotateDirection.clockwise:
                    particle.rotate.status = exports.AnimationStatus.increasing;
                    break;
            }
            const rotateAnimation = rotateOptions.animation;
            if (rotateAnimation.enable) {
                particle.rotate.decay = identity$2 - getRangeValue(rotateAnimation.decay);
                particle.rotate.velocity =
                    (getRangeValue(rotateAnimation.speed) / doublePIDeg) * this.#container.retina.reduceFactor;
                if (!rotateAnimation.sync) {
                    particle.rotate.velocity *= getRandom();
                }
            }
            particle.rotation = particle.rotate.value;
        }
        isEnabled(particle) {
            const rotate = particle.options.rotate;
            if (!rotate) {
                return false;
            }
            return !particle.destroyed && !particle.spawning && (!!rotate.value || rotate.animation.enable || rotate.path);
        }
        loadOptions(options, ...sources) {
            loadOptionProperty(options, "rotate", Rotate, ...sources);
        }
        update(particle, delta) {
            if (!this.isEnabled(particle)) {
                return;
            }
            particle.isRotating = !!particle.rotate;
            if (!particle.rotate) {
                return;
            }
            updateAnimation(particle, particle.rotate, false, exports.DestroyType.none, delta);
            particle.rotation = particle.rotate.value;
        }
    }

    async function loadRotateUpdater(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register(e => {
            e.pluginManager.addParticleUpdater("rotate", container => {
                return Promise.resolve(new RotateUpdater(container));
            });
        });
    }

    function drawSquare(data) {
        const { context, radius } = data, fixedRadius = radius * Math.SQRT1_2, fixedDiameter = fixedRadius * double;
        context.rect(-fixedRadius, -fixedRadius, fixedDiameter, fixedDiameter);
    }

    const sides = 4;
    class SquareDrawer {
        draw(data) {
            drawSquare(data);
        }
        getSidesCount() {
            return sides;
        }
    }

    async function loadSquareShape(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register(e => {
            e.pluginManager.addShape(["edge", "square"], () => Promise.resolve(new SquareDrawer()));
        });
    }

    const defaultInset$1 = 2, origin = { x: 0, y: 0 };
    function drawStar(data) {
        const { context, particle, radius } = data, sides = particle.sides, inset = particle.starInset ?? defaultInset$1;
        context.moveTo(origin.x, origin.y - radius);
        for (let i = 0; i < sides; i++) {
            context.rotate(Math.PI / sides);
            context.lineTo(origin.x, origin.y - radius * inset);
            context.rotate(Math.PI / sides);
            context.lineTo(origin.x, origin.y - radius);
        }
    }

    const defaultInset = 2, defaultSides = 5;
    class StarDrawer {
        draw(data) {
            drawStar(data);
        }
        getSidesCount(particle) {
            const star = particle.shapeData;
            return Math.round(getRangeValue(star?.sides ?? defaultSides));
        }
        particleInit(_container, particle) {
            const star = particle.shapeData;
            particle.starInset = getRangeValue(star?.inset ?? defaultInset);
        }
    }

    async function loadStarShape(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register(e => {
            e.pluginManager.addShape(["star"], () => Promise.resolve(new StarDrawer()));
        });
    }

    async function loadSlim(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register(async (e) => {
            const loadInteractivityForSlim = async (e) => {
                await loadInteractivityPlugin(e);
                await Promise.all([
                    loadExternalParallaxInteraction(e),
                    loadExternalAttractInteraction(e),
                    loadExternalBounceInteraction(e),
                    loadExternalBubbleInteraction(e),
                    loadExternalConnectInteraction(e),
                    loadExternalDestroyInteraction(e),
                    loadExternalGrabInteraction(e),
                    loadExternalPauseInteraction(e),
                    loadExternalPushInteraction(e),
                    loadExternalRemoveInteraction(e),
                    loadExternalRepulseInteraction(e),
                    loadExternalSlowInteraction(e),
                    loadParticlesAttractInteraction(e),
                    loadParticlesCollisionsInteraction(e),
                    loadParticlesLinksInteraction(e),
                ]);
            };
            await Promise.all([
                loadBasic(e),
                loadInteractivityForSlim(e),
                loadEasingQuadPlugin(e),
                loadEmojiShape(e),
                loadImageShape(e),
                loadLineShape(e),
                loadPolygonShape(e),
                loadSquareShape(e),
                loadStarShape(e),
                loadLifeUpdater(e),
                loadPaintUpdater(e),
                loadRotateUpdater(e),
            ]);
        });
    }

    const validTypes = ["text", "character", "char", "multiline-text"];
    const firstIndex$1 = 0, minLength$1 = 0;
    function drawText(data) {
        const { context, particle, fill, stroke, radius, opacity } = data, character = particle.shapeData;
        if (!character) {
            return;
        }
        const textData = character.value;
        particle.textLines ??= itemFromSingleOrMultiple(textData, particle.randomIndexData)?.split("\n") ?? [];
        particle.maxTextLength ??= particle.textLines.length
            ? Math.max(...particle.textLines.map(t => t.length))
            : (particle.textLines[firstIndex$1]?.length ?? minLength$1);
        if (!particle.textLines.length || !particle.maxTextLength) {
            return;
        }
        const lines = particle.textLines, style = character.style ?? "", weight = character.weight ?? "400", font = character.font ?? "Verdana", size = (Math.round(radius) * double) / (lines.length * particle.maxTextLength);
        context.font = `${style} ${weight} ${size.toString()}px "${font}"`;
        const originalGlobalAlpha = context.globalAlpha;
        context.globalAlpha = opacity;
        for (let i = 0; i < lines.length; i++) {
            const currentLine = lines[i];
            if (!currentLine) {
                continue;
            }
            drawTextLine(context, currentLine, size, i, fill, stroke);
        }
        context.globalAlpha = originalGlobalAlpha;
    }
    function drawTextLine(context, line, size, index, fill, stroke) {
        const pos = {
            x: -(line.length * size * half),
            y: size * half + index * size,
        };
        if (fill) {
            context.fillText(line, pos.x, pos.y);
        }
        if (stroke) {
            context.strokeText(line, pos.x, pos.y);
        }
    }

    const firstIndex = 0, minLength = 0;
    class TextDrawer {
        draw(data) {
            drawText(data);
        }
        async init(container) {
            const options = container.actualOptions;
            if (validTypes.find(t => isInArray(t, options.particles.shape.type))) {
                const shapeOptions = validTypes
                    .map(t => options.particles.shape.options[t])
                    .find(t => !!t), promises = [];
                executeOnSingleOrMultiple(shapeOptions, shape => {
                    promises.push(loadFont(shape.font, shape.weight));
                });
                await Promise.all(promises);
            }
        }
        particleInit(_container, particle) {
            if (!particle.shape || !validTypes.includes(particle.shape)) {
                return;
            }
            const character = particle.shapeData;
            if (character === undefined) {
                return;
            }
            const textData = character.value;
            if (!textData) {
                return;
            }
            particle.textLines = itemFromSingleOrMultiple(textData, particle.randomIndexData)?.split("\n") ?? [];
            particle.maxTextLength = particle.textLines.length
                ? Math.max(...particle.textLines.map(t => t.length))
                : (particle.textLines[firstIndex]?.length ?? minLength);
        }
    }

    async function loadTextShape(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register(e => {
            e.pluginManager.addShape(validTypes, () => Promise.resolve(new TextDrawer()));
        });
    }

    var TiltDirection;
    (function (TiltDirection) {
        TiltDirection["clockwise"] = "clockwise";
        TiltDirection["counterClockwise"] = "counter-clockwise";
        TiltDirection["random"] = "random";
    })(TiltDirection || (TiltDirection = {}));

    class TiltAnimation {
        decay = 0;
        enable = false;
        speed = 0;
        sync = false;
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadProperty(this, "enable", data.enable);
            loadRangeProperty(this, "speed", data.speed);
            loadRangeProperty(this, "decay", data.decay);
            loadProperty(this, "sync", data.sync);
        }
    }

    class Tilt extends ValueWithRandom {
        animation = new TiltAnimation();
        direction = TiltDirection.clockwise;
        enable = false;
        load(data) {
            super.load(data);
            if (isNull(data)) {
                return;
            }
            this.animation.load(data.animation);
            loadProperty(this, "direction", data.direction);
            loadProperty(this, "enable", data.enable);
        }
    }

    const maxAngle$2 = 360;
    class TiltUpdater {
        #container;
        constructor(container) {
            this.#container = container;
        }
        getTransformValues(particle) {
            const tilt = particle.tilt?.enable && particle.tilt;
            return {
                b: tilt ? Math.cos(tilt.value) * tilt.cosDirection : undefined,
                c: tilt ? Math.sin(tilt.value) * tilt.sinDirection : undefined,
            };
        }
        init(particle) {
            const tiltOptions = particle.options.tilt;
            if (!tiltOptions) {
                return;
            }
            particle.tilt = {
                enable: tiltOptions.enable,
                value: degToRad(getRangeValue(tiltOptions.value)),
                sinDirection: getRandom() >= half ? identity$2 : -identity$2,
                cosDirection: getRandom() >= half ? identity$2 : -identity$2,
                min: 0,
                max: doublePI,
            };
            let tiltDirection = tiltOptions.direction;
            if (tiltDirection === TiltDirection.random) {
                const index = Math.floor(getRandom() * double), minIndex = 0;
                tiltDirection = index > minIndex ? TiltDirection.counterClockwise : TiltDirection.clockwise;
            }
            switch (tiltDirection) {
                case TiltDirection.counterClockwise:
                case "counterClockwise":
                    particle.tilt.status = exports.AnimationStatus.decreasing;
                    break;
                case TiltDirection.clockwise:
                    particle.tilt.status = exports.AnimationStatus.increasing;
                    break;
            }
            const tiltAnimation = particle.options.tilt?.animation;
            if (tiltAnimation?.enable) {
                particle.tilt.decay = identity$2 - getRangeValue(tiltAnimation.decay);
                particle.tilt.velocity = (getRangeValue(tiltAnimation.speed) / maxAngle$2) * this.#container.retina.reduceFactor;
                if (!tiltAnimation.sync) {
                    particle.tilt.velocity *= getRandom();
                }
            }
        }
        isEnabled(particle) {
            const tiltAnimation = particle.options.tilt?.animation;
            return !particle.destroyed && !particle.spawning && !!tiltAnimation?.enable;
        }
        loadOptions(options, ...sources) {
            loadOptionProperty(options, "tilt", Tilt, ...sources);
        }
        update(particle, delta) {
            if (!this.isEnabled(particle) || !particle.tilt) {
                return;
            }
            updateAnimation(particle, particle.tilt, false, exports.DestroyType.none, delta);
        }
    }

    async function loadTiltUpdater(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register(e => {
            e.pluginManager.addParticleUpdater("tilt", container => {
                return Promise.resolve(new TiltUpdater(container));
            });
        });
    }

    class TwinkleLinksValues {
        color;
        enable = false;
        frequency = 0.05;
        opacity = 1;
        load(data) {
            if (isNull(data)) {
                return;
            }
            if (data.color !== undefined) {
                this.color = OptionsColor.create(this.color, data.color);
            }
            loadProperty(this, "enable", data.enable);
            loadProperty(this, "frequency", data.frequency);
            loadRangeProperty(this, "opacity", data.opacity);
        }
    }

    class TwinkleParticlesValues {
        enable = false;
        fillColor;
        frequency = 0.05;
        opacity = 1;
        strokeColor;
        load(data) {
            if (isNull(data)) {
                return;
            }
            if (data.fillColor !== undefined) {
                this.fillColor = OptionsColor.create(this.fillColor, data.fillColor);
            }
            if (data.strokeColor !== undefined) {
                this.strokeColor = OptionsColor.create(this.strokeColor, data.strokeColor);
            }
            loadProperty(this, "enable", data.enable);
            loadProperty(this, "frequency", data.frequency);
            loadRangeProperty(this, "opacity", data.opacity);
        }
    }

    class Twinkle {
        links = new TwinkleLinksValues();
        particles = new TwinkleParticlesValues();
        load(data) {
            if (isNull(data)) {
                return;
            }
            this.links.load(data.links);
            this.particles.load(data.particles);
        }
    }

    class TwinkleUpdater {
        #container;
        #pluginManager;
        constructor(pluginManager, container) {
            this.#pluginManager = pluginManager;
            this.#container = container;
        }
        getColorStyles(particle, _context, _radius, opacity) {
            const pOptions = particle.options, container = this.#container, twinkleOptions = pOptions["twinkle"];
            if (!twinkleOptions) {
                return {};
            }
            const twinkle = twinkleOptions.particles, twinkling = twinkle.enable && getRandom() < twinkle.frequency, zIndexOptions = particle.options.zIndex, zOffset = 1, zOpacityFactor = (zOffset - particle.zIndexFactor) ** zIndexOptions.opacityRate, twinklingOpacity = twinkling ? getRangeValue(twinkle.opacity) * zOpacityFactor : opacity, twinkleFillRgb = rangeColorToHsl(this.#pluginManager, twinkle.fillColor), twinkleStrokeRgb = rangeColorToHsl(this.#pluginManager, twinkle.strokeColor), getTwinkleFillStyle = () => {
                if (!twinkleFillRgb) {
                    return undefined;
                }
                return getStyleFromHsl(twinkleFillRgb, container.hdr, twinklingOpacity, container.peakNits, container.hdrMode);
            }, getTwinkleStrokeStyle = () => {
                if (!twinkleStrokeRgb) {
                    return undefined;
                }
                return getStyleFromHsl(twinkleStrokeRgb, container.hdr, twinklingOpacity, container.peakNits, container.hdrMode);
            }, twinkleFillStyle = getTwinkleFillStyle(), twinkleStrokeStyle = getTwinkleStrokeStyle(), res = {}, needsTwinkle = twinkling && (!!twinkleFillStyle || !!twinkleStrokeStyle);
            res.fill = needsTwinkle ? twinkleFillStyle : undefined;
            res.stroke = needsTwinkle ? twinkleStrokeStyle : undefined;
            return res;
        }
        init() {
        }
        isEnabled(particle) {
            const pOptions = particle.options, twinkleOptions = pOptions.twinkle;
            if (!twinkleOptions) {
                return false;
            }
            return twinkleOptions.particles.enable;
        }
        loadOptions(options, ...sources) {
            loadOptionProperty(options, "twinkle", Twinkle, ...sources);
        }
        update() {
        }
    }

    async function loadTwinkleUpdater(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register(e => {
            e.pluginManager.addParticleUpdater("twinkle", container => {
                return Promise.resolve(new TwinkleUpdater(e.pluginManager, container));
            });
        });
    }

    class WobbleSpeed {
        angle = 50;
        move = 10;
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadRangeProperty(this, "angle", data.angle);
            loadRangeProperty(this, "move", data.move);
        }
    }

    class Wobble {
        distance = 5;
        enable = false;
        speed = new WobbleSpeed();
        load(data) {
            if (isNull(data)) {
                return;
            }
            loadRangeProperty(this, "distance", data.distance);
            loadProperty(this, "enable", data.enable);
            if (data.speed !== undefined) {
                if (isNumber(data.speed)) {
                    this.speed.load({ angle: data.speed });
                }
                else {
                    const rangeSpeed = data.speed;
                    if ("min" in rangeSpeed) {
                        this.speed.load({ angle: rangeSpeed });
                    }
                    else {
                        this.speed.load(data.speed);
                    }
                }
            }
        }
    }

    const defaultDistance$1 = 0, distanceFactor = 60;
    function updateWobble(container, particle, delta) {
        const { wobble: wobbleOptions } = particle.options, { wobble } = particle;
        if (!wobbleOptions?.enable || !wobble) {
            return;
        }
        const reduceFactor = container.retina.reduceFactor, angleSpeed = wobble.angleSpeed * delta.factor * reduceFactor, moveSpeed = wobble.moveSpeed * delta.factor * reduceFactor, distance = (moveSpeed * (particle.retina.wobbleDistance ?? defaultDistance$1)) / (millisecondsToSeconds / distanceFactor), max = doublePI, { position } = particle;
        wobble.angle += angleSpeed;
        if (wobble.angle > max) {
            wobble.angle -= max;
        }
        position.x += distance * Math.cos(wobble.angle);
        position.y += distance * Math.abs(Math.sin(wobble.angle));
    }

    const maxAngle$1 = 360, moveSpeedFactor$1 = 10, defaultDistance = 0;
    class WobbleUpdater {
        #container;
        constructor(container) {
            this.#container = container;
        }
        init(particle) {
            const wobbleOpt = particle.options.wobble;
            if (wobbleOpt?.enable) {
                particle.wobble = {
                    angle: getRandom() * doublePI,
                    angleSpeed: getRangeValue(wobbleOpt.speed.angle) / maxAngle$1,
                    moveSpeed: getRangeValue(wobbleOpt.speed.move) / moveSpeedFactor$1,
                };
            }
            else {
                particle.wobble = {
                    angle: 0,
                    angleSpeed: 0,
                    moveSpeed: 0,
                };
            }
            particle.retina.wobbleDistance =
                getRangeValue(wobbleOpt?.distance ?? defaultDistance) * this.#container.retina.pixelRatio;
        }
        isEnabled(particle) {
            return !particle.destroyed && !particle.spawning && !!particle.options.wobble?.enable;
        }
        loadOptions(options, ...sources) {
            loadOptionProperty(options, "wobble", Wobble, ...sources);
        }
        update(particle, delta) {
            if (!this.isEnabled(particle)) {
                return;
            }
            updateWobble(this.#container, particle, delta);
        }
    }

    async function loadWobbleUpdater(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register(e => {
            e.pluginManager.addParticleUpdater("wobble", container => {
                return Promise.resolve(new WobbleUpdater(container));
            });
        });
    }

    async function loadFull(engine) {
        engine.checkVersion("4.4.0");
        await engine.pluginManager.register(async (e) => {
            const loadEmittersPluginBundle = async (e) => {
                await loadEmittersPlugin(e);
                await Promise.all([
                    loadEmittersShapeCircle(e),
                    loadEmittersShapeSquare(e),
                ]);
            }, loadInteractivityForFull = async (e) => {
                await loadSlim(e);
                await Promise.all([
                    loadExternalDragInteraction(e),
                    loadExternalTrailInteraction(e),
                    loadAbsorbersPlugin(e),
                    loadEmittersPluginBundle(e),
                ]);
            };
            await Promise.all([
                loadInteractivityForFull(e),
                loadDestroyUpdater(e),
                loadRollUpdater(e),
                loadTiltUpdater(e),
                loadTwinkleUpdater(e),
                loadWobbleUpdater(e),
                loadTextShape(e),
            ]);
        });
    }

    const globalObject = globalThis;
    globalObject.loadFull = loadFull;
    globalObject.tsParticles = tsParticles;

    const fColorIndex = 0, sColorIndex = 1;
    function setTransformValue(factor, newFactor, key) {
        const newValue = newFactor[key];
        if (newValue !== undefined) {
            factor[key] = (factor[key] ?? defaultTransformValue) * newValue;
        }
    }
    class RenderManager {
        #backgroundElement;
        #backgroundWarnings;
        #canvasClearPlugins;
        #canvasManager;
        #colorPlugins;
        #container;
        #context;
        #contextSettings;
        #drawParticlePlugins;
        #drawParticlesCleanupPlugins;
        #drawParticlesSetupPlugins;
        #layers;
        #pluginManager;
        #postDrawUpdaters;
        #preDrawUpdaters;
        #reusableColorStyles = {};
        #reusablePluginColors = [undefined, undefined];
        #reusableTransform = {};
        constructor(pluginManager, container, canvasManager) {
            this.#pluginManager = pluginManager;
            this.#container = container;
            this.#canvasManager = canvasManager;
            this.#context = null;
            this.#backgroundElement = null;
            this.#backgroundWarnings = new Set();
            this.#preDrawUpdaters = [];
            this.#postDrawUpdaters = [];
            this.#canvasClearPlugins = [];
            this.#colorPlugins = [];
            this.#drawParticlePlugins = [];
            this.#drawParticlesCleanupPlugins = [];
            this.#drawParticlesSetupPlugins = [];
            this.#layers = {
                0: [],
                1: [],
                2: [],
                3: [],
                4: [],
                5: [],
                6: [],
                7: [],
            };
        }
        get settings() {
            return this.#contextSettings;
        }
        canvasClear() {
            if (!this.#container.actualOptions.clear) {
                return;
            }
            this.draw(ctx => {
                ctx.clearRect(originPoint.x, originPoint.y, this.#canvasManager.size.width, this.#canvasManager.size.height);
            });
        }
        clear() {
            for (const plugin of this.#canvasClearPlugins) {
                if (plugin.canvasClear?.() ?? false) {
                    return;
                }
            }
            for (const layer of Object.values(exports.DrawLayer)) {
                if (typeof layer === "number") {
                    for (const plugin of this.#getLayerPlugins(layer)) {
                        if (plugin.canvasClear?.() ?? false) {
                            return;
                        }
                    }
                }
            }
            this.canvasClear();
        }
        destroy() {
            this.stop();
            this.#backgroundElement = null;
            this.#backgroundWarnings.clear();
            this.#preDrawUpdaters = [];
            this.#postDrawUpdaters = [];
            this.#canvasClearPlugins = [];
            this.#colorPlugins = [];
            this.#drawParticlePlugins = [];
            this.#drawParticlesCleanupPlugins = [];
            this.#drawParticlesSetupPlugins = [];
            for (const layer of Object.values(exports.DrawLayer)) {
                if (typeof layer === "number") {
                    this.#layers[layer] = [];
                }
            }
        }
        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 <= minimumSize) {
                return;
            }
            const pfColor = particle.getFillColor(), psColor = particle.getStrokeColor();
            let [fColor, sColor] = this.#getPluginParticleColors(particle);
            fColor ??= pfColor;
            sColor ??= psColor;
            if (!fColor && !sColor) {
                return;
            }
            const container = this.#container, zIndexOptions = particle.options.zIndex, zIndexFactor = zIndexFactorOffset - particle.zIndexFactor, { fillOpacity, opacity, strokeOpacity } = particle.getOpacity(), transform = this.#reusableTransform, colorStyles = this.#reusableColorStyles, fill = fColor
                ? getStyleFromHsl(fColor, container.hdr, fillOpacity * opacity, container.peakNits, container.hdrMode)
                : undefined, stroke = sColor
                ? getStyleFromHsl(sColor, container.hdr, strokeOpacity * opacity, container.peakNits, container.hdrMode)
                : fill;
            transform.a = transform.b = transform.c = transform.d = undefined;
            colorStyles.fill = fill;
            colorStyles.stroke = stroke;
            this.draw((context) => {
                for (const plugin of this.#drawParticlesSetupPlugins) {
                    plugin.drawParticleSetup?.(context, particle, delta);
                }
                this.#applyPreDrawUpdaters(context, particle, radius, opacity, colorStyles, transform);
                this.#drawParticle({
                    container,
                    context,
                    particle,
                    delta,
                    colorStyles,
                    radius: radius * zIndexFactor ** zIndexOptions.sizeRate,
                    opacity: opacity,
                    transform,
                });
                this.#applyPostDrawUpdaters(particle);
                for (const plugin of this.#drawParticlesCleanupPlugins) {
                    plugin.drawParticleCleanup?.(context, particle, delta);
                }
            });
        }
        drawParticlePlugins(particle, delta) {
            this.draw(ctx => {
                for (const plugin of this.#drawParticlePlugins) {
                    this.#drawParticlePlugin(ctx, plugin, particle, delta);
                }
            });
        }
        drawParticles(delta) {
            const { particles, actualOptions } = this.#container;
            this.clear();
            particles.update(delta);
            this.draw(ctx => {
                const width = this.#canvasManager.size.width, height = this.#canvasManager.size.height;
                if (this.#backgroundElement) {
                    try {
                        ctx.drawImage(this.#backgroundElement, originPoint.x, originPoint.y, width, height);
                    }
                    catch {
                        this.#warnOnce("background-element-draw-error", "Error drawing background element onto canvas");
                    }
                }
                const background = actualOptions.background;
                if (background.draw) {
                    try {
                        background.draw(ctx, delta);
                    }
                    catch {
                        this.#warnOnce("background-draw-error", "Error in background.draw callback");
                    }
                }
                for (const plugin of this.#getLayerPlugins(exports.DrawLayer.BackgroundMask)) {
                    plugin.canvasPaint?.();
                }
                for (const plugin of this.#getLayerPlugins(exports.DrawLayer.CanvasSetup)) {
                    plugin.drawSettingsSetup?.(ctx, delta);
                }
                for (const plugin of this.#getLayerPlugins(exports.DrawLayer.PluginContent)) {
                    plugin.draw?.(ctx, delta);
                }
                particles.drawParticles(delta);
                for (const plugin of this.#getLayerPlugins(exports.DrawLayer.CanvasCleanup)) {
                    plugin.clearDraw?.(ctx, delta);
                    plugin.drawSettingsCleanup?.(ctx, delta);
                }
            });
        }
        init() {
            this.initUpdaters();
            this.initPlugins();
            this.#resolveBackgroundElement();
            this.paint();
        }
        initPlugins() {
            this.#canvasClearPlugins = [];
            this.#colorPlugins = [];
            this.#drawParticlePlugins = [];
            this.#drawParticlesSetupPlugins = [];
            this.#drawParticlesCleanupPlugins = [];
            for (const layer of Object.values(exports.DrawLayer)) {
                if (typeof layer === "number") {
                    this.#layers[layer] = [];
                }
            }
            for (const plugin of this.#container.plugins) {
                if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
                    this.#colorPlugins.push(plugin);
                }
                if (plugin.drawParticle) {
                    this.#drawParticlePlugins.push(plugin);
                }
                if (plugin.drawParticleSetup) {
                    this.#drawParticlesSetupPlugins.push(plugin);
                }
                if (plugin.drawParticleCleanup) {
                    this.#drawParticlesCleanupPlugins.push(plugin);
                }
                if (plugin.canvasClear) {
                    this.#canvasClearPlugins.push(plugin);
                }
                if (plugin.canvasPaint) {
                    this.#getLayerPlugins(exports.DrawLayer.BackgroundMask).push(plugin);
                }
                if (plugin.drawSettingsSetup) {
                    this.#getLayerPlugins(exports.DrawLayer.CanvasSetup).push(plugin);
                }
                if (plugin.draw) {
                    this.#getLayerPlugins(exports.DrawLayer.PluginContent).push(plugin);
                }
                if (plugin.clearDraw ?? plugin.drawSettingsCleanup) {
                    this.#getLayerPlugins(exports.DrawLayer.CanvasCleanup).push(plugin);
                }
            }
        }
        initUpdaters() {
            this.#preDrawUpdaters = [];
            this.#postDrawUpdaters = [];
            for (const updater of this.#container.particleUpdaters) {
                if (updater.afterDraw) {
                    this.#postDrawUpdaters.push(updater);
                }
                if (updater.getColorStyles ?? updater.getTransformValues ?? updater.beforeDraw) {
                    this.#preDrawUpdaters.push(updater);
                }
            }
        }
        paint() {
            let handled = false;
            for (const plugin of this.#getLayerPlugins(exports.DrawLayer.BackgroundMask)) {
                handled = plugin.canvasPaint?.() ?? false;
                if (handled) {
                    break;
                }
            }
            if (handled) {
                return;
            }
            this.paintBase();
        }
        paintBase(baseColor) {
            this.draw(ctx => {
                ctx.fillStyle = baseColor ?? "rgba(0,0,0,0)";
                ctx.fillRect(originPoint.x, originPoint.y, this.#canvasManager.size.width, this.#canvasManager.size.height);
            });
        }
        paintImage(image, opacity) {
            this.draw(ctx => {
                if (!image) {
                    return;
                }
                const prevAlpha = ctx.globalAlpha;
                ctx.globalAlpha = opacity;
                ctx.drawImage(image, originPoint.x, originPoint.y, this.#canvasManager.size.width, this.#canvasManager.size.height);
                ctx.globalAlpha = prevAlpha;
            });
        }
        setContext(context) {
            this.#context = context;
            if (this.#context) {
                this.#context.globalCompositeOperation = defaultCompositeValue;
            }
        }
        setContextSettings(settings) {
            this.#contextSettings = settings;
        }
        stop() {
            this.draw(ctx => {
                ctx.clearRect(originPoint.x, originPoint.y, this.#canvasManager.size.width, this.#canvasManager.size.height);
            });
        }
        #applyPostDrawUpdaters(particle) {
            for (const updater of this.#postDrawUpdaters) {
                updater.afterDraw?.(particle);
            }
        }
        #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?.(particle);
            }
        }
        #drawAfterEffect(drawer, data) {
            if (!drawer?.drawAfter) {
                return;
            }
            const { particle } = data;
            if (!particle.effect) {
                return;
            }
            drawer.drawAfter(data);
        }
        #drawBeforeEffect(drawer, data) {
            if (!drawer?.drawBefore) {
                return;
            }
            const { particle } = data;
            if (!particle.effect) {
                return;
            }
            drawer.drawBefore(data);
        }
        #drawParticle(data) {
            const { container, context, particle, delta, colorStyles, radius, opacity, transform } = data, { effectDrawers, shapeDrawers } = container, pos = particle.getPosition(), transformData = particle.getTransformData(transform), drawScale = defaultZoom, drawPosition = {
                x: pos.x,
                y: pos.y,
            };
            context.setTransform(transformData.a, transformData.b, transformData.c, transformData.d, pos.x, pos.y);
            if (colorStyles.fill) {
                context.fillStyle = colorStyles.fill;
            }
            const fillEnabled = !!particle.fillEnabled, strokeWidth = particle.strokeWidth ?? minStrokeWidth;
            context.lineWidth = strokeWidth;
            if (colorStyles.stroke) {
                context.strokeStyle = colorStyles.stroke;
            }
            const drawData = {
                context,
                particle,
                radius,
                drawRadius: radius * drawScale,
                opacity,
                delta,
                pixelRatio: container.retina.pixelRatio,
                fill: fillEnabled,
                stroke: strokeWidth > minStrokeWidth,
                transformData,
                position: { ...pos },
                drawPosition,
                drawScale,
            };
            for (const plugin of container.plugins) {
                plugin.drawParticleTransform?.(drawData);
            }
            const effect = particle.effect ? effectDrawers.get(particle.effect) : undefined, shape = particle.shape ? shapeDrawers.get(particle.shape) : undefined;
            this.#drawBeforeEffect(effect, drawData);
            this.#drawShapeBeforeDraw(shape, drawData);
            this.#drawShape(shape, drawData);
            this.#drawShapeAfterDraw(shape, drawData);
            this.#drawAfterEffect(effect, drawData);
            context.resetTransform();
        }
        #drawParticlePlugin(context, plugin, particle, delta) {
            if (!plugin.drawParticle) {
                return;
            }
            plugin.drawParticle(context, particle, delta);
        }
        #drawShape(drawer, data) {
            if (!drawer) {
                return;
            }
            const { context, fill, particle, stroke } = data;
            if (!particle.shape) {
                return;
            }
            context.beginPath();
            drawer.draw(data);
            if (particle.shapeClose) {
                context.closePath();
            }
            if (fill) {
                context.fill();
            }
            if (stroke) {
                context.stroke();
            }
        }
        #drawShapeAfterDraw(drawer, data) {
            if (!drawer?.afterDraw) {
                return;
            }
            const { particle } = data;
            if (!particle.shape) {
                return;
            }
            drawer.afterDraw(data);
        }
        #drawShapeBeforeDraw(drawer, data) {
            if (!drawer?.beforeDraw) {
                return;
            }
            const { particle } = data;
            if (!particle.shape) {
                return;
            }
            drawer.beforeDraw(data);
        }
        #getLayerPlugins(layer) {
            return this.#layers[layer];
        }
        #getPluginParticleColors(particle) {
            let fColor, sColor;
            for (const plugin of this.#colorPlugins) {
                if (!fColor && plugin.particleFillColor) {
                    fColor = rangeColorToHsl(this.#pluginManager, plugin.particleFillColor(particle));
                }
                if (!sColor && plugin.particleStrokeColor) {
                    sColor = rangeColorToHsl(this.#pluginManager, plugin.particleStrokeColor(particle));
                }
                if (fColor && sColor) {
                    break;
                }
            }
            this.#reusablePluginColors[fColorIndex] = fColor;
            this.#reusablePluginColors[sColorIndex] = sColor;
            return this.#reusablePluginColors;
        }
        #resolveBackgroundElement() {
            const background = this.#container.actualOptions.background;
            this.#backgroundElement = null;
            if (!background.element) {
                return;
            }
            if (typeof background.element === "string") {
                if (typeof document !== "undefined") {
                    const node = document.querySelector(background.element);
                    if ((typeof HTMLCanvasElement !== "undefined" && node instanceof HTMLCanvasElement) ||
                        (typeof HTMLVideoElement !== "undefined" && node instanceof HTMLVideoElement) ||
                        (typeof HTMLImageElement !== "undefined" && node instanceof HTMLImageElement)) {
                        this.#backgroundElement = node;
                    }
                    else if (node) {
                        this.#warnOnce("background-element-not-supported", `Background element "${background.element}" is not a supported drawable element (canvas, video, or img)`);
                    }
                    else {
                        this.#warnOnce("background-element-not-found", `Background element selector "${background.element}" not found`);
                    }
                }
            }
            else if ((typeof HTMLCanvasElement !== "undefined" && background.element instanceof HTMLCanvasElement) ||
                (typeof OffscreenCanvas !== "undefined" && background.element instanceof OffscreenCanvas) ||
                (typeof HTMLVideoElement !== "undefined" && background.element instanceof HTMLVideoElement) ||
                (typeof HTMLImageElement !== "undefined" && background.element instanceof HTMLImageElement)) {
                this.#backgroundElement = background.element;
            }
        }
        #warnOnce(key, message) {
            if (!this.#backgroundWarnings.has(key)) {
                this.#backgroundWarnings.add(key);
                getLogger().warning(message);
            }
        }
    }

    const transferredCanvases = new WeakMap(), getTransferredCanvas = (canvas) => {
        const transferredCanvas = transferredCanvases.get(canvas);
        if (transferredCanvas) {
            return transferredCanvas;
        }
        if (typeof canvas.transferControlToOffscreen !== "function") {
            throw new TypeError("OffscreenCanvas is required but not supported by this browser");
        }
        try {
            const offscreenCanvas = canvas.transferControlToOffscreen();
            transferredCanvases.set(canvas, offscreenCanvas);
            return offscreenCanvas;
        }
        catch {
            throw new TypeError("OffscreenCanvas transfer failed");
        }
    }, isHtmlCanvasElement = (canvas) => {
        return typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement;
    };
    function setStyle(canvas, style, important = false) {
        if (!style) {
            return;
        }
        const element = canvas, elementStyle = element.style, keys = new Set();
        for (let i = 0; i < elementStyle.length; i++) {
            const key = elementStyle.item(i);
            if (!key) {
                continue;
            }
            keys.add(key);
        }
        for (let i = 0; i < style.length; i++) {
            const key = style.item(i);
            if (!key) {
                continue;
            }
            keys.add(key);
        }
        for (const key of keys) {
            const value = style.getPropertyValue(key);
            if (value) {
                elementStyle.setProperty(key, value, important ? "important" : "");
            }
            else {
                elementStyle.removeProperty(key);
            }
        }
    }
    class CanvasManager {
        domElement;
        render;
        renderCanvas;
        size;
        zoom = defaultZoom;
        #container;
        #generated;
        #hdrMediaListeners;
        #mutationObserver;
        #originalStyle;
        #pluginManager;
        #pointerEvents;
        #resizePlugins;
        #standardSize;
        #zoomCenter;
        constructor(pluginManager, container) {
            this.#pluginManager = pluginManager;
            this.#container = container;
            this.render = new RenderManager(pluginManager, container, this);
            this.#standardSize = {
                height: 0,
                width: 0,
            };
            const pxRatio = container.retina.pixelRatio, stdSize = this.#standardSize;
            this.size = {
                height: stdSize.height * pxRatio,
                width: stdSize.width * pxRatio,
            };
            this.#generated = false;
            this.#resizePlugins = [];
            this.#pointerEvents = "none";
        }
        get #fullScreen() {
            return this.#container.actualOptions.fullScreen.enable;
        }
        destroy() {
            this.stop();
            if (this.#generated) {
                const element = this.domElement;
                element?.remove();
                this.domElement = undefined;
                this.renderCanvas = undefined;
            }
            else {
                this.#resetOriginalStyle();
            }
            this.render.destroy();
            this.#resizePlugins = [];
        }
        getZoomCenter() {
            const pxRatio = this.#container.retina.pixelRatio, { width, height } = this.size;
            if (this.#zoomCenter) {
                return this.#zoomCenter;
            }
            return {
                x: (width * half) / pxRatio,
                y: (height * half) / pxRatio,
            };
        }
        init() {
            this.#safeMutationObserver(obs => {
                obs.disconnect();
            });
            this.#mutationObserver = safeMutationObserver(records => {
                for (const record of records) {
                    if (record.type === "attributes" && record.attributeName === "style") {
                        this.#repairStyle();
                    }
                }
            });
            this.resize();
            this.#initStyle();
            this.#safeMutationObserver(obs => {
                const element = this.domElement;
                if (!element || !(element instanceof Node)) {
                    return;
                }
                obs.observe(element, { attributes: true });
            });
            this.initPlugins();
            this.#initContext();
            this.initBackground();
            this.#initHdrListeners();
            this.render.init();
        }
        initBackground() {
            const container = this.#container, options = container.actualOptions, background = options.background, element = this.domElement;
            if (!element) {
                return;
            }
            const elementStyle = element.style, color = rangeColorToRgb(this.#pluginManager, background.color);
            if (color) {
                const hdrOptions = container.actualOptions.hdr;
                elementStyle.backgroundColor = getStyleFromRgb(color, container.hdr, background.opacity, hdrOptions.peakNits, hdrOptions.mode);
            }
            else {
                elementStyle.backgroundColor = "";
            }
            elementStyle.backgroundImage = background.image || "";
            elementStyle.backgroundPosition = background.position || "";
            elementStyle.backgroundRepeat = background.repeat || "";
            elementStyle.backgroundSize = background.size || "";
        }
        initPlugins() {
            this.#resizePlugins = [];
            for (const plugin of this.#container.plugins) {
                if (plugin.resize) {
                    this.#resizePlugins.push(plugin);
                }
            }
        }
        loadCanvas(canvas) {
            if (this.#generated && this.domElement) {
                this.domElement.remove();
            }
            const domCanvas = isHtmlCanvasElement(canvas) ? canvas : undefined;
            this.domElement = domCanvas;
            this.#generated = domCanvas ? domCanvas.dataset[generatedAttribute] === "true" : false;
            this.renderCanvas = domCanvas ? getTransferredCanvas(domCanvas) : canvas;
            const domElement = this.domElement;
            if (domElement) {
                domElement.ariaHidden = "true";
                this.#originalStyle = cloneStyle(domElement.style);
            }
            const standardSize = this.#standardSize, renderCanvas = this.renderCanvas;
            if (domElement) {
                standardSize.height = domElement.offsetHeight;
                standardSize.width = domElement.offsetWidth;
            }
            else {
                standardSize.height = renderCanvas.height;
                standardSize.width = renderCanvas.width;
            }
            const pxRatio = this.#container.retina.pixelRatio, retinaSize = this.size;
            renderCanvas.height = retinaSize.height = standardSize.height * pxRatio;
            renderCanvas.width = retinaSize.width = standardSize.width * pxRatio;
        }
        resize() {
            const element = this.domElement;
            if (!element) {
                return false;
            }
            const container = this.#container, renderCanvas = this.renderCanvas;
            if (renderCanvas === undefined) {
                return false;
            }
            const currentSize = container.canvas.#standardSize, newSize = {
                width: element.offsetWidth,
                height: element.offsetHeight,
            }, pxRatio = container.retina.pixelRatio, retinaSize = {
                width: newSize.width * pxRatio,
                height: newSize.height * pxRatio,
            };
            if (newSize.height === currentSize.height &&
                newSize.width === currentSize.width &&
                retinaSize.height === renderCanvas.height &&
                retinaSize.width === renderCanvas.width) {
                return false;
            }
            const oldSize = { ...currentSize };
            currentSize.height = newSize.height;
            currentSize.width = newSize.width;
            const canvasSize = this.size;
            renderCanvas.width = canvasSize.width = retinaSize.width;
            renderCanvas.height = canvasSize.height = retinaSize.height;
            if (this.#container.started) {
                container.particles.setResizeFactor({
                    width: currentSize.width / oldSize.width,
                    height: currentSize.height / oldSize.height,
                });
            }
            return true;
        }
        setPointerEvents(type) {
            const element = this.domElement;
            if (!element) {
                return;
            }
            this.#pointerEvents = type;
            this.#repairStyle();
        }
        setZoom(zoomLevel, center) {
            this.zoom = zoomLevel;
            this.#zoomCenter = center;
        }
        stop() {
            this.#safeMutationObserver(obs => {
                obs.disconnect();
            });
            this.#mutationObserver = undefined;
            this.#removeHdrListeners();
            this.render.stop();
        }
        async windowResize() {
            if (!this.domElement || !this.resize()) {
                return;
            }
            const container = this.#container, needsRefresh = container.updateActualOptions();
            container.particles.setDensity();
            this.#applyResizePlugins();
            if (needsRefresh) {
                await container.refresh();
            }
        }
        #applyResizePlugins() {
            for (const plugin of this.#resizePlugins) {
                plugin.resize?.();
            }
        }
        #initContext() {
            const container = this.#container, canSupportHdr = container.actualOptions.hdr.enable &&
                safeMatchMedia("(color-gamut: p3)")?.matches &&
                safeMatchMedia("(dynamic-range: high)")?.matches;
            container.hdr = canSupportHdr ?? false;
            container.hdrMode = container.actualOptions.hdr.mode;
            container.peakNits = container.actualOptions.hdr.peakNits;
            const renderCanvas = this.renderCanvas;
            if (!renderCanvas) {
                return;
            }
            this.render.setContextSettings({
                alpha: true,
                desynchronized: true,
                willReadFrequently: false,
                ...(canSupportHdr
                    ? { colorSpace: "display-p3", colorType: "float16" }
                    : { colorSpace: "srgb" }),
            });
            let context;
            try {
                context = renderCanvas.getContext("2d", this.render.settings);
            }
            catch {
                context = null;
            }
            if (canSupportHdr && !context) {
                container.hdr = false;
                const sdrSettings = {
                    alpha: true,
                    desynchronized: true,
                    willReadFrequently: false,
                    colorSpace: "srgb",
                };
                this.render.setContextSettings(sdrSettings);
                try {
                    context = renderCanvas.getContext("2d", sdrSettings);
                }
                catch {
                    context = null;
                }
            }
            this.render.setContext(context);
        }
        #initHdrListeners() {
            this.#removeHdrListeners();
            const p3Query = safeMatchMedia("(color-gamut: p3)"), hdrQuery = safeMatchMedia("(dynamic-range: high)"), handleChange = () => {
                this.#recreateRenderCanvas();
                this.#initContext();
                this.initBackground();
            }, listeners = [];
            if (p3Query) {
                p3Query.addEventListener("change", handleChange);
                listeners.push({ handler: handleChange, mql: p3Query });
            }
            if (hdrQuery) {
                hdrQuery.addEventListener("change", handleChange);
                listeners.push({ handler: handleChange, mql: hdrQuery });
            }
            this.#hdrMediaListeners = listeners;
        }
        #initStyle() {
            const element = this.domElement, options = this.#container.actualOptions;
            if (!element) {
                return;
            }
            if (this.#fullScreen) {
                this.#setFullScreenStyle();
            }
            else {
                this.#resetOriginalStyle();
            }
            for (const key in options.style) {
                if (!key || !(key in options.style)) {
                    continue;
                }
                const value = options.style[key];
                if (!value) {
                    continue;
                }
                element.style.setProperty(key, value, "important");
            }
        }
        #recreateRenderCanvas() {
            const renderCanvas = this.renderCanvas;
            if (!renderCanvas) {
                return;
            }
            if (this.domElement) {
                return;
            }
            this.renderCanvas = new OffscreenCanvas(renderCanvas.width, renderCanvas.height);
        }
        #removeHdrListeners() {
            if (!this.#hdrMediaListeners) {
                return;
            }
            for (const { handler, mql } of this.#hdrMediaListeners) {
                mql.removeEventListener("change", handler);
            }
            this.#hdrMediaListeners = undefined;
        }
        #repairStyle() {
            const element = this.domElement;
            if (!element) {
                return;
            }
            this.#safeMutationObserver(observer => {
                observer.disconnect();
            });
            this.#initStyle();
            this.initBackground();
            const pointerEvents = this.#pointerEvents;
            element.style.pointerEvents = pointerEvents;
            element.style.setProperty("pointer-events", pointerEvents);
            this.#safeMutationObserver(observer => {
                if (!(element instanceof Node)) {
                    return;
                }
                observer.observe(element, { attributes: true });
            });
        }
        #resetOriginalStyle() {
            const element = this.domElement, originalStyle = this.#originalStyle;
            if (!element || !originalStyle) {
                return;
            }
            setStyle(element, originalStyle, true);
        }
        #safeMutationObserver(callback) {
            if (!this.#mutationObserver) {
                return;
            }
            callback(this.#mutationObserver);
        }
        #setFullScreenStyle() {
            const element = this.domElement;
            if (!element) {
                return;
            }
            setStyle(element, getFullScreenStyle(this.#container.actualOptions.fullScreen.zIndex), true);
        }
    }

    class EventListeners {
        #container;
        #handlers;
        #resizeObserver;
        #resizeTimeout;
        constructor(container) {
            this.#container = container;
            this.#handlers = {
                visibilityChange: () => {
                    this.#handleVisibilityChange();
                },
                resize: () => {
                    this.#handleWindowResize();
                },
            };
        }
        addListeners() {
            this.#manageListeners(true);
        }
        removeListeners() {
            this.#manageListeners(false);
        }
        #handleVisibilityChange() {
            const container = this.#container, options = container.actualOptions;
            if (!options.pauseOnBlur) {
                return;
            }
            if (safeDocument().hidden) {
                container.pageHidden = true;
                container.pause();
            }
            else {
                container.pageHidden = false;
                if (container.animationStatus) {
                    container.play(true);
                }
                else {
                    container.draw(true);
                }
            }
        }
        #handleWindowResize() {
            if (this.#resizeTimeout) {
                clearTimeout(this.#resizeTimeout);
                this.#resizeTimeout = undefined;
            }
            const handleResize = async () => {
                const canvas = this.#container.canvas;
                await canvas.windowResize();
            };
            this.#resizeTimeout = setTimeout(() => void handleResize(), this.#container.actualOptions.resize.delay * millisecondsToSeconds);
        }
        #manageListeners(add) {
            const handlers = this.#handlers;
            this.#manageResize(add);
            manageListener(document, visibilityChangeEvent, handlers.visibilityChange, add, false);
        }
        #manageResize(add) {
            const handlers = this.#handlers, container = this.#container, options = container.actualOptions;
            if (!options.resize.enable) {
                return;
            }
            if (typeof ResizeObserver === "undefined") {
                manageListener(globalThis, resizeEvent, handlers.resize, add);
                return;
            }
            const canvasEl = container.canvas.domElement;
            if (this.#resizeObserver && !add) {
                if (canvasEl) {
                    this.#resizeObserver.unobserve(canvasEl);
                }
                this.#resizeObserver.disconnect();
                this.#resizeObserver = undefined;
            }
            else if (!this.#resizeObserver && add && canvasEl) {
                this.#resizeObserver = new ResizeObserver((entries) => {
                    const entry = entries.find(e => e.target === canvasEl);
                    if (!entry) {
                        return;
                    }
                    this.#handleWindowResize();
                });
                this.#resizeObserver.observe(canvasEl);
            }
        }
    }

    function loadEffectData(effect, effectOptions, id, reduceDuplicates) {
        const effectData = effectOptions.options[effect];
        return deepExtend({
            close: effectOptions.close,
        }, itemFromSingleOrMultiple(effectData, id, reduceDuplicates));
    }
    function loadShapeData(shape, shapeOptions, id, reduceDuplicates) {
        const shapeData = shapeOptions.options[shape];
        return deepExtend({
            close: shapeOptions.close,
        }, itemFromSingleOrMultiple(shapeData, id, reduceDuplicates));
    }
    function fixOutMode(data) {
        if (!isInArray(data.outMode, data.checkModes)) {
            return;
        }
        const diameter = data.radius * double;
        if (data.coord > data.maxCoord - diameter) {
            data.setCb(-data.radius);
        }
        else if (data.coord < diameter) {
            data.setCb(data.radius);
        }
    }
    function normalizeAngle(angle, modulus) {
        const normalized = angle % modulus;
        return normalized < defaultAngle ? normalized + modulus : normalized;
    }
    function initParticleState(particle, id, group) {
        particle.id = id;
        particle.group = group;
        particle.justWarped = false;
        particle.effectClose = true;
        particle.shapeClose = true;
        particle.pathRotation = false;
        particle.lastPathTime = 0;
        particle.destroyed = false;
        particle.unbreakable = false;
        particle.isRotating = false;
        particle.rotation = 0;
        particle.misplaced = false;
        particle.retina = {
            maxDistance: {},
            maxSpeed: 0,
            moveDrift: 0,
            moveSpeed: 0,
            sizeAnimationSpeed: 0,
        };
        particle.size = {
            value: 1,
            max: 1,
            min: 1,
            enable: false,
        };
        particle.outType = exports.ParticleOutType.normal;
        particle.ignoresResizeRatio = true;
    }
    function resolveParticleOptions(particle, container, pluginManager, overrideOptions) {
        const mainOptions = container.actualOptions, particlesOptions = loadParticlesOptions(pluginManager, container, mainOptions.particles), reduceDuplicates = particlesOptions.reduceDuplicates;
        particle.effect = itemFromSingleOrMultiple(particlesOptions.effect.type, particle.id, reduceDuplicates);
        particle.shape = itemFromSingleOrMultiple(particlesOptions.shape.type, particle.id, reduceDuplicates);
        const effectOptions = particlesOptions.effect, shapeOptions = particlesOptions.shape;
        if (overrideOptions) {
            if (overrideOptions.effect) {
                const overrideEffectType = overrideOptions.effect.type;
                if (overrideEffectType && overrideEffectType !== particle.effect) {
                    const effect = itemFromSingleOrMultiple(overrideEffectType, particle.id, reduceDuplicates);
                    if (effect) {
                        particle.effect = effect;
                    }
                }
                effectOptions.load(overrideOptions.effect);
            }
            if (overrideOptions.shape) {
                const overrideShapeType = overrideOptions.shape.type;
                if (overrideShapeType && overrideShapeType !== particle.shape) {
                    const shape = itemFromSingleOrMultiple(overrideShapeType, particle.id, reduceDuplicates);
                    if (shape) {
                        particle.shape = shape;
                    }
                }
                shapeOptions.load(overrideOptions.shape);
            }
        }
        if (particle.effect === randomColorValue) {
            const availableEffects = [...container.effectDrawers.keys()];
            particle.effect = availableEffects[Math.floor(getRandom() * availableEffects.length)];
        }
        if (particle.shape === randomColorValue) {
            const availableShapes = [...container.shapeDrawers.keys()];
            particle.shape = availableShapes[Math.floor(getRandom() * availableShapes.length)];
        }
        particle.effectData = particle.effect
            ? loadEffectData(particle.effect, effectOptions, particle.id, reduceDuplicates)
            : undefined;
        particle.shapeData = particle.shape
            ? loadShapeData(particle.shape, shapeOptions, particle.id, reduceDuplicates)
            : undefined;
        particlesOptions.load(overrideOptions);
        const effectData = particle.effectData, shapeData = particle.shapeData;
        if (effectData) {
            particlesOptions.load(effectData.particles);
        }
        if (shapeData) {
            particlesOptions.load(shapeData.particles);
        }
        particle.effectClose = effectData?.close ?? particlesOptions.effect.close;
        particle.shapeClose = shapeData?.close ?? particlesOptions.shape.close;
        return particlesOptions;
    }
    function initParticleDrawers(particle, container) {
        let effectDrawer, shapeDrawer;
        if (particle.effect) {
            effectDrawer = container.effectDrawers.get(particle.effect);
        }
        if (effectDrawer?.loadEffect) {
            effectDrawer.loadEffect(particle);
        }
        if (particle.shape) {
            shapeDrawer = container.shapeDrawers.get(particle.shape);
        }
        if (shapeDrawer?.loadShape) {
            shapeDrawer.loadShape(particle);
        }
        const sideCountFunc = shapeDrawer?.getSidesCount;
        if (sideCountFunc) {
            particle.sides = sideCountFunc(particle);
        }
    }
    function runUpdaterPreInit(updaters, particle) {
        for (const updater of updaters) {
            updater.preInit?.(particle);
        }
    }
    function runUpdaterInit(updaters, particle) {
        for (const updater of updaters) {
            updater.init(particle);
        }
    }
    function runDrawerInit(container, particle) {
        const shapeDrawer = particle.shape ? container.shapeDrawers.get(particle.shape) : undefined, effectDrawer = particle.effect ? container.effectDrawers.get(particle.effect) : undefined;
        effectDrawer?.particleInit?.(container, particle);
        shapeDrawer?.particleInit?.(container, particle);
    }
    function runParticleCreatedPlugins(container, particle) {
        for (const plugin of container.particleCreatedPlugins) {
            plugin.particleCreated?.(particle);
        }
    }
    class Particle {
        backColor;
        destroyed;
        direction;
        effect;
        effectClose;
        effectData;
        fillColor;
        fillEnabled;
        fillOpacity;
        group;
        id;
        ignoresResizeRatio;
        initialPosition;
        initialVelocity;
        isRotating;
        justWarped;
        lastPathTime;
        misplaced;
        moveCenter;
        offset;
        opacity;
        options;
        outType;
        pathRotation;
        position;
        randomIndexData;
        retina;
        roll;
        rotation;
        shape;
        shapeClose;
        shapeData;
        sides;
        size;
        spawning;
        strokeColor;
        strokeOpacity;
        strokeWidth;
        unbreakable;
        velocity;
        zIndexFactor;
        #cachedOpacityData = {
            fillOpacity: defaultOpacity$3,
            opacity: defaultOpacity$3,
            strokeOpacity: defaultOpacity$3,
        };
        #cachedPosition = Vector3d.origin;
        #cachedRotateData = { sin: 0, cos: 0 };
        #cachedTransform = {
            a: 1,
            b: 0,
            c: 0,
            d: 1,
        };
        #container;
        #modifiers = [];
        #pluginManager;
        constructor(pluginManager, container) {
            this.#pluginManager = pluginManager;
            this.#container = container;
        }
        addModifier(modifier) {
            this.#modifiers.push(modifier);
            this.#modifiers.sort((a, b) => a.priority - b.priority);
        }
        clearModifiers() {
            this.#modifiers.length = 0;
        }
        destroy(override) {
            if (this.unbreakable || this.destroyed) {
                return;
            }
            this.destroyed = true;
            this.clearModifiers();
            const container = this.#container, shapeDrawer = this.shape ? container.shapeDrawers.get(this.shape) : undefined;
            shapeDrawer?.particleDestroy?.(this);
            for (const plugin of container.particleDestroyedPlugins) {
                plugin.particleDestroyed?.(this, override);
            }
            for (const updater of container.particleUpdaters) {
                updater.particleDestroyed?.(this, override);
            }
            this.#container.dispatchEvent(exports.EventType.particleDestroyed, {
                particle: this,
            });
        }
        draw(delta) {
            const container = this.#container, render = container.canvas.render;
            render.drawParticlePlugins(this, delta);
            render.drawParticle(this, delta);
        }
        getAngle() {
            return this.rotation + (this.pathRotation ? this.velocity.angle : defaultAngle);
        }
        getFillColor() {
            return this.#getRollColor(this.#applyModifiers(getHslFromAnimation(this.fillColor), m => m.fillColor));
        }
        getMass() {
            return this.getRadius() ** squareExp * Math.PI * half;
        }
        getModifier(id) {
            return this.#modifiers.find(m => m.id === id);
        }
        getOpacity() {
            const zIndexOptions = this.options.zIndex, zIndexFactor = zIndexFactorOffset - this.zIndexFactor, zOpacityFactor = zIndexFactor ** zIndexOptions.opacityRate, baseOpacity = getRangeValue(this.opacity?.value ?? defaultOpacity$3), modifierOpacity = this.#applyModifiers(undefined, m => m.opacity), opacity = modifierOpacity ?? baseOpacity, fillOpacity = this.fillOpacity ?? defaultOpacity$3, strokeOpacity = this.strokeOpacity ?? defaultOpacity$3;
            this.#cachedOpacityData.fillOpacity = fillOpacity;
            this.#cachedOpacityData.opacity = opacity * zOpacityFactor;
            this.#cachedOpacityData.strokeOpacity = strokeOpacity;
            return this.#cachedOpacityData;
        }
        getPosition() {
            this.#cachedPosition.x = this.position.x + this.offset.x;
            this.#cachedPosition.y = this.position.y + this.offset.y;
            this.#cachedPosition.z = this.position.z;
            return this.#cachedPosition;
        }
        getRadius() {
            return this.#applyModifiers(this.size.value, m => m.radius);
        }
        getRotateData() {
            const angle = this.getAngle();
            this.#cachedRotateData.sin = Math.sin(angle);
            this.#cachedRotateData.cos = Math.cos(angle);
            return this.#cachedRotateData;
        }
        getStrokeColor() {
            return this.#getRollColor(this.#applyModifiers(getHslFromAnimation(this.strokeColor), m => m.strokeColor));
        }
        getTransformData(externalTransform) {
            const rotateData = this.getRotateData(), rotating = this.isRotating;
            this.#cachedTransform.a = rotateData.cos * (externalTransform.a ?? defaultTransform.a);
            this.#cachedTransform.b = rotating
                ? rotateData.sin * (externalTransform.b ?? identity$2)
                : (externalTransform.b ?? defaultTransform.b);
            this.#cachedTransform.c = rotating
                ? -rotateData.sin * (externalTransform.c ?? identity$2)
                : (externalTransform.c ?? defaultTransform.c);
            this.#cachedTransform.d = rotateData.cos * (externalTransform.d ?? defaultTransform.d);
            return this.#cachedTransform;
        }
        init(id, position, overrideOptions, group) {
            const container = this.#container;
            initParticleState(this, id, group);
            this.options = resolveParticleOptions(this, container, this.#pluginManager, overrideOptions);
            container.retina.initParticle(this);
            runUpdaterPreInit(container.particleUpdaters, this);
            this.#initPosition(position);
            this.initialVelocity = this.#calculateVelocity();
            this.velocity = this.initialVelocity.copy();
            this.zIndexFactor = this.position.z / container.zLayers;
            this.sides = 24;
            initParticleDrawers(this, container);
            this.spawning = false;
            runUpdaterInit(container.particleUpdaters, this);
            runDrawerInit(container, this);
            runParticleCreatedPlugins(container, this);
        }
        isInsideCanvas(direction) {
            return this.#getInsideCanvasResult({ direction }).inside;
        }
        isInsideCanvasForOutMode(outMode, direction) {
            return this.#getInsideCanvasResult({ direction, outMode }).inside;
        }
        isShowingBack() {
            if (!this.roll) {
                return false;
            }
            const angle = this.roll.angle;
            if (this.roll.horizontal && this.roll.vertical) {
                const adjustedAngle = normalizeAngle(angle, doublePI);
                return adjustedAngle >= Math.PI * half && adjustedAngle < Math.PI * triple * half;
            }
            if (this.roll.horizontal) {
                const adjustedAngle = normalizeAngle(angle + Math.PI * half, doublePI);
                return adjustedAngle >= Math.PI && adjustedAngle < Math.PI * double;
            }
            if (this.roll.vertical) {
                const adjustedAngle = normalizeAngle(angle, doublePI);
                return adjustedAngle >= Math.PI && adjustedAngle < Math.PI * double;
            }
            return false;
        }
        isVisible() {
            return !this.destroyed && !this.spawning && this.isInsideCanvas();
        }
        removeModifier(id) {
            const idx = this.#modifiers.findIndex(m => m.id === id);
            if (idx >= defaultAngle) {
                this.#modifiers.splice(idx, identity$2);
            }
        }
        reset() {
            for (const updater of this.#container.particleUpdaters) {
                updater.reset?.(this);
            }
        }
        #applyModifiers(base, getter) {
            let value = base;
            for (const mod of this.#modifiers) {
                if (mod.enabled) {
                    const override = getter(mod);
                    if (override !== undefined) {
                        value = override;
                    }
                }
            }
            return value;
        }
        #calcPosition(position, zIndex) {
            let tryCount = defaultRetryCount, posVec = position ? Vector3d.create(position.x, position.y, zIndex) : undefined;
            const container = this.#container, plugins = container.particlePositionPlugins, outModes = this.options.move.outModes, radius = this.getRadius(), canvasSize = container.canvas.size;
            for (;;) {
                for (const plugin of plugins) {
                    const pluginPos = plugin.particlePosition?.(posVec, this);
                    if (pluginPos) {
                        return Vector3d.create(pluginPos.x, pluginPos.y, zIndex);
                    }
                }
                const exactPosition = calcExactPositionOrRandomFromSize({
                    size: canvasSize,
                    position: posVec,
                }), pos = Vector3d.create(exactPosition.x, exactPosition.y, zIndex);
                this.#fixHorizontal(pos, radius, outModes.left ?? outModes.default);
                this.#fixHorizontal(pos, radius, outModes.right ?? outModes.default);
                this.#fixVertical(pos, radius, outModes.top ?? outModes.default);
                this.#fixVertical(pos, radius, outModes.bottom ?? outModes.default);
                let isValidPosition = true;
                for (const plugin of container.particles.checkParticlePositionPlugins) {
                    isValidPosition = plugin.checkParticlePosition?.(this, pos, tryCount) ?? true;
                    if (!isValidPosition) {
                        break;
                    }
                }
                if (isValidPosition) {
                    return pos;
                }
                tryCount += tryCountIncrement;
                posVec = undefined;
            }
        }
        #calculateVelocity() {
            const moveOptions = this.options.move, baseVelocity = getParticleBaseVelocity(this.direction), res = baseVelocity.copy();
            if (moveOptions.direction === exports.MoveDirection.inside || moveOptions.direction === exports.MoveDirection.outside) {
                return res;
            }
            const rad = degToRad(getRangeValue(moveOptions.angle.value)), radOffset = degToRad(getRangeValue(moveOptions.angle.offset)), range = {
                left: radOffset - rad * half,
                right: radOffset + rad * half,
            };
            if (!moveOptions.straight) {
                res.angle += randomInRangeValue(setRangeValue(range.left, range.right));
            }
            if (moveOptions.random && typeof moveOptions.speed === "number") {
                res.length *= getRandom();
            }
            return res;
        }
        #fixHorizontal(pos, radius, outMode) {
            fixOutMode({
                outMode,
                checkModes: [exports.OutMode.bounce],
                coord: pos.x,
                maxCoord: this.#container.canvas.size.width,
                setCb: (value) => (pos.x += value),
                radius,
            });
        }
        #fixVertical(pos, radius, outMode) {
            fixOutMode({
                outMode,
                checkModes: [exports.OutMode.bounce],
                coord: pos.y,
                maxCoord: this.#container.canvas.size.height,
                setCb: (value) => (pos.y += value),
                radius,
            });
        }
        #getDefaultInsideCanvasResult(direction, outMode) {
            const radius = this.getRadius(), canvasSize = this.#container.canvas.size, position = this.position, isBounce = outMode === exports.OutMode.bounce;
            if (direction === exports.OutModeDirection.bottom) {
                return {
                    inside: isBounce ? position.y + radius < canvasSize.height : position.y - radius < canvasSize.height,
                    reason: "default",
                };
            }
            if (direction === exports.OutModeDirection.left) {
                return {
                    inside: isBounce ? position.x - radius > defaultAngle : position.x + radius > defaultAngle,
                    reason: "default",
                };
            }
            if (direction === exports.OutModeDirection.right) {
                return {
                    inside: isBounce ? position.x + radius < canvasSize.width : position.x - radius < canvasSize.width,
                    reason: "default",
                };
            }
            if (direction === exports.OutModeDirection.top) {
                return {
                    inside: isBounce ? position.y - radius > defaultAngle : position.y + radius > defaultAngle,
                    reason: "default",
                };
            }
            return {
                inside: position.x >= -radius &&
                    position.y >= -radius &&
                    position.y <= canvasSize.height + radius &&
                    position.x <= canvasSize.width + radius,
                reason: "default",
            };
        }
        #getInsideCanvasCallbackData(direction, outMode) {
            return {
                canvasSize: this.#container.canvas.size,
                direction,
                outMode,
                particle: this,
                radius: this.getRadius(),
            };
        }
        #getInsideCanvasResult(data) {
            const defaultResult = this.#getDefaultInsideCanvasResult(data.direction, data.outMode), container = this.#container, shapeDrawer = this.shape ? container.shapeDrawers.get(this.shape) : undefined, effectDrawer = this.effect ? container.effectDrawers.get(this.effect) : undefined, shapeCheck = shapeDrawer?.isInsideCanvas, effectCheck = effectDrawer?.isInsideCanvas;
            if (!shapeCheck && !effectCheck) {
                return defaultResult;
            }
            const callbackData = this.#getInsideCanvasCallbackData(data.direction, data.outMode), shapeResult = shapeCheck ? this.#normalizeInsideCanvasResult(shapeCheck(callbackData), "shape") : undefined, effectResult = effectCheck ? this.#normalizeInsideCanvasResult(effectCheck(callbackData), "effect") : undefined;
            if (shapeResult && effectResult) {
                const margin = Math.max(shapeResult.margin ?? defaultAngle, effectResult.margin ?? defaultAngle);
                return {
                    inside: shapeResult.inside && effectResult.inside,
                    margin: margin > defaultAngle ? margin : undefined,
                    reason: "combined",
                };
            }
            return shapeResult ?? effectResult ?? defaultResult;
        }
        #getRollColor(color) {
            if (!color || !this.roll || (!this.backColor && !this.roll.alter)) {
                return color;
            }
            if (!this.isShowingBack()) {
                return color;
            }
            if (this.backColor) {
                return this.backColor;
            }
            if (this.roll.alter) {
                return alterHsl(color, this.roll.alter.type, this.roll.alter.value);
            }
            return color;
        }
        #initPosition(position) {
            const container = this.#container, zIndexValue = Math.floor(getRangeValue(this.options.zIndex.value)), initialPosition = this.#calcPosition(position, clamp(zIndexValue, minZ, container.zLayers));
            if (!initialPosition) {
                throw new Error("a valid position cannot be found for particle");
            }
            this.position = initialPosition;
            this.initialPosition = this.position.copy();
            const canvasSize = container.canvas.size;
            this.moveCenter = {
                ...getPosition(this.options.move.center, canvasSize),
                radius: this.options.move.center.radius,
                mode: this.options.move.center.mode,
            };
            this.direction = getParticleDirectionAngle(this.options.move.direction, this.position, this.moveCenter);
            switch (this.options.move.direction) {
                case exports.MoveDirection.inside:
                    this.outType = exports.ParticleOutType.inside;
                    break;
                case exports.MoveDirection.outside:
                    this.outType = exports.ParticleOutType.outside;
                    break;
            }
            this.offset = Vector.origin;
        }
        #normalizeInsideCanvasResult(result, reason) {
            if (typeof result === "boolean") {
                return {
                    inside: result,
                    reason,
                };
            }
            return {
                inside: result.inside,
                margin: result.margin,
                reason: result.reason ?? reason,
            };
        }
    }

    class SpatialHashGrid {
        #cellSize;
        #cells = new Map();
        #circlePool = [];
        #circlePoolIdx;
        #pendingCellSize;
        #rectanglePool = [];
        #rectanglePoolIdx;
        constructor(cellSize) {
            this.#cellSize = cellSize;
            this.#circlePoolIdx = 0;
            this.#rectanglePoolIdx = 0;
        }
        clear() {
            this.#cells.clear();
            const pendingCellSize = this.#pendingCellSize;
            if (pendingCellSize) {
                this.#cellSize = pendingCellSize;
            }
            this.#pendingCellSize = undefined;
        }
        insert(particle) {
            const { x, y } = particle.getPosition(), key = this.#cellKeyFromCoords(x, y);
            if (!this.#cells.has(key)) {
                this.#cells.set(key, []);
            }
            this.#cells.get(key)?.push(particle);
        }
        query(range, check, out = []) {
            const bounds = this.#getRangeBounds(range);
            if (!bounds) {
                return out;
            }
            const minCellX = Math.floor(bounds.minX / this.#cellSize), maxCellX = Math.floor(bounds.maxX / this.#cellSize), minCellY = Math.floor(bounds.minY / this.#cellSize), maxCellY = Math.floor(bounds.maxY / this.#cellSize);
            for (let cx = minCellX; cx <= maxCellX; cx++) {
                for (let cy = minCellY; cy <= maxCellY; cy++) {
                    const key = `${cx}_${cy}`, cellParticles = this.#cells.get(key);
                    if (!cellParticles) {
                        continue;
                    }
                    for (const p of cellParticles) {
                        if (check && !check(p)) {
                            continue;
                        }
                        if (range.contains(p.getPosition())) {
                            out.push(p);
                        }
                    }
                }
            }
            return out;
        }
        queryCircle(position, radius, check, out = []) {
            const circle = this.#acquireCircle(position.x, position.y, radius), result = this.query(circle, check, out);
            this.#releaseShapes();
            return result;
        }
        queryRectangle(position, size, check, out = []) {
            const rect = this.#acquireRectangle(position.x, position.y, size.width, size.height), result = this.query(rect, check, out);
            this.#releaseShapes();
            return result;
        }
        setCellSize(cellSize) {
            this.#pendingCellSize = cellSize;
        }
        #acquireCircle(x, y, r) {
            return (this.#circlePool[this.#circlePoolIdx++] ??= new Circle(x, y, r)).reset(x, y, r);
        }
        #acquireRectangle(x, y, w, h) {
            return (this.#rectanglePool[this.#rectanglePoolIdx++] ??= new Rectangle(x, y, w, h)).reset(x, y, w, h);
        }
        #cellKeyFromCoords(x, y) {
            const cellX = Math.floor(x / this.#cellSize), cellY = Math.floor(y / this.#cellSize);
            return `${cellX}_${cellY}`;
        }
        #getRangeBounds(range) {
            if (range instanceof Circle) {
                const r = range.radius, { x, y } = range.position;
                return {
                    minX: x - r,
                    maxX: x + r,
                    minY: y - r,
                    maxY: y + r,
                };
            }
            if (range instanceof Rectangle) {
                const { x, y } = range.position, { width, height } = range.size;
                return {
                    minX: x,
                    maxX: x + width,
                    minY: y,
                    maxY: y + height,
                };
            }
            return null;
        }
        #releaseShapes() {
            this.#circlePoolIdx = 0;
            this.#rectanglePoolIdx = 0;
        }
    }

    class ParticlesManager {
        checkParticlePositionPlugins;
        grid;
        #array;
        #container;
        #groupLimits;
        #limit;
        #nextId;
        #particleBuckets;
        #particleResetPlugins;
        #particleUpdatePlugins;
        #pluginManager;
        #pool;
        #postParticleUpdatePlugins;
        #postUpdatePlugins;
        #resizeFactor;
        #updatePlugins;
        #zBuckets;
        constructor(pluginManager, container) {
            this.#pluginManager = pluginManager;
            this.#container = container;
            this.#nextId = 0;
            this.#array = [];
            this.#pool = [];
            this.#limit = 0;
            this.#groupLimits = new Map();
            this.#particleBuckets = new Map();
            this.#zBuckets = this.#createBuckets(this.#container.zLayers);
            this.grid = new SpatialHashGrid(spatialHashGridCellSize);
            this.checkParticlePositionPlugins = [];
            this.#particleResetPlugins = [];
            this.#particleUpdatePlugins = [];
            this.#postUpdatePlugins = [];
            this.#postParticleUpdatePlugins = [];
            this.#updatePlugins = [];
        }
        get count() {
            return this.#array.length;
        }
        addParticle(position, overrideOptions, group, initializer) {
            const limitMode = this.#container.actualOptions.particles.number.limit.mode, limit = group === undefined ? this.#limit : (this.#groupLimits.get(group) ?? this.#limit), currentCount = this.count;
            if (limit > minLimit) {
                switch (limitMode) {
                    case exports.LimitMode.delete: {
                        const countToRemove = currentCount + countOffset - limit;
                        if (countToRemove > minCount) {
                            this.removeQuantity(countToRemove);
                        }
                        break;
                    }
                    case exports.LimitMode.wait:
                        if (currentCount >= limit) {
                            return;
                        }
                        break;
                }
            }
            try {
                const particle = this.#pool.pop() ?? new Particle(this.#pluginManager, this.#container);
                particle.init(this.#nextId, position, overrideOptions, group);
                let canAdd = true;
                if (initializer) {
                    canAdd = initializer(particle);
                }
                if (!canAdd) {
                    this.#pool.push(particle);
                    return;
                }
                this.#array.push(particle);
                this.#insertParticleIntoBucket(particle);
                this.#nextId++;
                this.#container.dispatchEvent(exports.EventType.particleAdded, {
                    particle,
                });
                return particle;
            }
            catch (e) {
                getLogger().warning(`error adding particle: ${e}`);
            }
            return undefined;
        }
        clear() {
            this.#array = [];
            this.#particleBuckets.clear();
            this.#resetBuckets(this.#container.zLayers);
        }
        destroy() {
            this.#array = [];
            this.#pool.length = 0;
            this.#particleBuckets.clear();
            this.#zBuckets = [];
            this.checkParticlePositionPlugins = [];
            this.#particleResetPlugins = [];
            this.#particleUpdatePlugins = [];
            this.#postUpdatePlugins = [];
            this.#postParticleUpdatePlugins = [];
            this.#updatePlugins = [];
        }
        drawParticles(delta) {
            for (let i = this.#zBuckets.length - one; i >= minIndex; i--) {
                const bucket = this.#zBuckets[i];
                if (!bucket) {
                    continue;
                }
                for (const particle of bucket) {
                    particle.draw(delta);
                }
            }
        }
        filter(condition) {
            return this.#array.filter(condition);
        }
        find(condition) {
            return this.#array.find(condition);
        }
        get(index) {
            return this.#array[index];
        }
        async init() {
            const container = this.#container, options = container.actualOptions;
            this.checkParticlePositionPlugins = [];
            this.#updatePlugins = [];
            this.#particleUpdatePlugins = [];
            this.#postUpdatePlugins = [];
            this.#particleResetPlugins = [];
            this.#postParticleUpdatePlugins = [];
            this.#particleBuckets.clear();
            this.#resetBuckets(container.zLayers);
            this.grid = new SpatialHashGrid(spatialHashGridCellSize * container.retina.pixelRatio);
            for (const plugin of container.plugins) {
                if (plugin.redrawInit) {
                    await plugin.redrawInit();
                }
                if (plugin.checkParticlePosition) {
                    this.checkParticlePositionPlugins.push(plugin);
                }
                if (plugin.update) {
                    this.#updatePlugins.push(plugin);
                }
                if (plugin.particleUpdate) {
                    this.#particleUpdatePlugins.push(plugin);
                }
                if (plugin.postUpdate) {
                    this.#postUpdatePlugins.push(plugin);
                }
                if (plugin.particleReset) {
                    this.#particleResetPlugins.push(plugin);
                }
                if (plugin.postParticleUpdate) {
                    this.#postParticleUpdatePlugins.push(plugin);
                }
            }
            await this.#container.initDrawersAndUpdaters();
            for (const drawer of this.#container.effectDrawers.values()) {
                await drawer.init?.(container);
            }
            for (const drawer of this.#container.shapeDrawers.values()) {
                await drawer.init?.(container);
            }
            let handled = false;
            for (const plugin of container.plugins) {
                handled = plugin.particlesInitialization?.() ?? handled;
                if (handled) {
                    break;
                }
            }
            if (!handled) {
                const particlesOptions = options.particles, groups = particlesOptions.groups;
                for (const group in groups) {
                    const groupOptions = groups[group];
                    if (!groupOptions) {
                        continue;
                    }
                    for (let i = this.count, j = 0; j < groupOptions.number.value && i < particlesOptions.number.value; i++, j++) {
                        this.addParticle(undefined, groupOptions, group);
                    }
                }
                for (let i = this.count; i < particlesOptions.number.value; i++) {
                    this.addParticle();
                }
            }
        }
        push(nb, position, overrideOptions, group) {
            for (let i = 0; i < nb; i++) {
                this.addParticle(position, overrideOptions, group);
            }
        }
        async redraw() {
            this.clear();
            await this.init();
            this.#container.canvas.render.drawParticles({ value: 0, factor: 0 });
        }
        remove(particle, group, override) {
            this.removeAt(this.#array.indexOf(particle), undefined, group, override);
        }
        removeAt(index, quantity = defaultRemoveQuantity, group, override) {
            if (index < minIndex || index > this.count) {
                return;
            }
            let deleted = 0;
            for (let i = index; deleted < quantity && i < this.count; i++) {
                if (this.#removeParticle(i, group, override)) {
                    i--;
                    deleted++;
                }
            }
        }
        removeQuantity(quantity, group) {
            this.removeAt(minIndex, quantity, group);
        }
        setDensity() {
            const options = this.#container.actualOptions, groups = options.particles.groups;
            let pluginsCount = 0;
            for (const plugin of this.#container.plugins) {
                if (plugin.particlesDensityCount) {
                    pluginsCount += plugin.particlesDensityCount();
                }
            }
            for (const group in groups) {
                const groupData = groups[group];
                if (!groupData) {
                    continue;
                }
                const groupDataOptions = loadParticlesOptions(this.#pluginManager, this.#container, groupData);
                this.#applyDensity(groupDataOptions, pluginsCount, group);
            }
            this.#applyDensity(options.particles, pluginsCount);
        }
        setResizeFactor(factor) {
            this.#resizeFactor = factor;
        }
        update(delta) {
            this.grid.clear();
            for (const plugin of this.#updatePlugins) {
                plugin.update?.(delta);
            }
            const particlesToDelete = this.#updateParticlesPhase1(delta);
            for (const plugin of this.#postUpdatePlugins) {
                plugin.postUpdate?.(delta);
            }
            this.#updateParticlesPhase2(delta, particlesToDelete);
            if (particlesToDelete.size) {
                for (const particle of particlesToDelete) {
                    this.remove(particle);
                }
            }
            this.#resizeFactor = undefined;
        }
        #addToPool(...particles) {
            this.#pool.push(...particles);
        }
        #applyDensity(options, pluginsCount, group, groupOptions) {
            const numberOptions = options.number;
            if (!numberOptions.density.enable) {
                if (group === undefined) {
                    this.#limit = numberOptions.limit.value;
                }
                else if (groupOptions?.number.limit.value ?? numberOptions.limit.value) {
                    this.#groupLimits.set(group, groupOptions?.number.limit.value ?? numberOptions.limit.value);
                }
                return;
            }
            const densityFactor = this.#initDensityFactor(numberOptions.density), optParticlesNumber = numberOptions.value, optParticlesLimit = numberOptions.limit.value > minLimit ? numberOptions.limit.value : optParticlesNumber, particlesNumber = Math.min(optParticlesNumber, optParticlesLimit) * densityFactor + pluginsCount, particlesCount = Math.min(this.count, this.filter(t => t.group === group).length);
            if (group === undefined) {
                this.#limit = numberOptions.limit.value * densityFactor;
            }
            else {
                this.#groupLimits.set(group, numberOptions.limit.value * densityFactor);
            }
            if (particlesCount < particlesNumber) {
                this.push(Math.abs(particlesNumber - particlesCount), undefined, options, group);
            }
            else if (particlesCount > particlesNumber) {
                this.removeQuantity(particlesCount - particlesNumber, group);
            }
        }
        #createBuckets(zLayers) {
            const bucketCount = Math.max(Math.floor(zLayers), one);
            return Array.from({ length: bucketCount }, () => []);
        }
        #getBucketIndex(zIndex) {
            const maxBucketIndex = this.#zBuckets.length - one;
            if (maxBucketIndex <= minIndex) {
                return minIndex;
            }
            return Math.min(Math.max(Math.floor(zIndex), minIndex), maxBucketIndex);
        }
        #initDensityFactor(densityOptions) {
            const container = this.#container;
            if (!densityOptions.enable) {
                return defaultDensityFactor;
            }
            const canvasSize = container.canvas.size, pxRatio = container.retina.pixelRatio;
            if (!canvasSize.width || !canvasSize.height) {
                return defaultDensityFactor;
            }
            return ((canvasSize.width * canvasSize.height) / (densityOptions.height * densityOptions.width * pxRatio ** squareExp));
        }
        #insertParticleIntoBucket(particle) {
            const bucketIndex = this.#getBucketIndex(particle.position.z), bucket = this.#zBuckets[bucketIndex];
            if (!bucket) {
                return;
            }
            bucket.push(particle);
            this.#particleBuckets.set(particle.id, bucketIndex);
        }
        #removeParticle(index, group, override) {
            const particle = this.#array[index];
            if (!particle) {
                return false;
            }
            if (particle.group !== group) {
                return false;
            }
            this.#array.splice(index, deleteCount);
            this.#removeParticleFromBucket(particle);
            particle.destroy(override);
            this.#container.dispatchEvent(exports.EventType.particleRemoved, {
                particle,
            });
            this.#addToPool(particle);
            return true;
        }
        #removeParticleFromBucket(particle) {
            const bucketIndex = this.#particleBuckets.get(particle.id) ?? this.#getBucketIndex(particle.position.z), bucket = this.#zBuckets[bucketIndex];
            if (!bucket) {
                this.#particleBuckets.delete(particle.id);
                return;
            }
            const idx = bucket.findIndex(p => p.id === particle.id);
            if (idx >= minIndex) {
                bucket.splice(idx, deleteCount);
            }
            this.#particleBuckets.delete(particle.id);
        }
        #resetBuckets(zLayers) {
            const bucketCount = Math.max(Math.floor(zLayers), one);
            if (this.#zBuckets.length !== bucketCount) {
                this.#zBuckets = this.#createBuckets(bucketCount);
                return;
            }
            for (const bucket of this.#zBuckets) {
                bucket.length = minIndex;
            }
        }
        #updateParticleBucket(particle) {
            const newBucketIndex = this.#getBucketIndex(particle.position.z), currentBucketIndex = this.#particleBuckets.get(particle.id);
            if (currentBucketIndex === undefined) {
                this.#insertParticleIntoBucket(particle);
                return;
            }
            if (currentBucketIndex === newBucketIndex) {
                return;
            }
            const currentBucket = this.#zBuckets[currentBucketIndex];
            if (currentBucket) {
                const idx = currentBucket.findIndex(p => p.id === particle.id);
                if (idx >= minIndex) {
                    currentBucket.splice(idx, deleteCount);
                }
            }
            const newBucket = this.#zBuckets[newBucketIndex];
            if (!newBucket) {
                this.#particleBuckets.set(particle.id, newBucketIndex);
                return;
            }
            newBucket.push(particle);
            if (newBucket.length >= double) {
                const prev = newBucket[newBucket.length - double];
                if (prev && particle.id < prev.id) {
                    newBucket.sort((a, b) => a.id - b.id);
                }
            }
            this.#particleBuckets.set(particle.id, newBucketIndex);
        }
        #updateParticlesPhase1(delta) {
            const particlesToDelete = new Set(), resizeFactor = this.#resizeFactor;
            for (const particle of this.#array) {
                if (resizeFactor && !particle.ignoresResizeRatio) {
                    particle.position.x *= resizeFactor.width;
                    particle.position.y *= resizeFactor.height;
                    particle.initialPosition.x *= resizeFactor.width;
                    particle.initialPosition.y *= resizeFactor.height;
                }
                particle.ignoresResizeRatio = false;
                for (const plugin of this.#particleResetPlugins) {
                    plugin.particleReset?.(particle);
                }
                for (const plugin of this.#particleUpdatePlugins) {
                    if (particle.destroyed) {
                        break;
                    }
                    plugin.particleUpdate?.(particle, delta);
                }
                if (particle.destroyed) {
                    particlesToDelete.add(particle);
                    continue;
                }
                this.grid.insert(particle);
            }
            return particlesToDelete;
        }
        #updateParticlesPhase2(delta, particlesToDelete) {
            for (const particle of this.#array) {
                if (particle.destroyed) {
                    particlesToDelete.add(particle);
                    continue;
                }
                for (const updater of this.#container.particleUpdaters) {
                    updater.update(particle, delta);
                }
                if (!particle.spawning) {
                    for (const plugin of this.#postParticleUpdatePlugins) {
                        plugin.postParticleUpdate?.(particle, delta);
                    }
                }
                this.#updateParticleBucket(particle);
            }
        }
    }

    class Retina {
        pixelRatio;
        reduceFactor;
        #container;
        constructor(container) {
            this.#container = container;
            this.pixelRatio = defaultRatio$1;
            this.reduceFactor = defaultReduceFactor;
        }
        init() {
            const container = this.#container, options = container.actualOptions;
            this.pixelRatio = options.detectRetina ? devicePixelRatio : defaultRatio$1;
            this.reduceFactor = defaultReduceFactor;
            const ratio = this.pixelRatio, canvas = container.canvas, element = canvas.domElement;
            if (element) {
                canvas.size.width = element.offsetWidth * ratio;
                canvas.size.height = element.offsetHeight * ratio;
            }
        }
        initParticle(particle) {
            const options = particle.options, ratio = this.pixelRatio, moveOptions = options.move, moveDistance = moveOptions.distance, props = particle.retina;
            props.maxSpeed = getRangeValue(moveOptions.gravity.maxSpeed) * ratio;
            props.moveDrift = getRangeValue(moveOptions.drift) * ratio;
            props.moveSpeed = getRangeValue(moveOptions.speed) * ratio;
            const maxDistance = props.maxDistance;
            maxDistance.horizontal = moveDistance.horizontal === undefined ? undefined : moveDistance.horizontal * ratio;
            maxDistance.vertical = moveDistance.vertical === undefined ? undefined : moveDistance.vertical * ratio;
        }
    }

    function guardCheck(container) {
        return !container.destroyed;
    }
    function updateDelta(delta, value, fpsLimit = defaultFps, smooth = false) {
        delta.value = value;
        delta.factor = smooth ? defaultFps / fpsLimit : (defaultFps * value) / millisecondsToSeconds;
    }
    function loadContainerOptions(pluginManager, container, ...sourceOptionsArr) {
        const options = new Options(pluginManager, container);
        loadOptions(options, ...sourceOptionsArr);
        return options;
    }
    class Container {
        actualOptions;
        canvas;
        destroyed;
        effectDrawers;
        fpsLimit;
        hdr;
        hdrMode;
        id;
        pageHidden;
        particleCreatedPlugins;
        particleDestroyedPlugins;
        particlePositionPlugins;
        particleUpdaters;
        particles;
        peakNits;
        plugins;
        retina;
        shapeDrawers;
        started;
        zLayers;
        #delay;
        #delayTimeout;
        #delta = { value: 0, factor: 0 };
        #dispatchCallback;
        #drawAnimationFrame;
        #duration;
        #eventListeners;
        #firstStart;
        #initialSourceOptions;
        #lastFrameTime;
        #lifeTime;
        #onDestroy;
        #options;
        #paused;
        #pluginManager;
        #smooth;
        #sourceOptions;
        constructor(params) {
            const { dispatchCallback, pluginManager, id, onDestroy, sourceOptions } = params;
            this.#pluginManager = pluginManager;
            this.#dispatchCallback = dispatchCallback;
            this.#onDestroy = onDestroy;
            this.id = Symbol(id);
            this.fpsLimit = 120;
            this.hdr = false;
            this.hdrMode = exports.HdrMode.standard;
            this.peakNits = 400;
            this.#smooth = false;
            this.#delay = 0;
            this.#duration = 0;
            this.#lifeTime = 0;
            this.#firstStart = true;
            this.started = false;
            this.destroyed = false;
            this.#paused = true;
            this.#lastFrameTime = 0;
            this.zLayers = 100;
            this.pageHidden = false;
            this.#sourceOptions = sourceOptions;
            this.#initialSourceOptions = sourceOptions;
            this.effectDrawers = new Map();
            this.shapeDrawers = new Map();
            this.particleUpdaters = [];
            this.retina = new Retina(this);
            this.canvas = new CanvasManager(this.#pluginManager, this);
            this.particles = new ParticlesManager(this.#pluginManager, this);
            this.plugins = [];
            this.particleDestroyedPlugins = [];
            this.particleCreatedPlugins = [];
            this.particlePositionPlugins = [];
            this.#options = loadContainerOptions(this.#pluginManager, this);
            this.actualOptions = loadContainerOptions(this.#pluginManager, this);
            this.#eventListeners = new EventListeners(this);
            this.dispatchEvent(exports.EventType.containerBuilt);
        }
        get animationStatus() {
            return !this.#paused && !this.pageHidden && guardCheck(this);
        }
        get options() {
            return this.#options;
        }
        get sourceOptions() {
            return this.#sourceOptions;
        }
        addLifeTime(value) {
            this.#lifeTime += value;
        }
        alive() {
            return !this.#duration || this.#lifeTime <= this.#duration;
        }
        destroy(remove = true) {
            if (!guardCheck(this)) {
                return;
            }
            this.stop();
            this.particles.destroy();
            this.canvas.destroy();
            for (const [, effectDrawer] of this.effectDrawers) {
                effectDrawer.destroy?.(this);
            }
            for (const [, shapeDrawer] of this.shapeDrawers) {
                shapeDrawer.destroy?.(this);
            }
            for (const plugin of this.plugins) {
                plugin.destroy?.();
            }
            this.effectDrawers = new Map();
            this.shapeDrawers = new Map();
            this.particleUpdaters = [];
            this.plugins.length = 0;
            this.#pluginManager.clearPlugins(this);
            this.destroyed = true;
            this.#onDestroy(remove);
            this.dispatchEvent(exports.EventType.containerDestroyed);
        }
        dispatchEvent(type, data) {
            this.#dispatchCallback(type, {
                container: this,
                data,
            });
        }
        draw(force) {
            if (!guardCheck(this)) {
                return;
            }
            let refreshTime = force;
            this.#drawAnimationFrame = animate((timestamp) => {
                if (refreshTime) {
                    this.#lastFrameTime = undefined;
                    refreshTime = false;
                }
                this.#nextFrame(timestamp);
            });
        }
        async export(type, options = {}) {
            for (const plugin of this.plugins) {
                if (!plugin.export) {
                    continue;
                }
                const res = await plugin.export(type, options);
                if (!res.supported) {
                    continue;
                }
                return res.blob;
            }
            getLogger().error(`Export plugin with type ${type} not found`);
            return undefined;
        }
        async init() {
            if (!guardCheck(this)) {
                return;
            }
            const allContainerPlugins = new Map();
            for (const plugin of this.#pluginManager.plugins) {
                const containerPlugin = await plugin.getPlugin(this);
                if (containerPlugin.preInit) {
                    await containerPlugin.preInit();
                }
                allContainerPlugins.set(plugin, containerPlugin);
            }
            await this.initDrawersAndUpdaters();
            this.#options = loadContainerOptions(this.#pluginManager, this, this.#initialSourceOptions, this.sourceOptions);
            this.actualOptions = loadContainerOptions(this.#pluginManager, this, this.#options);
            this.plugins.length = 0;
            this.particleDestroyedPlugins.length = 0;
            this.particleCreatedPlugins.length = 0;
            this.particlePositionPlugins.length = 0;
            for (const [plugin, containerPlugin] of allContainerPlugins) {
                if (plugin.needsPlugin(this.actualOptions)) {
                    this.plugins.push(containerPlugin);
                    if (containerPlugin.particleCreated) {
                        this.particleCreatedPlugins.push(containerPlugin);
                    }
                    if (containerPlugin.particleDestroyed) {
                        this.particleDestroyedPlugins.push(containerPlugin);
                    }
                    if (containerPlugin.particlePosition) {
                        this.particlePositionPlugins.push(containerPlugin);
                    }
                }
            }
            this.retina.init();
            this.canvas.init();
            this.updateActualOptions();
            this.canvas.initBackground();
            this.canvas.resize();
            const { delay, duration, fpsLimit, smooth, zLayers } = this.actualOptions, hdrOptions = this.actualOptions.hdr;
            this.hdrMode = hdrOptions.mode;
            this.peakNits = hdrOptions.peakNits;
            this.zLayers = zLayers;
            this.#duration = getRangeValue(duration) * millisecondsToSeconds;
            this.#delay = getRangeValue(delay) * millisecondsToSeconds;
            this.#lifeTime = 0;
            this.fpsLimit = fpsLimit > minFpsLimit ? fpsLimit : defaultFpsLimit;
            this.#smooth = smooth;
            for (const plugin of this.plugins) {
                await plugin.init?.();
            }
            await this.particles.init();
            this.dispatchEvent(exports.EventType.containerInit);
            this.particles.setDensity();
            for (const plugin of this.plugins) {
                plugin.particlesSetup?.();
            }
            this.dispatchEvent(exports.EventType.particlesSetup);
        }
        async initDrawersAndUpdaters() {
            const pluginManager = this.#pluginManager;
            this.effectDrawers = await pluginManager.getEffectDrawers(this, true);
            this.shapeDrawers = await pluginManager.getShapeDrawers(this, true);
            this.particleUpdaters = await pluginManager.getUpdaters(this, true);
        }
        pause() {
            if (!guardCheck(this)) {
                return;
            }
            if (this.#drawAnimationFrame !== undefined) {
                cancelAnimation(this.#drawAnimationFrame);
                this.#drawAnimationFrame = undefined;
            }
            if (this.#paused) {
                return;
            }
            for (const plugin of this.plugins) {
                plugin.pause?.();
            }
            if (!this.pageHidden) {
                this.#paused = true;
            }
            this.dispatchEvent(exports.EventType.containerPaused);
        }
        play(force) {
            if (!guardCheck(this)) {
                return;
            }
            const needsUpdate = this.#paused || force;
            if (this.#firstStart && !this.actualOptions.autoPlay) {
                this.#firstStart = false;
                return;
            }
            if (this.#paused) {
                this.#paused = false;
            }
            if (needsUpdate) {
                for (const plugin of this.plugins) {
                    if (plugin.play) {
                        plugin.play();
                    }
                }
            }
            this.dispatchEvent(exports.EventType.containerPlay);
            this.draw(needsUpdate ?? false);
        }
        async refresh() {
            if (!guardCheck(this)) {
                return;
            }
            this.stop();
            return this.start();
        }
        async reset(sourceOptions) {
            if (!guardCheck(this)) {
                return;
            }
            this.#initialSourceOptions = sourceOptions;
            this.#sourceOptions = sourceOptions;
            this.#options = loadContainerOptions(this.#pluginManager, this, this.#initialSourceOptions, this.sourceOptions);
            this.actualOptions = loadContainerOptions(this.#pluginManager, this, this.#options);
            return this.refresh();
        }
        async start() {
            if (!guardCheck(this) || this.started) {
                return;
            }
            await this.init();
            this.started = true;
            await new Promise(resolve => {
                const start = async () => {
                    this.#eventListeners.addListeners();
                    for (const plugin of this.plugins) {
                        await plugin.start?.();
                    }
                    this.dispatchEvent(exports.EventType.containerStarted);
                    this.play();
                    resolve();
                };
                this.#delayTimeout = setTimeout(() => void start(), this.#delay);
            });
        }
        stop() {
            if (!guardCheck(this) || !this.started) {
                return;
            }
            if (this.#delayTimeout) {
                clearTimeout(this.#delayTimeout);
                this.#delayTimeout = undefined;
            }
            this.#firstStart = true;
            this.started = false;
            this.#eventListeners.removeListeners();
            this.pause();
            this.particles.clear();
            this.canvas.stop();
            for (const plugin of this.plugins) {
                plugin.stop?.();
            }
            this.particleCreatedPlugins.length = 0;
            this.particleDestroyedPlugins.length = 0;
            this.particlePositionPlugins.length = 0;
            this.#sourceOptions = this.#options;
            this.dispatchEvent(exports.EventType.containerStopped);
        }
        updateActualOptions() {
            let refresh = false;
            for (const plugin of this.plugins) {
                if (plugin.updateActualOptions) {
                    refresh = plugin.updateActualOptions() || refresh;
                }
            }
            return refresh;
        }
        #nextFrame(timestamp) {
            try {
                if (!this.#smooth &&
                    this.#lastFrameTime !== undefined &&
                    timestamp < this.#lastFrameTime + millisecondsToSeconds / this.fpsLimit) {
                    this.draw(false);
                    return;
                }
                this.#lastFrameTime ??= timestamp;
                updateDelta(this.#delta, timestamp - this.#lastFrameTime, this.fpsLimit, this.#smooth);
                this.addLifeTime(this.#delta.value);
                this.#lastFrameTime = timestamp;
                if (this.#delta.value > millisecondsToSeconds) {
                    this.draw(false);
                    return;
                }
                this.canvas.render.drawParticles(this.#delta);
                if (!this.alive()) {
                    this.destroy();
                    return;
                }
                if (this.animationStatus) {
                    this.draw(false);
                }
            }
            catch (e) {
                getLogger().error("error in animation loop", e);
            }
        }
    }

    var Container$1 = /*#__PURE__*/Object.freeze({
        __proto__: null,
        Container: Container
    });

    const touchDelay = 500;
    class InteractivityEventListeners {
        #canPush = true;
        #clickPositionPlugins;
        #container;
        #handlers;
        #interactionManager;
        #touches;
        constructor(container, interactionManager) {
            this.#container = container;
            this.#clickPositionPlugins = [];
            this.#interactionManager = interactionManager;
            this.#touches = new Map();
            this.#handlers = {
                mouseDown: () => {
                    this.#mouseDown();
                },
                mouseLeave: () => {
                    this.#mouseTouchFinish();
                },
                mouseMove: (e) => {
                    this.#mouseTouchMove(e);
                },
                mouseUp: (e) => {
                    this.#mouseTouchClick(e);
                },
                touchStart: (e) => {
                    this.#touchStart(e);
                },
                touchMove: (e) => {
                    this.#mouseTouchMove(e);
                },
                touchEnd: (e) => {
                    this.#touchEnd(e);
                },
                touchCancel: (e) => {
                    this.#touchEnd(e);
                },
                touchEndClick: (e) => {
                    this.#touchEndClick(e);
                },
                visibilityChange: () => {
                    this.#handleVisibilityChange();
                },
            };
        }
        addListeners() {
            this.#manageListeners(true);
        }
        init() {
            this.#clickPositionPlugins.length = 0;
            for (const plugin of this.#container.plugins.filter(p => !!p.clickPositionValid)) {
                this.#clickPositionPlugins.push(plugin);
            }
        }
        removeListeners() {
            this.#manageListeners(false);
        }
        #doMouseTouchClick(e) {
            const container = this.#container, interactionManager = this.#interactionManager, options = container.actualOptions;
            if (this.#canPush) {
                const mouseInteractivity = interactionManager.interactivityData.mouse, mousePos = mouseInteractivity.position;
                if (!mousePos) {
                    return;
                }
                mouseInteractivity.clickPosition = { ...mousePos };
                mouseInteractivity.clickTime = performance.now();
                const onClick = options.interactivity?.events.onClick;
                if (!onClick?.mode) {
                    return;
                }
                executeOnSingleOrMultiple(onClick.mode, mode => {
                    interactionManager.handleClickMode(mode);
                });
            }
            if (e.type === "touchend") {
                setTimeout(() => {
                    this.#mouseTouchFinish();
                }, touchDelay);
            }
        }
        #handleVisibilityChange() {
            this.#mouseTouchFinish();
        }
        #manageInteractivityListeners(add) {
            const handlers = this.#handlers, container = this.#container, interactionManager = this.#interactionManager, options = container.actualOptions, interactivityEl = interactionManager.interactivityData.element;
            if (!interactivityEl) {
                return;
            }
            const html = interactivityEl, canvas = container.canvas;
            canvas.setPointerEvents(html === canvas.domElement ? "initial" : "none");
            if (add && !(options.interactivity?.events.onHover.enable || options.interactivity?.events.onClick.enable)) {
                return;
            }
            manageListener(interactivityEl, mouseMoveEvent, handlers.mouseMove, add);
            manageListener(interactivityEl, touchStartEvent, handlers.touchStart, add);
            manageListener(interactivityEl, touchMoveEvent, handlers.touchMove, add);
            if (add) {
                if (options.interactivity?.events.onClick.enable) {
                    manageListener(interactivityEl, touchEndEvent, handlers.touchEndClick, add);
                    manageListener(interactivityEl, mouseUpEvent, handlers.mouseUp, add);
                    manageListener(interactivityEl, mouseDownEvent, handlers.mouseDown, add);
                }
                else {
                    manageListener(interactivityEl, touchEndEvent, handlers.touchEnd, add);
                }
            }
            else {
                manageListener(interactivityEl, touchEndEvent, handlers.touchEndClick, add);
                manageListener(interactivityEl, mouseUpEvent, handlers.mouseUp, add);
                manageListener(interactivityEl, mouseDownEvent, handlers.mouseDown, add);
                manageListener(interactivityEl, touchEndEvent, handlers.touchEnd, add);
            }
            manageListener(interactivityEl, mouseLeaveEvent, handlers.mouseLeave, add);
            manageListener(interactivityEl, touchCancelEvent, handlers.touchCancel, add);
        }
        #manageListeners(add) {
            const handlers = this.#handlers, container = this.#container, interactionManager = this.#interactionManager, options = container.actualOptions, detectType = options.interactivity?.detectsOn, canvasEl = container.canvas.domElement;
            if (detectType === InteractivityDetect.window) {
                interactionManager.interactivityData.element = safeDocument();
            }
            else if (detectType === InteractivityDetect.parent && canvasEl) {
                interactionManager.interactivityData.element = canvasEl.parentElement ?? canvasEl.parentNode;
            }
            else {
                interactionManager.interactivityData.element = canvasEl;
            }
            this.#manageInteractivityListeners(add);
            manageListener(document, visibilityChangeEvent, handlers.visibilityChange, add, false);
        }
        #mouseDown() {
            const { interactivityData } = this.#interactionManager, { mouse } = interactivityData;
            mouse.clicking = true;
            mouse.downPosition = mouse.position;
        }
        #mouseTouchClick(e) {
            const container = this.#container, interactionManager = this.#interactionManager, options = container.actualOptions, { mouse } = interactionManager.interactivityData;
            mouse.inside = true;
            let handled = false;
            const mousePosition = mouse.position;
            if (!mousePosition || !options.interactivity?.events.onClick.enable) {
                return;
            }
            for (const plugin of this.#clickPositionPlugins) {
                handled = plugin.clickPositionValid?.(mousePosition) ?? false;
                if (handled) {
                    break;
                }
            }
            if (!handled) {
                this.#doMouseTouchClick(e);
            }
            mouse.clicking = false;
        }
        #mouseTouchFinish() {
            const { interactivityData } = this.#interactionManager, { mouse } = interactivityData;
            delete mouse.position;
            delete mouse.clickPosition;
            delete mouse.downPosition;
            interactivityData.status = mouseLeaveEvent;
            mouse.inside = false;
            mouse.clicking = false;
        }
        #mouseTouchMove(e) {
            const container = this.#container, interactionManager = this.#interactionManager, options = container.actualOptions, interactivity = interactionManager.interactivityData, canvasEl = container.canvas.domElement;
            if (!interactivity.element) {
                return;
            }
            interactivity.mouse.inside = true;
            let pos;
            if (e.type.startsWith("pointer")) {
                this.#canPush = true;
                const mouseEvent = e;
                if (interactivity.element === safeDocument()) {
                    if (canvasEl) {
                        const clientRect = canvasEl.getBoundingClientRect();
                        pos = {
                            x: mouseEvent.clientX - clientRect.left,
                            y: mouseEvent.clientY - clientRect.top,
                        };
                    }
                }
                else if (options.interactivity?.detectsOn === InteractivityDetect.parent) {
                    const source = mouseEvent.target, target = mouseEvent.currentTarget;
                    if (canvasEl) {
                        const sourceRect = source.getBoundingClientRect(), targetRect = target.getBoundingClientRect(), canvasRect = canvasEl.getBoundingClientRect();
                        pos = {
                            x: mouseEvent.offsetX + double * sourceRect.left - (targetRect.left + canvasRect.left),
                            y: mouseEvent.offsetY + double * sourceRect.top - (targetRect.top + canvasRect.top),
                        };
                    }
                    else {
                        pos = {
                            x: mouseEvent.offsetX,
                            y: mouseEvent.offsetY,
                        };
                    }
                }
                else if (mouseEvent.target === canvasEl) {
                    pos = {
                        x: mouseEvent.offsetX,
                        y: mouseEvent.offsetY,
                    };
                }
            }
            else {
                this.#canPush = e.type !== "touchmove";
                if (canvasEl) {
                    const touchEvent = e, lastTouch = touchEvent.touches[touchEvent.touches.length - lengthOffset], canvasRect = canvasEl.getBoundingClientRect();
                    if (!lastTouch) {
                        return;
                    }
                    pos = {
                        x: lastTouch.clientX - canvasRect.left,
                        y: lastTouch.clientY - canvasRect.top,
                    };
                }
            }
            const pxRatio = container.retina.pixelRatio;
            if (pos) {
                pos.x *= pxRatio;
                pos.y *= pxRatio;
            }
            interactivity.mouse.position = pos;
            interactivity.status = mouseMoveEvent;
        }
        #touchEnd(e) {
            const evt = e, touches = Array.from(evt.changedTouches);
            for (const touch of touches) {
                this.#touches.delete(touch.identifier);
            }
            this.#mouseTouchFinish();
        }
        #touchEndClick(e) {
            const evt = e, touches = Array.from(evt.changedTouches);
            for (const touch of touches) {
                this.#touches.delete(touch.identifier);
            }
            this.#mouseTouchClick(e);
        }
        #touchStart(e) {
            const evt = e, touches = Array.from(evt.changedTouches);
            for (const touch of touches) {
                this.#touches.set(touch.identifier, performance.now());
            }
            this.#mouseTouchMove(e);
        }
    }

    const clickRadius = 1, touchEndLengthOffset = 1, minCoordinate = 0;
    function safeIntersectionObserver(callback) {
        if (typeof IntersectionObserver === "undefined") {
            return;
        }
        return new IntersectionObserver(callback);
    }
    class InteractionManager {
        interactivityData;
        #clickHandlers;
        #container;
        #eventListeners;
        #externalInteractors;
        #interactors;
        #intersectionObserver;
        #particleInteractors;
        #pluginManager;
        constructor(pluginManager, container) {
            this.#container = container;
            this.#pluginManager = pluginManager;
            this.#interactors = [];
            this.#externalInteractors = [];
            this.#particleInteractors = [];
            this.#clickHandlers = new Map();
            this.#eventListeners = new InteractivityEventListeners(container, this);
            this.interactivityData = {
                mouse: {
                    clicking: false,
                    inside: false,
                },
            };
            this.#intersectionObserver = safeIntersectionObserver(entries => {
                this.#intersectionManager(entries);
            });
        }
        addClickHandler(callback) {
            const container = this.#container, interactivityData = this.interactivityData;
            if (container.destroyed) {
                return;
            }
            const el = interactivityData.element;
            if (!el) {
                return;
            }
            const clickOrTouchHandler = (e, pos, radius) => {
                if (container.destroyed) {
                    return;
                }
                const pxRatio = container.retina.pixelRatio, posRetina = {
                    x: pos.x * pxRatio,
                    y: pos.y * pxRatio,
                }, particles = container.particles.grid.queryCircle(posRetina, radius * pxRatio);
                callback(e, particles);
            }, clickHandler = (e) => {
                if (container.destroyed) {
                    return;
                }
                const mouseEvent = e, pos = {
                    x: mouseEvent.offsetX,
                    y: mouseEvent.offsetY,
                };
                clickOrTouchHandler(e, pos, clickRadius);
            }, touchStartHandler = () => {
                if (container.destroyed) {
                    return;
                }
                touched = true;
                touchMoved = false;
            }, touchMoveHandler = () => {
                if (container.destroyed) {
                    return;
                }
                touchMoved = true;
            }, touchEndHandler = (e) => {
                if (container.destroyed) {
                    return;
                }
                if (touched && !touchMoved) {
                    const touchEvent = e, lastTouch = touchEvent.touches[touchEvent.touches.length - touchEndLengthOffset];
                    if (!lastTouch) {
                        return;
                    }
                    const element = container.canvas.domElement, canvasRect = element ? element.getBoundingClientRect() : undefined, pos = {
                        x: lastTouch.clientX - (canvasRect ? canvasRect.left : minCoordinate),
                        y: lastTouch.clientY - (canvasRect ? canvasRect.top : minCoordinate),
                    };
                    clickOrTouchHandler(e, pos, Math.max(lastTouch.radiusX, lastTouch.radiusY));
                }
                touched = false;
                touchMoved = false;
            }, touchCancelHandler = () => {
                if (container.destroyed) {
                    return;
                }
                touched = false;
                touchMoved = false;
            };
            let touched = false, touchMoved = false;
            this.#clickHandlers.set(clickEvent, clickHandler);
            this.#clickHandlers.set(touchStartEvent, touchStartHandler);
            this.#clickHandlers.set(touchMoveEvent, touchMoveHandler);
            this.#clickHandlers.set(touchEndEvent, touchEndHandler);
            this.#clickHandlers.set(touchCancelEvent, touchCancelHandler);
            for (const [key, handler] of this.#clickHandlers) {
                el.addEventListener(key, handler);
            }
        }
        addListeners() {
            this.#eventListeners.addListeners();
        }
        clearClickHandlers() {
            const container = this.#container, interactivityData = this.interactivityData;
            if (container.destroyed) {
                return;
            }
            for (const [key, handler] of this.#clickHandlers) {
                interactivityData.element?.removeEventListener(key, handler);
            }
            this.#clickHandlers.clear();
        }
        externalInteract(delta) {
            for (const interactor of this.#externalInteractors) {
                const interactivityData = this.interactivityData;
                if (interactor.isEnabled(interactivityData)) {
                    interactor.interact(interactivityData, delta);
                }
            }
        }
        handleClickMode(mode) {
            if (this.#container.destroyed) {
                return;
            }
            const interactivityData = this.interactivityData;
            for (const interactor of this.#externalInteractors) {
                interactor.handleClickMode?.(mode, interactivityData);
            }
        }
        init() {
            this.#eventListeners.init();
            for (const interactor of this.#interactors) {
                switch (interactor.type) {
                    case InteractorType.external:
                        this.#externalInteractors.push(interactor);
                        break;
                    case InteractorType.particles:
                        this.#particleInteractors.push(interactor);
                        break;
                }
                interactor.init();
            }
        }
        async initInteractors() {
            const interactors = await this.#pluginManager.getInteractors?.(this.#container, true);
            if (!interactors) {
                return;
            }
            this.#interactors = interactors;
            this.#externalInteractors = [];
            this.#particleInteractors = [];
        }
        particlesInteract(particle, delta) {
            const interactivityData = this.interactivityData;
            for (const interactor of this.#externalInteractors) {
                interactor.clear(particle, delta);
            }
            for (const interactor of this.#particleInteractors) {
                if (interactor.isEnabled(particle, interactivityData)) {
                    interactor.interact(particle, interactivityData, delta);
                }
            }
        }
        removeListeners() {
            this.#eventListeners.removeListeners();
        }
        reset(particle) {
            const interactivityData = this.interactivityData;
            for (const interactor of this.#externalInteractors) {
                if (interactor.isEnabled(interactivityData)) {
                    interactor.reset(interactivityData, particle);
                }
            }
            for (const interactor of this.#particleInteractors) {
                if (interactor.isEnabled(particle, interactivityData)) {
                    interactor.reset(interactivityData, particle);
                }
            }
        }
        startObserving() {
            const interactivityData = this.interactivityData;
            if (interactivityData.element instanceof HTMLElement && this.#intersectionObserver) {
                this.#intersectionObserver.observe(interactivityData.element);
            }
        }
        stopObserving() {
            const interactivityData = this.interactivityData;
            if (interactivityData.element instanceof HTMLElement && this.#intersectionObserver) {
                this.#intersectionObserver.unobserve(interactivityData.element);
            }
        }
        updateMaxDistance() {
            let maxTotalDistance = 0;
            for (const interactor of this.#interactors) {
                if (interactor.maxDistance > maxTotalDistance) {
                    maxTotalDistance = interactor.maxDistance;
                }
            }
            const container = this.#container;
            container.particles.grid.setCellSize(maxTotalDistance * container.retina.pixelRatio);
        }
        #intersectionManager(entries) {
            const container = this.#container;
            if (container.destroyed || !container.actualOptions.pauseOnOutsideViewport) {
                return;
            }
            for (const entry of entries) {
                if (entry.target !== this.interactivityData.element) {
                    continue;
                }
                if (entry.isIntersecting) {
                    container.play();
                }
                else {
                    container.pause();
                }
            }
        }
    }

    class InteractivityPluginInstance {
        interactionManager;
        #container;
        #pluginManager;
        constructor(pluginManager, container) {
            this.#container = container;
            this.#pluginManager = pluginManager;
            this.interactionManager = new InteractionManager(pluginManager, container);
            this.#container.addClickHandler = (callback) => {
                this.interactionManager.addClickHandler(callback);
            };
        }
        addClickHandler(callback) {
            this.interactionManager.addClickHandler(callback);
        }
        clearClickHandlers() {
            this.interactionManager.clearClickHandlers();
        }
        destroy() {
            this.clearClickHandlers();
            this.#pluginManager.interactors?.delete(this.#container);
        }
        particleCreated(particle) {
            const interactivityParticle = particle, interactivity = new Interactivity(this.#pluginManager, this.#container);
            interactivity.load(this.#container.actualOptions.interactivity);
            interactivity.load(interactivityParticle.options.interactivity);
            interactivityParticle.interactivity = interactivity;
        }
        particleReset(particle) {
            this.interactionManager.reset(particle);
        }
        postParticleUpdate(particle, delta) {
            this.interactionManager.particlesInteract(particle, delta);
        }
        postUpdate(delta) {
            this.interactionManager.externalInteract(delta);
            this.interactionManager.updateMaxDistance();
        }
        async preInit() {
            await this.interactionManager.initInteractors();
            this.interactionManager.init();
        }
        async redrawInit() {
            await this.interactionManager.initInteractors();
            this.interactionManager.init();
        }
        start() {
            this.interactionManager.addListeners();
            this.interactionManager.startObserving();
            return Promise.resolve();
        }
        stop() {
            this.interactionManager.removeListeners();
            this.interactionManager.stopObserving();
        }
    }

    var InteractivityPluginInstance$1 = /*#__PURE__*/Object.freeze({
        __proto__: null,
        InteractivityPluginInstance: InteractivityPluginInstance
    });

    const defaultIndex$1 = 0;
    class AbsorbersInstancesManager {
        #containerArrays;
        #pluginManager;
        constructor(pluginManager) {
            this.#pluginManager = pluginManager;
            this.#containerArrays = new Map();
        }
        async addAbsorber(container, options, position) {
            const { AbsorberInstance } = await Promise.resolve().then(function () { return AbsorberInstance$1; }), absorber = new AbsorberInstance(this.#pluginManager, container, options, position), array = this.getArray(container);
            array.push(absorber);
            return absorber;
        }
        clear(container) {
            this.initContainer(container);
            this.#containerArrays.set(container, []);
        }
        getArray(container) {
            this.initContainer(container);
            let array = this.#containerArrays.get(container);
            if (!array) {
                array = [];
                this.#containerArrays.set(container, array);
            }
            return array;
        }
        initContainer(container) {
            if (this.#containerArrays.has(container)) {
                return;
            }
            this.#containerArrays.set(container, []);
            container.getAbsorber ??= (idxOrName) => {
                const array = this.getArray(container);
                return idxOrName === undefined || isNumber(idxOrName)
                    ? array[idxOrName ?? defaultIndex$1]
                    : array.find(t => t.name === idxOrName);
            };
            container.addAbsorber ??= (options, position) => {
                return this.addAbsorber(container, options, position);
            };
        }
        removeAbsorber(container, absorber) {
            const index = this.getArray(container).indexOf(absorber), deleteCount = 1;
            if (index >= defaultIndex$1) {
                this.getArray(container).splice(index, deleteCount);
            }
        }
    }

    var AbsorbersInstancesManager$1 = /*#__PURE__*/Object.freeze({
        __proto__: null,
        AbsorbersInstancesManager: AbsorbersInstancesManager
    });

    class AbsorbersPluginInstance {
        #container;
        #instancesManager;
        constructor(container, instancesManager) {
            this.#container = container;
            this.#instancesManager = instancesManager;
            this.#instancesManager.initContainer(container);
        }
        draw(context) {
            for (const absorber of this.#instancesManager.getArray(this.#container)) {
                absorber.draw(context);
            }
        }
        async init() {
            const absorbers = this.#container.actualOptions.absorbers, promises = executeOnSingleOrMultiple(absorbers, async (absorber) => {
                await this.#instancesManager.addAbsorber(this.#container, absorber);
            });
            if (isArray(promises)) {
                await Promise.all(promises);
            }
            else {
                await promises;
            }
        }
        particleUpdate(particle, delta) {
            for (const absorber of this.#instancesManager.getArray(this.#container)) {
                absorber.attract(particle, delta);
                if (particle.destroyed) {
                    break;
                }
            }
        }
        resize() {
            for (const absorber of this.#instancesManager.getArray(this.#container)) {
                absorber.resize();
            }
        }
        stop() {
            this.#instancesManager.clear(this.#container);
        }
    }

    var AbsorbersPluginInstance$1 = /*#__PURE__*/Object.freeze({
        __proto__: null,
        AbsorbersPluginInstance: AbsorbersPluginInstance
    });

    const shapeGenerators = new Map();
    class ShapeManager {
        addShapeGenerator(name, generator) {
            if (!this.getShapeGenerator(name)) {
                shapeGenerators.set(name, generator);
            }
        }
        getShapeGenerator(name) {
            return shapeGenerators.get(name);
        }
        getSupportedShapeGenerators() {
            return shapeGenerators.keys();
        }
    }

    var ShapeManager$1 = /*#__PURE__*/Object.freeze({
        __proto__: null,
        ShapeManager: ShapeManager
    });

    const defaultIndex = 0;
    class EmittersInstancesManager {
        #containerArrays;
        #pluginManager;
        constructor(pluginManager) {
            this.#containerArrays = new Map();
            this.#pluginManager = pluginManager;
        }
        async addEmitter(container, options, position) {
            const emitterOptions = new Emitter();
            emitterOptions.load(options);
            const { EmitterInstance } = await Promise.resolve().then(function () { return EmitterInstance$1; }), emitter = new EmitterInstance(this.#pluginManager, container, (emitter) => {
                this.removeEmitter(container, emitter);
            }, emitterOptions, position);
            await emitter.init();
            this.getArray(container).push(emitter);
            return emitter;
        }
        clear(container) {
            this.initContainer(container);
            this.#containerArrays.set(container, []);
        }
        getArray(container) {
            this.initContainer(container);
            let array = this.#containerArrays.get(container);
            if (!array) {
                array = [];
                this.#containerArrays.set(container, array);
            }
            return array;
        }
        initContainer(container) {
            if (this.#containerArrays.has(container)) {
                return;
            }
            this.#containerArrays.set(container, []);
            container.getEmitter = (idxOrName) => {
                const array = this.getArray(container);
                return idxOrName === undefined || isNumber(idxOrName)
                    ? array[idxOrName ?? defaultIndex]
                    : array.find(t => t.name === idxOrName);
            };
            container.addEmitter = async (options, position) => this.addEmitter(container, options, position);
            container.removeEmitter = (idxOrName) => {
                const emitter = container.getEmitter?.(idxOrName);
                if (emitter) {
                    this.removeEmitter(container, emitter);
                }
            };
            container.playEmitter = (idxOrName) => {
                const emitter = container.getEmitter?.(idxOrName);
                if (emitter) {
                    emitter.externalPlay();
                }
            };
            container.pauseEmitter = (idxOrName) => {
                const emitter = container.getEmitter?.(idxOrName);
                if (emitter) {
                    emitter.externalPause();
                }
            };
        }
        removeEmitter(container, emitter) {
            const index = this.getArray(container).indexOf(emitter), minIndex = 0, deleteCount = 1;
            if (index >= minIndex) {
                this.getArray(container).splice(index, deleteCount);
            }
        }
    }

    var EmittersInstancesManager$1 = /*#__PURE__*/Object.freeze({
        __proto__: null,
        EmittersInstancesManager: EmittersInstancesManager
    });

    class EmittersPluginInstance {
        #container;
        #instancesManager;
        constructor(instancesManager, container) {
            this.#instancesManager = instancesManager;
            this.#container = container;
            this.#instancesManager.initContainer(container);
        }
        async init() {
            const emittersOptions = this.#container.actualOptions.emitters;
            if (isArray(emittersOptions)) {
                for (const emitterOptions of emittersOptions) {
                    await this.#instancesManager.addEmitter(this.#container, emitterOptions);
                }
            }
            else {
                await this.#instancesManager.addEmitter(this.#container, emittersOptions);
            }
        }
        pause() {
            for (const emitter of this.#instancesManager.getArray(this.#container)) {
                emitter.pause();
            }
        }
        play() {
            for (const emitter of this.#instancesManager.getArray(this.#container)) {
                emitter.play();
            }
        }
        resize() {
            for (const emitter of this.#instancesManager.getArray(this.#container)) {
                emitter.resize();
            }
        }
        stop() {
            this.#instancesManager.clear(this.#container);
        }
        update(delta) {
            this.#instancesManager.getArray(this.#container).forEach(emitter => {
                emitter.update(delta);
            });
        }
    }

    var EmittersPluginInstance$1 = /*#__PURE__*/Object.freeze({
        __proto__: null,
        EmittersPluginInstance: EmittersPluginInstance
    });

    class BlendPluginInstance {
        layer = exports.DrawLayer.CanvasSetup;
        #container;
        #defaultCompositeValue;
        constructor(container) {
            this.#container = container;
        }
        drawParticleCleanup(context, particle) {
            if (!particle.options.blend?.enable) {
                return;
            }
            context.globalCompositeOperation = particle.originalBlendMode ?? defaultCompositeValue;
            particle.originalBlendMode = undefined;
        }
        drawParticleSetup(context, particle) {
            if (!particle.options.blend?.enable) {
                return;
            }
            particle.originalBlendMode = context.globalCompositeOperation;
            context.globalCompositeOperation = particle.options.blend.mode;
        }
        drawSettingsCleanup(context) {
            if (!this.#defaultCompositeValue) {
                return;
            }
            context.globalCompositeOperation = this.#defaultCompositeValue;
        }
        drawSettingsSetup(context) {
            const previousComposite = context.globalCompositeOperation, blend = this.#container.actualOptions.blend;
            this.#defaultCompositeValue = previousComposite;
            context.globalCompositeOperation = blend?.enable ? blend.mode : previousComposite;
        }
    }

    var BlendPluginInstance$1 = /*#__PURE__*/Object.freeze({
        __proto__: null,
        BlendPluginInstance: BlendPluginInstance
    });

    const moveSpeedFactor = 60, minSpinRadius = 0, spinFactor = 0.01, defaultPathDelay = 0, noDecay = 1;
    function applyDistance(particle) {
        const initialPosition = particle.initialPosition, { dx, dy } = getDistances(initialPosition, particle.position), dxFixed = Math.abs(dx), dyFixed = Math.abs(dy), { maxDistance } = particle.retina, hDistance = maxDistance.horizontal, vDistance = maxDistance.vertical;
        if (!hDistance && !vDistance) {
            return;
        }
        const hasHDistance = (hDistance && dxFixed >= hDistance) ?? false, hasVDistance = (vDistance && dyFixed >= vDistance) ?? false;
        if ((hasHDistance || hasVDistance) && !particle.misplaced) {
            particle.misplaced = (!!hDistance && dxFixed > hDistance) || (!!vDistance && dyFixed > vDistance);
            if (hDistance) {
                particle.velocity.x = particle.velocity.y * half - particle.velocity.x;
            }
            if (vDistance) {
                particle.velocity.y = particle.velocity.x * half - particle.velocity.y;
            }
        }
        else if ((!hDistance || dxFixed < hDistance) && (!vDistance || dyFixed < vDistance) && particle.misplaced) {
            particle.misplaced = false;
        }
        else if (particle.misplaced) {
            const pos = particle.position, vel = particle.velocity;
            if (hDistance &&
                ((pos.x < initialPosition.x && vel.x < minVelocity) || (pos.x > initialPosition.x && vel.x > minVelocity))) {
                vel.x *= -getRandom();
            }
            if (vDistance &&
                ((pos.y < initialPosition.y && vel.y < minVelocity) || (pos.y > initialPosition.y && vel.y > minVelocity))) {
                vel.y *= -getRandom();
            }
        }
    }
    function move(particle, moveOptions, moveSpeed, maxSpeed, moveDrift, reduceFactor, delta) {
        applyPath(particle, delta);
        const gravityOptions = particle.gravity, gravityFactor = gravityOptions?.enable && gravityOptions.inverse ? -identity$2 : identity$2;
        if (moveDrift && moveSpeed) {
            particle.velocity.x += (moveDrift * delta.factor) / (moveSpeedFactor * moveSpeed);
        }
        if (gravityOptions?.enable && moveSpeed) {
            particle.velocity.y +=
                (gravityFactor * (gravityOptions.acceleration * delta.factor)) / (moveSpeedFactor * moveSpeed);
        }
        const decay = particle.moveDecay;
        particle.velocity.multTo(decay ?? noDecay);
        const velocity = particle.velocity.mult(moveSpeed);
        if (gravityOptions?.enable &&
            maxSpeed > minVelocity &&
            ((!gravityOptions.inverse && velocity.y >= minVelocity && velocity.y >= maxSpeed) ||
                (gravityOptions.inverse && velocity.y <= minVelocity && velocity.y <= -maxSpeed))) {
            velocity.y = gravityFactor * maxSpeed;
            if (moveSpeed) {
                particle.velocity.y = velocity.y / moveSpeed;
            }
        }
        const zIndexOptions = particle.options.zIndex, zVelocityFactor = (identity$2 - particle.zIndexFactor) ** zIndexOptions.velocityRate;
        velocity.multTo(zVelocityFactor);
        velocity.multTo(reduceFactor);
        const { position } = particle;
        position.addTo(velocity);
        if (moveOptions.vibrate) {
            position.x += Math.sin(position.x * Math.cos(position.y)) * reduceFactor;
            position.y += Math.cos(position.y * Math.sin(position.x)) * reduceFactor;
        }
    }
    function spin(container, particle, moveSpeed, reduceFactor) {
        if (!particle.spin) {
            return;
        }
        const spinClockwise = particle.spin.direction === exports.RotateDirection.clockwise, updateFunc = {
            x: spinClockwise ? Math.cos : Math.sin,
            y: spinClockwise ? Math.sin : Math.cos,
        };
        particle.position.x =
            particle.spin.center.x + particle.spin.radius * updateFunc.x(particle.spin.angle) * reduceFactor;
        particle.position.y =
            particle.spin.center.y + particle.spin.radius * updateFunc.y(particle.spin.angle) * reduceFactor;
        particle.spin.radius += particle.spin.acceleration * reduceFactor;
        const maxCanvasSize = Math.max(container.canvas.size.width, container.canvas.size.height), halfMaxSize = maxCanvasSize * half;
        if (particle.spin.radius > halfMaxSize) {
            particle.spin.radius = halfMaxSize;
            particle.spin.acceleration *= -identity$2;
        }
        else if (particle.spin.radius < minSpinRadius) {
            particle.spin.radius = minSpinRadius;
            particle.spin.acceleration *= -identity$2;
        }
        particle.spin.angle += moveSpeed * spinFactor * (identity$2 - particle.spin.radius / maxCanvasSize);
    }
    function applyPath(particle, delta) {
        const particlesOptions = particle.options, pathOptions = particlesOptions.move.path, pathEnabled = pathOptions.enable;
        if (!pathEnabled) {
            return;
        }
        const pathDelay = particle.pathDelay ?? defaultPathDelay;
        if (particle.lastPathTime <= pathDelay) {
            particle.lastPathTime += delta.value;
            return;
        }
        const path = particle.pathGenerator?.generate(particle, delta);
        if (path) {
            particle.velocity.addTo(path);
        }
        if (pathOptions.clamp) {
            particle.velocity.x = clamp(particle.velocity.x, -identity$2, identity$2);
            particle.velocity.y = clamp(particle.velocity.y, -identity$2, identity$2);
        }
        particle.lastPathTime -= pathDelay;
    }
    function getProximitySpeedFactor(particle) {
        const mod = particle.getModifier("slow");
        return mod?.enabled ? (mod.speedFactor ?? identity$2) : identity$2;
    }
    function initSpin(container, particle) {
        const options = particle.options, spinOptions = options.move.spin;
        if (!spinOptions.enable) {
            return;
        }
        const spinPos = spinOptions.position ?? { x: 50, y: 50 }, spinFactor = 0.01, spinCenter = {
            x: spinPos.x * spinFactor * container.canvas.size.width,
            y: spinPos.y * spinFactor * container.canvas.size.height,
        }, pos = particle.getPosition(), distance = getDistance(pos, spinCenter), spinAcceleration = getRangeValue(spinOptions.acceleration);
        particle.retina.spinAcceleration = spinAcceleration * container.retina.pixelRatio;
        particle.spin = {
            center: spinCenter,
            direction: particle.velocity.x >= minVelocity ? exports.RotateDirection.clockwise : exports.RotateDirection.counterClockwise,
            angle: getRandom() * doublePI,
            radius: distance,
            acceleration: particle.retina.spinAcceleration,
        };
    }

    const defaultSizeFactor = 1, defaultDeltaFactor = 1;
    class MovePluginInstance {
        availablePathGenerators;
        pathGenerators;
        #container;
        #pluginManager;
        constructor(pluginManager, container) {
            this.#pluginManager = pluginManager;
            this.#container = container;
            this.availablePathGenerators = new Map();
            this.pathGenerators = new Map();
        }
        destroy() {
            this.availablePathGenerators = new Map();
            this.pathGenerators = new Map();
        }
        isEnabled(particle) {
            return !particle.destroyed && particle.options.move.enable;
        }
        particleCreated(particle) {
            const options = particle.options, moveOptions = options.move, gravityOptions = moveOptions.gravity, pathOptions = moveOptions.path;
            particle.moveDecay = decayOffset - getRangeValue(moveOptions.decay);
            particle.pathDelay = getRangeValue(pathOptions.delay.value) * millisecondsToSeconds;
            if (pathOptions.generator) {
                let pathGenerator = this.pathGenerators.get(pathOptions.generator);
                if (!pathGenerator) {
                    pathGenerator = this.availablePathGenerators.get(pathOptions.generator);
                    if (pathGenerator) {
                        this.pathGenerators.set(pathOptions.generator, pathGenerator);
                        pathGenerator.init();
                    }
                }
                particle.pathGenerator = pathGenerator;
            }
            particle.gravity = {
                enable: gravityOptions.enable,
                acceleration: getRangeValue(gravityOptions.acceleration),
                inverse: gravityOptions.inverse,
            };
            initSpin(this.#container, particle);
        }
        particleDestroyed(particle) {
            const pathGenerator = particle.pathGenerator;
            pathGenerator?.reset(particle);
        }
        particleUpdate(particle, delta) {
            const particleOptions = particle.options, moveOptions = particleOptions.move;
            if (!moveOptions.enable) {
                return;
            }
            const container = this.#container, slowFactor = getProximitySpeedFactor(particle), reduceFactor = container.retina.reduceFactor, baseSpeed = particle.retina.moveSpeed, moveDrift = particle.retina.moveDrift, maxSize = particle.size.max, sizeFactor = moveOptions.size ? particle.getRadius() / maxSize : defaultSizeFactor, deltaFactor = delta.factor || defaultDeltaFactor, moveSpeed = baseSpeed * sizeFactor * slowFactor * deltaFactor * half, maxSpeed = particle.retina.maxSpeed;
            if (moveOptions.spin.enable) {
                spin(container, particle, moveSpeed, reduceFactor);
            }
            else {
                move(particle, moveOptions, moveSpeed, maxSpeed, moveDrift, reduceFactor, delta);
            }
            applyDistance(particle);
        }
        preInit() {
            return this.#init();
        }
        redrawInit() {
            return this.#init();
        }
        update() {
            for (const pathGenerator of this.pathGenerators.values()) {
                pathGenerator.update();
            }
        }
        async #init() {
            const availablePathGenerators = await this.#pluginManager.getPathGenerators?.(this.#container, true);
            if (!availablePathGenerators) {
                return;
            }
            this.availablePathGenerators = availablePathGenerators;
            this.pathGenerators = new Map();
            for (const pathGenerator of this.pathGenerators.values()) {
                pathGenerator.init();
            }
        }
    }

    var MovePluginInstance$1 = /*#__PURE__*/Object.freeze({
        __proto__: null,
        MovePluginInstance: MovePluginInstance
    });

    class ImagePreloaderInstance {
        #container;
        #engine;
        constructor(engine, container) {
            this.#engine = engine;
            this.#container = container;
        }
        destroy() {
            this.#engine.images?.delete(this.#container);
        }
    }

    var ImagePreloaderInstance$1 = /*#__PURE__*/Object.freeze({
        __proto__: null,
        ImagePreloaderInstance: ImagePreloaderInstance
    });

    const minRetries = 0;
    class OverlapPluginInstance {
        #container;
        constructor(container) {
            this.#container = container;
        }
        checkParticlePosition(particle, position, tryCount) {
            return !this.#hasOverlaps(particle, position, tryCount);
        }
        #hasOverlaps(particle, pos, tryCount) {
            const collisionsOptions = particle.options.collisions;
            if (!collisionsOptions?.enable) {
                return false;
            }
            const overlapOptions = collisionsOptions.overlap;
            if (overlapOptions.enable) {
                return false;
            }
            const retries = overlapOptions.retries;
            if (retries >= minRetries && tryCount > retries) {
                throw new Error(`Particle is overlapping and can't be placed`);
            }
            return !!this.#container.particles.find(p => getDistance(pos, p.position) < particle.getRadius() + p.getRadius());
        }
    }

    var OverlapPluginInstance$1 = /*#__PURE__*/Object.freeze({
        __proto__: null,
        OverlapPluginInstance: OverlapPluginInstance
    });

    function getLinkKey(ids) {
        return [...ids].sort((a, b) => a - b).join("_");
    }
    function setLinkFrequency(particles, dictionary) {
        const key = getLinkKey(particles.map(t => t.id));
        let res = dictionary.get(key);
        if (res === undefined) {
            res = getRandom();
            dictionary.set(key, res);
        }
        return res;
    }

    const minOpacity = 0, minWidth = 0, minDistance = 0, maxFrequency = 1, defaultFrequency = 0;
    class LinkInstance {
        #colorCache = new Map();
        #container;
        #freqs;
        #pluginManager;
        constructor(pluginManager, container) {
            this.#pluginManager = pluginManager;
            this.#container = container;
            this.#freqs = { links: new Map(), triangles: new Map() };
        }
        drawParticle(context, particle) {
            const { links, options } = particle;
            if (!links?.length || !options.links) {
                return;
            }
            const linkOpts = options.links, width = particle.retina.linksWidth ?? minWidth, pos1 = particle.getPosition(), twinkle = particle.options["twinkle"]?.links, trianglesEnabled = linkOpts.triangles.enable, p1Destinations = trianglesEnabled ? new Set(links.map(l => l.destination.id)) : null, originalAlpha = context.globalAlpha;
            let currentColorStyle = "", currentWidth = -1, currentAlpha = -1, pathOpen = false;
            const flushLines = () => {
                if (pathOpen) {
                    context.stroke();
                    pathOpen = false;
                }
            };
            for (const link of links) {
                if (linkOpts.frequency < maxFrequency &&
                    this.#getLinkFrequency(particle, link.destination) > linkOpts.frequency) {
                    continue;
                }
                const pos2 = link.destination.getPosition();
                if (trianglesEnabled && !link.isWarped && p1Destinations) {
                    flushLines();
                    this.#drawTriangles(options, particle, link, p1Destinations, pos1, pos2, context);
                }
                if (link.opacity <= minOpacity || width <= minWidth) {
                    continue;
                }
                if (!linkOpts.enable) {
                    continue;
                }
                let opacity = link.opacity, colorLine = link.color;
                const twinkleRgb = twinkle?.enable && getRandom() < twinkle.frequency
                    ? rangeColorToRgb(this.#pluginManager, twinkle.color)
                    : undefined;
                if (twinkle && twinkleRgb) {
                    colorLine = twinkleRgb;
                    opacity = getRangeValue(twinkle.opacity);
                }
                if (!colorLine) {
                    const linkColor = linkOpts.id !== undefined
                        ? this.#container.particles.linksColors.get(linkOpts.id)
                        : this.#container.particles.linksColor;
                    colorLine = getLinkColor(particle, link.destination, linkColor);
                }
                if (!colorLine) {
                    continue;
                }
                const colorStyle = this.#getCachedStyle(colorLine);
                if (colorStyle !== currentColorStyle || width !== currentWidth || opacity !== currentAlpha) {
                    flushLines();
                    context.strokeStyle = colorStyle;
                    context.lineWidth = width;
                    context.globalAlpha = opacity;
                    currentColorStyle = colorStyle;
                    currentWidth = width;
                    currentAlpha = opacity;
                    context.beginPath();
                    pathOpen = true;
                }
                if (link.isWarped) {
                    const canvasSize = this.#container.canvas.size, dx = pos2.x - pos1.x, dy = pos2.y - pos1.y;
                    let sx = originPoint.x, sy = originPoint.y;
                    if (Math.abs(dx) > canvasSize.width * half) {
                        sx = dx > minDistance ? -canvasSize.width : canvasSize.width;
                    }
                    if (Math.abs(dy) > canvasSize.height * half) {
                        sy = dy > minDistance ? -canvasSize.height : canvasSize.height;
                    }
                    context.moveTo(pos1.x, pos1.y);
                    context.lineTo(pos2.x + sx, pos2.y + sy);
                    context.moveTo(pos1.x - sx, pos1.y - sy);
                    context.lineTo(pos2.x, pos2.y);
                }
                else {
                    context.moveTo(pos1.x, pos1.y);
                    context.lineTo(pos2.x, pos2.y);
                }
            }
            flushLines();
            context.globalAlpha = originalAlpha;
        }
        init() {
            this.#freqs.links.clear();
            this.#freqs.triangles.clear();
            this.#colorCache.clear();
            return Promise.resolve();
        }
        particleCreated(particle) {
            particle.links = [];
            if (!particle.options.links) {
                return;
            }
            particle.linksDistance = particle.options.links.distance;
            particle.linksWidth = particle.options.links.width;
            const ratio = this.#container.retina.pixelRatio;
            particle.retina.linksDistance = particle.linksDistance * ratio;
            particle.retina.linksWidth = particle.linksWidth * ratio;
        }
        particleDestroyed(particle) {
            particle.links = [];
        }
        #drawTriangles(options, p1, link, p1Destinations, pos1, pos2, context) {
            const p2 = link.destination, triangleOptions = options.links?.triangles;
            if (!triangleOptions?.enable || !p2.options.links?.triangles.enable) {
                return;
            }
            const p2Links = p2.links;
            if (!p2Links?.length) {
                return;
            }
            for (const vertex of p2Links) {
                if (vertex.isWarped ||
                    this.#getLinkFrequency(p2, vertex.destination) > p2.options.links.frequency ||
                    !p1Destinations.has(vertex.destination.id)) {
                    continue;
                }
                const p3 = vertex.destination;
                if (this.#getTriangleFrequency(p1, p2, p3) > (options.links?.triangles.frequency ?? defaultFrequency)) {
                    continue;
                }
                const opacityTriangle = triangleOptions.opacity ?? (link.opacity + vertex.opacity) * half, colorTriangle = rangeColorToRgb(this.#pluginManager, triangleOptions.color) ?? link.color;
                if (!colorTriangle || opacityTriangle <= minOpacity) {
                    continue;
                }
                const pos3 = p3.getPosition();
                context.save();
                context.fillStyle = this.#getCachedStyle(colorTriangle);
                context.globalAlpha = opacityTriangle;
                context.beginPath();
                context.moveTo(pos1.x, pos1.y);
                context.lineTo(pos2.x, pos2.y);
                context.lineTo(pos3.x, pos3.y);
                context.closePath();
                context.fill();
                context.restore();
            }
        }
        #getCachedStyle(rgb) {
            const key = `${rgb.r},${rgb.g},${rgb.b}-${this.#container.hdr}-${this.#container.peakNits}-${this.#container.hdrMode}`;
            let style = this.#colorCache.get(key);
            if (!style) {
                style = getStyleFromRgb(rgb, this.#container.hdr, undefined, this.#container.peakNits, this.#container.hdrMode);
                this.#colorCache.set(key, style);
            }
            return style;
        }
        #getLinkFrequency(p1, p2) {
            return setLinkFrequency([p1, p2], this.#freqs.links);
        }
        #getTriangleFrequency(p1, p2, p3) {
            return setLinkFrequency([p1, p2, p3], this.#freqs.triangles);
        }
    }

    var LinkInstance$1 = /*#__PURE__*/Object.freeze({
        __proto__: null,
        LinkInstance: LinkInstance
    });

    const absorbFactor = 0.033, minOrbitLength = 0, minRadius = 0, minMass = 0, minAngle = 0, maxAngle = doublePI, maxDegreeAngle = 360, angleIncrementFactor = identity$2 / maxDegreeAngle, defaultLifeDelay$1 = 0, minLifeCount$1 = 0, defaultSpawnDelay$1 = 0, defaultLifeCount$1 = -1;
    class AbsorberInstance {
        color;
        limit;
        mass;
        name;
        opacity;
        options;
        position;
        size;
        #container;
        #currentDuration;
        #currentSpawnDelay;
        #duration;
        #firstSpawn;
        #immortal;
        #initialPosition;
        #lifeCount;
        #pluginManager;
        #spawnDelay;
        constructor(pluginManager, container, options, position) {
            this.#container = container;
            this.#pluginManager = pluginManager;
            this.#currentDuration = 0;
            this.#currentSpawnDelay = 0;
            this.#initialPosition = position ? Vector.create(position.x, position.y) : undefined;
            if (options instanceof Absorber) {
                this.options = options;
            }
            else {
                this.options = new Absorber();
                this.options.load(options);
            }
            this.name = this.options.name;
            this.opacity = this.options.opacity;
            this.size = getRangeValue(this.options.size.value) * container.retina.pixelRatio;
            this.mass = this.size * this.options.size.density * container.retina.reduceFactor;
            const limit = this.options.size.limit;
            this.limit = {
                radius: limit.radius * container.retina.pixelRatio * container.retina.reduceFactor,
                mass: limit.mass,
            };
            this.color = rangeColorToRgb(this.#pluginManager, this.options.color) ?? {
                b: 0,
                g: 0,
                r: 0,
            };
            this.position = this.#initialPosition?.copy() ?? this.#calcPosition();
            this.#firstSpawn = !this.options.life.wait;
            this.#lifeCount = this.options.life.count ?? defaultLifeCount$1;
            this.#immortal = this.#lifeCount <= minLifeCount$1;
            this.#spawnDelay = container.retina.reduceFactor
                ? (getRangeValue(this.options.life.delay ?? defaultLifeDelay$1) * millisecondsToSeconds) /
                    container.retina.reduceFactor
                : Infinity;
        }
        attract(particle, delta) {
            const container = this.#container, options = this.options, pos = particle.getPosition(), { dx, dy, distance } = getDistances(this.position, pos), v = Vector.create(dx, dy);
            v.length = (this.mass / Math.pow(distance, squareExp)) * container.retina.reduceFactor;
            if (distance < this.size + particle.getRadius()) {
                const sizeFactor = particle.getRadius() * absorbFactor * container.retina.pixelRatio * delta.factor;
                if ((this.size > particle.getRadius() && distance < this.size - particle.getRadius()) ||
                    (particle.absorberOrbit !== undefined && particle.absorberOrbit.length < minOrbitLength)) {
                    if (options.destroy) {
                        particle.destroy();
                    }
                    else {
                        particle.needsNewPosition = true;
                        this.#updateParticlePosition(particle, delta, v);
                    }
                }
                else {
                    if (options.destroy) {
                        particle.size.value -= sizeFactor;
                    }
                    this.#updateParticlePosition(particle, delta, v);
                }
                if (this.limit.radius <= minRadius || this.size < this.limit.radius) {
                    this.size += sizeFactor;
                }
                if (this.limit.mass <= minMass || this.mass < this.limit.mass) {
                    this.mass += sizeFactor * this.options.size.density * container.retina.reduceFactor;
                }
            }
            else {
                this.#updateParticlePosition(particle, delta, v);
            }
        }
        draw(context) {
            context.translate(this.position.x, this.position.y);
            context.beginPath();
            context.arc(originPoint.x, originPoint.y, this.size, minAngle, maxAngle, false);
            context.closePath();
            context.fillStyle = getStyleFromRgb(this.color, this.#container.hdr, this.opacity, this.#container.peakNits, this.#container.hdrMode);
            context.fill();
        }
        resize() {
            const initialPosition = this.#initialPosition;
            this.position =
                initialPosition && isPointInside(initialPosition, this.#container.canvas.size, Vector.origin)
                    ? initialPosition
                    : this.#calcPosition();
        }
        update(delta) {
            if (this.#firstSpawn) {
                this.#firstSpawn = false;
                this.#currentSpawnDelay = this.#spawnDelay ?? defaultSpawnDelay$1;
            }
            if (this.#duration !== undefined) {
                this.#currentDuration += delta.value;
                if (this.#currentDuration >= this.#duration) {
                    if (!this.#immortal) {
                        this.#lifeCount--;
                    }
                    if (this.#lifeCount > minLifeCount$1 || this.#immortal) {
                        this.position = this.#calcPosition();
                        this.#spawnDelay = this.#container.retina.reduceFactor
                            ? (getRangeValue(this.options.life.delay ?? defaultLifeDelay$1) * millisecondsToSeconds) /
                                this.#container.retina.reduceFactor
                            : Infinity;
                    }
                    this.#currentDuration -= this.#duration;
                    this.#duration = undefined;
                }
            }
            if (this.#spawnDelay !== undefined) {
                this.#currentSpawnDelay += delta.value;
                if (this.#currentSpawnDelay >= this.#spawnDelay) {
                    this.#play();
                    this.#currentSpawnDelay -= this.#spawnDelay;
                    this.#spawnDelay = undefined;
                }
            }
        }
        #calcPosition() {
            const exactPosition = calcPositionOrRandomFromSizeRanged({
                size: this.#container.canvas.size,
                position: this.options.position,
            });
            return Vector.create(exactPosition.x, exactPosition.y);
        }
        #play() {
            if (!((this.#lifeCount > minLifeCount$1 || this.#immortal || !this.options.life.count) &&
                (this.#firstSpawn || this.#currentSpawnDelay >= (this.#spawnDelay ?? defaultSpawnDelay$1)))) {
                return;
            }
            if (this.#lifeCount > minLifeCount$1 || this.#immortal) {
                this.#prepareToDie();
            }
        }
        #prepareToDie() {
            const duration = this.options.life.duration !== undefined ? getRangeValue(this.options.life.duration) : undefined, minDuration = 0;
            if ((this.#lifeCount > minLifeCount$1 || this.#immortal) && duration !== undefined && duration > minDuration) {
                this.#duration = duration * millisecondsToSeconds;
            }
        }
        #updateParticlePosition(particle, delta, v) {
            if (particle.destroyed) {
                return;
            }
            const container = this.#container, canvasSize = container.canvas.size;
            if (particle.needsNewPosition) {
                const newPosition = calcPositionOrRandomFromSize({ size: canvasSize });
                particle.position.setTo(newPosition);
                particle.velocity.setTo(particle.initialVelocity);
                particle.absorberOrbit = undefined;
                particle.needsNewPosition = false;
            }
            if (this.options.orbits) {
                if (particle.absorberOrbit === undefined) {
                    particle.absorberOrbit = Vector.origin;
                    particle.absorberOrbit.length = getDistance(particle.getPosition(), this.position);
                    particle.absorberOrbit.angle = getRandom() * maxAngle;
                }
                if (particle.absorberOrbit.length <= this.size && !this.options.destroy) {
                    const minSize = Math.min(canvasSize.width, canvasSize.height), offset = 1, randomOffset = 0.1, randomFactor = 0.2;
                    particle.absorberOrbit.length = minSize * (offset + (getRandom() * randomFactor - randomOffset));
                }
                particle.absorberOrbitDirection ??=
                    particle.velocity.x >= minVelocity ? exports.RotateDirection.clockwise : exports.RotateDirection.counterClockwise;
                const orbitRadius = particle.absorberOrbit.length, orbitAngle = particle.absorberOrbit.angle, orbitDirection = particle.absorberOrbitDirection;
                particle.velocity.setTo(Vector.origin);
                const maxSize = particle.size.max, sizeFactor = particle.options.move.size ? particle.getRadius() / maxSize : identity$2, deltaFactor = delta.factor || identity$2, baseSpeed = particle.retina.moveSpeed, moveSpeed = baseSpeed * sizeFactor * deltaFactor * half;
                particle.position.x = this.position.x + orbitRadius * Math.cos(orbitAngle);
                particle.position.y =
                    this.position.y +
                        orbitRadius * (orbitDirection === exports.RotateDirection.clockwise ? identity$2 : -identity$2) * Math.sin(orbitAngle);
                particle.absorberOrbit.length = Math.max(minOrbitLength, particle.absorberOrbit.length - v.length);
                particle.absorberOrbit.angle += moveSpeed * angleIncrementFactor * container.retina.reduceFactor;
            }
            else {
                particle.velocity.addTo(v);
            }
        }
    }

    var AbsorberInstance$1 = /*#__PURE__*/Object.freeze({
        __proto__: null,
        AbsorberInstance: AbsorberInstance
    });

    const defaultLifeDelay = 0, minLifeCount = 0, defaultSpawnDelay = 0, defaultEmitDelay = 0, defaultLifeCount = -1, defaultColorAnimationFactor = 1, colorFactor = 3.6, defaultStrokeWidth = 1;
    function setParticlesOptionsFillColor(particlesOptions, color, opacity, enable) {
        const paint = (particlesOptions.paint ??= new Paint());
        paint.fill = {
            color: AnimatableColor.create(undefined, { value: color }),
            enable,
            opacity,
        };
    }
    function setParticlesOptionsStrokeColor(particlesOptions, color, opacity, width) {
        const paint = (particlesOptions.paint ??= new Paint());
        paint.stroke = {
            color: AnimatableColor.create(undefined, { value: color }),
            opacity,
            width,
        };
    }
    class EmitterInstance {
        fill;
        name;
        options;
        position;
        size;
        spawnFillColor;
        spawnFillEnabled;
        spawnFillOpacity;
        spawnStrokeColor;
        spawnStrokeOpacity;
        spawnStrokeWidth;
        #container;
        #currentDuration;
        #currentEmitDelay;
        #currentSpawnDelay;
        #duration;
        #emitDelay;
        #firstSpawn;
        #immortal;
        #initialPosition;
        #lifeCount;
        #mutationObserver;
        #particlesOptions;
        #paused;
        #pluginManager;
        #removeCallback;
        #resizeObserver;
        #shape;
        #size;
        #spawnDelay;
        #startParticlesAdded;
        constructor(pluginManager, container, removeCallback, options, position) {
            this.#pluginManager = pluginManager;
            this.#container = container;
            this.#removeCallback = removeCallback;
            this.#currentDuration = 0;
            this.#currentEmitDelay = 0;
            this.#currentSpawnDelay = 0;
            this.#initialPosition = position;
            if (options instanceof Emitter) {
                this.options = options;
            }
            else {
                this.options = new Emitter();
                this.options.load(options);
            }
            this.#spawnDelay = container.retina.reduceFactor
                ? (getRangeValue(this.options.life.delay ?? defaultLifeDelay) * millisecondsToSeconds) /
                    container.retina.reduceFactor
                : Infinity;
            this.position = this.#initialPosition ?? this.#calcPosition();
            this.name = this.options.name;
            this.fill = this.options.fill;
            this.#firstSpawn = !this.options.life.wait;
            this.#startParticlesAdded = false;
            const particlesOptions = deepExtend({}, this.options.particles);
            particlesOptions.move ??= {};
            particlesOptions.move.direction ??= this.options.direction;
            if (this.options.spawn.fill?.color) {
                this.spawnFillColor = rangeColorToHsl(this.#pluginManager, this.options.spawn.fill.color);
            }
            if (this.options.spawn.stroke?.color) {
                this.spawnStrokeColor = rangeColorToHsl(this.#pluginManager, this.options.spawn.stroke.color);
            }
            this.#paused = !this.options.autoPlay;
            this.#particlesOptions = particlesOptions;
            this.#size = this.#calcSize();
            this.size =
                this.#size.mode === exports.PixelMode.percent
                    ? {
                        width: (this.#size.width / percentDenominator) * this.#container.canvas.size.width,
                        height: (this.#size.height / percentDenominator) * this.#container.canvas.size.height,
                    }
                    : { width: this.#size.width, height: this.#size.height };
            this.#lifeCount = this.options.life.count ?? defaultLifeCount;
            this.#immortal = this.#lifeCount <= minLifeCount;
            if (this.options.domId) {
                const element = safeDocument().getElementById(this.options.domId);
                if (element) {
                    this.#mutationObserver = new MutationObserver(() => {
                        this.resize();
                    });
                    this.#resizeObserver = new ResizeObserver(() => {
                        this.resize();
                    });
                    this.#mutationObserver.observe(element, {
                        attributes: true,
                        attributeFilter: ["style", "width", "height"],
                    });
                    this.#resizeObserver.observe(element);
                }
            }
            const shapeOptions = this.options.shape, shapeGenerator = this.#pluginManager.emitterShapeManager?.getShapeGenerator(shapeOptions.type);
            if (shapeGenerator) {
                this.#shape = shapeGenerator.generate(this.#container, this.position, this.size, this.fill, shapeOptions.options);
            }
            this.#container.dispatchEvent("emitterCreated", {
                emitter: this,
            });
            this.play();
        }
        externalPause() {
            this.#paused = true;
            this.pause();
        }
        externalPlay() {
            this.#paused = false;
            this.play();
        }
        async init() {
            await this.#shape?.init();
        }
        pause() {
            if (this.#paused) {
                return;
            }
            this.#emitDelay = undefined;
        }
        play() {
            if (this.#paused) {
                return;
            }
            if (!((this.#lifeCount > minLifeCount || this.#immortal || !this.options.life.count) &&
                (this.#firstSpawn || this.#currentSpawnDelay >= (this.#spawnDelay ?? defaultSpawnDelay)))) {
                return;
            }
            const container = this.#container;
            if (this.#emitDelay === undefined) {
                const delay = getRangeValue(this.options.rate.delay);
                this.#emitDelay = container.retina.reduceFactor
                    ? (delay * millisecondsToSeconds) / container.retina.reduceFactor
                    : Infinity;
            }
            if (this.#lifeCount > minLifeCount || this.#immortal) {
                this.#prepareToDie();
            }
        }
        resize() {
            const initialPosition = this.#initialPosition, container = this.#container;
            this.position =
                initialPosition && isPointInside(initialPosition, container.canvas.size, Vector.origin)
                    ? initialPosition
                    : this.#calcPosition();
            this.#size = this.#calcSize();
            this.size =
                this.#size.mode === exports.PixelMode.percent
                    ? {
                        width: (this.#size.width / percentDenominator) * container.canvas.size.width,
                        height: (this.#size.height / percentDenominator) * container.canvas.size.height,
                    }
                    : { width: this.#size.width, height: this.#size.height };
            this.#shape?.resize(this.position, this.size);
        }
        update(delta) {
            if (this.#paused) {
                return;
            }
            const container = this.#container;
            if (this.#firstSpawn) {
                this.#firstSpawn = false;
                this.#currentSpawnDelay = this.#spawnDelay ?? defaultSpawnDelay;
                this.#currentEmitDelay = this.#emitDelay ?? defaultEmitDelay;
            }
            if (!this.#startParticlesAdded) {
                this.#startParticlesAdded = true;
                this.#emitParticles(this.options.startCount);
            }
            if (this.#duration !== undefined) {
                this.#currentDuration += delta.value;
                if (this.#currentDuration >= this.#duration) {
                    this.pause();
                    if (this.#spawnDelay !== undefined) {
                        this.#spawnDelay = undefined;
                    }
                    if (!this.#immortal) {
                        this.#lifeCount--;
                    }
                    if (this.#lifeCount > minLifeCount || this.#immortal) {
                        this.position = this.#calcPosition();
                        this.#shape?.resize(this.position, this.size);
                        this.#spawnDelay = container.retina.reduceFactor
                            ? (getRangeValue(this.options.life.delay ?? defaultLifeDelay) * millisecondsToSeconds) /
                                container.retina.reduceFactor
                            : Infinity;
                    }
                    else {
                        this.#destroy();
                    }
                    this.#currentDuration -= this.#duration;
                    this.#duration = undefined;
                }
            }
            if (this.#spawnDelay !== undefined) {
                this.#currentSpawnDelay += delta.value;
                if (this.#currentSpawnDelay >= this.#spawnDelay) {
                    this.#container.dispatchEvent("emitterPlay");
                    this.play();
                    this.#currentSpawnDelay -= this.#spawnDelay;
                    this.#spawnDelay = undefined;
                }
            }
            if (this.#emitDelay !== undefined) {
                this.#currentEmitDelay += delta.value;
                if (this.#currentEmitDelay >= this.#emitDelay) {
                    this.#emit();
                    this.#currentEmitDelay -= this.#emitDelay;
                }
            }
        }
        #calcPosition() {
            const container = this.#container;
            if (this.options.domId) {
                const element = safeDocument().getElementById(this.options.domId);
                if (element) {
                    const elRect = element.getBoundingClientRect(), pxRatio = container.retina.pixelRatio;
                    return {
                        x: (elRect.x + elRect.width * half) * pxRatio,
                        y: (elRect.y + elRect.height * half) * pxRatio,
                    };
                }
            }
            return calcPositionOrRandomFromSizeRanged({
                size: container.canvas.size,
                position: this.options.position,
            });
        }
        #calcSize() {
            const container = this.#container;
            if (this.options.domId) {
                const element = safeDocument().getElementById(this.options.domId);
                if (element) {
                    const elRect = element.getBoundingClientRect();
                    return {
                        width: elRect.width * container.retina.pixelRatio,
                        height: elRect.height * container.retina.pixelRatio,
                        mode: exports.PixelMode.precise,
                    };
                }
            }
            return (this.options.size ??
                (() => {
                    const size = new EmitterSize();
                    size.load({
                        height: 0,
                        mode: exports.PixelMode.percent,
                        width: 0,
                    });
                    return size;
                })());
        }
        #destroy() {
            this.#mutationObserver?.disconnect();
            this.#mutationObserver = undefined;
            this.#resizeObserver?.disconnect();
            this.#resizeObserver = undefined;
            this.#removeCallback(this);
            this.#container.dispatchEvent("emitterDestroyed", {
                emitter: this,
            });
        }
        #emit() {
            if (this.#paused) {
                return;
            }
            const quantity = getRangeValue(this.options.rate.quantity);
            this.#emitParticles(quantity);
        }
        #emitParticles(quantity) {
            const singleParticlesOptions = (itemFromSingleOrMultiple(this.#particlesOptions) ??
                {}), fillHslAnimation = this.options.spawn.fill?.color?.animation, fillEnabled = this.options.spawn.fill?.enable ?? !!this.options.spawn.fill?.color, fillOpacity = this.options.spawn.fill?.opacity === undefined
                ? defaultOpacity$3
                : getRangeValue(this.options.spawn.fill.opacity), strokeHslAnimation = this.options.spawn.stroke?.color?.animation, strokeOpacity = this.options.spawn.stroke?.opacity === undefined
                ? defaultOpacity$3
                : getRangeValue(this.options.spawn.stroke.opacity), strokeWidth = this.options.spawn.stroke?.width === undefined
                ? defaultStrokeWidth
                : getRangeValue(this.options.spawn.stroke.width), reduceFactor = this.#container.retina.reduceFactor, needsFillColorAnimation = !!fillHslAnimation, needsStrokeColorAnimation = !!strokeHslAnimation, needsShapeData = !!this.#shape, needsColorAnimation = needsFillColorAnimation || needsStrokeColorAnimation, needsCopy = needsColorAnimation || needsShapeData, maxValues = needsColorAnimation ? { h: hMax, s: sMax, l: lMax } : null, shapeOptions = this.options.shape;
            for (let i = 0; i < quantity * reduceFactor; i++) {
                const particlesOptions = needsCopy
                    ? deepExtend({}, singleParticlesOptions)
                    : singleParticlesOptions;
                this.spawnFillOpacity = fillOpacity;
                this.spawnFillEnabled = fillEnabled;
                this.spawnStrokeOpacity = strokeOpacity;
                this.spawnStrokeWidth = strokeWidth;
                if (this.spawnFillColor) {
                    if (fillHslAnimation && maxValues) {
                        this.spawnFillColor.h = this.#setColorAnimation(fillHslAnimation.h, this.spawnFillColor.h, maxValues.h, colorFactor);
                        this.spawnFillColor.s = this.#setColorAnimation(fillHslAnimation.s, this.spawnFillColor.s, maxValues.s);
                        this.spawnFillColor.l = this.#setColorAnimation(fillHslAnimation.l, this.spawnFillColor.l, maxValues.l);
                    }
                    setParticlesOptionsFillColor(particlesOptions, this.spawnFillColor, this.spawnFillOpacity, this.spawnFillEnabled);
                }
                if (this.spawnStrokeColor) {
                    if (strokeHslAnimation && maxValues) {
                        this.spawnStrokeColor.h = this.#setColorAnimation(strokeHslAnimation.h, this.spawnStrokeColor.h, maxValues.h, colorFactor);
                        this.spawnStrokeColor.s = this.#setColorAnimation(strokeHslAnimation.s, this.spawnStrokeColor.s, maxValues.s);
                        this.spawnStrokeColor.l = this.#setColorAnimation(strokeHslAnimation.l, this.spawnStrokeColor.l, maxValues.l);
                    }
                    setParticlesOptionsStrokeColor(particlesOptions, this.spawnStrokeColor, this.spawnStrokeOpacity, this.spawnStrokeWidth);
                }
                let position = this.position;
                if (this.#shape) {
                    const shapePosData = this.#shape.randomPosition();
                    if (shapePosData) {
                        position = shapePosData.position;
                        const replaceData = shapeOptions.replace;
                        if (replaceData.color && shapePosData.color) {
                            setParticlesOptionsFillColor(particlesOptions, shapePosData.color, replaceData.opacity ? (shapePosData.opacity ?? defaultOpacity$3) : defaultOpacity$3, true);
                        }
                    }
                    else {
                        position = null;
                    }
                }
                if (position) {
                    this.#container.particles.addParticle(position, particlesOptions);
                }
            }
        }
        #prepareToDie() {
            if (this.#paused) {
                return;
            }
            const duration = this.options.life.duration !== undefined ? getRangeValue(this.options.life.duration) : undefined, minDuration = 0, minLifeCount = 0;
            if ((this.#lifeCount > minLifeCount || this.#immortal) && duration !== undefined && duration > minDuration) {
                this.#duration = duration * millisecondsToSeconds;
            }
        }
        #setColorAnimation(animation, initValue, maxValue, factor = defaultColorAnimationFactor) {
            const container = this.#container;
            if (!animation.enable) {
                return initValue;
            }
            const colorOffset = randomInRangeValue(animation.offset), delay = getRangeValue(this.options.rate.delay), emitFactor = container.retina.reduceFactor
                ? (delay * millisecondsToSeconds) / container.retina.reduceFactor
                : Infinity, colorSpeed = getRangeValue(animation.speed);
            return (initValue + (colorSpeed * container.fpsLimit) / emitFactor + colorOffset * factor) % maxValue;
        }
    }

    var EmitterInstance$1 = /*#__PURE__*/Object.freeze({
        __proto__: null,
        EmitterInstance: EmitterInstance
    });

    exports.AnimatableColor = AnimatableColor;
    exports.AnimationOptions = AnimationOptions;
    exports.AnimationValueWithRandom = AnimationValueWithRandom;
    exports.Background = Background;
    exports.BaseRange = BaseRange;
    exports.Circle = Circle;
    exports.ColorAnimation = ColorAnimation;
    exports.Fill = Fill;
    exports.FullScreen = FullScreen;
    exports.HDROptions = HDROptions;
    exports.HslAnimation = HslAnimation;
    exports.Move = Move;
    exports.MoveAngle = MoveAngle;
    exports.MoveCenter = MoveCenter;
    exports.MoveGravity = MoveGravity;
    exports.MovePath = MovePath;
    exports.OptionLoader = OptionLoader;
    exports.Options = Options;
    exports.OptionsColor = OptionsColor;
    exports.OutModes = OutModes;
    exports.Paint = Paint;
    exports.ParticlesBounce = ParticlesBounce;
    exports.ParticlesBounceFactor = ParticlesBounceFactor;
    exports.ParticlesDensity = ParticlesDensity;
    exports.ParticlesNumber = ParticlesNumber;
    exports.ParticlesNumberLimit = ParticlesNumberLimit;
    exports.ParticlesOptions = ParticlesOptions;
    exports.RangedAnimationOptions = RangedAnimationOptions;
    exports.RangedAnimationValueWithRandom = RangedAnimationValueWithRandom;
    exports.Rectangle = Rectangle;
    exports.ResizeEvent = ResizeEvent;
    exports.Shape = Shape;
    exports.Spin = Spin;
    exports.Stroke = Stroke;
    exports.ValueWithRandom = ValueWithRandom;
    exports.Vector = Vector;
    exports.Vector3d = Vector3d;
    exports.ZIndex = ZIndex;
    exports.alterHsl = alterHsl;
    exports.animate = animate;
    exports.areBoundsInside = areBoundsInside;
    exports.calcExactPositionOrRandomFromSize = calcExactPositionOrRandomFromSize;
    exports.calcPositionFromSize = calcPositionFromSize;
    exports.calcPositionOrRandomFromSize = calcPositionOrRandomFromSize;
    exports.calcPositionOrRandomFromSizeRanged = calcPositionOrRandomFromSizeRanged;
    exports.calculateBounds = calculateBounds;
    exports.cancelAnimation = cancelAnimation;
    exports.canvasFirstIndex = canvasFirstIndex;
    exports.canvasTag = canvasTag;
    exports.checkDistance = checkDistance;
    exports.circleBounce = circleBounce;
    exports.circleBounceDataFromParticle = circleBounceDataFromParticle;
    exports.clamp = clamp;
    exports.cloneStyle = cloneStyle;
    exports.collisionVelocity = collisionVelocity;
    exports.colorMix = colorMix;
    exports.colorToRgb = colorToRgb;
    exports.countOffset = countOffset;
    exports.decayOffset = decayOffset;
    exports.deepExtend = deepExtend;
    exports.defaultAlpha = defaultAlpha$1;
    exports.defaultAngle = defaultAngle;
    exports.defaultCompositeValue = defaultCompositeValue;
    exports.defaultDensityFactor = defaultDensityFactor;
    exports.defaultFps = defaultFps;
    exports.defaultFpsLimit = defaultFpsLimit;
    exports.defaultLoops = defaultLoops;
    exports.defaultOpacity = defaultOpacity$3;
    exports.defaultRatio = defaultRatio$1;
    exports.defaultReduceFactor = defaultReduceFactor;
    exports.defaultRemoveQuantity = defaultRemoveQuantity;
    exports.defaultRetryCount = defaultRetryCount;
    exports.defaultRgbMin = defaultRgbMin;
    exports.defaultTime = defaultTime;
    exports.defaultTransform = defaultTransform;
    exports.defaultTransformValue = defaultTransformValue;
    exports.defaultVelocity = defaultVelocity;
    exports.defaultZoom = defaultZoom;
    exports.degToRad = degToRad;
    exports.deleteCount = deleteCount;
    exports.double = double;
    exports.doublePI = doublePI;
    exports.empty = empty;
    exports.executeOnSingleOrMultiple = executeOnSingleOrMultiple;
    exports.generatedAttribute = generatedAttribute;
    exports.generatedFalse = generatedFalse;
    exports.generatedTrue = generatedTrue;
    exports.getDistance = getDistance;
    exports.getDistanceSq = getDistanceSq;
    exports.getDistances = getDistances;
    exports.getFullScreenStyle = getFullScreenStyle;
    exports.getHslAnimationFromHsl = getHslAnimationFromHsl;
    exports.getHslFromAnimation = getHslFromAnimation;
    exports.getItemMapFromInitializer = getItemMapFromInitializer;
    exports.getItemsFromInitializer = getItemsFromInitializer;
    exports.getLinkColor = getLinkColor;
    exports.getLinkRandomColor = getLinkRandomColor;
    exports.getLogger = getLogger;
    exports.getParticleBaseVelocity = getParticleBaseVelocity;
    exports.getParticleDirectionAngle = getParticleDirectionAngle;
    exports.getPosition = getPosition;
    exports.getRandom = getRandom;
    exports.getRandomFn = getRandomFn;
    exports.getRandomInRange = getRandomInRange;
    exports.getRandomRgbColor = getRandomRgbColor;
    exports.getRangeMax = getRangeMax;
    exports.getRangeMin = getRangeMin;
    exports.getRangeValue = getRangeValue;
    exports.getStyleFromHsl = getStyleFromHsl;
    exports.getStyleFromRgb = getStyleFromRgb;
    exports.hMax = hMax;
    exports.hMin = hMin;
    exports.hPhase = hPhase;
    exports.half = half;
    exports.hslToRgb = hslToRgb;
    exports.hslToRgbFloat = hslToRgbFloat;
    exports.hslaToRgba = hslaToRgba;
    exports.identity = identity$2;
    exports.inverseFactorNumerator = inverseFactorNumerator;
    exports.isArray = isArray;
    exports.isBoolean = isBoolean;
    exports.isFunction = isFunction;
    exports.isInArray = isInArray;
    exports.isNull = isNull;
    exports.isNumber = isNumber;
    exports.isObject = isObject;
    exports.isPointInside = isPointInside;
    exports.isString = isString;
    exports.itemFromArray = itemFromArray;
    exports.itemFromSingleOrMultiple = itemFromSingleOrMultiple;
    exports.lFactor = lFactor;
    exports.lMax = lMax;
    exports.lMin = lMin;
    exports.lengthOffset = lengthOffset;
    exports.loadExtendProperty = loadExtendProperty;
    exports.loadFull = loadFull;
    exports.loadLazyProperty = loadLazyProperty;
    exports.loadMinIndex = loadMinIndex;
    exports.loadNestedProperty = loadNestedProperty;
    exports.loadOptionProperty = loadOptionProperty;
    exports.loadOptions = loadOptions;
    exports.loadParticlesOptions = loadParticlesOptions;
    exports.loadProperty = loadProperty;
    exports.loadRandomFactor = loadRandomFactor;
    exports.loadRangeProperty = loadRangeProperty;
    exports.manageListener = manageListener;
    exports.maxNits = maxNits;
    exports.midColorValue = midColorValue;
    exports.millisecondsToSeconds = millisecondsToSeconds;
    exports.minCount = minCount;
    exports.minDistance = minDistance$6;
    exports.minFpsLimit = minFpsLimit;
    exports.minIndex = minIndex;
    exports.minLimit = minLimit;
    exports.minRadius = minRadius$5;
    exports.minStrokeWidth = minStrokeWidth;
    exports.minVelocity = minVelocity;
    exports.minZ = minZ;
    exports.minimumSize = minimumSize;
    exports.mix = mix;
    exports.none = none;
    exports.one = one;
    exports.originPoint = originPoint;
    exports.parseAlpha = parseAlpha;
    exports.percentDenominator = percentDenominator;
    exports.phaseNumerator = phaseNumerator;
    exports.quarter = quarter;
    exports.randomColorValue = randomColorValue;
    exports.randomInRangeValue = randomInRangeValue;
    exports.rangeColorToHsl = rangeColorToHsl;
    exports.rangeColorToRgb = rangeColorToRgb;
    exports.removeDeleteCount = removeDeleteCount;
    exports.removeMinIndex = removeMinIndex;
    exports.resizeEvent = resizeEvent;
    exports.rgbMax = rgbMax;
    exports.rgbToHsl = rgbToHsl;
    exports.sMax = sMax;
    exports.sMin = sMin;
    exports.sNormalizedOffset = sNormalizedOffset;
    exports.safeDocument = safeDocument;
    exports.safeMatchMedia = safeMatchMedia;
    exports.safeMutationObserver = safeMutationObserver;
    exports.setAnimationFunctions = setAnimationFunctions;
    exports.setLogger = setLogger;
    exports.setRandom = setRandom;
    exports.setRangeValue = setRangeValue;
    exports.sextuple = sextuple;
    exports.spatialHashGridCellSize = spatialHashGridCellSize;
    exports.squareExp = squareExp;
    exports.stringToAlpha = stringToAlpha;
    exports.stringToRgb = stringToRgb;
    exports.threeQuarter = threeQuarter;
    exports.triple = triple;
    exports.tryCountIncrement = tryCountIncrement;
    exports.tsParticles = tsParticles;
    exports.updateColor = updateColor;
    exports.updateColorValue = updateColorValue;
    exports.visibilityChangeEvent = visibilityChangeEvent;
    exports.zIndexFactorOffset = zIndexFactorOffset;

}));
Object.assign(globalThis.window || globalThis, { loadExtendProperty: (globalThis.__tsParticlesInternals.bundles.full || {}).loadExtendProperty, loadFull: (globalThis.__tsParticlesInternals.bundles.full || {}).loadFull, loadLazyProperty: (globalThis.__tsParticlesInternals.bundles.full || {}).loadLazyProperty, loadMinIndex: (globalThis.__tsParticlesInternals.bundles.full || {}).loadMinIndex, loadNestedProperty: (globalThis.__tsParticlesInternals.bundles.full || {}).loadNestedProperty, loadOptionProperty: (globalThis.__tsParticlesInternals.bundles.full || {}).loadOptionProperty, loadOptions: (globalThis.__tsParticlesInternals.bundles.full || {}).loadOptions, loadParticlesOptions: (globalThis.__tsParticlesInternals.bundles.full || {}).loadParticlesOptions, loadProperty: (globalThis.__tsParticlesInternals.bundles.full || {}).loadProperty, loadRandomFactor: (globalThis.__tsParticlesInternals.bundles.full || {}).loadRandomFactor, loadRangeProperty: (globalThis.__tsParticlesInternals.bundles.full || {}).loadRangeProperty, tsParticles: (globalThis.__tsParticlesInternals.bundles.full || {}).tsParticles });
globalThis.__tsParticlesInternals = globalThis.__tsParticlesInternals || {};
if (!globalThis.__tsParticlesInternals.engine || !globalThis.__tsParticlesInternals.engine.tsParticles) {
  globalThis.__tsParticlesInternals.engine = globalThis.__tsParticlesInternals.bundles.full || {};
}
delete (globalThis.window || globalThis).tsparticlesInternalExports;