/*
MIT License

Copyright (c) 2012 - 2025 @jonobr1 / http://jono.fyi

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
var Two = (() => {
  var __defProp = Object.defineProperty;
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
  var __getOwnPropNames = Object.getOwnPropertyNames;
  var __hasOwnProp = Object.prototype.hasOwnProperty;
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
  var __export = (target, all) => {
    for (var name in all)
      __defProp(target, name, { get: all[name], enumerable: true });
  };
  var __copyProps = (to, from, except, desc) => {
    if (from && typeof from === "object" || typeof from === "function") {
      for (let key of __getOwnPropNames(from))
        if (!__hasOwnProp.call(to, key) && key !== except)
          __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
    }
    return to;
  };
  var __toCommonJS = (mod2) => __copyProps(__defProp({}, "__esModule", { value: true }), mod2);
  var __publicField = (obj, key, value) => {
    __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
    return value;
  };

  // src/two.js
  var two_exports = {};
  __export(two_exports, {
    default: () => Two
  });

  // src/utils/canvas-polyfill.js
  var CanvasPolyfill = {
    Image: null,
    isHeadless: false,
    shim: function(elem, name) {
      elem.tagName = elem.nodeName = name || "canvas";
      elem.nodeType = 1;
      elem.getAttribute = function(prop) {
        return this[prop];
      };
      elem.setAttribute = function(prop, val) {
        this[prop] = val;
        return this;
      };
      return elem;
    },
    polyfill: function(canvas3, Image) {
      CanvasPolyfill.shim(canvas3);
      if (typeof Image !== "undefined") {
        CanvasPolyfill.Image = Image;
      }
      CanvasPolyfill.isHeadless = true;
      return canvas3;
    }
  };

  // src/utils/curves.js
  var curves_exports = {};
  __export(curves_exports, {
    Curve: () => Curve,
    getAnchorsFromArcData: () => getAnchorsFromArcData,
    getComponentOnCubicBezier: () => getComponentOnCubicBezier,
    getControlPoints: () => getControlPoints,
    getCurveBoundingBox: () => getCurveBoundingBox,
    getCurveFromPoints: () => getCurveFromPoints,
    getCurveLength: () => getCurveLength,
    getReflection: () => getReflection,
    integrate: () => integrate,
    subdivide: () => subdivide
  });

  // src/utils/math.js
  var math_exports = {};
  __export(math_exports, {
    HALF_PI: () => HALF_PI,
    NumArray: () => NumArray,
    TWO_PI: () => TWO_PI,
    decomposeMatrix: () => decomposeMatrix,
    getComputedMatrix: () => getComputedMatrix,
    getPoT: () => getPoT,
    lerp: () => lerp,
    mod: () => mod,
    setMatrix: () => setMatrix,
    toFixed: () => toFixed
  });

  // src/utils/root.js
  var root;
  if (typeof window !== "undefined") {
    root = window;
  } else if (typeof global !== "undefined") {
    root = global;
  } else if (typeof self !== "undefined") {
    root = self;
  }

  // src/utils/math.js
  var Matrix;
  var TWO_PI = Math.PI * 2;
  var HALF_PI = Math.PI * 0.5;
  function decomposeMatrix(matrix, b, c, d, e, f) {
    let a;
    if (arguments.length <= 1) {
      a = matrix.a;
      b = matrix.b;
      c = matrix.c;
      d = matrix.d;
      e = matrix.e;
      f = matrix.f;
    } else {
      a = matrix;
    }
    return {
      translateX: e,
      translateY: f,
      scaleX: Math.sqrt(a * a + b * b),
      scaleY: Math.sqrt(c * c + d * d),
      rotation: 180 * Math.atan2(b, a) / Math.PI
    };
  }
  function setMatrix(matrix) {
    Matrix = matrix;
  }
  function getComputedMatrix(object, matrix) {
    matrix = matrix && matrix.identity() || new Matrix();
    let parent = object;
    const matrices = [];
    while (parent && parent._matrix) {
      matrices.push(parent._matrix);
      parent = parent.parent;
    }
    matrices.reverse();
    for (let i = 0; i < matrices.length; i++) {
      const m = matrices[i];
      const e = m.elements;
      matrix.multiply(
        e[0],
        e[1],
        e[2],
        e[3],
        e[4],
        e[5],
        e[6],
        e[7],
        e[8],
        e[9]
      );
    }
    return matrix;
  }
  function lerp(a, b, t) {
    return t * (b - a) + a;
  }
  var pots = [2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096];
  function getPoT(value) {
    let i = 0;
    while (pots[i] && pots[i] < value) {
      i++;
    }
    return pots[i];
  }
  function mod(v, l) {
    while (v < 0) {
      v += l;
    }
    return v % l;
  }
  var NumArray = root.Float32Array || Array;
  var floor = Math.floor;
  function toFixed(v) {
    return floor(v * 1e6) / 1e6;
  }

  // src/utils/path-commands.js
  var Commands = {
    move: "M",
    line: "L",
    curve: "C",
    arc: "A",
    close: "Z"
  };

  // src/events.js
  var Events = class {
    _events = {};
    _bound = false;
    constructor() {
    }
    addEventListener(name, handler) {
      const list = this._events[name] || (this._events[name] = []);
      list.push(handler);
      this._bound = true;
      return this;
    }
    on() {
      return this.addEventListener.apply(this, arguments);
    }
    bind() {
      return this.addEventListener.apply(this, arguments);
    }
    removeEventListener(name, handler) {
      if (!this._events) {
        return this;
      }
      if (!name && !handler) {
        this._events = {};
        this._bound = false;
        return this;
      }
      const names = name ? [name] : Object.keys(this._events);
      for (let i = 0, l = names.length; i < l; i++) {
        name = names[i];
        let list = this._events[name];
        if (list) {
          let events = [];
          if (handler) {
            for (let j = 0, k = list.length; j < k; j++) {
              let e = list[j];
              e = e.handler ? e.handler : e;
              if (handler !== e) {
                events.push(e);
              }
            }
          }
          this._events[name] = events;
        }
      }
      return this;
    }
    off() {
      return this.removeEventListener.apply(this, arguments);
    }
    unbind() {
      return this.removeEventListener.apply(this, arguments);
    }
    dispatchEvent(name) {
      if (!this._events) {
        return this;
      }
      const args = Array.prototype.slice.call(arguments, 1);
      const events = this._events[name];
      if (events) {
        for (let i = 0; i < events.length; i++) {
          events[i].call(this, ...args);
        }
      }
      return this;
    }
    trigger() {
      return this.dispatchEvent.apply(this, arguments);
    }
    listen(obj, name, handler) {
      const scope = this;
      if (obj) {
        e.obj = obj;
        e.name = name;
        e.handler = handler;
        obj.on(name, e);
      }
      function e() {
        handler.apply(scope, arguments);
      }
      return scope;
    }
    ignore(obj, name, handler) {
      obj.off(name, handler);
      return this;
    }
  };
  __publicField(Events, "Types", {
    play: "play",
    pause: "pause",
    update: "update",
    render: "render",
    resize: "resize",
    change: "change",
    remove: "remove",
    insert: "insert",
    order: "order",
    load: "load"
  });
  __publicField(Events, "Methods", [
    "addEventListener",
    "on",
    "removeEventListener",
    "off",
    "unbind",
    "dispatchEvent",
    "trigger",
    "listen",
    "ignore"
  ]);

  // src/vector.js
  var proto = {
    x: {
      enumerable: true,
      get: function() {
        return this._x;
      },
      set: function(v) {
        if (this._x !== v) {
          this._x = v;
          if (this._bound) {
            this.dispatchEvent(Events.Types.change);
          }
        }
      }
    },
    y: {
      enumerable: true,
      get: function() {
        return this._y;
      },
      set: function(v) {
        if (this._y !== v) {
          this._y = v;
          if (this._bound) {
            this.dispatchEvent(Events.Types.change);
          }
        }
      }
    }
  };
  var _Vector = class extends Events {
    _x = 0;
    _y = 0;
    constructor(x = 0, y = 0) {
      super();
      for (let prop in proto) {
        Object.defineProperty(this, prop, proto[prop]);
      }
      this.x = x;
      this.y = y;
    }
    static add(v1, v2) {
      return new _Vector(v1.x + v2.x, v1.y + v2.y);
    }
    static sub(v1, v2) {
      return new _Vector(v1.x - v2.x, v1.y - v2.y);
    }
    static subtract(v1, v2) {
      return _Vector.sub(v1, v2);
    }
    static ratioBetween(v1, v2) {
      return (v1.x * v2.x + v1.y * v2.y) / (v1.length() * v2.length());
    }
    static angleBetween(v1, v2) {
      if (arguments.length >= 4) {
        const dx2 = arguments[0] - arguments[2];
        const dy2 = arguments[1] - arguments[3];
        return Math.atan2(dy2, dx2);
      }
      const dx = v1.x - v2.x;
      const dy = v1.y - v2.y;
      return Math.atan2(dy, dx);
    }
    static distanceBetween(v1, v2) {
      return Math.sqrt(_Vector.distanceBetweenSquared(v1, v2));
    }
    static distanceBetweenSquared(v1, v2) {
      const dx = v1.x - v2.x;
      const dy = v1.y - v2.y;
      return dx * dx + dy * dy;
    }
    set(x, y) {
      this.x = x;
      this.y = y;
      return this;
    }
    copy(v) {
      this.x = v.x;
      this.y = v.y;
      return this;
    }
    clear() {
      this.x = 0;
      this.y = 0;
      return this;
    }
    clone() {
      return new _Vector(this.x, this.y);
    }
    add(x, y) {
      if (arguments.length <= 0) {
        return this;
      } else if (arguments.length <= 1) {
        if (typeof x === "number") {
          this.x += x;
          this.y += x;
        } else if (x && typeof x.x === "number" && typeof x.y === "number") {
          this.x += x.x;
          this.y += x.y;
        }
      } else {
        this.x += x;
        this.y += y;
      }
      return this;
    }
    addSelf(v) {
      return this.add.apply(this, arguments);
    }
    sub(x, y) {
      if (arguments.length <= 0) {
        return this;
      } else if (arguments.length <= 1) {
        if (typeof x === "number") {
          this.x -= x;
          this.y -= x;
        } else if (x && typeof x.x === "number" && typeof x.y === "number") {
          this.x -= x.x;
          this.y -= x.y;
        }
      } else {
        this.x -= x;
        this.y -= y;
      }
      return this;
    }
    subtract() {
      return this.sub.apply(this, arguments);
    }
    subSelf(v) {
      return this.sub.apply(this, arguments);
    }
    subtractSelf(v) {
      return this.sub.apply(this, arguments);
    }
    multiply(x, y) {
      if (arguments.length <= 0) {
        return this;
      } else if (arguments.length <= 1) {
        if (typeof x === "number") {
          this.x *= x;
          this.y *= x;
        } else if (x && typeof x.x === "number" && typeof x.y === "number") {
          this.x *= x.x;
          this.y *= x.y;
        }
      } else {
        this.x *= x;
        this.y *= y;
      }
      return this;
    }
    multiplySelf(v) {
      return this.multiply.apply(this, arguments);
    }
    multiplyScalar(s) {
      return this.multiply(s);
    }
    divide(x, y) {
      if (arguments.length <= 0) {
        return this;
      } else if (arguments.length <= 1) {
        if (typeof x === "number") {
          this.x /= x;
          this.y /= x;
        } else if (x && typeof x.x === "number" && typeof x.y === "number") {
          this.x /= x.x;
          this.y /= x.y;
        }
      } else {
        this.x /= x;
        this.y /= y;
      }
      if (isNaN(this.x)) {
        this.x = 0;
      }
      if (isNaN(this.y)) {
        this.y = 0;
      }
      return this;
    }
    divideSelf(v) {
      return this.divide.apply(this, arguments);
    }
    divideScalar(s) {
      return this.divide(s);
    }
    negate() {
      return this.multiply(-1);
    }
    dot(v) {
      return this.x * v.x + this.y * v.y;
    }
    length() {
      return Math.sqrt(this.lengthSquared());
    }
    lengthSquared() {
      return this.x * this.x + this.y * this.y;
    }
    normalize() {
      return this.divideScalar(this.length());
    }
    distanceTo(v) {
      return Math.sqrt(this.distanceToSquared(v));
    }
    distanceToSquared(v) {
      const dx = this.x - v.x;
      const dy = this.y - v.y;
      return dx * dx + dy * dy;
    }
    setLength(l) {
      return this.normalize().multiplyScalar(l);
    }
    equals(v, eps) {
      eps = typeof eps === "undefined" ? 1e-4 : eps;
      return this.distanceTo(v) < eps;
    }
    lerp(v, t) {
      const x = (v.x - this.x) * t + this.x;
      const y = (v.y - this.y) * t + this.y;
      return this.set(x, y);
    }
    isZero(eps) {
      eps = typeof eps === "undefined" ? 1e-4 : eps;
      return this.length() < eps;
    }
    toString() {
      return this.x + ", " + this.y;
    }
    toObject() {
      return { x: toFixed(this.x), y: toFixed(this.y) };
    }
    rotate(radians) {
      const x = this.x;
      const y = this.y;
      const cos7 = Math.cos(radians);
      const sin7 = Math.sin(radians);
      this.x = x * cos7 - y * sin7;
      this.y = x * sin7 + y * cos7;
      return this;
    }
  };
  var Vector = _Vector;
  __publicField(Vector, "zero", new _Vector());
  __publicField(Vector, "left", new _Vector(-1, 0));
  __publicField(Vector, "right", new _Vector(1, 0));
  __publicField(Vector, "up", new _Vector(0, -1));
  __publicField(Vector, "down", new _Vector(0, 1));

  // src/anchor.js
  var Anchor = class extends Vector {
    controls = {
      left: new Vector(),
      right: new Vector()
    };
    _command = Commands.move;
    _relative = true;
    _rx = 0;
    _ry = 0;
    _xAxisRotation = 0;
    _largeArcFlag = 0;
    _sweepFlag = 1;
    constructor(x = 0, y = 0, ax = 0, ay = 0, bx = 0, by = 0, command = Commands.move) {
      super(x, y);
      for (let prop in proto2) {
        Object.defineProperty(this, prop, proto2[prop]);
      }
      this.command = command;
      this.relative = true;
      const broadcast = Anchor.makeBroadcast(this);
      this.controls.left.set(ax, ay).addEventListener(Events.Types.change, broadcast);
      this.controls.right.set(bx, by).addEventListener(Events.Types.change, broadcast);
    }
    static makeBroadcast(scope) {
      return broadcast;
      function broadcast() {
        if (scope._bound) {
          scope.dispatchEvent(Events.Types.change);
        }
      }
    }
    static fromObject(obj) {
      return new Anchor().copy(obj);
    }
    copy(v) {
      this.x = v.x;
      this.y = v.y;
      if (typeof v.command === "string") {
        this.command = v.command;
      }
      if (v.controls) {
        if (v.controls.left) {
          this.controls.left.copy(v.controls.left);
        }
        if (v.controls.right) {
          this.controls.right.copy(v.controls.right);
        }
      }
      if (typeof v.relative === "boolean") {
        this.relative = v.relative;
      }
      if (typeof v.rx === "number") {
        this.rx = v.rx;
      }
      if (typeof v.ry === "number") {
        this.ry = v.ry;
      }
      if (typeof v.xAxisRotation === "number") {
        this.xAxisRotation = v.xAxisRotation;
      }
      if (typeof v.largeArcFlag === "number") {
        this.largeArcFlag = v.largeArcFlag;
      }
      if (typeof v.sweepFlag === "number") {
        this.sweepFlag = v.sweepFlag;
      }
      return this;
    }
    clone() {
      return new Anchor().copy(this);
    }
    toObject() {
      return {
        x: toFixed(this.x),
        y: toFixed(this.y),
        command: this.command,
        relative: this.relative,
        controls: {
          left: this.controls.left.toObject(),
          right: this.controls.right.toObject()
        },
        rx: toFixed(this.rx),
        ry: toFixed(this.ry),
        xAxisRotation: toFixed(this.xAxisRotation),
        largeArcFlag: toFixed(this.largeArcFlag),
        sweepFlag: toFixed(this.sweepFlag)
      };
    }
    toString() {
      return JSON.stringify(this.toObject());
    }
  };
  var proto2 = {
    command: {
      enumerable: true,
      get: function() {
        return this._command;
      },
      set: function(command) {
        if (this._command !== command) {
          this._command = command;
          if (this._bound) {
            this.dispatchEvent(Events.Types.change);
          }
        }
      }
    },
    relative: {
      enumerable: true,
      get: function() {
        return this._relative;
      },
      set: function(relative) {
        if (this._relative !== !!relative) {
          this._relative = !!relative;
          if (this._bound) {
            this.dispatchEvent(Events.Types.change);
          }
        }
      }
    },
    rx: {
      enumerable: true,
      get: function() {
        return this._rx;
      },
      set: function(rx) {
        if (this._rx !== rx) {
          this._rx = rx;
          if (this._bound) {
            this.dispatchEvent(Events.Types.change);
          }
        }
      }
    },
    ry: {
      enumerable: true,
      get: function() {
        return this._ry;
      },
      set: function(ry) {
        if (this._ry !== ry) {
          this._ry = ry;
          if (this._bound) {
            this.dispatchEvent(Events.Types.change);
          }
        }
      }
    },
    xAxisRotation: {
      enumerable: true,
      get: function() {
        return this._xAxisRotation;
      },
      set: function(xAxisRotation) {
        if (this._xAxisRotation !== xAxisRotation) {
          this._xAxisRotation = xAxisRotation;
          if (this._bound) {
            this.dispatchEvent(Events.Types.change);
          }
        }
      }
    },
    largeArcFlag: {
      enumerable: true,
      get: function() {
        return this._largeArcFlag;
      },
      set: function(largeArcFlag) {
        if (this._largeArcFlag !== largeArcFlag) {
          this._largeArcFlag = largeArcFlag;
          if (this._bound) {
            this.dispatchEvent(Events.Types.change);
          }
        }
      }
    },
    sweepFlag: {
      get: function() {
        return this._sweepFlag;
      },
      set: function(sweepFlag) {
        if (this._sweepFlag !== sweepFlag) {
          this._sweepFlag = sweepFlag;
          if (this._bound) {
            this.dispatchEvent(Events.Types.change);
          }
        }
      }
    }
  };

  // src/constants.js
  var count = 0;
  var Constants = {
    NextFrameId: null,
    Types: {
      webgl: "WebGLRenderer",
      svg: "SVGRenderer",
      canvas: "CanvasRenderer"
    },
    Version: "v0.8.19",
    PublishDate: "2025-06-27T18:00:39.187Z",
    Identifier: "two-",
    Resolution: 12,
    AutoCalculateImportedMatrices: true,
    Instances: [],
    uniqueId: function() {
      return count++;
    }
  };

  // src/utils/curves.js
  var Curve = {
    CollinearityEpsilon: Math.pow(10, -30),
    RecursionLimit: 16,
    CuspLimit: 0,
    Tolerance: {
      distance: 0.25,
      angle: 0,
      epsilon: Number.EPSILON
    },
    abscissas: [
      [0.5773502691896257],
      [0, 0.7745966692414834],
      [0.33998104358485626, 0.8611363115940526],
      [0, 0.5384693101056831, 0.906179845938664],
      [
        0.2386191860831969,
        0.6612093864662645,
        0.932469514203152
      ],
      [
        0,
        0.4058451513773972,
        0.7415311855993945,
        0.9491079123427585
      ],
      [
        0.1834346424956498,
        0.525532409916329,
        0.7966664774136267,
        0.9602898564975363
      ],
      [
        0,
        0.3242534234038089,
        0.6133714327005904,
        0.8360311073266358,
        0.9681602395076261
      ],
      [
        0.14887433898163122,
        0.4333953941292472,
        0.6794095682990244,
        0.8650633666889845,
        0.9739065285171717
      ],
      [
        0,
        0.26954315595234496,
        0.5190961292068118,
        0.7301520055740494,
        0.8870625997680953,
        0.978228658146057
      ],
      [
        0.1252334085114689,
        0.3678314989981802,
        0.5873179542866175,
        0.7699026741943047,
        0.9041172563704749,
        0.9815606342467192
      ],
      [
        0,
        0.2304583159551348,
        0.44849275103644687,
        0.6423493394403402,
        0.8015780907333099,
        0.9175983992229779,
        0.9841830547185881
      ],
      [
        0.10805494870734367,
        0.31911236892788974,
        0.5152486363581541,
        0.6872929048116855,
        0.827201315069765,
        0.9284348836635735,
        0.9862838086968123
      ],
      [
        0,
        0.20119409399743451,
        0.3941513470775634,
        0.5709721726085388,
        0.7244177313601701,
        0.8482065834104272,
        0.937273392400706,
        0.9879925180204854
      ],
      [
        0.09501250983763744,
        0.2816035507792589,
        0.45801677765722737,
        0.6178762444026438,
        0.755404408355003,
        0.8656312023878318,
        0.9445750230732326,
        0.9894009349916499
      ]
    ],
    weights: [
      [1],
      [0.8888888888888888, 0.5555555555555556],
      [0.6521451548625461, 0.34785484513745385],
      [
        0.5688888888888889,
        0.47862867049936647,
        0.23692688505618908
      ],
      [
        0.46791393457269104,
        0.3607615730481386,
        0.17132449237917036
      ],
      [
        0.4179591836734694,
        0.3818300505051189,
        0.27970539148927664,
        0.1294849661688697
      ],
      [
        0.362683783378362,
        0.31370664587788727,
        0.22238103445337448,
        0.10122853629037626
      ],
      [
        0.3302393550012598,
        0.31234707704000286,
        0.26061069640293544,
        0.1806481606948574,
        0.08127438836157441
      ],
      [
        0.29552422471475287,
        0.26926671930999635,
        0.21908636251598204,
        0.1494513491505806,
        0.06667134430868814
      ],
      [
        0.2729250867779006,
        0.26280454451024665,
        0.23319376459199048,
        0.18629021092773426,
        0.1255803694649046,
        0.05566856711617366
      ],
      [
        0.24914704581340277,
        0.2334925365383548,
        0.20316742672306592,
        0.16007832854334622,
        0.10693932599531843,
        0.04717533638651183
      ],
      [
        0.2325515532308739,
        0.22628318026289723,
        0.2078160475368885,
        0.17814598076194574,
        0.13887351021978725,
        0.09212149983772845,
        0.04048400476531588
      ],
      [
        0.2152638534631578,
        0.2051984637212956,
        0.18553839747793782,
        0.15720316715819355,
        0.12151857068790319,
        0.08015808715976021,
        0.03511946033175186
      ],
      [
        0.2025782419255613,
        0.19843148532711158,
        0.1861610000155622,
        0.16626920581699392,
        0.13957067792615432,
        0.10715922046717194,
        0.07036604748810812,
        0.03075324199611727
      ],
      [
        0.1894506104550685,
        0.18260341504492358,
        0.16915651939500254,
        0.14959598881657674,
        0.12462897125553388,
        0.09515851168249279,
        0.062253523938647894,
        0.027152459411754096
      ]
    ]
  };
  function getComponentOnCubicBezier(t, a, b, c, d) {
    const k = 1 - t;
    return k * k * k * a + 3 * k * k * t * b + 3 * k * t * t * c + t * t * t * d;
  }
  function subdivide(x1, y1, x2, y2, x3, y3, x4, y4, limit) {
    limit = limit || Curve.RecursionLimit;
    const amount = limit + 1;
    if (Math.abs(x1 - x4) < 1e-3 && Math.abs(y1 - y4) < 1e-3) {
      return [new Anchor(x4, y4)];
    }
    const result = [];
    for (let i = 0; i < amount; i++) {
      const t = i / amount;
      const x = getComponentOnCubicBezier(t, x1, x2, x3, x4);
      const y = getComponentOnCubicBezier(t, y1, y2, y3, y4);
      result.push(new Anchor(x, y));
    }
    return result;
  }
  function getCurveLength(x1, y1, x2, y2, x3, y3, x4, y4, limit) {
    if (x1 === x2 && y1 === y2 && x3 === x4 && y3 === y4) {
      const dx = x4 - x1;
      const dy = y4 - y1;
      return Math.sqrt(dx * dx + dy * dy);
    }
    const ax = 9 * (x2 - x3) + 3 * (x4 - x1), bx = 6 * (x1 + x3) - 12 * x2, cx = 3 * (x2 - x1), ay = 9 * (y2 - y3) + 3 * (y4 - y1), by = 6 * (y1 + y3) - 12 * y2, cy = 3 * (y2 - y1);
    function integrand(t) {
      const dx = (ax * t + bx) * t + cx, dy = (ay * t + by) * t + cy;
      return Math.sqrt(dx * dx + dy * dy);
    }
    return integrate(integrand, 0, 1, limit || Curve.RecursionLimit);
  }
  function getCurveBoundingBox(x1, y1, x2, y2, x3, y3, x4, y4) {
    const tvalues = [];
    const bounds = [[], []];
    let a, b, c, t, t1, t2, b2ac, sqrtb2ac;
    for (let i = 0; i < 2; ++i) {
      if (i == 0) {
        b = 6 * x1 - 12 * x2 + 6 * x3;
        a = -3 * x1 + 9 * x2 - 9 * x3 + 3 * x4;
        c = 3 * x2 - 3 * x1;
      } else {
        b = 6 * y1 - 12 * y2 + 6 * y3;
        a = -3 * y1 + 9 * y2 - 9 * y3 + 3 * y4;
        c = 3 * y2 - 3 * y1;
      }
      if (Math.abs(a) < 1e-12) {
        if (Math.abs(b) < 1e-12) {
          continue;
        }
        t = -c / b;
        if (0 < t && t < 1) {
          tvalues.push(t);
        }
        continue;
      }
      b2ac = b * b - 4 * c * a;
      sqrtb2ac = Math.sqrt(b2ac);
      if (b2ac < 0) {
        continue;
      }
      t1 = (-b + sqrtb2ac) / (2 * a);
      if (0 < t1 && t1 < 1) {
        tvalues.push(t1);
      }
      t2 = (-b - sqrtb2ac) / (2 * a);
      if (0 < t2 && t2 < 1) {
        tvalues.push(t2);
      }
    }
    let j = tvalues.length;
    let jlen = j;
    let mt;
    while (j--) {
      t = tvalues[j];
      mt = 1 - t;
      bounds[0][j] = mt * mt * mt * x1 + 3 * mt * mt * t * x2 + 3 * mt * t * t * x3 + t * t * t * x4;
      bounds[1][j] = mt * mt * mt * y1 + 3 * mt * mt * t * y2 + 3 * mt * t * t * y3 + t * t * t * y4;
    }
    bounds[0][jlen] = x1;
    bounds[1][jlen] = y1;
    bounds[0][jlen + 1] = x4;
    bounds[1][jlen + 1] = y4;
    bounds[0].length = bounds[1].length = jlen + 2;
    return {
      min: { x: Math.min.apply(0, bounds[0]), y: Math.min.apply(0, bounds[1]) },
      max: { x: Math.max.apply(0, bounds[0]), y: Math.max.apply(0, bounds[1]) }
    };
  }
  function integrate(f, a, b, n) {
    let x = Curve.abscissas[n - 2], w = Curve.weights[n - 2], A = 0.5 * (b - a), B = A + a, i = 0, m = n + 1 >> 1, sum = n & 1 ? w[i++] * f(B) : 0;
    while (i < m) {
      const Ax = A * x[i];
      sum += w[i++] * (f(B + Ax) + f(B - Ax));
    }
    return A * sum;
  }
  function getCurveFromPoints(points, closed2) {
    const l = points.length, last = l - 1;
    for (let i = 0; i < l; i++) {
      const point = points[i];
      const prev = closed2 ? mod(i - 1, l) : Math.max(i - 1, 0);
      const next = closed2 ? mod(i + 1, l) : Math.min(i + 1, last);
      const a = points[prev];
      const b = point;
      const c = points[next];
      getControlPoints(a, b, c);
      b.command = i === 0 ? Commands.move : Commands.curve;
    }
  }
  function getControlPoints(a, b, c) {
    const a1 = Vector.angleBetween(a, b);
    const a2 = Vector.angleBetween(c, b);
    let d1 = Vector.distanceBetween(a, b);
    let d2 = Vector.distanceBetween(c, b);
    let mid = (a1 + a2) / 2;
    if (d1 < 1e-4 || d2 < 1e-4) {
      if (typeof b.relative === "boolean" && !b.relative) {
        b.controls.left.copy(b);
        b.controls.right.copy(b);
      }
      return b;
    }
    d1 *= 0.33;
    d2 *= 0.33;
    if (a2 < a1) {
      mid += HALF_PI;
    } else {
      mid -= HALF_PI;
    }
    b.controls.left.x = Math.cos(mid) * d1;
    b.controls.left.y = Math.sin(mid) * d1;
    mid -= Math.PI;
    b.controls.right.x = Math.cos(mid) * d2;
    b.controls.right.y = Math.sin(mid) * d2;
    if (typeof b.relative === "boolean" && !b.relative) {
      b.controls.left.x += b.x;
      b.controls.left.y += b.y;
      b.controls.right.x += b.x;
      b.controls.right.y += b.y;
    }
    return b;
  }
  function getReflection(a, b, relative) {
    return new Vector(
      2 * a.x - (b.x + a.x) - (relative ? a.x : 0),
      2 * a.y - (b.y + a.y) - (relative ? a.y : 0)
    );
  }
  function getAnchorsFromArcData(center, xAxisRotation, rx, ry, ts, td, ccw) {
    const resolution = Constants.Resolution;
    const anchors = [];
    for (let i = 0; i < resolution; i++) {
      let pct = (i + 1) / resolution;
      if (ccw) {
        pct = 1 - pct;
      }
      const theta = pct * td + ts;
      const x = rx * Math.cos(theta);
      const y = ry * Math.sin(theta);
      const anchor2 = new Anchor(x, y);
      anchor2.command = Commands.line;
      anchors.push(anchor2);
    }
  }

  // src/utils/underscore.js
  var slice = Array.prototype.slice;
  function isArrayLike(collection) {
    if (collection === null || collection === void 0)
      return false;
    const length = collection.length;
    return typeof length == "number" && length >= 0 && length < 4294967296;
  }
  var _ = {
    isNaN: function(obj) {
      return typeof obj === "number" && obj !== +obj;
    },
    isElement: function(obj) {
      return !!(obj && obj.nodeType === 1);
    },
    isObject: function(obj) {
      const type = typeof obj;
      return type === "function" || type === "object" && !!obj;
    },
    isFunction: function(obj) {
      return typeof obj === "function";
    },
    extend: function(base) {
      const sources = slice.call(arguments, 1);
      for (let i = 0; i < sources.length; i++) {
        const obj = sources[i];
        for (let k in obj) {
          base[k] = obj[k];
        }
      }
      return base;
    },
    defaults: function(base) {
      const sources = slice.call(arguments, 1);
      for (let i = 0; i < sources.length; i++) {
        const obj = sources[i];
        for (let k in obj) {
          if (base[k] === void 0) {
            base[k] = obj[k];
          }
        }
      }
      return base;
    },
    each: function(obj, iteratee, context) {
      const ctx = context || this;
      const keys = !isArrayLike(obj) && Object.keys(obj);
      const length = (keys || obj).length;
      for (let i = 0; i < length; i++) {
        const k = keys ? keys[i] : i;
        iteratee.call(ctx, obj[k], k, obj);
      }
      return obj;
    },
    performance: root.performance && root.performance.now ? root.performance : Date
  };

  // src/utils/dom.js
  var dom = {
    hasEventListeners: typeof root.addEventListener === "function",
    bind: function(elem, event, func, bool) {
      if (this.hasEventListeners) {
        elem.addEventListener(event, func, !!bool);
      } else {
        elem.attachEvent("on" + event, func);
      }
      return dom;
    },
    unbind: function(elem, event, func, bool) {
      if (dom.hasEventListeners) {
        elem.removeEventListeners(event, func, !!bool);
      } else {
        elem.detachEvent("on" + event, func);
      }
      return dom;
    },
    getRequestAnimationFrame: function() {
      const vendors = ["ms", "moz", "webkit", "o"];
      let lastTime = 0;
      let request = root.requestAnimationFrame;
      if (!request) {
        for (let i = 0; i < vendors.length; i++) {
          request = root[vendors[i] + "RequestAnimationFrame"] || request;
        }
        request = request || fallbackRequest;
      }
      function fallbackRequest(callback, element) {
        const currTime = new Date().getTime();
        const timeToCall = Math.max(0, 16 - (currTime - lastTime));
        const id = root.setTimeout(nextRequest, timeToCall);
        lastTime = currTime + timeToCall;
        function nextRequest() {
          callback(currTime + timeToCall);
        }
        return id;
      }
      return request;
    }
  };
  var temp = root.document ? root.document.createElement("div") : {};
  temp.id = "help-two-load";
  Object.defineProperty(dom, "temp", {
    enumerable: true,
    get: function() {
      if (_.isElement(temp) && !root.document.head.contains(temp)) {
        temp.style.display = "none";
        root.document.head.appendChild(temp);
      }
      return temp;
    }
  });

  // src/utils/error.js
  var TwoError = class extends Error {
    name = "Two.js";
    message;
    constructor(message) {
      super();
      this.message = message;
    }
  };

  // src/utils/device-pixel-ratio.js
  var devicePixelRatio = root.devicePixelRatio || 1;
  function getBackingStoreRatio(ctx) {
    return ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1;
  }
  function getRatio(ctx) {
    return devicePixelRatio / getBackingStoreRatio(ctx);
  }

  // src/registry.js
  var Registry = class {
    map = {};
    constructor() {
    }
    add(id, obj) {
      this.map[id] = obj;
      return this;
    }
    remove(id) {
      delete this.map[id];
      return this;
    }
    get(id) {
      return this.map[id];
    }
    contains(id) {
      return id in this.map;
    }
  };

  // src/collection.js
  var Collection = class extends Array {
    #events = new Events();
    get _events() {
      return this.#events;
    }
    set _events(e) {
      this.#events = e;
    }
    get _bound() {
      return this.#events._bound;
    }
    set _bound(v) {
      this.#events._bound = v;
    }
    addEventListener() {
      return this.#events.addEventListener.apply(this, arguments);
    }
    on() {
      return this.#events.on.apply(this, arguments);
    }
    bind() {
      return this.#events.bind.apply(this, arguments);
    }
    removeEventListener() {
      return this.#events.removeEventListener.apply(this, arguments);
    }
    off() {
      return this.#events.off.apply(this, arguments);
    }
    unbind() {
      return this.#events.unbind.apply(this, arguments);
    }
    dispatchEvent() {
      return this.#events.dispatchEvent.apply(this, arguments);
    }
    trigger() {
      return this.#events.trigger.apply(this, arguments);
    }
    listen() {
      return this.#events.listen.apply(this, arguments);
    }
    ignore() {
      return this.#events.ignore.apply(this, arguments);
    }
    constructor() {
      super();
      if (arguments[0] && Array.isArray(arguments[0])) {
        if (arguments[0].length > 0) {
          this.push.apply(this, arguments[0]);
        }
      } else if (arguments.length > 0) {
        this.push.apply(this, arguments);
      }
    }
    pop() {
      const popped = super.pop.apply(this, arguments);
      this.trigger(Events.Types.remove, [popped]);
      return popped;
    }
    shift() {
      const shifted = super.shift.apply(this, arguments);
      this.trigger(Events.Types.remove, [shifted]);
      return shifted;
    }
    push() {
      const pushed = super.push.apply(this, arguments);
      this.trigger(Events.Types.insert, arguments);
      return pushed;
    }
    unshift() {
      const unshifted = super.unshift.apply(this, arguments);
      this.trigger(Events.Types.insert, arguments);
      return unshifted;
    }
    splice() {
      const spliced = super.splice.apply(this, arguments);
      this.trigger(Events.Types.remove, spliced);
      if (arguments.length > 2) {
        const inserted = this.slice(
          arguments[0],
          arguments[0] + arguments.length - 2
        );
        this.trigger(Events.Types.insert, inserted);
        this.trigger(Events.Types.order);
      }
      return spliced;
    }
    sort() {
      super.sort.apply(this, arguments);
      this.trigger(Events.Types.order);
      return this;
    }
    reverse() {
      super.reverse.apply(this, arguments);
      this.trigger(Events.Types.order);
      return this;
    }
    indexOf() {
      return super.indexOf.apply(this, arguments);
    }
    map(func, scope) {
      const results = [];
      for (let key = 0; key < this.length; key++) {
        const value = this[key];
        let result;
        if (scope) {
          result = func.call(scope, value, key);
        } else {
          result = func(value, key);
        }
        results.push(result);
      }
      return results;
    }
  };

  // src/element.js
  var _Element = class extends Events {
    _flagId = false;
    _flagClassName = false;
    _renderer = {};
    _id = Constants.Identifier + Constants.uniqueId();
    _className = "";
    classList = [];
    constructor() {
      super();
      for (let prop in proto3) {
        Object.defineProperty(this, prop, proto3[prop]);
      }
    }
    static fromObject(obj) {
      const elem = new _Element().copy(obj);
      if ("id" in obj) {
        elem.id = obj.id;
      }
      return elem;
    }
    flagReset() {
      this._flagId = this._flagClassName = false;
      return this;
    }
    copy(element) {
      this.renderer.type = element.renderer.type;
      this.className = element.className;
      return this;
    }
    toObject() {
      return {
        renderer: { type: this.renderer.type },
        id: this.id,
        className: this.className
      };
    }
  };
  var Element = _Element;
  __publicField(Element, "Properties", ["renderer", "id", "className"]);
  var proto3 = {
    renderer: {
      enumerable: false,
      get: function() {
        return this._renderer;
      }
    },
    id: {
      enumerable: true,
      get: function() {
        return this._id;
      },
      set: function(v) {
        const id = this._id;
        if (v === this._id) {
          return;
        }
        this._id = v;
        this._flagId = true;
        if (this.parent) {
          delete this.parent.children.ids[id];
          this.parent.children.ids[this._id] = this;
        }
      }
    },
    className: {
      enumerable: true,
      get: function() {
        return this._className;
      },
      set: function(v) {
        if (this._className !== v) {
          this._flagClassName = true;
          this.classList = v.split(/\s+?/);
          this._className = v;
        }
      }
    }
  };

  // src/effects/texture.js
  var anchor;
  var regex = {
    video: /\.(mp4|webm|ogg)$/i,
    image: /\.(jpe?g|png|gif|tiff|webp)$/i,
    effect: /texture|gradient/i
  };
  if (root.document) {
    anchor = document.createElement("a");
  }
  var _Texture = class extends Element {
    _flagSrc = false;
    _flagImage = false;
    _flagVideo = false;
    _flagLoaded = false;
    _flagRepeat = false;
    _flagOffset = false;
    _flagScale = false;
    _src = "";
    _image = null;
    _loaded = false;
    _repeat = "no-repeat";
    _scale = 1;
    _offset = null;
    constructor(src, callback) {
      super();
      for (let prop in proto4) {
        Object.defineProperty(this, prop, proto4[prop]);
      }
      this._renderer.type = "texture";
      this._renderer.flagOffset = FlagOffset.bind(this);
      this._renderer.flagScale = FlagScale.bind(this);
      this.loaded = false;
      this.repeat = "no-repeat";
      this.offset = new Vector();
      if (typeof callback === "function") {
        const loaded = function() {
          this.unbind(Events.Types.load, loaded);
          if (typeof callback === "function") {
            callback();
          }
        }.bind(this);
        this.bind(Events.Types.load, loaded);
      }
      if (typeof src === "string") {
        this.src = src;
      } else if (typeof src === "object") {
        const elemString = Object.prototype.toString.call(src);
        if (elemString === "[object HTMLImageElement]" || elemString === "[object HTMLCanvasElement]" || elemString === "[object HTMLVideoElement]" || elemString === "[object Image]") {
          this.image = src;
        }
      }
      this._update();
    }
    fromObject(obj) {
      const texture = new _Texture().copy(obj);
      if ("id" in obj) {
        texture.id = obj.id;
      }
      return texture;
    }
    static getAbsoluteURL(path) {
      if (!anchor) {
        return path;
      }
      anchor.href = path;
      return anchor.href;
    }
    static loadHeadlessBuffer(texture, onLoad) {
      texture.image.onload = onLoad;
      texture.image.src = texture.src;
    }
    static getTag(image) {
      return image && image.nodeName && image.nodeName.toLowerCase() || "img";
    }
    static getImage(src) {
      const absoluteSrc = _Texture.getAbsoluteURL(src);
      if (_Texture.ImageRegistry.contains(absoluteSrc)) {
        return _Texture.ImageRegistry.get(absoluteSrc);
      }
      let image;
      if (CanvasPolyfill.Image) {
        image = new CanvasPolyfill.Image();
        CanvasPolyfill.shim(image, "img");
      } else if (root.document) {
        if (regex.video.test(absoluteSrc)) {
          image = document.createElement("video");
        } else {
          image = document.createElement("img");
        }
      } else {
        console.warn("Two.js: no prototypical image defined for Two.Texture");
      }
      image.crossOrigin = "anonymous";
      image.referrerPolicy = "no-referrer";
      return image;
    }
    static load(texture, callback) {
      let image = texture.image;
      let tag = _Texture.getTag(image);
      if (texture._flagImage) {
        if (/canvas/i.test(tag)) {
          _Texture.Register.canvas(texture, callback);
        } else {
          texture._src = !CanvasPolyfill.isHeadless && image.getAttribute("two-src") || image.src;
          _Texture.Register[tag](texture, callback);
        }
      }
      if (texture._flagSrc) {
        if (!image) {
          image = _Texture.getImage(texture.src);
          texture.image = image;
        }
        tag = _Texture.getTag(image);
        _Texture.Register[tag](texture, callback);
      }
    }
    clone() {
      const clone = new _Texture(this.src);
      clone.repeat = this.repeat;
      clone.offset.copy(this.offset);
      clone.scale = this.scale;
      return clone;
    }
    copy(texture) {
      this.src = texture.src;
      this.repeat = texture.repeat;
      this.offset = typeof texture.offset === "number" || texture.offset instanceof Vector ? texture.offset : new Vector().copy(texture.offset);
      this.scale = typeof texture.scale === "number" || texture.scale instanceof Vector ? texture.scale : new Vector().copy(texture.scale);
      return this;
    }
    toObject() {
      const result = super.toObject.call(this);
      result.renderer.type = "texture";
      result.src = this.src;
      result.repeat = this.repeat;
      result.offset = this.offset.toObject();
      result.scale = typeof this.scale === "number" ? this.scale : this.scale.toObject();
      return result;
    }
    _update() {
      if (this._flagSrc || this._flagImage) {
        this.trigger(Events.Types.change);
        if (this._flagSrc || this._flagImage) {
          this.loaded = false;
          _Texture.load(
            this,
            function() {
              this.loaded = true;
              this.trigger(Events.Types.change).trigger(Events.Types.load);
            }.bind(this)
          );
        }
      }
      if (this._image && this._image.readyState >= 4) {
        this._flagVideo = true;
      }
      return this;
    }
    flagReset() {
      this._flagSrc = this._flagImage = this._flagLoaded = this._flagRepeat = this._flagVideo = this._flagScale = this._flagOffset = false;
      super.flagReset.call(this);
      return this;
    }
    dispose() {
      if ("elem" in this._renderer) {
        const elem = this._renderer.elem;
        elem.parentNode.removeChild(elem);
      }
      if ("effect" in this._renderer) {
        this._renderer.effect = null;
      }
      return this;
    }
  };
  var Texture = _Texture;
  __publicField(Texture, "Properties", ["src", "loaded", "repeat", "scale", "offset", "image"]);
  __publicField(Texture, "RegularExpressions", regex);
  __publicField(Texture, "ImageRegistry", new Registry());
  __publicField(Texture, "Register", {
    canvas: function(texture, callback) {
      texture._src = "#" + texture.id;
      _Texture.ImageRegistry.add(texture.src, texture.image);
      if (typeof callback === "function") {
        callback();
      }
    },
    img: function(texture, callback) {
      const image = texture.image;
      const loaded = function(e) {
        if (!CanvasPolyfill.isHeadless && image.removeEventListener && typeof image.removeEventListener === "function") {
          image.removeEventListener("load", loaded, false);
          image.removeEventListener("error", error, false);
        }
        if (typeof callback === "function") {
          callback();
        }
      };
      const error = function(e) {
        if (!CanvasPolyfill.isHeadless && typeof image.removeEventListener === "function") {
          image.removeEventListener("load", loaded, false);
          image.removeEventListener("error", error, false);
        }
        throw new TwoError("unable to load " + texture.src);
      };
      if (typeof image.width === "number" && image.width > 0 && typeof image.height === "number" && image.height > 0) {
        loaded();
      } else if (!CanvasPolyfill.isHeadless && typeof image.addEventListener === "function") {
        image.addEventListener("load", loaded, false);
        image.addEventListener("error", error, false);
      }
      texture._src = _Texture.getAbsoluteURL(texture._src);
      if (!CanvasPolyfill.isHeadless && image && image.getAttribute("two-src")) {
        return;
      }
      if (!CanvasPolyfill.isHeadless) {
        image.setAttribute("two-src", texture.src);
      }
      _Texture.ImageRegistry.add(texture.src, image);
      if (CanvasPolyfill.isHeadless) {
        _Texture.loadHeadlessBuffer(texture, loaded);
      } else {
        texture.image.src = texture.src;
      }
    },
    video: function(texture, callback) {
      if (CanvasPolyfill.isHeadless) {
        throw new TwoError(
          "video textures are not implemented in headless environments."
        );
      }
      const loaded = function(e) {
        texture.image.removeEventListener("canplaythrough", loaded, false);
        texture.image.removeEventListener("error", error, false);
        texture.image.width = texture.image.videoWidth;
        texture.image.height = texture.image.videoHeight;
        if (typeof callback === "function") {
          callback();
        }
      };
      const error = function(e) {
        texture.image.removeEventListener("canplaythrough", loaded, false);
        texture.image.removeEventListener("error", error, false);
        throw new TwoError("unable to load " + texture.src);
      };
      texture._src = _Texture.getAbsoluteURL(texture._src);
      if (!texture.image.getAttribute("two-src")) {
        texture.image.setAttribute("two-src", texture.src);
        _Texture.ImageRegistry.add(texture.src, texture.image);
      }
      if (texture.image.readyState >= 4) {
        loaded();
      } else {
        texture.image.addEventListener("canplaythrough", loaded, false);
        texture.image.addEventListener("error", error, false);
        texture.image.src = texture.src;
        texture.image.load();
      }
    }
  });
  var proto4 = {
    src: {
      enumerable: true,
      get: function() {
        return this._src;
      },
      set: function(v) {
        this._src = v;
        this._flagSrc = true;
      }
    },
    loaded: {
      enumerable: true,
      get: function() {
        return this._loaded;
      },
      set: function(v) {
        this._loaded = v;
        this._flagLoaded = true;
      }
    },
    repeat: {
      enumerable: true,
      get: function() {
        return this._repeat;
      },
      set: function(v) {
        this._repeat = v;
        this._flagRepeat = true;
      }
    },
    image: {
      enumerable: true,
      get: function() {
        return this._image;
      },
      set: function(image) {
        const tag = Texture.getTag(image);
        let index;
        switch (tag) {
          case "canvas":
            index = "#" + image.id;
            break;
          default:
            index = image.src;
        }
        if (Texture.ImageRegistry.contains(index)) {
          this._image = Texture.ImageRegistry.get(image.src);
        } else {
          this._image = image;
        }
        this._flagImage = true;
      }
    },
    offset: {
      enumerable: true,
      get: function() {
        return this._offset;
      },
      set: function(v) {
        if (this._offset) {
          this._offset.unbind(Events.Types.change, this._renderer.flagOffset);
        }
        this._offset = v;
        this._offset.bind(Events.Types.change, this._renderer.flagOffset);
        this._flagOffset = true;
      }
    },
    scale: {
      enumerable: true,
      get: function() {
        return this._scale;
      },
      set: function(v) {
        if (this._scale instanceof Vector) {
          this._scale.unbind(Events.Types.change, this._renderer.flagScale);
        }
        this._scale = v;
        if (this._scale instanceof Vector) {
          this._scale.bind(Events.Types.change, this._renderer.flagScale);
        }
        this._flagScale = true;
      }
    }
  };
  function FlagOffset() {
    this._flagOffset = true;
  }
  function FlagScale() {
    this._flagScale = true;
  }

  // src/effects/stop.js
  var _Stop = class extends Element {
    _flagOffset = true;
    _flagOpacity = true;
    _flagColor = true;
    _offset = 0;
    _opacity = 1;
    _color = "#fff";
    constructor(offset, color, opacity) {
      super();
      for (let prop in proto5) {
        Object.defineProperty(this, prop, proto5[prop]);
      }
      this._renderer.type = "stop";
      this.offset = typeof offset === "number" ? offset : _Stop.Index <= 0 ? 0 : 1;
      this.opacity = typeof opacity === "number" ? opacity : 1;
      this.color = typeof color === "string" ? color : _Stop.Index <= 0 ? "#fff" : "#000";
      _Stop.Index = (_Stop.Index + 1) % 2;
    }
    static fromObject(obj) {
      const stop = new _Stop().copy(obj);
      if ("id" in obj) {
        stop.id = obj.id;
      }
      return stop;
    }
    copy(stop) {
      super.copy.call(this, stop);
      for (let i = 0; i < _Stop.Properties.length; i++) {
        const k = _Stop.Properties[i];
        if (k in stop) {
          this[k] = stop[k];
        }
      }
      return this;
    }
    clone(parent) {
      const clone = new _Stop();
      _.each(
        _Stop.Properties,
        function(property) {
          clone[property] = this[property];
        },
        this
      );
      if (parent && parent.stops) {
        parent.stops.push(clone);
      }
      return clone;
    }
    toObject() {
      const result = super.toObject.call(this);
      result.renderer.type = "stop";
      _.each(
        _Stop.Properties,
        (k) => {
          result[k] = this[k];
        },
        this
      );
      return result;
    }
    flagReset() {
      this._flagOffset = this._flagColor = this._flagOpacity = false;
      super.flagReset.call(this);
      return this;
    }
  };
  var Stop = _Stop;
  __publicField(Stop, "Index", 0);
  __publicField(Stop, "Properties", ["offset", "opacity", "color"]);
  var proto5 = {
    offset: {
      enumerable: true,
      get: function() {
        return this._offset;
      },
      set: function(v) {
        this._offset = v;
        this._flagOffset = true;
        if (this.parent) {
          this.parent._flagStops = true;
        }
      }
    },
    opacity: {
      enumerable: true,
      get: function() {
        return this._opacity;
      },
      set: function(v) {
        this._opacity = v;
        this._flagOpacity = true;
        if (this.parent) {
          this.parent._flagStops = true;
        }
      }
    },
    color: {
      enumerable: true,
      get: function() {
        return this._color;
      },
      set: function(v) {
        this._color = v;
        this._flagColor = true;
        if (this.parent) {
          this.parent._flagStops = true;
        }
      }
    }
  };

  // src/effects/gradient.js
  var _Gradient = class extends Element {
    _flagStops = false;
    _flagSpread = false;
    _flagUnits = false;
    _spread = "";
    _units = "";
    constructor(stops) {
      super();
      for (let prop in proto6) {
        Object.defineProperty(this, prop, proto6[prop]);
      }
      this._renderer.type = "gradient";
      this._renderer.flagStops = FlagStops.bind(this);
      this._renderer.bindStops = BindStops.bind(this);
      this._renderer.unbindStops = UnbindStops.bind(this);
      this.spread = "pad";
      this.units = "objectBoundingBox";
      if (stops) {
        this.stops = stops;
      }
    }
    static fromObject(obj) {
      let stops = obj.stops;
      if (stops && stops.length > 0) {
        stops = stops.map((o) => o instanceof Stop ? o : new Stop().copy(o));
      }
      const gradient = new _Gradient().copy(obj);
      if ("id" in obj) {
        gradient.id = obj.id;
      }
      return gradient;
    }
    clone(parent) {
      const stops = this.stops.map((s) => {
        return s.clone();
      });
      const clone = new _Gradient(stops);
      _.each(
        _Gradient.Properties,
        (k) => {
          clone[k] = this[k];
        },
        this
      );
      if (parent) {
        parent.add(clone);
      }
      return clone;
    }
    copy(gradient) {
      super.copy.call(this, gradient);
      for (let i = 0; i < _Gradient.Properties.length; i++) {
        const k = _Gradient.Properties[i];
        if (k in gradient) {
          this[k] = gradient[k];
        }
      }
      return this;
    }
    toObject() {
      const result = {
        stops: this.stops.map((s) => {
          return s.toObject();
        })
      };
      _.each(
        _Gradient.Properties,
        (k) => {
          result[k] = this[k];
        },
        this
      );
      return result;
    }
    _update() {
      if (this._flagSpread || this._flagStops) {
        this.trigger(Events.Types.change);
      }
      return this;
    }
    flagReset() {
      this._flagSpread = this._flagUnits = this._flagStops = false;
      super.flagReset.call(this);
      return this;
    }
    dispose() {
      if ("elem" in this._renderer) {
        const elem = this._renderer.elem;
        elem.parentNode.removeChild(elem);
      }
      if ("effect" in this._renderer) {
        this._renderer.effect = null;
      }
      return this;
    }
  };
  var Gradient = _Gradient;
  __publicField(Gradient, "Stop", Stop);
  __publicField(Gradient, "Properties", ["spread", "stops", "units"]);
  var proto6 = {
    spread: {
      enumerable: true,
      get: function() {
        return this._spread;
      },
      set: function(v) {
        this._spread = v;
        this._flagSpread = true;
      }
    },
    units: {
      enumerable: true,
      get: function() {
        return this._units;
      },
      set: function(v) {
        this._units = v;
        this._flagUnits = true;
      }
    },
    stops: {
      enumerable: true,
      get: function() {
        return this._stops;
      },
      set: function(stops) {
        const bindStops = this._renderer.bindStops;
        const unbindStops = this._renderer.unbindStops;
        if (this._stops) {
          this._stops.unbind(Events.Types.insert, bindStops).unbind(Events.Types.remove, unbindStops);
        }
        this._stops = new Collection((stops || []).slice(0));
        this._stops.bind(Events.Types.insert, bindStops).bind(Events.Types.remove, unbindStops);
        bindStops(this._stops);
      }
    }
  };
  function FlagStops() {
    this._flagStops = true;
  }
  function BindStops(items) {
    let i = items.length;
    while (i--) {
      items[i].bind(Events.Types.change, this._renderer.flagStops);
      items[i].parent = this;
    }
    this._renderer.flagStops();
  }
  function UnbindStops(items) {
    let i = items.length;
    while (i--) {
      items[i].unbind(Events.Types.change, this._renderer.flagStops);
      delete items[i].parent;
    }
    this._renderer.flagStops();
  }

  // src/effects/linear-gradient.js
  var _LinearGradient = class extends Gradient {
    _flagEndPoints = false;
    _left = null;
    _right = null;
    constructor(x1, y1, x2, y2, stops) {
      super(stops);
      for (let prop in proto7) {
        Object.defineProperty(this, prop, proto7[prop]);
      }
      this._renderer.type = "linear-gradient";
      this._renderer.flagEndPoints = FlagEndPoints.bind(this);
      this.left = new Vector();
      this.right = new Vector();
      if (typeof x1 === "number") {
        this.left.x = x1;
      }
      if (typeof y1 === "number") {
        this.left.y = y1;
      }
      if (typeof x2 === "number") {
        this.right.x = x2;
      }
      if (typeof y2 === "number") {
        this.right.y = y2;
      }
    }
    static fromObject(obj) {
      const gradient = new _LinearGradient().copy(obj);
      if ("id" in obj) {
        gradient.id = obj.id;
      }
      return gradient;
    }
    copy(gradient) {
      super.copy.call(this, gradient);
      for (let i = 0; i < _LinearGradient.Properties.length; i++) {
        const k = _LinearGradient.Properties[i];
        if (k in gradient) {
          this[k] = gradient[k] instanceof Vector ? gradient[k] : new Vector().copy(gradient[k]);
        }
      }
      return this;
    }
    clone(parent) {
      const stops = this.stops.map(function(stop) {
        return stop.clone();
      });
      const clone = new _LinearGradient(
        this.left._x,
        this.left._y,
        this.right._x,
        this.right._y,
        stops
      );
      _.each(
        Gradient.Properties,
        function(k) {
          clone[k] = this[k];
        },
        this
      );
      if (parent) {
        parent.add(clone);
      }
      return clone;
    }
    toObject() {
      const result = super.toObject.call(this);
      result.left = this.left.toObject();
      result.right = this.right.toObject();
      return result;
    }
    _update() {
      if (this._flagEndPoints || this._flagSpread || this._flagStops) {
        this.trigger(Events.Types.change);
      }
      return this;
    }
    flagReset() {
      this._flagEndPoints = false;
      super.flagReset.call(this);
      return this;
    }
  };
  var LinearGradient = _LinearGradient;
  __publicField(LinearGradient, "Stop", Stop);
  __publicField(LinearGradient, "Properties", ["left", "right"]);
  var proto7 = {
    left: {
      enumerable: true,
      get: function() {
        return this._left;
      },
      set: function(v) {
        if (this._left instanceof Vector) {
          this._left.unbind(Events.Types.change, this._renderer.flagEndPoints);
        }
        this._left = v;
        this._left.bind(Events.Types.change, this._renderer.flagEndPoints);
        this._flagEndPoints = true;
      }
    },
    right: {
      enumerable: true,
      get: function() {
        return this._right;
      },
      set: function(v) {
        if (this._right instanceof Vector) {
          this._right.unbind(Events.Types.change, this._renderer.flagEndPoints);
        }
        this._right = v;
        this._right.bind(Events.Types.change, this._renderer.flagEndPoints);
        this._flagEndPoints = true;
      }
    }
  };
  function FlagEndPoints() {
    this._flagEndPoints = true;
  }

  // src/effects/radial-gradient.js
  var _RadialGradient = class extends Gradient {
    _flagRadius = false;
    _flagCenter = false;
    _flagFocal = false;
    _radius = 0;
    _center = null;
    _focal = null;
    constructor(cx, cy, r, stops, fx, fy) {
      super(stops);
      for (let prop in proto8) {
        Object.defineProperty(this, prop, proto8[prop]);
      }
      this._renderer.type = "radial-gradient";
      this._renderer.flagCenter = FlagCenter.bind(this);
      this._renderer.flagFocal = FlagFocal.bind(this);
      this.center = new Vector();
      this.radius = typeof r === "number" ? r : 1;
      this.focal = new Vector();
      if (typeof cx === "number") {
        this.center.x = cx;
      }
      if (typeof cy === "number") {
        this.center.y = cy;
      }
      this.focal.copy(this.center);
      if (typeof fx === "number") {
        this.focal.x = fx;
      }
      if (typeof fy === "number") {
        this.focal.y = fy;
      }
    }
    static fromObject(obj) {
      const gradient = new _RadialGradient().copy(obj);
      if ("id" in obj) {
        gradient.id = obj.id;
      }
      return gradient;
    }
    copy(gradient) {
      super.copy.call(this, gradient);
      for (let i = 0; i < _RadialGradient.Properties.length; i++) {
        const k = _RadialGradient.Properties[i];
        if (k in gradient) {
          if (/(center|focal)i/.test(k)) {
            this[k] = gradient[k] instanceof Vector ? gradient[k] : new Vector().copy(gradient[k]);
          } else if (typeof gradient[k] === "number") {
            this[k] = gradient[MediaKeySystemAccess];
          }
        }
      }
      return this;
    }
    clone(parent) {
      const stops = this.stops.map(function(stop) {
        return stop.clone();
      });
      const clone = new _RadialGradient(
        this.center._x,
        this.center._y,
        this._radius,
        stops,
        this.focal._x,
        this.focal._y
      );
      _.each(
        Gradient.Properties.concat(_RadialGradient.Properties),
        function(k) {
          clone[k] = this[k];
        },
        this
      );
      if (parent) {
        parent.add(clone);
      }
      return clone;
    }
    toObject() {
      const result = super.toObject.call(this);
      _.each(
        _RadialGradient.Properties,
        function(k) {
          result[k] = this[k];
        },
        this
      );
      result.center = this.center.toObject();
      result.focal = this.focal.toObject();
      return result;
    }
    _update() {
      if (this._flagRadius || this._flatCenter || this._flagFocal || this._flagSpread || this._flagStops) {
        this.trigger(Events.Types.change);
      }
      return this;
    }
    flagReset() {
      this._flagRadius = this._flagCenter = this._flagFocal = false;
      super.flagReset.call(this);
      return this;
    }
  };
  var RadialGradient = _RadialGradient;
  __publicField(RadialGradient, "Stop", Stop);
  __publicField(RadialGradient, "Properties", ["center", "radius", "focal"]);
  var proto8 = {
    radius: {
      enumerable: true,
      get: function() {
        return this._radius;
      },
      set: function(v) {
        this._radius = v;
        this._flagRadius = true;
      }
    },
    center: {
      enumerable: true,
      get: function() {
        return this._center;
      },
      set: function(v) {
        if (this._center) {
          this._center.unbind(Events.Types.change, this._renderer.flagCenter);
        }
        this._center = v;
        this._center.bind(Events.Types.change, this._renderer.flagCenter);
        this._flagCenter = true;
      }
    },
    focal: {
      enumerable: true,
      get: function() {
        return this._focal;
      },
      set: function(v) {
        if (this._focal) {
          this._focal.unbind(Events.Types.change, this._renderer.flagFocal);
        }
        this._focal = v;
        this._focal.bind(Events.Types.change, this._renderer.flagFocal);
        this._flagFocal = true;
      }
    }
  };
  function FlagCenter() {
    this._flagCenter = true;
  }
  function FlagFocal() {
    this._flagFocal = true;
  }

  // src/utils/shape.js
  function contains(path, t) {
    if (t === 0 || t === 1) {
      return true;
    }
    const length = path._length;
    const target = length * t;
    let elapsed = 0;
    for (let i = 0; i < path._lengths.length; i++) {
      const dist = path._lengths[i];
      if (elapsed >= target) {
        return target - elapsed >= 0;
      }
      elapsed += dist;
    }
    return false;
  }
  function getIdByLength(path, target) {
    const total = path._length;
    if (target <= 0) {
      return 0;
    } else if (target >= total) {
      return path._lengths.length - 1;
    }
    for (let i = 0, sum = 0; i < path._lengths.length; i++) {
      if (sum + path._lengths[i] >= target) {
        target -= sum;
        return Math.max(i - 1, 0) + target / path._lengths[i];
      }
      sum += path._lengths[i];
    }
    return -1;
  }
  function getCurveLength2(a, b, limit) {
    let x1, x2, x3, x4, y1, y2, y3, y4;
    const right = b.controls && b.controls.right;
    const left = a.controls && a.controls.left;
    x1 = b.x;
    y1 = b.y;
    x2 = (right || b).x;
    y2 = (right || b).y;
    x3 = (left || a).x;
    y3 = (left || a).y;
    x4 = a.x;
    y4 = a.y;
    if (right && b._relative) {
      x2 += b.x;
      y2 += b.y;
    }
    if (left && a._relative) {
      x3 += a.x;
      y3 += a.y;
    }
    return getCurveLength(x1, y1, x2, y2, x3, y3, x4, y4, limit);
  }
  function getSubdivisions(a, b, limit) {
    let x1, x2, x3, x4, y1, y2, y3, y4;
    const right = b.controls && b.controls.right;
    const left = a.controls && a.controls.left;
    x1 = b.x;
    y1 = b.y;
    x2 = (right || b).x;
    y2 = (right || b).y;
    x3 = (left || a).x;
    y3 = (left || a).y;
    x4 = a.x;
    y4 = a.y;
    if (right && b._relative) {
      x2 += b.x;
      y2 += b.y;
    }
    if (left && a._relative) {
      x3 += a.x;
      y3 += a.y;
    }
    return subdivide(x1, y1, x2, y2, x3, y3, x4, y4, limit);
  }
  function getEffectFromObject(obj) {
    switch (obj.renderer.type) {
      case "texture":
        return Texture.fromObject(obj);
      case "gradient":
        return Gradient.fromObject(obj);
      case "linear-gradient":
        return LinearGradient.fromObject(obj);
      case "radial-gradient":
        return RadialGradient.fromObject(obj);
    }
    return obj;
  }

  // src/matrix.js
  var cos = Math.cos;
  var sin = Math.sin;
  var tan = Math.tan;
  var array = [];
  var _Matrix = class extends Events {
    elements = new NumArray(9);
    manual = false;
    constructor(a, b, c, d, e, f) {
      super();
      let elements = a;
      if (!Array.isArray(elements)) {
        elements = Array.prototype.slice.call(arguments);
      }
      this.identity();
      if (elements.length > 0) {
        this.set(elements);
      }
    }
    static Multiply(A, B, C) {
      if (B.length <= 3) {
        const e = A;
        let x, y, z;
        const a = B[0] || 0, b = B[1] || 0, c = B[2] || 0;
        x = e[0] * a + e[1] * b + e[2] * c;
        y = e[3] * a + e[4] * b + e[5] * c;
        z = e[6] * a + e[7] * b + e[8] * c;
        return [x, y, z];
      }
      const A0 = A[0], A1 = A[1], A2 = A[2];
      const A3 = A[3], A4 = A[4], A5 = A[5];
      const A6 = A[6], A7 = A[7], A8 = A[8];
      const B0 = B[0], B1 = B[1], B2 = B[2];
      const B3 = B[3], B4 = B[4], B5 = B[5];
      const B6 = B[6], B7 = B[7], B8 = B[8];
      C = C || new NumArray(9);
      C[0] = A0 * B0 + A1 * B3 + A2 * B6;
      C[1] = A0 * B1 + A1 * B4 + A2 * B7;
      C[2] = A0 * B2 + A1 * B5 + A2 * B8;
      C[3] = A3 * B0 + A4 * B3 + A5 * B6;
      C[4] = A3 * B1 + A4 * B4 + A5 * B7;
      C[5] = A3 * B2 + A4 * B5 + A5 * B8;
      C[6] = A6 * B0 + A7 * B3 + A8 * B6;
      C[7] = A6 * B1 + A7 * B4 + A8 * B7;
      C[8] = A6 * B2 + A7 * B5 + A8 * B8;
      return C;
    }
    static fromObject(obj) {
      return new _Matrix().copy(obj);
    }
    set(a, b, c, d, e, f, g, h, i) {
      if (typeof b === "undefined") {
        const elements = a;
        a = elements[0];
        b = elements[1];
        c = elements[2];
        d = elements[3];
        e = elements[4];
        f = elements[5];
        g = elements[6];
        h = elements[7];
        i = elements[8];
      }
      this.elements[0] = a;
      this.elements[1] = b;
      this.elements[2] = c;
      this.elements[3] = d;
      this.elements[4] = e;
      this.elements[5] = f;
      this.elements[6] = g;
      this.elements[7] = h;
      this.elements[8] = i;
      return this.trigger(Events.Types.change);
    }
    copy(m) {
      this.elements[0] = m.elements[0];
      this.elements[1] = m.elements[1];
      this.elements[2] = m.elements[2];
      this.elements[3] = m.elements[3];
      this.elements[4] = m.elements[4];
      this.elements[5] = m.elements[5];
      this.elements[6] = m.elements[6];
      this.elements[7] = m.elements[7];
      this.elements[8] = m.elements[8];
      this.manual = m.manual;
      return this.trigger(Events.Types.change);
    }
    identity() {
      this.elements[0] = _Matrix.Identity[0];
      this.elements[1] = _Matrix.Identity[1];
      this.elements[2] = _Matrix.Identity[2];
      this.elements[3] = _Matrix.Identity[3];
      this.elements[4] = _Matrix.Identity[4];
      this.elements[5] = _Matrix.Identity[5];
      this.elements[6] = _Matrix.Identity[6];
      this.elements[7] = _Matrix.Identity[7];
      this.elements[8] = _Matrix.Identity[8];
      return this.trigger(Events.Types.change);
    }
    multiply(a, b, c, d, e, f, g, h, i) {
      if (typeof b === "undefined") {
        this.elements[0] *= a;
        this.elements[1] *= a;
        this.elements[2] *= a;
        this.elements[3] *= a;
        this.elements[4] *= a;
        this.elements[5] *= a;
        this.elements[6] *= a;
        this.elements[7] *= a;
        this.elements[8] *= a;
        return this.trigger(Events.Types.change);
      }
      if (typeof c === "undefined") {
        c = 1;
      }
      if (typeof d === "undefined") {
        a = a || 0;
        b = b || 0;
        c = c || 0;
        e = this.elements;
        const x = e[0] * a + e[1] * b + e[2] * c;
        const y = e[3] * a + e[4] * b + e[5] * c;
        const z = e[6] * a + e[7] * b + e[8] * c;
        return [x, y, z];
      }
      const A = this.elements;
      const B = [a, b, c, d, e, f, g, h, i];
      const A0 = A[0], A1 = A[1], A2 = A[2];
      const A3 = A[3], A4 = A[4], A5 = A[5];
      const A6 = A[6], A7 = A[7], A8 = A[8];
      const B0 = B[0], B1 = B[1], B2 = B[2];
      const B3 = B[3], B4 = B[4], B5 = B[5];
      const B6 = B[6], B7 = B[7], B8 = B[8];
      this.elements[0] = A0 * B0 + A1 * B3 + A2 * B6;
      this.elements[1] = A0 * B1 + A1 * B4 + A2 * B7;
      this.elements[2] = A0 * B2 + A1 * B5 + A2 * B8;
      this.elements[3] = A3 * B0 + A4 * B3 + A5 * B6;
      this.elements[4] = A3 * B1 + A4 * B4 + A5 * B7;
      this.elements[5] = A3 * B2 + A4 * B5 + A5 * B8;
      this.elements[6] = A6 * B0 + A7 * B3 + A8 * B6;
      this.elements[7] = A6 * B1 + A7 * B4 + A8 * B7;
      this.elements[8] = A6 * B2 + A7 * B5 + A8 * B8;
      return this.trigger(Events.Types.change);
    }
    inverse(output) {
      const a = this.elements;
      output = output || new _Matrix();
      const a00 = a[0], a01 = a[1], a02 = a[2];
      const a10 = a[3], a11 = a[4], a12 = a[5];
      const a20 = a[6], a21 = a[7], a22 = a[8];
      const b01 = a22 * a11 - a12 * a21;
      const b11 = -a22 * a10 + a12 * a20;
      const b21 = a21 * a10 - a11 * a20;
      let det = a00 * b01 + a01 * b11 + a02 * b21;
      if (!det) {
        return null;
      }
      det = 1 / det;
      output.elements[0] = b01 * det;
      output.elements[1] = (-a22 * a01 + a02 * a21) * det;
      output.elements[2] = (a12 * a01 - a02 * a11) * det;
      output.elements[3] = b11 * det;
      output.elements[4] = (a22 * a00 - a02 * a20) * det;
      output.elements[5] = (-a12 * a00 + a02 * a10) * det;
      output.elements[6] = b21 * det;
      output.elements[7] = (-a21 * a00 + a01 * a20) * det;
      output.elements[8] = (a11 * a00 - a01 * a10) * det;
      return output;
    }
    scale(sx, sy) {
      const l = arguments.length;
      if (l <= 1) {
        sy = sx;
      }
      return this.multiply(sx, 0, 0, 0, sy, 0, 0, 0, 1);
    }
    rotate(n) {
      const c = cos(n);
      const s = sin(n);
      return this.multiply(c, -s, 0, s, c, 0, 0, 0, 1);
    }
    translate(x, y) {
      return this.multiply(1, 0, x, 0, 1, y, 0, 0, 1);
    }
    skewX(n) {
      const a = tan(n);
      return this.multiply(1, a, 0, 0, 1, 0, 0, 0, 1);
    }
    skewY(n) {
      const a = tan(n);
      return this.multiply(1, 0, 0, a, 1, 0, 0, 0, 1);
    }
    toString(fullMatrix) {
      array.length = 0;
      this.toTransformArray(fullMatrix, array);
      return array.map(toFixed).join(" ");
    }
    toTransformArray(fullMatrix, output) {
      const elements = this.elements;
      const hasOutput = !!output;
      const a = elements[0];
      const b = elements[1];
      const c = elements[2];
      const d = elements[3];
      const e = elements[4];
      const f = elements[5];
      if (fullMatrix) {
        const g = elements[6];
        const h = elements[7];
        const i = elements[8];
        if (hasOutput) {
          output[0] = a;
          output[1] = d;
          output[2] = g;
          output[3] = b;
          output[4] = e;
          output[5] = h;
          output[6] = c;
          output[7] = f;
          output[8] = i;
          return;
        }
        return [a, d, g, b, e, h, c, f, i];
      }
      if (hasOutput) {
        output[0] = a;
        output[1] = d;
        output[2] = b;
        output[3] = e;
        output[4] = c;
        output[5] = f;
        return;
      }
      return [
        a,
        d,
        b,
        e,
        c,
        f
      ];
    }
    toArray(fullMatrix, output) {
      const elements = this.elements;
      const hasOutput = !!output;
      const a = elements[0];
      const b = elements[1];
      const c = elements[2];
      const d = elements[3];
      const e = elements[4];
      const f = elements[5];
      if (fullMatrix) {
        const g = elements[6];
        const h = elements[7];
        const i = elements[8];
        if (hasOutput) {
          output[0] = a;
          output[1] = b;
          output[2] = c;
          output[3] = d;
          output[4] = e;
          output[5] = f;
          output[6] = g;
          output[7] = h;
          output[8] = i;
          return;
        }
        return [a, b, c, d, e, f, g, h, i];
      }
      if (hasOutput) {
        output[0] = a;
        output[1] = b;
        output[2] = c;
        output[3] = d;
        output[4] = e;
        output[5] = f;
        return;
      }
      return [a, b, c, d, e, f];
    }
    toObject() {
      return {
        renderer: { type: "matrix" },
        elements: this.toArray(true),
        manual: !!this.manual
      };
    }
    clone() {
      return new _Matrix().copy(this);
    }
  };
  var Matrix2 = _Matrix;
  __publicField(Matrix2, "Identity", [1, 0, 0, 0, 1, 0, 0, 0, 1]);
  setMatrix(Matrix2);

  // src/shape.js
  var _Shape = class extends Element {
    _flagMatrix = true;
    _flagScale = false;
    _matrix = null;
    _worldMatrix = null;
    _position = null;
    _rotation = 0;
    _scale = 1;
    _skewX = 0;
    _skewY = 0;
    constructor() {
      super();
      for (let prop in proto9) {
        Object.defineProperty(this, prop, proto9[prop]);
      }
      this._renderer.flagMatrix = FlagMatrix.bind(this);
      this.isShape = true;
      this.matrix = new Matrix2();
      this.worldMatrix = new Matrix2();
      this.position = new Vector();
      this.rotation = 0;
      this.scale = 1;
      this.skewX = 0;
      this.skewY = 0;
    }
    static fromObject(obj) {
      const shape = new _Shape().copy(obj);
      if ("id" in obj) {
        shape.id = obj.id;
      }
      return shape;
    }
    get renderer() {
      return this._renderer;
    }
    set renderer(v) {
      this._renderer = v;
    }
    get translation() {
      return proto9.position.get.apply(this, arguments);
    }
    set translation(v) {
      proto9.position.set.apply(this, arguments);
    }
    addTo(group) {
      group.add(this);
      return this;
    }
    remove() {
      if (!this.parent) {
        return this;
      }
      this.parent.remove(this);
      return this;
    }
    copy(shape) {
      super.copy.call(this, shape);
      if ("position" in shape) {
        if (shape.position instanceof Vector) {
          this.position = shape.position;
        } else {
          this.position.copy(shape.position);
        }
      }
      if ("rotation" in shape) {
        this.rotation = shape.rotation;
      }
      if ("scale" in shape) {
        this.scale = typeof shape.scale === "number" || shape.scale instanceof Vector ? shape.scale : new Vector(shape.scale.x, shape.scale.y);
      }
      if ("skewX" in shape) {
        this.skewX = shape.skewX;
      }
      if ("skewY" in shape) {
        this.skewY = shape.skewY;
      }
      if ("matrix" in shape && shape.matrix.manual) {
        this.matrix.copy(shape.matrix);
        this.matrix.manual = true;
      }
      return this;
    }
    clone(parent) {
      const clone = new _Shape();
      clone.position.copy(this.position);
      clone.rotation = this.rotation;
      clone.scale = this.scale;
      clone.skewX = this.skewX;
      clone.skewY = this.skewY;
      if (this.matrix.manual) {
        clone.matrix.copy(this.matrix);
      }
      if (parent) {
        parent.add(clone);
      }
      return clone._update();
    }
    toObject() {
      const result = super.toObject.call(this);
      result.renderer = { type: "shape" };
      result.isShape = true;
      result.translation = this.translation.toObject();
      result.rotation = this.translation.rotation;
      result.scale = this.scale instanceof Vector ? this.scale.toObject() : this.scale;
      result.skewX = this.skewX;
      result.skewY = this.skewY;
      result.matrix = this.matrix.toObject();
      return result;
    }
    _update(bubbles) {
      if (!this._matrix.manual && this._flagMatrix) {
        this._matrix.identity().translate(this.position.x, this.position.y);
        this._matrix.rotate(this.rotation);
        if (this._scale instanceof Vector) {
          this._matrix.scale(this._scale.x, this._scale.y);
        } else {
          this._matrix.scale(this._scale);
        }
        this._matrix.skewX(this.skewX);
        this._matrix.skewY(this.skewY);
      }
      if (bubbles) {
        if (this.parent && this.parent._update) {
          this.parent._update();
        }
      }
      return this;
    }
    flagReset() {
      this._flagMatrix = this._flagScale = false;
      super.flagReset.call(this);
      return this;
    }
  };
  var Shape = _Shape;
  __publicField(Shape, "Properties", [
    "position",
    "rotation",
    "scale",
    "skewX",
    "skewY",
    "matrix",
    "worldMatrix"
  ]);
  var proto9 = {
    position: {
      enumerable: true,
      get: function() {
        return this._position;
      },
      set: function(v) {
        if (this._position) {
          this._position.unbind(Events.Types.change, this._renderer.flagMatrix);
        }
        this._position = v;
        this._position.bind(Events.Types.change, this._renderer.flagMatrix);
        FlagMatrix.call(this);
      }
    },
    rotation: {
      enumerable: true,
      get: function() {
        return this._rotation;
      },
      set: function(v) {
        this._rotation = v;
        this._flagMatrix = true;
      }
    },
    scale: {
      enumerable: true,
      get: function() {
        return this._scale;
      },
      set: function(v) {
        if (this._scale instanceof Vector) {
          this._scale.unbind(Events.Types.change, this._renderer.flagMatrix);
        }
        this._scale = v;
        if (this._scale instanceof Vector) {
          this._scale.bind(Events.Types.change, this._renderer.flagMatrix);
        }
        this._flagMatrix = true;
        this._flagScale = true;
      }
    },
    skewX: {
      enumerable: true,
      get: function() {
        return this._skewX;
      },
      set: function(v) {
        this._skewX = v;
        this._flagMatrix = true;
      }
    },
    skewY: {
      enumerable: true,
      get: function() {
        return this._skewY;
      },
      set: function(v) {
        this._skewY = v;
        this._flagMatrix = true;
      }
    },
    matrix: {
      enumerable: true,
      get: function() {
        return this._matrix;
      },
      set: function(v) {
        this._matrix = v;
        this._flagMatrix = true;
      }
    },
    worldMatrix: {
      enumerable: true,
      get: function() {
        getComputedMatrix(this, this._worldMatrix);
        return this._worldMatrix;
      },
      set: function(v) {
        this._worldMatrix = v;
      }
    }
  };
  function FlagMatrix() {
    this._flagMatrix = true;
  }

  // src/path.js
  var min = Math.min;
  var max = Math.max;
  var ceil = Math.ceil;
  var floor2 = Math.floor;
  var vector = new Vector();
  var _Path = class extends Shape {
    _flagVertices = true;
    _flagLength = true;
    _flagFill = true;
    _flagStroke = true;
    _flagLinewidth = true;
    _flagOpacity = true;
    _flagVisible = true;
    _flagCap = true;
    _flagJoin = true;
    _flagMiter = true;
    _flagMask = false;
    _flagClip = false;
    _length = 0;
    _fill = "#fff";
    _stroke = "#000";
    _linewidth = 1;
    _opacity = 1;
    _visible = true;
    _cap = "round";
    _join = "round";
    _miter = 4;
    _closed = true;
    _curved = false;
    _automatic = true;
    _beginning = 0;
    _ending = 1;
    _mask = null;
    _clip = false;
    _dashes = null;
    constructor(vertices, closed2, curved, manual) {
      super();
      for (let prop in proto10) {
        Object.defineProperty(this, prop, proto10[prop]);
      }
      this._renderer.type = "path";
      this._renderer.flagVertices = FlagVertices.bind(this);
      this._renderer.bindVertices = BindVertices.bind(this);
      this._renderer.unbindVertices = UnbindVertices.bind(this);
      this._renderer.flagFill = FlagFill.bind(this);
      this._renderer.flagStroke = FlagStroke.bind(this);
      this._renderer.vertices = [];
      this._renderer.collection = [];
      this.closed = !!closed2;
      this.curved = !!curved;
      this.beginning = 0;
      this.ending = 1;
      this.fill = "#fff";
      this.stroke = "#000";
      this.linewidth = 1;
      this.opacity = 1;
      this.className = "";
      this.visible = true;
      this.cap = "butt";
      this.join = "miter";
      this.miter = 4;
      this.vertices = vertices;
      this.automatic = !manual;
      this.dashes = [];
      this.dashes.offset = 0;
    }
    static fromObject(obj) {
      const fill = typeof obj.fill === "string" ? obj.fill : getEffectFromObject(obj.fill);
      const stroke = typeof obj.stroke === "string" ? obj.stroke : getEffectFromObject(obj.stroke);
      const path = new _Path().copy({ ...obj, fill, stroke });
      if ("id" in obj) {
        path.id = obj.id;
      }
      return path;
    }
    copy(path) {
      super.copy.call(this, path);
      this.vertices = [];
      for (let j = 0; j < path.vertices.length; j++) {
        const v = path.vertices[j];
        if (v instanceof Anchor) {
          this.vertices.push(path.vertices[j].clone());
        } else {
          this.vertices.push(new Anchor().copy(v));
        }
      }
      for (let i = 0; i < _Path.Properties.length; i++) {
        const k = _Path.Properties[i];
        if (k in path) {
          this[k] = path[k];
        }
      }
      return this;
    }
    clone(parent) {
      const clone = new _Path();
      for (let j = 0; j < this.vertices.length; j++) {
        clone.vertices.push(this.vertices[j].clone());
      }
      for (let i = 0; i < _Path.Properties.length; i++) {
        const k = _Path.Properties[i];
        clone[k] = this[k];
      }
      clone.className = this.className;
      clone.translation.copy(this.translation);
      clone.rotation = this.rotation;
      clone.scale = this.scale;
      clone.skewX = this.skewX;
      clone.skewY = this.skewY;
      if (this.matrix.manual) {
        clone.matrix.copy(this.matrix);
      }
      if (parent) {
        parent.add(clone);
      }
      return clone._update();
    }
    toObject() {
      const result = super.toObject.call(this);
      result.renderer.type = "path";
      result.vertices = this.vertices.map((v) => v.toObject());
      _.each(
        _Path.Properties,
        (k) => {
          if (typeof this[k] !== "undefined") {
            if (this[k].toObject) {
              result[k] = this[k].toObject();
            } else {
              result[k] = this[k];
            }
          }
        },
        this
      );
      return result;
    }
    noFill() {
      this.fill = "none";
      return this;
    }
    noStroke() {
      this.stroke = "none";
      this.linewidth = 0;
      return this;
    }
    corner() {
      const rect = this.getBoundingClientRect(true);
      const hw = rect.width / 2;
      const hh = rect.height / 2;
      const cx = rect.left + rect.width / 2;
      const cy = rect.top + rect.height / 2;
      for (let i = 0; i < this.vertices.length; i++) {
        const v = this.vertices[i];
        v.x -= cx;
        v.y -= cy;
        v.x += hw;
        v.y += hh;
      }
      if (this.mask) {
        this.mask.translation.x -= cx;
        this.mask.translation.x += hw;
        this.mask.translation.y -= cy;
        this.mask.translation.y += hh;
      }
      return this;
    }
    center() {
      const rect = this.getBoundingClientRect(true);
      const cx = rect.left + rect.width / 2 - this.translation.x;
      const cy = rect.top + rect.height / 2 - this.translation.y;
      for (let i = 0; i < this.vertices.length; i++) {
        const v = this.vertices[i];
        v.x -= cx;
        v.y -= cy;
      }
      if (this.mask) {
        this.mask.translation.x -= cx;
        this.mask.translation.y -= cy;
      }
      return this;
    }
    getBoundingClientRect(shallow) {
      let matrix, border, l, i, v0, v1;
      let left = Infinity, right = -Infinity, top = Infinity, bottom = -Infinity;
      this._update(true);
      matrix = shallow ? this.matrix : this.worldMatrix;
      border = (this.linewidth || 0) / 2;
      l = this._renderer.vertices.length;
      if (this.linewidth > 0 || this.stroke && !/(transparent|none)/i.test(this.stroke)) {
        if (this.matrix.manual) {
          const { scaleX, scaleY } = decomposeMatrix(
            matrix.elements[0],
            matrix.elements[3],
            matrix.elements[1],
            matrix.elements[4],
            matrix.elements[2],
            matrix.elements[5]
          );
          if (typeof scaleX === "number" && typeof scaleY === "number") {
            border = Math.max(scaleX, scaleY) * (this.linewidth || 0) / 2;
          }
        } else {
          border *= typeof this.scale === "number" ? this.scale : Math.max(this.scale.x, this.scale.y);
        }
      }
      if (l <= 0) {
        return {
          width: 0,
          height: 0
        };
      }
      for (i = 0; i < l; i++) {
        v1 = this._renderer.vertices[i];
        v0 = this._renderer.vertices[(i + l - 1) % l];
        const [v0x, v0y] = matrix.multiply(v0.x, v0.y);
        const [v1x, v1y] = matrix.multiply(v1.x, v1.y);
        if (v0.controls && v1.controls) {
          let rx = v0.controls.right.x;
          let ry = v0.controls.right.y;
          if (v0.relative) {
            rx += v0.x;
            ry += v0.y;
          }
          let [c0x, c0y] = matrix.multiply(rx, ry);
          let lx = v1.controls.left.x;
          let ly = v1.controls.left.y;
          if (v1.relative) {
            lx += v1.x;
            ly += v1.y;
          }
          let [c1x, c1y] = matrix.multiply(lx, ly);
          const bb = getCurveBoundingBox(v0x, v0y, c0x, c0y, c1x, c1y, v1x, v1y);
          top = min(bb.min.y - border, top);
          left = min(bb.min.x - border, left);
          right = max(bb.max.x + border, right);
          bottom = max(bb.max.y + border, bottom);
        } else {
          if (i <= 1) {
            top = min(v0y - border, top);
            left = min(v0x - border, left);
            right = max(v0x + border, right);
            bottom = max(v0y + border, bottom);
          }
          top = min(v1y - border, top);
          left = min(v1x - border, left);
          right = max(v1x + border, right);
          bottom = max(v1y + border, bottom);
        }
      }
      return {
        top,
        left,
        right,
        bottom,
        width: right - left,
        height: bottom - top
      };
    }
    getPointAt(t, obj) {
      let ia, ib, result;
      let x, x1, x2, x3, x4, y, y1, y2, y3, y4, left, right;
      let target = this.length * Math.min(Math.max(t, 0), 1);
      const length = this.vertices.length;
      const last = length - 1;
      let a = null;
      let b = null;
      for (let i = 0, l = this._lengths.length, sum = 0; i < l; i++) {
        if (sum + this._lengths[i] >= target) {
          if (this._closed) {
            ia = mod(i, length);
            ib = mod(i - 1, length);
            if (i === 0) {
              ia = ib;
              ib = i;
            }
          } else {
            ia = i;
            ib = Math.min(Math.max(i - 1, 0), last);
          }
          a = this.vertices[ia];
          b = this.vertices[ib];
          target -= sum;
          if (this._lengths[i] !== 0) {
            t = target / this._lengths[i];
          } else {
            t = 0;
          }
          break;
        }
        sum += this._lengths[i];
      }
      if (a === null || b === null) {
        return null;
      }
      if (!a) {
        return b;
      } else if (!b) {
        return a;
      }
      right = b.controls && b.controls.right;
      left = a.controls && a.controls.left;
      x1 = b.x;
      y1 = b.y;
      x2 = (right || b).x;
      y2 = (right || b).y;
      x3 = (left || a).x;
      y3 = (left || a).y;
      x4 = a.x;
      y4 = a.y;
      if (right && b.relative) {
        x2 += b.x;
        y2 += b.y;
      }
      if (left && a.relative) {
        x3 += a.x;
        y3 += a.y;
      }
      x = getComponentOnCubicBezier(t, x1, x2, x3, x4);
      y = getComponentOnCubicBezier(t, y1, y2, y3, y4);
      const t1x = lerp(x1, x2, t);
      const t1y = lerp(y1, y2, t);
      const t2x = lerp(x2, x3, t);
      const t2y = lerp(y2, y3, t);
      const t3x = lerp(x3, x4, t);
      const t3y = lerp(y3, y4, t);
      const brx = lerp(t1x, t2x, t);
      const bry = lerp(t1y, t2y, t);
      const alx = lerp(t2x, t3x, t);
      const aly = lerp(t2y, t3y, t);
      if (_.isObject(obj)) {
        obj.x = x;
        obj.y = y;
        if (obj instanceof Anchor) {
          obj.controls.left.x = brx;
          obj.controls.left.y = bry;
          obj.controls.right.x = alx;
          obj.controls.right.y = aly;
          if (!(typeof obj.relative === "boolean") || obj.relative) {
            obj.controls.left.x -= x;
            obj.controls.left.y -= y;
            obj.controls.right.x -= x;
            obj.controls.right.y -= y;
          }
        }
        obj.t = t;
        return obj;
      }
      result = new Anchor(
        x,
        y,
        brx - x,
        bry - y,
        alx - x,
        aly - y,
        this._curved ? Commands.curve : Commands.line
      );
      result.t = t;
      return result;
    }
    plot() {
      if (this.curved) {
        getCurveFromPoints(this._collection, this.closed);
        return this;
      }
      for (let i = 0; i < this._collection.length; i++) {
        this._collection[i].command = i === 0 ? Commands.move : Commands.line;
      }
      return this;
    }
    subdivide(limit) {
      this._update();
      const last = this.vertices.length - 1;
      const closed2 = this._closed || this.vertices[last]._command === Commands.close;
      let b = this.vertices[last];
      let points = [], verts;
      _.each(
        this.vertices,
        function(a, i) {
          if (i <= 0 && !closed2) {
            b = a;
            return;
          }
          if (a.command === Commands.move) {
            points.push(new Anchor(b.x, b.y));
            if (i > 0) {
              points[points.length - 1].command = Commands.line;
            }
            b = a;
            return;
          }
          verts = getSubdivisions(a, b, limit);
          points = points.concat(verts);
          _.each(verts, function(v, i2) {
            if (i2 <= 0 && b.command === Commands.move) {
              v.command = Commands.move;
            } else {
              v.command = Commands.line;
            }
          });
          if (i >= last) {
            if (this._closed && this._automatic) {
              b = a;
              verts = getSubdivisions(a, b, limit);
              points = points.concat(verts);
              _.each(verts, function(v, i2) {
                if (i2 <= 0 && b.command === Commands.move) {
                  v.command = Commands.move;
                } else {
                  v.command = Commands.line;
                }
              });
            }
            points.push(new Anchor(a.x, a.y));
            points[points.length - 1].command = closed2 ? Commands.close : Commands.line;
          }
          b = a;
        },
        this
      );
      this._automatic = false;
      this._curved = false;
      this.vertices = points;
      return this;
    }
    _updateLength(limit, silent) {
      if (!silent) {
        this._update();
      }
      const length = this.vertices.length;
      const last = length - 1;
      const closed2 = false;
      let b = this.vertices[last];
      let sum = 0;
      if (typeof this._lengths === "undefined") {
        this._lengths = [];
      }
      _.each(
        this.vertices,
        function(a, i) {
          if (i <= 0 && !closed2 || a.command === Commands.move) {
            b = a;
            this._lengths[i] = 0;
            return;
          }
          this._lengths[i] = getCurveLength2(a, b, limit);
          sum += this._lengths[i];
          if (i >= last && closed2) {
            b = this.vertices[(i + 1) % length];
            this._lengths[i + 1] = getCurveLength2(a, b, limit);
            sum += this._lengths[i + 1];
          }
          b = a;
        },
        this
      );
      this._length = sum;
      this._flagLength = false;
      return this;
    }
    _update() {
      if (this._flagVertices) {
        if (this._automatic) {
          this.plot();
        }
        if (this._flagLength) {
          this._updateLength(void 0, true);
        }
        const l = this._collection.length;
        const closed2 = this._closed;
        const beginning = Math.min(this._beginning, this._ending);
        const ending = Math.max(this._beginning, this._ending);
        const bid = getIdByLength(this, beginning * this._length);
        const eid = getIdByLength(this, ending * this._length);
        const low = ceil(bid);
        const high = floor2(eid);
        let left, right, prev, next, v, i;
        this._renderer.vertices.length = 0;
        for (i = 0; i < l; i++) {
          if (this._renderer.collection.length <= i) {
            this._renderer.collection.push(new Anchor());
          }
          if (i > high && !right) {
            v = this._renderer.collection[i].copy(this._collection[i]);
            this.getPointAt(ending, v);
            v.command = this._renderer.collection[i].command;
            this._renderer.vertices.push(v);
            right = v;
            prev = this._collection[i - 1];
            if (prev && prev.controls) {
              if (v.relative) {
                v.controls.right.clear();
              } else {
                v.controls.right.copy(v);
              }
              if (prev.relative) {
                this._renderer.collection[i - 1].controls.right.copy(prev.controls.right).lerp(Vector.zero, 1 - v.t);
              } else {
                this._renderer.collection[i - 1].controls.right.copy(prev.controls.right).lerp(prev, 1 - v.t);
              }
            }
          } else if (i >= low && i <= high) {
            v = this._renderer.collection[i].copy(this._collection[i]);
            this._renderer.vertices.push(v);
            if (i === high && contains(this, ending)) {
              right = v;
              if (!closed2 && right.controls) {
                if (right.relative) {
                  right.controls.right.clear();
                } else {
                  right.controls.right.copy(right);
                }
              }
            } else if (i === low && contains(this, beginning)) {
              left = v;
              left.command = Commands.move;
              if (!closed2 && left.controls) {
                if (left.relative) {
                  left.controls.left.clear();
                } else {
                  left.controls.left.copy(left);
                }
              }
            }
          }
        }
        if (low > 0 && !left) {
          i = low - 1;
          v = this._renderer.collection[i].copy(this._collection[i]);
          this.getPointAt(beginning, v);
          v.command = Commands.move;
          this._renderer.vertices.unshift(v);
          next = this._collection[i + 1];
          if (next && next.controls) {
            v.controls.left.clear();
            if (next.relative) {
              this._renderer.collection[i + 1].controls.left.copy(next.controls.left).lerp(Vector.zero, v.t);
            } else {
              vector.copy(next);
              this._renderer.collection[i + 1].controls.left.copy(next.controls.left).lerp(next, v.t);
            }
          }
        }
      }
      Shape.prototype._update.apply(this, arguments);
      return this;
    }
    flagReset() {
      this._flagVertices = this._flagLength = this._flagFill = this._flagStroke = this._flagLinewidth = this._flagOpacity = this._flagVisible = this._flagCap = this._flagJoin = this._flagMiter = this._flagClip = false;
      Shape.prototype.flagReset.call(this);
      return this;
    }
  };
  var Path = _Path;
  __publicField(Path, "Properties", [
    "fill",
    "stroke",
    "linewidth",
    "opacity",
    "visible",
    "cap",
    "join",
    "miter",
    "closed",
    "curved",
    "automatic",
    "beginning",
    "ending",
    "dashes"
  ]);
  __publicField(Path, "Utils", {
    getCurveLength: getCurveLength2
  });
  var proto10 = {
    linewidth: {
      enumerable: true,
      get: function() {
        return this._linewidth;
      },
      set: function(v) {
        this._linewidth = v;
        this._flagLinewidth = true;
      }
    },
    opacity: {
      enumerable: true,
      get: function() {
        return this._opacity;
      },
      set: function(v) {
        this._opacity = v;
        this._flagOpacity = true;
      }
    },
    visible: {
      enumerable: true,
      get: function() {
        return this._visible;
      },
      set: function(v) {
        this._visible = v;
        this._flagVisible = true;
      }
    },
    cap: {
      enumerable: true,
      get: function() {
        return this._cap;
      },
      set: function(v) {
        this._cap = v;
        this._flagCap = true;
      }
    },
    join: {
      enumerable: true,
      get: function() {
        return this._join;
      },
      set: function(v) {
        this._join = v;
        this._flagJoin = true;
      }
    },
    miter: {
      enumerable: true,
      get: function() {
        return this._miter;
      },
      set: function(v) {
        this._miter = v;
        this._flagMiter = true;
      }
    },
    fill: {
      enumerable: true,
      get: function() {
        return this._fill;
      },
      set: function(f) {
        if (this._fill instanceof Gradient || this._fill instanceof LinearGradient || this._fill instanceof RadialGradient || this._fill instanceof Texture) {
          this._fill.unbind(Events.Types.change, this._renderer.flagFill);
        }
        this._fill = f;
        this._flagFill = true;
        if (this._fill instanceof Gradient || this._fill instanceof LinearGradient || this._fill instanceof RadialGradient || this._fill instanceof Texture) {
          this._fill.bind(Events.Types.change, this._renderer.flagFill);
        }
      }
    },
    stroke: {
      enumerable: true,
      get: function() {
        return this._stroke;
      },
      set: function(f) {
        if (this._stroke instanceof Gradient || this._stroke instanceof LinearGradient || this._stroke instanceof RadialGradient || this._stroke instanceof Texture) {
          this._stroke.unbind(Events.Types.change, this._renderer.flagStroke);
        }
        this._stroke = f;
        this._flagStroke = true;
        if (this._stroke instanceof Gradient || this._stroke instanceof LinearGradient || this._stroke instanceof RadialGradient || this._stroke instanceof Texture) {
          this._stroke.bind(Events.Types.change, this._renderer.flagStroke);
        }
      }
    },
    length: {
      get: function() {
        if (this._flagLength) {
          this._updateLength();
        }
        return this._length;
      }
    },
    closed: {
      enumerable: true,
      get: function() {
        return this._closed;
      },
      set: function(v) {
        this._closed = !!v;
        this._flagVertices = true;
      }
    },
    curved: {
      enumerable: true,
      get: function() {
        return this._curved;
      },
      set: function(v) {
        this._curved = !!v;
        this._flagVertices = true;
      }
    },
    automatic: {
      enumerable: true,
      get: function() {
        return this._automatic;
      },
      set: function(v) {
        if (v === this._automatic) {
          return;
        }
        this._automatic = !!v;
        const method = this._automatic ? "ignore" : "listen";
        _.each(this.vertices, function(v2) {
          v2[method]();
        });
      }
    },
    beginning: {
      enumerable: true,
      get: function() {
        return this._beginning;
      },
      set: function(v) {
        this._beginning = v;
        this._flagVertices = true;
      }
    },
    ending: {
      enumerable: true,
      get: function() {
        return this._ending;
      },
      set: function(v) {
        this._ending = v;
        this._flagVertices = true;
      }
    },
    vertices: {
      enumerable: true,
      get: function() {
        return this._collection;
      },
      set: function(vertices) {
        const bindVertices = this._renderer.bindVertices;
        const unbindVertices = this._renderer.unbindVertices;
        if (this._collection) {
          this._collection.unbind(Events.Types.insert, bindVertices).unbind(Events.Types.remove, unbindVertices);
        }
        if (vertices instanceof Collection) {
          this._collection = vertices;
        } else {
          this._collection = new Collection(vertices || []);
        }
        this._collection.bind(Events.Types.insert, bindVertices).bind(Events.Types.remove, unbindVertices);
        bindVertices(this._collection);
      }
    },
    mask: {
      enumerable: true,
      get: function() {
        return this._mask;
      },
      set: function(v) {
        this._mask = v;
        this._flagMask = true;
        if (_.isObject(v) && !v.clip) {
          v.clip = true;
        }
      }
    },
    clip: {
      enumerable: true,
      get: function() {
        return this._clip;
      },
      set: function(v) {
        this._clip = v;
        this._flagClip = true;
      }
    },
    dashes: {
      enumerable: true,
      get: function() {
        return this._dashes;
      },
      set: function(v) {
        if (typeof v.offset !== "number") {
          v.offset = this.dashes && this._dashes.offset || 0;
        }
        this._dashes = v;
      }
    }
  };
  function FlagVertices() {
    this._flagVertices = true;
    this._flagLength = true;
    if (this.parent) {
      this.parent._flagLength = true;
    }
  }
  function BindVertices(items) {
    let i = items.length;
    while (i--) {
      items[i].bind(Events.Types.change, this._renderer.flagVertices);
    }
    this._renderer.flagVertices();
  }
  function UnbindVertices(items) {
    let i = items.length;
    while (i--) {
      items[i].unbind(Events.Types.change, this._renderer.flagVertices);
    }
    this._renderer.flagVertices();
  }
  function FlagFill() {
    this._flagFill = true;
  }
  function FlagStroke() {
    this._flagStroke = true;
  }

  // src/shapes/rectangle.js
  var _Rectangle = class extends Path {
    constructor(x, y, width, height) {
      const points = [
        new Anchor(),
        new Anchor(),
        new Anchor(),
        new Anchor()
      ];
      super(points, true, false, true);
      this._renderer.type = "rectangle";
      for (let prop in proto11) {
        Object.defineProperty(this, prop, proto11[prop]);
      }
      this.width = typeof width === "number" ? width : 1;
      this.height = typeof height === "number" ? height : 1;
      this.origin = new Vector();
      if (typeof x === "number") {
        this.translation.x = x;
      }
      if (typeof y === "number") {
        this.translation.y = y;
      }
      this._update();
    }
    static fromObject(obj) {
      const rectangle = new _Rectangle().copy(obj);
      if ("id" in obj) {
        rectangle.id = obj.id;
      }
      return rectangle;
    }
    copy(rectangle) {
      super.copy.call(this, rectangle);
      for (let i = 0; i < _Rectangle.Properties.length; i++) {
        const k = _Rectangle.Properties[i];
        if (k in rectangle && typeof rectangle[k] === "number") {
          this[k] = rectangle[k];
        }
      }
      return this;
    }
    _flagWidth = 0;
    _flagHeight = 0;
    _width = 0;
    _height = 0;
    _origin = null;
    _update() {
      if (this._flagVertices || this._flagWidth || this._flagHeight) {
        const xr = this._width / 2;
        const yr = this._height / 2;
        if (!this._closed && this.vertices.length === 4) {
          this.vertices.push(new Anchor());
        }
        this.vertices[0].set(-xr, -yr).sub(this._origin).command = Commands.move;
        this.vertices[1].set(xr, -yr).sub(this._origin).command = Commands.line;
        this.vertices[2].set(xr, yr).sub(this._origin).command = Commands.line;
        this.vertices[3].set(-xr, yr).sub(this._origin).command = Commands.line;
        if (this.vertices[4]) {
          this.vertices[4].set(-xr, -yr).sub(this._origin).command = Commands.line;
        }
      }
      super._update.call(this);
      return this;
    }
    flagReset() {
      this._flagWidth = this._flagHeight = false;
      super.flagReset.call(this);
      return this;
    }
    clone(parent) {
      const clone = new _Rectangle(0, 0, this.width, this.height);
      clone.translation.copy(this.translation);
      clone.rotation = this.rotation;
      clone.scale = this.scale;
      clone.skewX = this.skewX;
      clone.skewY = this.skewY;
      if (this.matrix.manual) {
        clone.matrix.copy(this.matrix);
      }
      for (let i = 0; i < Path.Properties.length; i++) {
        const k = Path.Properties[i];
        clone[k] = this[k];
      }
      if (parent) {
        parent.add(clone);
      }
      return clone;
    }
    toObject() {
      const object = super.toObject.call(this);
      object.renderer.type = "rectangle";
      object.width = this.width;
      object.height = this.height;
      object.origin = this.origin.toObject();
      return object;
    }
  };
  var Rectangle = _Rectangle;
  __publicField(Rectangle, "Properties", ["width", "height"]);
  var proto11 = {
    width: {
      enumerable: true,
      get: function() {
        return this._width;
      },
      set: function(v) {
        this._width = v;
        this._flagWidth = true;
      }
    },
    height: {
      enumerable: true,
      get: function() {
        return this._height;
      },
      set: function(v) {
        this._height = v;
        this._flagHeight = true;
      }
    },
    origin: {
      enumerable: true,
      get: function() {
        return this._origin;
      },
      set: function(v) {
        if (this._origin) {
          this._origin.unbind(Events.Types.change, this._renderer.flagVertices);
        }
        this._origin = v;
        this._origin.bind(Events.Types.change, this._renderer.flagVertices);
        this._renderer.flagVertices();
      }
    }
  };

  // src/effects/sprite.js
  var _Sprite = class extends Rectangle {
    _flagTexture = false;
    _flagColumns = false;
    _flagRows = false;
    _flagFrameRate = false;
    _flagIndex = false;
    _amount = 1;
    _duration = 0;
    _startTime = 0;
    _playing = false;
    _firstFrame = 0;
    _lastFrame = 0;
    _loop = true;
    _texture = null;
    _columns = 1;
    _rows = 1;
    _frameRate = 0;
    _index = 0;
    _origin = null;
    constructor(path, ox, oy, cols, rows, frameRate) {
      super(ox, oy, 0, 0);
      for (let prop in proto12) {
        Object.defineProperty(this, prop, proto12[prop]);
      }
      this.noStroke();
      this.noFill();
      if (path instanceof Texture) {
        this.texture = path;
      } else if (typeof path === "string") {
        this.texture = new Texture(path);
      }
      this.origin = new Vector();
      this._update();
      if (typeof cols === "number") {
        this.columns = cols;
      }
      if (typeof rows === "number") {
        this.rows = rows;
      }
      if (typeof frameRate === "number") {
        this.frameRate = frameRate;
      }
      this.index = 0;
    }
    static fromObject(obj) {
      const sprite = new _Sprite().copy(obj);
      if ("id" in obj) {
        sprite.id = obj.id;
      }
      return sprite;
    }
    copy(sprite) {
      super.copy.call(this, sprite);
      for (let i = 0; i < _Sprite.Properties.length; i++) {
        const k = _Sprite.Properties[i];
        if (k in sprite) {
          this[k] = sprite[k];
        }
      }
      return this;
    }
    play(firstFrame, lastFrame, onLastFrame) {
      this._playing = true;
      this._firstFrame = 0;
      this._lastFrame = this.amount - 1;
      this._startTime = _.performance.now();
      if (typeof firstFrame === "number") {
        this._firstFrame = firstFrame;
      }
      if (typeof lastFrame === "number") {
        this._lastFrame = lastFrame;
      }
      if (typeof onLastFrame === "function") {
        this._onLastFrame = onLastFrame;
      } else {
        delete this._onLastFrame;
      }
      if (this._index !== this._firstFrame) {
        this._startTime -= 1e3 * Math.abs(this._index - this._firstFrame) / this._frameRate;
      }
      return this;
    }
    pause() {
      this._playing = false;
      return this;
    }
    stop() {
      this._playing = false;
      this._index = 0;
      return this;
    }
    clone(parent) {
      const clone = new _Sprite(
        this.texture,
        this.translation.x,
        this.translation.y,
        this.columns,
        this.rows,
        this.frameRate
      );
      if (this.playing) {
        clone.play(this._firstFrame, this._lastFrame);
      }
      clone.loop = this.loop;
      clone.firstFrame = this.firstFrame;
      clone.lastFrame = this.lastFrame;
      if (parent) {
        parent.add(clone);
      }
      return clone;
    }
    toObject() {
      const object = super.toObject.call(this);
      object.texture = this.texture.toObject();
      object.columns = this.columns;
      object.rows = this.rows;
      object.frameRate = this.frameRate;
      object.index = this.index;
      object.firstFrame = this.firstFrame;
      object.lastFrame = this.lastFrame;
      object.loop = this.loop;
      return object;
    }
    _update() {
      const effect = this._texture;
      const cols = this._columns;
      const rows = this._rows;
      let width, height, elapsed, amount, duration;
      let index, iw, ih, frames;
      if (effect) {
        if (this._flagColumns || this._flagRows) {
          this._amount = this._columns * this._rows;
        }
        if (this._flagFrameRate) {
          this._duration = 1e3 * this._amount / this._frameRate;
        }
        if (this._flagTexture) {
          this.fill = effect;
        }
        if (effect.loaded) {
          iw = effect.image.width;
          ih = effect.image.height;
          width = iw / cols;
          height = ih / rows;
          amount = this._amount;
          if (this.width !== width) {
            this.width = width;
          }
          if (this.height !== height) {
            this.height = height;
          }
          if (this._playing && this._frameRate > 0) {
            if (_.isNaN(this._lastFrame)) {
              this._lastFrame = amount - 1;
            }
            elapsed = _.performance.now() - this._startTime;
            frames = this._lastFrame + 1;
            duration = 1e3 * (frames - this._firstFrame) / this._frameRate;
            if (this._loop) {
              elapsed = elapsed % duration;
            } else {
              elapsed = Math.min(elapsed, duration);
            }
            index = lerp(this._firstFrame, frames, elapsed / duration);
            index = Math.floor(index);
            if (index !== this._index) {
              this._index = index;
              if (index >= this._lastFrame - 1 && this._onLastFrame) {
                this._onLastFrame();
              }
            }
          }
          const col = this._index % cols;
          const row = Math.floor(this._index / cols);
          const ox = -width * col + (iw - width) / 2;
          const oy = -height * row + (ih - height) / 2;
          if (ox !== effect.offset.x) {
            effect.offset.x = ox;
          }
          if (oy !== effect.offset.y) {
            effect.offset.y = oy;
          }
        }
      }
      super._update.call(this);
      return this;
    }
    flagReset() {
      this._flagTexture = this._flagColumns = this._flagRows = this._flagFrameRate = false;
      super.flagReset.call(this);
      return this;
    }
  };
  var Sprite = _Sprite;
  __publicField(Sprite, "Properties", [
    "texture",
    "columns",
    "rows",
    "frameRate",
    "index",
    "firstFrame",
    "lastFrame",
    "loop"
  ]);
  var proto12 = {
    texture: {
      enumerable: true,
      get: function() {
        return this._texture;
      },
      set: function(v) {
        this._texture = v;
        this._flagTexture = true;
      }
    },
    columns: {
      enumerable: true,
      get: function() {
        return this._columns;
      },
      set: function(v) {
        this._columns = v;
        this._flagColumns = true;
      }
    },
    rows: {
      enumerable: true,
      get: function() {
        return this._rows;
      },
      set: function(v) {
        this._rows = v;
        this._flagRows = true;
      }
    },
    frameRate: {
      enumerable: true,
      get: function() {
        return this._frameRate;
      },
      set: function(v) {
        this._frameRate = v;
        this._flagFrameRate = true;
      }
    },
    index: {
      enumerable: true,
      get: function() {
        return this._index;
      },
      set: function(v) {
        this._index = v;
        this._flagIndex = true;
      }
    },
    firstFrame: {
      enumerable: true,
      get: function() {
        return this._firstFrame;
      },
      set: function(v) {
        this._firstFrame = v;
      }
    },
    lastFrame: {
      enumerable: true,
      get: function() {
        return this._lastFrame;
      },
      set: function(v) {
        this._lastFrame = v;
      }
    },
    loop: {
      enumerable: true,
      get: function() {
        return this._loop;
      },
      set: function(v) {
        this._loop = !!v;
      }
    }
  };

  // src/children.js
  var Children = class extends Collection {
    #ids = {};
    get ids() {
      return this.#ids;
    }
    constructor(children) {
      children = Array.isArray(children) ? children : Array.prototype.slice.call(arguments);
      super(children);
      this.attach(children);
      this.on(Events.Types.insert, this.attach);
      this.on(Events.Types.remove, this.detach);
    }
    attach(children) {
      for (let i = 0; i < children.length; i++) {
        const child = children[i];
        if (child && child.id) {
          this.ids[child.id] = child;
        }
      }
      return this;
    }
    detach(children) {
      for (let i = 0; i < children.length; i++) {
        delete this.ids[children[i].id];
      }
      return this;
    }
  };

  // src/shapes/arc-segment.js
  var _ArcSegment = class extends Path {
    _flagStartAngle = false;
    _flagEndAngle = false;
    _flagInnerRadius = false;
    _flagOuterRadius = false;
    _startAngle = 0;
    _endAngle = TWO_PI;
    _innerRadius = 0;
    _outerRadius = 0;
    constructor(x, y, ir, or, sa, ea, res) {
      const amount = res || Constants.Resolution * 3;
      const points = [];
      for (let i = 0; i < amount; i++) {
        points.push(new Anchor());
      }
      super(points, true, false, true);
      this._renderer.type = "arc-segment";
      for (let prop in proto13) {
        Object.defineProperty(this, prop, proto13[prop]);
      }
      if (typeof ir === "number") {
        this.innerRadius = ir;
      }
      if (typeof or === "number") {
        this.outerRadius = or;
      }
      if (typeof sa === "number") {
        this.startAngle = sa;
      }
      if (typeof ea === "number") {
        this.endAngle = ea;
      }
      this._update();
      if (typeof x === "number") {
        this.translation.x = x;
      }
      if (typeof y === "number") {
        this.translation.y = y;
      }
    }
    static fromObject(obj) {
      const segment = new _ArcSegment().copy(obj);
      if ("id" in obj) {
        segment.id = obj.id;
      }
      return segment;
    }
    copy(arcSegment) {
      super.copy.call(this, arcSegment);
      for (let i = 0; i < _ArcSegment.Properties.length; i++) {
        const k = _ArcSegment.Properties[i];
        if (k in arcSegment && typeof arcSegment[k] === "number") {
          this[k] = arcSegment[k];
        }
      }
      return this;
    }
    _update() {
      if (this._flagVertices || this._flagStartAngle || this._flagEndAngle || this._flagInnerRadius || this._flagOuterRadius) {
        const sa = this._startAngle;
        const ea = this._endAngle;
        const ir = this._innerRadius;
        const or = this._outerRadius;
        const connected = mod(sa, TWO_PI) === mod(ea, TWO_PI);
        const punctured = ir > 0;
        const vertices = this.vertices;
        let length = punctured ? vertices.length / 2 : vertices.length;
        let command, id = 0;
        let i, last, pct, v, theta, step, x, y, amp;
        if (connected) {
          length--;
        } else if (!punctured) {
          length -= 2;
        }
        for (i = 0, last = length - 1; i < length; i++) {
          pct = i / last;
          v = vertices[id];
          theta = pct * (ea - sa) + sa;
          step = (ea - sa) / length;
          x = or * Math.cos(theta);
          y = or * Math.sin(theta);
          switch (i) {
            case 0:
              command = Commands.move;
              break;
            default:
              command = Commands.curve;
          }
          v.command = command;
          v.x = x;
          v.y = y;
          v.controls.left.clear();
          v.controls.right.clear();
          if (v.command === Commands.curve) {
            amp = or * step / Math.PI;
            v.controls.left.x = amp * Math.cos(theta - HALF_PI);
            v.controls.left.y = amp * Math.sin(theta - HALF_PI);
            v.controls.right.x = amp * Math.cos(theta + HALF_PI);
            v.controls.right.y = amp * Math.sin(theta + HALF_PI);
            if (i === 1) {
              v.controls.left.multiplyScalar(2);
            }
            if (i === last) {
              v.controls.right.multiplyScalar(2);
            }
          }
          id++;
        }
        if (punctured) {
          if (connected) {
            vertices[id].command = Commands.close;
            id++;
          } else {
            length--;
            last = length - 1;
          }
          for (i = 0; i < length; i++) {
            pct = i / last;
            v = vertices[id];
            theta = (1 - pct) * (ea - sa) + sa;
            step = (ea - sa) / length;
            x = ir * Math.cos(theta);
            y = ir * Math.sin(theta);
            command = Commands.curve;
            if (i <= 0) {
              command = connected ? Commands.move : Commands.line;
            }
            v.command = command;
            v.x = x;
            v.y = y;
            v.controls.left.clear();
            v.controls.right.clear();
            if (v.command === Commands.curve) {
              amp = ir * step / Math.PI;
              v.controls.left.x = amp * Math.cos(theta + HALF_PI);
              v.controls.left.y = amp * Math.sin(theta + HALF_PI);
              v.controls.right.x = amp * Math.cos(theta - HALF_PI);
              v.controls.right.y = amp * Math.sin(theta - HALF_PI);
              if (i === 1) {
                v.controls.left.multiplyScalar(2);
              }
              if (i === last) {
                v.controls.right.multiplyScalar(2);
              }
            }
            id++;
          }
          vertices[id].copy(vertices[0]);
          vertices[id].command = Commands.line;
        } else if (!connected) {
          vertices[id].command = Commands.line;
          vertices[id].x = 0;
          vertices[id].y = 0;
          id++;
          vertices[id].copy(vertices[0]);
          vertices[id].command = Commands.line;
        }
      }
      super._update.call(this);
      return this;
    }
    flagReset() {
      super.flagReset.call(this);
      this._flagStartAngle = this._flagEndAngle = this._flagInnerRadius = this._flagOuterRadius = false;
      return this;
    }
    clone(parent) {
      const ir = this.innerRadius;
      const or = this.outerRadius;
      const sa = this.startAngle;
      const ea = this.endAngle;
      const resolution = this.vertices.length;
      const clone = new _ArcSegment(0, 0, ir, or, sa, ea, resolution);
      clone.translation.copy(this.translation);
      clone.rotation = this.rotation;
      clone.scale = this.scale;
      clone.skewX = this.skewX;
      clone.skewY = this.skewY;
      if (this.matrix.manual) {
        clone.matrix.copy(this.matrix);
      }
      for (let i = 0; i < Path.Properties.length; i++) {
        const k = Path.Properties[i];
        clone[k] = this[k];
      }
      if (parent) {
        parent.add(clone);
      }
      return clone;
    }
    toObject() {
      const object = super.toObject.call(this);
      object.renderer.type = "arc-segment";
      for (let i = 0; i < _ArcSegment.Properties.length; i++) {
        const k = _ArcSegment.Properties[i];
        object[k] = this[k];
      }
      return object;
    }
  };
  var ArcSegment = _ArcSegment;
  __publicField(ArcSegment, "Properties", ["startAngle", "endAngle", "innerRadius", "outerRadius"]);
  var proto13 = {
    startAngle: {
      enumerable: true,
      get: function() {
        return this._startAngle;
      },
      set: function(v) {
        this._startAngle = v;
        this._flagStartAngle = true;
      }
    },
    endAngle: {
      enumerable: true,
      get: function() {
        return this._endAngle;
      },
      set: function(v) {
        this._endAngle = v;
        this._flagEndAngle = true;
      }
    },
    innerRadius: {
      enumerable: true,
      get: function() {
        return this._innerRadius;
      },
      set: function(v) {
        this._innerRadius = v;
        this._flagInnerRadius = true;
      }
    },
    outerRadius: {
      enumerable: true,
      get: function() {
        return this._outerRadius;
      },
      set: function(v) {
        this._outerRadius = v;
        this._flagOuterRadius = true;
      }
    }
  };

  // src/shapes/circle.js
  var cos2 = Math.cos;
  var sin2 = Math.sin;
  var _Circle = class extends Path {
    _flagRadius = false;
    _radius = 0;
    constructor(ox, oy, r, resolution) {
      const amount = resolution ? Math.max(resolution, 2) : 4;
      const points = [];
      for (let i = 0; i < amount; i++) {
        points.push(new Anchor(0, 0, 0, 0, 0, 0));
      }
      super(points, true, true, true);
      this._renderer.type = "circle";
      for (let prop in proto14) {
        Object.defineProperty(this, prop, proto14[prop]);
      }
      if (typeof r === "number") {
        this.radius = r;
      }
      this._update();
      if (typeof ox === "number") {
        this.translation.x = ox;
      }
      if (typeof oy === "number") {
        this.translation.y = oy;
      }
    }
    static fromObject(obj) {
      const circle = new _Circle().copy(obj);
      if ("id" in obj) {
        circle.id = obj.id;
      }
      return circle;
    }
    copy(circle) {
      super.copy.call(this, circle);
      for (let i = 0; i < _Circle.Properties.length; i++) {
        const k = _Circle.Properties[i];
        if (k in circle && typeof circle[k] === "number") {
          this[k] = circle[k];
        }
      }
      return this;
    }
    _update() {
      if (this._flagVertices || this._flagRadius) {
        let length = this.vertices.length;
        if (!this._closed && length > 2) {
          length -= 1;
        }
        const c = 4 / 3 * Math.tan(Math.PI / (length * 2));
        const radius = this._radius;
        const rc = radius * c;
        for (let i = 0; i < this.vertices.length; i++) {
          const pct = i / length;
          const theta = pct * TWO_PI;
          const x = radius * cos2(theta);
          const y = radius * sin2(theta);
          const lx = rc * cos2(theta - HALF_PI);
          const ly = rc * sin2(theta - HALF_PI);
          const rx = rc * cos2(theta + HALF_PI);
          const ry = rc * sin2(theta + HALF_PI);
          const v = this.vertices[i];
          v.command = i === 0 ? Commands.move : Commands.curve;
          v.set(x, y);
          v.controls.left.set(lx, ly);
          v.controls.right.set(rx, ry);
        }
      }
      super._update.call(this);
      return this;
    }
    flagReset() {
      this._flagRadius = false;
      super.flagReset.call(this);
      return this;
    }
    clone(parent) {
      const clone = new _Circle(0, 0, this.radius, this.vertices.length);
      clone.translation.copy(this.translation);
      clone.rotation = this.rotation;
      clone.scale = this.scale;
      clone.skewX = this.skewX;
      clone.skewY = this.skewY;
      if (this.matrix.manual) {
        clone.matrix.copy(this.matrix);
      }
      for (let i = 0; i < Path.Properties.length; i++) {
        const k = Path.Properties[i];
        clone[k] = this[k];
      }
      if (parent) {
        parent.add(clone);
      }
      return clone;
    }
    toObject() {
      const object = super.toObject.call(this);
      object.renderer.type = "circle";
      for (let i = 0; i < _Circle.Properties.length; i++) {
        const k = _Circle.Properties[i];
        object[k] = this[k];
      }
      return object;
    }
  };
  var Circle = _Circle;
  __publicField(Circle, "Properties", ["radius"]);
  var proto14 = {
    radius: {
      enumerable: true,
      get: function() {
        return this._radius;
      },
      set: function(v) {
        this._radius = v;
        this._flagRadius = true;
      }
    }
  };

  // src/shapes/ellipse.js
  var cos3 = Math.cos;
  var sin3 = Math.sin;
  var _Ellipse = class extends Path {
    _flagWidth = false;
    _flagHeight = false;
    _width = 0;
    _height = 0;
    constructor(x, y, rx, ry, resolution) {
      if (typeof ry !== "number" && typeof rx === "number") {
        ry = rx;
      }
      const amount = resolution ? Math.max(resolution, 2) : 4;
      const points = [];
      for (let i = 0; i < amount; i++) {
        points.push(new Anchor());
      }
      super(points, true, true, true);
      this._renderer.type = "ellipse";
      for (let prop in proto15) {
        Object.defineProperty(this, prop, proto15[prop]);
      }
      if (typeof rx === "number") {
        this.width = rx * 2;
      }
      if (typeof ry === "number") {
        this.height = ry * 2;
      }
      this._update();
      if (typeof x === "number") {
        this.translation.x = x;
      }
      if (typeof y === "number") {
        this.translation.y = y;
      }
    }
    static fromObject(obj) {
      const ellipse = new _Ellipse().copy(obj);
      if ("id" in obj) {
        ellipse.id = obj.id;
      }
      return ellipse;
    }
    copy(ellipse) {
      super.copy.call(this, ellipse);
      for (let i = 0; i < _Ellipse.Properties.length; i++) {
        const k = _Ellipse.Properties[i];
        if (k in ellipse && typeof ellipse[k] === "number") {
          this[k] = ellipse[k];
        }
      }
      return this;
    }
    _update() {
      if (this._flagVertices || this._flagWidth || this._flagHeight) {
        let length = this.vertices.length;
        if (!this._closed && length > 2) {
          length -= 1;
        }
        const c = 4 / 3 * Math.tan(Math.PI / (this.vertices.length * 2));
        const radiusX = this._width / 2;
        const radiusY = this._height / 2;
        for (let i = 0; i < this.vertices.length; i++) {
          const pct = i / length;
          const theta = pct * TWO_PI;
          const x = radiusX * cos3(theta);
          const y = radiusY * sin3(theta);
          const lx = radiusX * c * cos3(theta - HALF_PI);
          const ly = radiusY * c * sin3(theta - HALF_PI);
          const rx = radiusX * c * cos3(theta + HALF_PI);
          const ry = radiusY * c * sin3(theta + HALF_PI);
          const v = this.vertices[i];
          v.command = i === 0 ? Commands.move : Commands.curve;
          v.set(x, y);
          v.controls.left.set(lx, ly);
          v.controls.right.set(rx, ry);
        }
      }
      super._update.call(this);
      return this;
    }
    flagReset() {
      this._flagWidth = this._flagHeight = false;
      super.flagReset.call(this);
      return this;
    }
    clone(parent) {
      const rx = this.width / 2;
      const ry = this.height / 2;
      const resolution = this.vertices.length;
      const clone = new _Ellipse(0, 0, rx, ry, resolution);
      clone.translation.copy(this.translation);
      clone.rotation = this.rotation;
      clone.scale = this.scale;
      clone.skewX = this.skewX;
      clone.skewY = this.skewY;
      if (this.matrix.manual) {
        clone.matrix.copy(this.matrix);
      }
      for (let i = 0; i < Path.Properties.length; i++) {
        const k = Path.Properties[i];
        clone[k] = this[k];
      }
      if (parent) {
        parent.add(clone);
      }
      return clone;
    }
    toObject() {
      const object = super.toObject.call(this);
      object.renderer.type = "ellipse";
      for (let i = 0; i < _Ellipse.Properties.length; i++) {
        const k = _Ellipse.Properties[i];
        object[k] = this[k];
      }
      return object;
    }
  };
  var Ellipse = _Ellipse;
  __publicField(Ellipse, "Properties", ["width", "height"]);
  var proto15 = {
    width: {
      enumerable: true,
      get: function() {
        return this._width;
      },
      set: function(v) {
        this._width = v;
        this._flagWidth = true;
      }
    },
    height: {
      enumerable: true,
      get: function() {
        return this._height;
      },
      set: function(v) {
        this._height = v;
        this._flagHeight = true;
      }
    }
  };

  // src/shapes/points.js
  var ceil2 = Math.ceil;
  var floor3 = Math.floor;
  var _Points = class extends Shape {
    _flagVertices = true;
    _flagLength = true;
    _flagFill = true;
    _flagStroke = true;
    _flagLinewidth = true;
    _flagOpacity = true;
    _flagVisible = true;
    _flagSize = true;
    _flagSizeAttenuation = true;
    _length = 0;
    _fill = "#fff";
    _stroke = "#000";
    _linewidth = 1;
    _opacity = 1;
    _visible = true;
    _size = 1;
    _sizeAttenuation = false;
    _beginning = 0;
    _ending = 1;
    _dashes = null;
    constructor(vertices) {
      super();
      for (let prop in proto16) {
        Object.defineProperty(this, prop, proto16[prop]);
      }
      this._renderer.type = "points";
      this._renderer.flagVertices = FlagVertices.bind(this);
      this._renderer.bindVertices = BindVertices.bind(this);
      this._renderer.unbindVertices = UnbindVertices.bind(this);
      this._renderer.flagFill = FlagFill.bind(this);
      this._renderer.flagStroke = FlagStroke.bind(this);
      this._renderer.vertices = null;
      this._renderer.collection = null;
      this.size = 1;
      this.sizeAttenuation = false;
      this.beginning = 0;
      this.ending = 1;
      this.fill = "#fff";
      this.stroke = "#000";
      this.linewidth = 1;
      this.opacity = 1;
      this.className = "";
      this.visible = true;
      this.vertices = vertices;
      this.dashes = [];
      this.dashes.offset = 0;
    }
    static fromObject(obj) {
      const fill = typeof obj.fill === "string" ? obj.fill : getEffectFromObject(obj.fill);
      const stroke = typeof obj.stroke === "string" ? obj.stroke : getEffectFromObject(obj.stroke);
      const points = new _Points().copy({ ...obj, fill, stroke });
      if ("id" in obj) {
        points.id = obj.id;
      }
      return points;
    }
    copy(points) {
      super.copy.call(this, points);
      for (let j = 0; j < points.vertices.length; j++) {
        const v = points.vertices[j];
        if (v instanceof Anchor) {
          this.vertices.push(points.vertices[j].clone());
        } else {
          this.vertices.push(new Anchor().copy(v));
        }
      }
      for (let i = 0; i < _Points.Properties.length; i++) {
        const k = _Points.Properties[i];
        if (k in points) {
          this[k] = points[k];
        }
      }
      return this;
    }
    clone(parent) {
      const clone = new _Points();
      for (let j = 0; j < this.vertices.length; j++) {
        clone.vertices.push(this.vertices[j].clone());
      }
      for (let i = 0; i < _Points.Properties.length; i++) {
        const k = _Points.Properties[i];
        clone[k] = this[k];
      }
      clone.className = this.className;
      clone.translation.copy(this.translation);
      clone.rotation = this.rotation;
      clone.scale = this.scale;
      clone.skewX = this.skewX;
      clone.skewY = this.skewY;
      if (this.matrix.manual) {
        clone.matrix.copy(this.matrix);
      }
      if (parent) {
        parent.add(clone);
      }
      return clone._update();
    }
    toObject() {
      const result = super.toObject.call(this);
      result.renderer.type = "points";
      result.vertices = this.vertices.map((v) => v.toObject());
      _.each(
        _Points.Properties,
        function(k) {
          if (typeof this[k] !== "undefined") {
            if (this[k].toObject) {
              result[k] = this[k].toObject();
            } else {
              result[k] = this[k];
            }
          }
        },
        this
      );
      return result;
    }
    noFill = Path.prototype.noFill;
    noStroke = Path.prototype.noStroke;
    corner = Path.prototype.corner;
    center = Path.prototype.center;
    getBoundingClientRect = Path.prototype.getBoundingClientRect;
    subdivide(limit) {
      this._update();
      let points = [];
      for (let i = 0; i < this.vertices.length; i++) {
        const a = this.vertices[i];
        const b = this.vertices[i - 1];
        if (!b) {
          continue;
        }
        const x1 = a.x;
        const y1 = a.y;
        const x2 = b.x;
        const y2 = b.y;
        const subdivisions = subdivide(x1, y1, x1, y1, x2, y2, x2, y2, limit);
        points = points.concat(subdivisions);
      }
      this.vertices = points;
      return this;
    }
    _updateLength = Path.prototype._updateLength;
    _update() {
      if (this._flagVertices) {
        if (this._flagLength) {
          this._updateLength(void 0, true);
        }
        const beginning = Math.min(this._beginning, this._ending);
        const ending = Math.max(this._beginning, this._ending);
        const bid = getIdByLength(this, beginning * this._length);
        const eid = getIdByLength(this, ending * this._length);
        const low = ceil2(bid);
        const high = floor3(eid);
        let j = 0, v;
        this._renderer.vertices = [];
        this._renderer.collection = [];
        for (let i = 0; i < this._collection.length; i++) {
          if (i >= low && i <= high) {
            v = this._collection[i];
            this._renderer.collection.push(v);
            this._renderer.vertices[j * 2 + 0] = v.x;
            this._renderer.vertices[j * 2 + 1] = v.y;
            j++;
          }
        }
      }
      super._update.apply(this, arguments);
      return this;
    }
    flagReset() {
      this._flagVertices = this._flagLength = this._flagFill = this._flagStroke = this._flagLinewidth = this._flagOpacity = this._flagVisible = this._flagSize = this._flagSizeAttenuation = false;
      super.flagReset.call(this);
      return this;
    }
  };
  var Points = _Points;
  __publicField(Points, "Properties", [
    "fill",
    "stroke",
    "linewidth",
    "opacity",
    "visible",
    "size",
    "sizeAttenuation",
    "beginning",
    "ending",
    "dashes"
  ]);
  var proto16 = {
    linewidth: {
      enumerable: true,
      get: function() {
        return this._linewidth;
      },
      set: function(v) {
        this._linewidth = v;
        this._flagLinewidth = true;
      }
    },
    opacity: {
      enumerable: true,
      get: function() {
        return this._opacity;
      },
      set: function(v) {
        this._opacity = v;
        this._flagOpacity = true;
      }
    },
    visible: {
      enumerable: true,
      get: function() {
        return this._visible;
      },
      set: function(v) {
        this._visible = v;
        this._flagVisible = true;
      }
    },
    size: {
      enumerable: true,
      get: function() {
        return this._size;
      },
      set: function(v) {
        this._size = v;
        this._flagSize = true;
      }
    },
    sizeAttenuation: {
      enumerable: true,
      get: function() {
        return this._sizeAttenuation;
      },
      set: function(v) {
        this._sizeAttenuation = v;
        this._flagSizeAttenuation = true;
      }
    },
    fill: {
      enumerable: true,
      get: function() {
        return this._fill;
      },
      set: function(f) {
        if (this._fill instanceof Gradient || this._fill instanceof LinearGradient || this._fill instanceof RadialGradient || this._fill instanceof Texture) {
          this._fill.unbind(Events.Types.change, this._renderer.flagFill);
        }
        this._fill = f;
        this._flagFill = true;
        if (this._fill instanceof Gradient || this._fill instanceof LinearGradient || this._fill instanceof RadialGradient || this._fill instanceof Texture) {
          this._fill.bind(Events.Types.change, this._renderer.flagFill);
        }
      }
    },
    stroke: {
      enumerable: true,
      get: function() {
        return this._stroke;
      },
      set: function(f) {
        if (this._stroke instanceof Gradient || this._stroke instanceof LinearGradient || this._stroke instanceof RadialGradient || this._stroke instanceof Texture) {
          this._stroke.unbind(Events.Types.change, this._renderer.flagStroke);
        }
        this._stroke = f;
        this._flagStroke = true;
        if (this._stroke instanceof Gradient || this._stroke instanceof LinearGradient || this._stroke instanceof RadialGradient || this._stroke instanceof Texture) {
          this._stroke.bind(Events.Types.change, this._renderer.flagStroke);
        }
      }
    },
    length: {
      get: function() {
        if (this._flagLength) {
          this._updateLength();
        }
        return this._length;
      }
    },
    beginning: {
      enumerable: true,
      get: function() {
        return this._beginning;
      },
      set: function(v) {
        this._beginning = v;
        this._flagVertices = true;
      }
    },
    ending: {
      enumerable: true,
      get: function() {
        return this._ending;
      },
      set: function(v) {
        this._ending = v;
        this._flagVertices = true;
      }
    },
    vertices: {
      enumerable: true,
      get: function() {
        return this._collection;
      },
      set: function(vertices) {
        const bindVertices = this._renderer.bindVertices;
        const unbindVertices = this._renderer.unbindVertices;
        if (this._collection) {
          this._collection.unbind(Events.Types.insert, bindVertices).unbind(Events.Types.remove, unbindVertices);
        }
        if (vertices instanceof Collection) {
          this._collection = vertices;
        } else {
          this._collection = new Collection(vertices || []);
        }
        this._collection.bind(Events.Types.insert, bindVertices).bind(Events.Types.remove, unbindVertices);
        bindVertices(this._collection);
      }
    },
    dashes: {
      enumerable: true,
      get: function() {
        return this._dashes;
      },
      set: function(v) {
        if (typeof v.offset !== "number") {
          v.offset = this.dashes && this._dashes.offset || 0;
        }
        this._dashes = v;
      }
    }
  };

  // src/shapes/polygon.js
  var cos4 = Math.cos;
  var sin4 = Math.sin;
  var _Polygon = class extends Path {
    _flagWidth = false;
    _flagHeight = false;
    _flagSides = false;
    _radius = 0;
    _width = 0;
    _height = 0;
    _sides = 0;
    constructor(x, y, radius, sides) {
      sides = Math.max(sides || 0, 3);
      super();
      this._renderer.type = "polygon";
      for (let prop in proto17) {
        Object.defineProperty(this, prop, proto17[prop]);
      }
      this.closed = true;
      this.automatic = false;
      if (typeof radius === "number") {
        this.radius = radius;
      }
      if (typeof sides === "number") {
        this.sides = sides;
      }
      this._update();
      if (typeof x === "number") {
        this.translation.x = x;
      }
      if (typeof y === "number") {
        this.translation.y = y;
      }
    }
    static fromObject(obj) {
      const polygon = new _Polygon().copy(obj);
      if ("id" in obj) {
        polygon.id = obj.id;
      }
      return polygon;
    }
    copy(polygon) {
      super.copy.call(this, polygon);
      for (let i = 0; i < _Polygon.Properties.length; i++) {
        const k = _Polygon.Properties[i];
        if (k in polygon && typeof polygon[k] === "number") {
          this[k] = polygon[k];
        }
      }
      return this;
    }
    _update() {
      if (this._flagVertices || this._flagWidth || this._flagHeight || this._flagSides) {
        const sides = this._sides;
        const amount = sides + 1;
        let length = this.vertices.length;
        if (length > sides) {
          this.vertices.splice(sides - 1, length - sides);
          length = sides;
        }
        for (let i = 0; i < amount; i++) {
          const pct = (i + 0.5) / sides;
          const theta = TWO_PI * pct + Math.PI / 2;
          const x = this._width * cos4(theta) / 2;
          const y = this._height * sin4(theta) / 2;
          if (i >= length) {
            this.vertices.push(new Anchor(x, y));
          } else {
            this.vertices[i].set(x, y);
          }
          this.vertices[i].command = i === 0 ? Commands.move : Commands.line;
        }
      }
      super._update.call(this);
      return this;
    }
    flagReset() {
      this._flagWidth = this._flagHeight = this._flagSides = false;
      super.flagReset.call(this);
      return this;
    }
    clone(parent) {
      const clone = new _Polygon(0, 0, 0, this.sides);
      clone.translation.copy(this.translation);
      clone.rotation = this.rotation;
      clone.scale = this.scale;
      clone.skewX = this.skewX;
      clone.skewY = this.skewY;
      clone.width = this.width;
      clone.height = this.height;
      if (this.matrix.manual) {
        clone.matrix.copy(this.matrix);
      }
      for (let i = 0; i < Path.Properties.length; i++) {
        const k = Path.Properties[i];
        clone[k] = this[k];
      }
      if (parent) {
        parent.add(clone);
      }
      return clone;
    }
    toObject() {
      const object = super.toObject.call(this);
      object.renderer.type = "polygon";
      for (let i = 0; i < _Polygon.Properties.length; i++) {
        const k = _Polygon.Properties[i];
        object[k] = this[k];
      }
      return object;
    }
  };
  var Polygon = _Polygon;
  __publicField(Polygon, "Properties", ["width", "height", "sides"]);
  var proto17 = {
    radius: {
      enumerable: true,
      get: function() {
        return this._radius;
      },
      set: function(v) {
        this._radius = v;
        this.width = v * 2;
        this.height = v * 2;
      }
    },
    width: {
      enumerable: true,
      get: function() {
        return this._width;
      },
      set: function(v) {
        this._width = v;
        this._flagWidth = true;
        this._radius = Math.max(this.width, this.height) / 2;
      }
    },
    height: {
      enumerable: true,
      get: function() {
        return this._height;
      },
      set: function(v) {
        this._height = v;
        this._flagHeight = true;
        this._radius = Math.max(this.width, this.height) / 2;
      }
    },
    sides: {
      enumerable: true,
      get: function() {
        return this._sides;
      },
      set: function(v) {
        this._sides = v;
        this._flagSides = true;
      }
    }
  };

  // src/shapes/rounded-rectangle.js
  var _RoundedRectangle = class extends Path {
    _flagWidth = false;
    _flagHeight = false;
    _flagRadius = false;
    _width = 0;
    _height = 0;
    _radius = 12;
    constructor(x, y, width, height, radius) {
      if (typeof radius === "undefined" && typeof width === "number" && typeof height === "number") {
        radius = Math.floor(Math.min(width, height) / 12);
      }
      const points = [];
      for (let i = 0; i < 10; i++) {
        points.push(
          new Anchor(0, 0, 0, 0, 0, 0, i === 0 ? Commands.move : Commands.curve)
        );
      }
      super(points);
      this._renderer.type = "rounded-rectangle";
      for (let prop in proto18) {
        Object.defineProperty(this, prop, proto18[prop]);
      }
      this.closed = true;
      this.automatic = false;
      this._renderer.flagRadius = FlagRadius.bind(this);
      if (typeof width === "number") {
        this.width = width;
      }
      if (typeof height === "number") {
        this.height = height;
      }
      if (typeof radius === "number") {
        this.radius = radius;
      }
      this._update();
      if (typeof x === "number") {
        this.translation.x = x;
      }
      if (typeof y === "number") {
        this.translation.y = y;
      }
    }
    static fromObject(obj) {
      const rectangle = new _RoundedRectangle().copy(obj);
      if ("id" in obj) {
        rectangle.id = obj.id;
      }
      return rectangle;
    }
    copy(roundedRectangle) {
      super.copy.call(this, roundedRectangle);
      for (let i = 0; i < _RoundedRectangle.Properties.length; i++) {
        const k = _RoundedRectangle.Properties[i];
        if (k in roundedRectangle) {
          const value = roundedRectangle[k];
          if (/radius/i.test(k)) {
            this[k] = typeof value === "number" || value instanceof Vector ? value : new Vector().copy(value);
          } else if (typeof value === "number") {
            this[k] = value;
          }
        }
      }
      return this;
    }
    _update() {
      if (this._flagVertices || this._flagWidth || this._flagHeight || this._flagRadius) {
        const width = this._width;
        const height = this._height;
        let rx, ry;
        if (this._radius instanceof Vector) {
          rx = this._radius.x;
          ry = this._radius.y;
        } else {
          rx = this._radius;
          ry = this._radius;
        }
        let v;
        let w = width / 2;
        let h = height / 2;
        v = this.vertices[0];
        v.x = -(w - rx);
        v.y = -h;
        v = this.vertices[1];
        v.x = w - rx;
        v.y = -h;
        v.controls.left.clear();
        v.controls.right.x = rx;
        v.controls.right.y = 0;
        v = this.vertices[2];
        v.x = w;
        v.y = -(h - ry);
        v.controls.right.clear();
        v.controls.left.clear();
        v = this.vertices[3];
        v.x = w;
        v.y = h - ry;
        v.controls.left.clear();
        v.controls.right.x = 0;
        v.controls.right.y = ry;
        v = this.vertices[4];
        v.x = w - rx;
        v.y = h;
        v.controls.right.clear();
        v.controls.left.clear();
        v = this.vertices[5];
        v.x = -(w - rx);
        v.y = h;
        v.controls.left.clear();
        v.controls.right.x = -rx;
        v.controls.right.y = 0;
        v = this.vertices[6];
        v.x = -w;
        v.y = h - ry;
        v.controls.left.clear();
        v.controls.right.clear();
        v = this.vertices[7];
        v.x = -w;
        v.y = -(h - ry);
        v.controls.left.clear();
        v.controls.right.x = 0;
        v.controls.right.y = -ry;
        v = this.vertices[8];
        v.x = -(w - rx);
        v.y = -h;
        v.controls.left.clear();
        v.controls.right.clear();
        v = this.vertices[9];
        v.copy(this.vertices[8]);
      }
      super._update.call(this);
      return this;
    }
    flagReset() {
      this._flagWidth = this._flagHeight = this._flagRadius = false;
      super.flagReset.call(this);
      return this;
    }
    clone(parent) {
      const width = this.width;
      const height = this.height;
      const radius = this.radius;
      const clone = new _RoundedRectangle(0, 0, width, height, radius);
      clone.translation.copy(this.translation);
      clone.rotation = this.rotation;
      clone.scale = this.scale;
      clone.skewX = this.skewX;
      clone.skewY = this.skewY;
      if (this.matrix.manual) {
        clone.matrix.copy(this.matrix);
      }
      for (let i = 0; i < Path.Properties.length; i++) {
        const k = Path.Properties[i];
        clone[k] = this[k];
      }
      if (parent) {
        parent.add(clone);
      }
      return clone;
    }
    toObject() {
      const object = super.toObject.call(this);
      object.renderer.type = "rounded-rectangle";
      for (let i = 0; i < _RoundedRectangle.Properties.length; i++) {
        const k = _RoundedRectangle.Properties[i];
        object[k] = this[k];
      }
      object.radius = typeof this.radius === "number" ? this.radius : this.radius.toObject();
      return object;
    }
  };
  var RoundedRectangle = _RoundedRectangle;
  __publicField(RoundedRectangle, "Properties", ["width", "height", "radius"]);
  var proto18 = {
    width: {
      enumerable: true,
      get: function() {
        return this._width;
      },
      set: function(v) {
        this._width = v;
        this._flagWidth = true;
      }
    },
    height: {
      enumerable: true,
      get: function() {
        return this._height;
      },
      set: function(v) {
        this._height = v;
        this._flagHeight = true;
      }
    },
    radius: {
      enumerable: true,
      get: function() {
        return this._radius;
      },
      set: function(v) {
        if (this._radius instanceof Vector) {
          this._radius.unbind(Events.Types.change, this._renderer.flagRadius);
        }
        this._radius = v;
        if (this._radius instanceof Vector) {
          this._radius.bind(Events.Types.change, this._renderer.flagRadius);
        }
        this._flagRadius = true;
      }
    }
  };
  function FlagRadius() {
    this._flagRadius = true;
  }

  // src/shapes/star.js
  var cos5 = Math.cos;
  var sin5 = Math.sin;
  var _Star = class extends Path {
    _flagInnerRadius = false;
    _flagOuterRadius = false;
    _flagSides = false;
    _innerRadius = 0;
    _outerRadius = 0;
    _sides = 0;
    constructor(x, y, innerRadius, outerRadius, sides) {
      if (arguments.length <= 3) {
        outerRadius = innerRadius;
        innerRadius = outerRadius / 2;
      }
      if (typeof sides !== "number" || sides <= 0) {
        sides = 5;
      }
      super();
      this._renderer.type = "star";
      for (let prop in proto19) {
        Object.defineProperty(this, prop, proto19[prop]);
      }
      this.closed = true;
      this.automatic = false;
      if (typeof innerRadius === "number") {
        this.innerRadius = innerRadius;
      }
      if (typeof outerRadius === "number") {
        this.outerRadius = outerRadius;
      }
      if (typeof sides === "number") {
        this.sides = sides;
      }
      this._update();
      if (typeof x === "number") {
        this.translation.x = x;
      }
      if (typeof y === "number") {
        this.translation.y = y;
      }
    }
    static fromObject(obj) {
      const star = new _Star().copy(obj);
      if ("id" in obj) {
        star.id = obj.id;
      }
      return star;
    }
    copy(star) {
      super.copy.call(this, star);
      for (let i = 0; i < _Star.Properties.length; i++) {
        const k = _Star.Properties[i];
        if (k in star && typeof star[k] === "number") {
          this[k] = star[k];
        }
      }
      return this;
    }
    _update() {
      if (this._flagVertices || this._flagInnerRadius || this._flagOuterRadius || this._flagSides) {
        const sides = this._sides * 2;
        const amount = sides + 1;
        let length = this.vertices.length;
        if (length > sides) {
          this.vertices.splice(sides - 1, length - sides);
          length = sides;
        }
        for (let i = 0; i < amount; i++) {
          const pct = (i + 0.5) / sides;
          const theta = TWO_PI * pct;
          const r = (!(i % 2) ? this._innerRadius : this._outerRadius) / 2;
          const x = r * cos5(theta);
          const y = r * sin5(theta);
          if (i >= length) {
            this.vertices.push(new Anchor(x, y));
          } else {
            this.vertices[i].set(x, y);
          }
          this.vertices[i].command = i === 0 ? Commands.move : Commands.line;
        }
      }
      super._update.call(this);
      return this;
    }
    flagReset() {
      this._flagInnerRadius = this._flagOuterRadius = this._flagSides = false;
      super.flagReset.call(this);
      return this;
    }
    clone(parent) {
      const ir = this.innerRadius;
      const or = this.outerRadius;
      const sides = this.sides;
      const clone = new _Star(0, 0, ir, or, sides);
      clone.translation.copy(this.translation);
      clone.rotation = this.rotation;
      clone.scale = this.scale;
      clone.skewX = this.skewX;
      clone.skewY = this.skewY;
      if (this.matrix.manual) {
        clone.matrix.copy(this.matrix);
      }
      for (let i = 0; i < Path.Properties.length; i++) {
        const k = Path.Properties[i];
        clone[k] = this[k];
      }
      if (parent) {
        parent.add(clone);
      }
      return clone;
    }
    toObject() {
      const object = super.toObject.call(this);
      object.renderer.type = "star";
      for (let i = 0; i < _Star.Properties.length; i++) {
        const k = _Star.Properties[i];
        object[k] = this[k];
      }
      return object;
    }
  };
  var Star = _Star;
  __publicField(Star, "Properties", ["innerRadius", "outerRadius", "sides"]);
  var proto19 = {
    innerRadius: {
      enumerable: true,
      get: function() {
        return this._innerRadius;
      },
      set: function(v) {
        this._innerRadius = v;
        this._flagInnerRadius = true;
      }
    },
    outerRadius: {
      enumerable: true,
      get: function() {
        return this._outerRadius;
      },
      set: function(v) {
        this._outerRadius = v;
        this._flagOuterRadius = true;
      }
    },
    sides: {
      enumerable: true,
      get: function() {
        return this._sides;
      },
      set: function(v) {
        this._sides = v;
        this._flagSides = true;
      }
    }
  };

  // src/text.js
  var canvas;
  var min2 = Math.min;
  var max2 = Math.max;
  if (root.document) {
    canvas = document.createElement("canvas");
  }
  var _Text = class extends Shape {
    _flagValue = true;
    _flagFamily = true;
    _flagSize = true;
    _flagLeading = true;
    _flagAlignment = true;
    _flagBaseline = true;
    _flagStyle = true;
    _flagWeight = true;
    _flagDecoration = true;
    _flagFill = true;
    _flagStroke = true;
    _flagLinewidth = true;
    _flagOpacity = true;
    _flagVisible = true;
    _flagMask = false;
    _flagClip = false;
    _flagDirection = true;
    _value = "";
    _family = "sans-serif";
    _size = 13;
    _leading = 17;
    _alignment = "center";
    _baseline = "middle";
    _style = "normal";
    _weight = 500;
    _decoration = "none";
    _direction = "ltr";
    _fill = "#000";
    _stroke = "none";
    _linewidth = 1;
    _opacity = 1;
    _visible = true;
    _mask = null;
    _clip = false;
    _dashes = null;
    constructor(message, x, y, styles) {
      super();
      for (let prop in proto20) {
        Object.defineProperty(this, prop, proto20[prop]);
      }
      this._renderer.type = "text";
      this._renderer.flagFill = FlagFill2.bind(this);
      this._renderer.flagStroke = FlagStroke2.bind(this);
      this.value = message;
      if (typeof x === "number") {
        this.translation.x = x;
      }
      if (typeof y === "number") {
        this.translation.y = y;
      }
      this.dashes = [];
      this.dashes.offset = 0;
      if (!_.isObject(styles)) {
        return this;
      }
      for (let i = 0; i < _Text.Properties.length; i++) {
        const property = _Text.Properties[i];
        if (property in styles) {
          this[property] = styles[property];
        }
      }
    }
    static Measure(text) {
      if (canvas) {
        const ctx = canvas.getContext("2d");
        ctx.font = [
          text._style,
          text._weight,
          `${text._size}px/${text._leading}px`,
          text._family
        ].join(" ");
        const metrics = ctx.measureText(text.value, 0, 0);
        const height = metrics.actualBoundingBoxDescent + metrics.actualBoundingBoxAscent;
        return {
          width: metrics.width,
          height
        };
      } else {
        const width = this.value.length * this.size * _Text.Ratio;
        const height = this.leading;
        console.warn(
          "Two.Text: unable to accurately measure text, so using an approximation."
        );
        return {
          width,
          height
        };
      }
    }
    static fromObject(obj) {
      const fill = typeof obj.fill === "string" ? obj.fill : getEffectFromObject(obj.fill);
      const stroke = typeof obj.stroke === "string" ? obj.stroke : getEffectFromObject(obj.stroke);
      const text = new _Text().copy({ ...obj, fill, stroke });
      if ("id" in obj) {
        text.id = obj.id;
      }
      return text;
    }
    copy(text) {
      super.copy.call(this, text);
      for (let i = 0; i < _Text.Properties.length; i++) {
        const k = _Text.Properties[i];
        if (k in text) {
          this[k] = text[k];
        }
      }
      return this;
    }
    clone(parent) {
      const clone = new _Text(this.value);
      clone.translation.copy(this.translation);
      clone.rotation = this.rotation;
      clone.scale = this.scale;
      for (let i = 0; i < _Text.Properties.length; i++) {
        const prop = _Text.Properties[i];
        clone[prop] = this[prop];
      }
      if (this.matrix.manual) {
        clone.matrix.copy(this.matrix);
      }
      if (parent) {
        parent.add(clone);
      }
      return clone._update();
    }
    toObject() {
      const result = super.toObject.call(this);
      result.renderer.type = "text";
      for (let i = 0; i < _Text.Properties.length; i++) {
        const prop = _Text.Properties[i];
        result[prop] = this[prop];
      }
      return result;
    }
    noFill() {
      this.fill = "none";
      return this;
    }
    noStroke() {
      this.stroke = "none";
      this.linewidth = 0;
      return this;
    }
    getBoundingClientRect(shallow) {
      let matrix;
      let left, right, top, bottom;
      this._update(true);
      matrix = shallow ? this.matrix : this.worldMatrix;
      const { width, height } = _Text.Measure(this);
      const border = (this._linewidth || 0) / 2;
      switch (this.alignment) {
        case "left":
          left = -border;
          right = width + border;
          break;
        case "right":
          left = -(width + border);
          right = border;
          break;
        default:
          left = -(width / 2 + border);
          right = width / 2 + border;
      }
      switch (this.baseline) {
        case "middle":
          top = -(height / 2 + border);
          bottom = height / 2 + border;
          break;
        default:
          top = -(height + border);
          bottom = border;
      }
      const [ax, ay] = matrix.multiply(left, top);
      const [bx, by] = matrix.multiply(left, bottom);
      const [cx, cy] = matrix.multiply(right, top);
      const [dx, dy] = matrix.multiply(right, bottom);
      top = min2(ay, by, cy, dy);
      left = min2(ax, bx, cx, dx);
      right = max2(ax, bx, cx, dx);
      bottom = max2(ay, by, cy, dy);
      return {
        top,
        left,
        right,
        bottom,
        width: right - left,
        height: bottom - top
      };
    }
    flagReset() {
      super.flagReset.call(this);
      this._flagValue = this._flagFamily = this._flagSize = this._flagLeading = this._flagAlignment = this._flagFill = this._flagStroke = this._flagLinewidth = this._flagOpacity = this._flagVisible = this._flagClip = this._flagDecoration = this._flagClassName = this._flagBaseline = this._flagWeight = this._flagStyle = this._flagDirection = false;
      return this;
    }
  };
  var Text = _Text;
  __publicField(Text, "Ratio", 0.6);
  __publicField(Text, "Properties", [
    "value",
    "family",
    "size",
    "leading",
    "alignment",
    "linewidth",
    "style",
    "weight",
    "decoration",
    "direction",
    "baseline",
    "opacity",
    "visible",
    "fill",
    "stroke",
    "dashes"
  ]);
  var proto20 = {
    value: {
      enumerable: true,
      get: function() {
        return this._value;
      },
      set: function(v) {
        this._value = v;
        this._flagValue = true;
      }
    },
    family: {
      enumerable: true,
      get: function() {
        return this._family;
      },
      set: function(v) {
        this._family = v;
        this._flagFamily = true;
      }
    },
    size: {
      enumerable: true,
      get: function() {
        return this._size;
      },
      set: function(v) {
        this._size = v;
        this._flagSize = true;
      }
    },
    leading: {
      enumerable: true,
      get: function() {
        return this._leading;
      },
      set: function(v) {
        this._leading = v;
        this._flagLeading = true;
      }
    },
    alignment: {
      enumerable: true,
      get: function() {
        return this._alignment;
      },
      set: function(v) {
        this._alignment = v;
        this._flagAlignment = true;
      }
    },
    linewidth: {
      enumerable: true,
      get: function() {
        return this._linewidth;
      },
      set: function(v) {
        this._linewidth = v;
        this._flagLinewidth = true;
      }
    },
    style: {
      enumerable: true,
      get: function() {
        return this._style;
      },
      set: function(v) {
        this._style = v;
        this._flagStyle = true;
      }
    },
    weight: {
      enumerable: true,
      get: function() {
        return this._weight;
      },
      set: function(v) {
        this._weight = v;
        this._flagWeight = true;
      }
    },
    decoration: {
      enumerable: true,
      get: function() {
        return this._decoration;
      },
      set: function(v) {
        this._decoration = v;
        this._flagDecoration = true;
      }
    },
    direction: {
      enumerable: true,
      get: function() {
        return this._direction;
      },
      set: function(v) {
        this._direction = v;
        this._flagDirection = true;
      }
    },
    baseline: {
      enumerable: true,
      get: function() {
        return this._baseline;
      },
      set: function(v) {
        this._baseline = v;
        this._flagBaseline = true;
      }
    },
    opacity: {
      enumerable: true,
      get: function() {
        return this._opacity;
      },
      set: function(v) {
        this._opacity = v;
        this._flagOpacity = true;
      }
    },
    visible: {
      enumerable: true,
      get: function() {
        return this._visible;
      },
      set: function(v) {
        this._visible = v;
        this._flagVisible = true;
      }
    },
    fill: {
      enumerable: true,
      get: function() {
        return this._fill;
      },
      set: function(f) {
        if (this._fill instanceof Gradient || this._fill instanceof LinearGradient || this._fill instanceof RadialGradient || this._fill instanceof Texture) {
          this._fill.unbind(Events.Types.change, this._renderer.flagFill);
        }
        this._fill = f;
        this._flagFill = true;
        if (this._fill instanceof Gradient || this._fill instanceof LinearGradient || this._fill instanceof RadialGradient || this._fill instanceof Texture) {
          this._fill.bind(Events.Types.change, this._renderer.flagFill);
        }
      }
    },
    stroke: {
      enumerable: true,
      get: function() {
        return this._stroke;
      },
      set: function(f) {
        if (this._stroke instanceof Gradient || this._stroke instanceof LinearGradient || this._stroke instanceof RadialGradient || this._stroke instanceof Texture) {
          this._stroke.unbind(Events.Types.change, this._renderer.flagStroke);
        }
        this._stroke = f;
        this._flagStroke = true;
        if (this._stroke instanceof Gradient || this._stroke instanceof LinearGradient || this._stroke instanceof RadialGradient || this._stroke instanceof Texture) {
          this._stroke.bind(Events.Types.change, this._renderer.flagStroke);
        }
      }
    },
    mask: {
      enumerable: true,
      get: function() {
        return this._mask;
      },
      set: function(v) {
        this._mask = v;
        this._flagMask = true;
        if (_.isObject(v) && !v.clip) {
          v.clip = true;
        }
      }
    },
    clip: {
      enumerable: true,
      get: function() {
        return this._clip;
      },
      set: function(v) {
        this._clip = v;
        this._flagClip = true;
      }
    },
    dashes: {
      enumerable: true,
      get: function() {
        return this._dashes;
      },
      set: function(v) {
        if (typeof v.offset !== "number") {
          v.offset = this.dashes && this._dashes.offset || 0;
        }
        this._dashes = v;
      }
    }
  };
  function FlagFill2() {
    this._flagFill = true;
  }
  function FlagStroke2() {
    this._flagStroke = true;
  }

  // src/group.js
  var min3 = Math.min;
  var max3 = Math.max;
  var _Group = class extends Shape {
    _flagAdditions = false;
    _flagSubtractions = false;
    _flagOrder = false;
    _flagOpacity = true;
    _flagBeginning = false;
    _flagEnding = false;
    _flagLength = false;
    _flagMask = false;
    _fill = "#fff";
    _stroke = "#000";
    _linewidth = 1;
    _opacity = 1;
    _visible = true;
    _cap = "round";
    _join = "round";
    _miter = 4;
    _closed = true;
    _curved = false;
    _automatic = true;
    _beginning = 0;
    _ending = 1;
    _length = 0;
    _mask = null;
    constructor(children) {
      super();
      for (let prop in proto21) {
        Object.defineProperty(this, prop, proto21[prop]);
      }
      this._renderer.type = "group";
      this.additions = [];
      this.subtractions = [];
      this.children = Array.isArray(children) ? children : Array.prototype.slice.call(arguments);
    }
    static InsertChildren(children) {
      for (let i = 0; i < children.length; i++) {
        replaceParent.call(this, children[i], this);
      }
    }
    static RemoveChildren(children) {
      for (let i = 0; i < children.length; i++) {
        replaceParent.call(this, children[i]);
      }
    }
    static OrderChildren(children) {
      this._flagOrder = true;
    }
    static fromObject(obj) {
      const group = new _Group();
      for (let i = 0; i < _Group.Properties.length; i++) {
        const k = _Group.Properties[i];
        if (k in obj) {
          if (/(fill|stroke)/i.test(k)) {
            group[k] = typeof obj[k] === "string" ? obj[k] : getEffectFromObject(obj[k]);
          } else {
            group[k] = obj[k];
          }
        }
      }
      if ("mask" in obj) {
        group.mask = getShapeFromObject(obj.mask);
      }
      if ("id" in obj) {
        group.id = obj.id;
      }
      group.children = obj.children.map(getShapeFromObject);
      return group;
      function getShapeFromObject(child) {
        if (child && child.renderer) {
          switch (child.renderer.type) {
            case "arc-segment":
              return ArcSegment.fromObject(child);
            case "circle":
              return Circle.fromObject(child);
            case "ellipse":
              return Ellipse.fromObject(child);
            case "points":
              return Points.fromObject(child);
            case "polygon":
              return Polygon.fromObject(child);
            case "rectangle":
              return Rectangle.fromObject(child);
            case "rounded-rectangle":
              return RoundedRectangle.fromObject(child);
            case "star":
              return Star.fromObject(child);
            case "path":
              return Path.fromObject(child);
            case "text":
              return Text.fromObject(child);
            case "group":
              return _Group.fromObject(child);
            case "shape":
              return Shape.fromObject(child);
            case "element":
              return Element.fromObject(child);
          }
        }
        return child;
      }
    }
    copy(group) {
      super.copy.call(this, group);
      console.warn("Two.Group.copy is not supported yet.");
      return this;
    }
    clone(parent) {
      const clone = new _Group();
      const children = this.children.map(function(child) {
        return child.clone();
      });
      clone.add(children);
      clone.opacity = this.opacity;
      if (this.mask) {
        clone.mask = this.mask;
      }
      clone.translation.copy(this.translation);
      clone.rotation = this.rotation;
      clone.scale = this.scale;
      clone.className = this.className;
      if (this.matrix.manual) {
        clone.matrix.copy(this.matrix);
      }
      if (parent) {
        parent.add(clone);
      }
      return clone._update();
    }
    toObject() {
      const result = super.toObject.call(this);
      result.renderer.type = "group";
      result.children = [];
      result.opacity = this.opacity;
      result.className = this.className;
      result.mask = this.mask ? this.mask.toObject() : null;
      _.each(
        this.children,
        (child, i) => {
          result.children[i] = child.toObject();
        },
        this
      );
      return result;
    }
    corner() {
      const rect = this.getBoundingClientRect(true);
      for (let i = 0; i < this.children.length; i++) {
        const child = this.children[i];
        child.translation.x -= rect.left;
        child.translation.y -= rect.top;
      }
      if (this.mask) {
        this.mask.translation.x -= rect.left;
        this.mask.translation.y -= rect.top;
      }
      return this;
    }
    center() {
      const rect = this.getBoundingClientRect(true);
      const cx = rect.left + rect.width / 2 - this.translation.x;
      const cy = rect.top + rect.height / 2 - this.translation.y;
      for (let i = 0; i < this.children.length; i++) {
        const child = this.children[i];
        if (child.isShape) {
          child.translation.x -= cx;
          child.translation.y -= cy;
        }
      }
      if (this.mask) {
        this.mask.translation.x -= cx;
        this.mask.translation.y -= cy;
      }
      return this;
    }
    getById(id) {
      let found = null;
      function search(node) {
        if (node.id === id) {
          return node;
        } else if (node.children) {
          if (node.children.ids[id]) {
            return node.children.ids[id];
          }
          for (let i = 0; i < node.children.length; i++) {
            found = search(node.children[i]);
            if (found) {
              return found;
            }
          }
        }
        return null;
      }
      return search(this);
    }
    getByClassName(className) {
      const found = [];
      function search(node) {
        if (Array.prototype.indexOf.call(node.classList, className) >= 0) {
          found.push(node);
        }
        if (node.children) {
          for (let i = 0; i < node.children.length; i++) {
            const child = node.children[i];
            search(child);
          }
        }
        return found;
      }
      return search(this);
    }
    getByType(type) {
      const found = [];
      function search(node) {
        if (node instanceof type) {
          found.push(node);
        }
        if (node.children) {
          for (let i = 0; i < node.children.length; i++) {
            const child = node.children[i];
            search(child);
          }
        }
        return found;
      }
      return search(this);
    }
    add(objects) {
      if (!(objects instanceof Array)) {
        objects = Array.prototype.slice.call(arguments);
      } else {
        objects = objects.slice();
      }
      for (let i = 0; i < objects.length; i++) {
        const child = objects[i];
        if (!(child && child.id)) {
          continue;
        }
        const index = Array.prototype.indexOf.call(this.children, child);
        if (index >= 0) {
          this.children.splice(index, 1);
        }
        this.children.push(child);
      }
      return this;
    }
    remove(objects) {
      const l = arguments.length, grandparent = this.parent;
      if (l <= 0 && grandparent) {
        grandparent.remove(this);
        return this;
      }
      if (!(objects instanceof Array)) {
        objects = Array.prototype.slice.call(arguments);
      } else {
        objects = objects.slice();
      }
      for (let i = 0; i < objects.length; i++) {
        const object = objects[i];
        if (!object || !this.children.ids[object.id]) {
          continue;
        }
        const index = this.children.indexOf(object);
        if (index >= 0) {
          this.children.splice(index, 1);
        }
      }
      return this;
    }
    getBoundingClientRect(shallow) {
      let rect, matrix, tc, lc, rc, bc;
      this._update(true);
      let left = Infinity, right = -Infinity, top = Infinity, bottom = -Infinity;
      const regex3 = /texture|gradient/i;
      matrix = shallow ? this.matrix : this.worldMatrix;
      for (let i = 0; i < this.children.length; i++) {
        const child = this.children[i];
        if (!child.visible || regex3.test(child._renderer.type)) {
          continue;
        }
        rect = child.getBoundingClientRect(shallow);
        tc = typeof rect.top !== "number" || _.isNaN(rect.top) || !isFinite(rect.top);
        lc = typeof rect.left !== "number" || _.isNaN(rect.left) || !isFinite(rect.left);
        rc = typeof rect.right !== "number" || _.isNaN(rect.right) || !isFinite(rect.right);
        bc = typeof rect.bottom !== "number" || _.isNaN(rect.bottom) || !isFinite(rect.bottom);
        if (tc || lc || rc || bc) {
          continue;
        }
        if (shallow) {
          const [ax, ay] = matrix.multiply(rect.left, rect.top);
          const [bx, by] = matrix.multiply(rect.right, rect.top);
          const [cx, cy] = matrix.multiply(rect.left, rect.bottom);
          const [dx, dy] = matrix.multiply(rect.right, rect.bottom);
          top = min3(ay, by, cy, dy, top);
          left = min3(ax, bx, cx, dx, left);
          right = max3(ax, bx, cx, dx, right);
          bottom = max3(ay, by, cy, dy, bottom);
        } else {
          top = min3(rect.top, top);
          left = min3(rect.left, left);
          right = max3(rect.right, right);
          bottom = max3(rect.bottom, bottom);
        }
      }
      return {
        top,
        left,
        right,
        bottom,
        width: right - left,
        height: bottom - top
      };
    }
    noFill() {
      this.children.forEach(function(child) {
        child.noFill();
      });
      return this;
    }
    noStroke() {
      this.children.forEach(function(child) {
        child.noStroke();
      });
      return this;
    }
    subdivide() {
      const args = arguments;
      this.children.forEach(function(child) {
        child.subdivide.apply(child, args);
      });
      return this;
    }
    _update() {
      let i, l, child;
      if (this._flagBeginning || this._flagEnding) {
        const beginning = Math.min(this._beginning, this._ending);
        const ending = Math.max(this._beginning, this._ending);
        const length = this.length;
        let sum = 0;
        const bd = beginning * length;
        const ed = ending * length;
        for (i = 0; i < this.children.length; i++) {
          child = this.children[i];
          l = child.length;
          if (bd > sum + l) {
            child.beginning = 1;
            child.ending = 1;
          } else if (ed < sum) {
            child.beginning = 0;
            child.ending = 0;
          } else if (bd > sum && bd < sum + l) {
            child.beginning = (bd - sum) / l;
            child.ending = 1;
          } else if (ed > sum && ed < sum + l) {
            child.beginning = 0;
            child.ending = (ed - sum) / l;
          } else {
            child.beginning = 0;
            child.ending = 1;
          }
          sum += l;
        }
      }
      return super._update.apply(this, arguments);
    }
    flagReset() {
      if (this._flagAdditions) {
        this.additions.length = 0;
        this._flagAdditions = false;
      }
      if (this._flagSubtractions) {
        this.subtractions.length = 0;
        this._flagSubtractions = false;
      }
      this._flagOrder = this._flagMask = this._flagOpacity = this._flagBeginning = this._flagEnding = false;
      super.flagReset.call(this);
      return this;
    }
  };
  var Group = _Group;
  __publicField(Group, "Children", Children);
  __publicField(Group, "Properties", [
    "fill",
    "stroke",
    "linewidth",
    "cap",
    "join",
    "miter",
    "closed",
    "curved",
    "automatic"
  ]);
  var proto21 = {
    visible: {
      enumerable: true,
      get: function() {
        return this._visible;
      },
      set: function(v) {
        this._flagVisible = this._visible !== v || this._flagVisible;
        this._visible = v;
      }
    },
    opacity: {
      enumerable: true,
      get: function() {
        return this._opacity;
      },
      set: function(v) {
        this._flagOpacity = this._opacity !== v || this._flagOpacity;
        this._opacity = v;
      }
    },
    beginning: {
      enumerable: true,
      get: function() {
        return this._beginning;
      },
      set: function(v) {
        this._flagBeginning = this._beginning !== v || this._flagBeginning;
        this._beginning = v;
      }
    },
    ending: {
      enumerable: true,
      get: function() {
        return this._ending;
      },
      set: function(v) {
        this._flagEnding = this._ending !== v || this._flagEnding;
        this._ending = v;
      }
    },
    length: {
      enumerable: true,
      get: function() {
        if (this._flagLength || this._length <= 0) {
          this._length = 0;
          if (!this.children) {
            return this._length;
          }
          for (let i = 0; i < this.children.length; i++) {
            const child = this.children[i];
            this._length += child.length;
          }
        }
        return this._length;
      }
    },
    fill: {
      enumerable: true,
      get: function() {
        return this._fill;
      },
      set: function(v) {
        this._fill = v;
        for (let i = 0; i < this.children.length; i++) {
          const child = this.children[i];
          child.fill = v;
        }
      }
    },
    stroke: {
      enumerable: true,
      get: function() {
        return this._stroke;
      },
      set: function(v) {
        this._stroke = v;
        for (let i = 0; i < this.children.length; i++) {
          const child = this.children[i];
          child.stroke = v;
        }
      }
    },
    linewidth: {
      enumerable: true,
      get: function() {
        return this._linewidth;
      },
      set: function(v) {
        this._linewidth = v;
        for (let i = 0; i < this.children.length; i++) {
          const child = this.children[i];
          child.linewidth = v;
        }
      }
    },
    join: {
      enumerable: true,
      get: function() {
        return this._join;
      },
      set: function(v) {
        this._join = v;
        for (let i = 0; i < this.children.length; i++) {
          const child = this.children[i];
          child.join = v;
        }
      }
    },
    miter: {
      enumerable: true,
      get: function() {
        return this._miter;
      },
      set: function(v) {
        this._miter = v;
        for (let i = 0; i < this.children.length; i++) {
          const child = this.children[i];
          child.miter = v;
        }
      }
    },
    cap: {
      enumerable: true,
      get: function() {
        return this._cap;
      },
      set: function(v) {
        this._cap = v;
        for (let i = 0; i < this.children.length; i++) {
          const child = this.children[i];
          child.cap = v;
        }
      }
    },
    closed: {
      enumerable: true,
      get: function() {
        return this._closed;
      },
      set: function(v) {
        this._closed = v;
        for (let i = 0; i < this.children.length; i++) {
          const child = this.children[i];
          child.closed = v;
        }
      }
    },
    curved: {
      enumerable: true,
      get: function() {
        return this._curved;
      },
      set: function(v) {
        this._curved = v;
        for (let i = 0; i < this.children.length; i++) {
          const child = this.children[i];
          child.curved = v;
        }
      }
    },
    automatic: {
      enumerable: true,
      get: function() {
        return this._automatic;
      },
      set: function(v) {
        this._automatic = v;
        for (let i = 0; i < this.children.length; i++) {
          const child = this.children[i];
          child.automatic = v;
        }
      }
    },
    children: {
      enumerable: true,
      get: function() {
        return this._children;
      },
      set: function(children) {
        const insertChildren = Group.InsertChildren.bind(this);
        const removeChildren = Group.RemoveChildren.bind(this);
        const orderChildren = Group.OrderChildren.bind(this);
        if (this._children) {
          this._children.unbind();
          if (this._children.length > 0) {
            removeChildren(this._children);
          }
        }
        this._children = new Children(children);
        this._children.bind(Events.Types.insert, insertChildren);
        this._children.bind(Events.Types.remove, removeChildren);
        this._children.bind(Events.Types.order, orderChildren);
        if (children.length > 0) {
          insertChildren(children);
        }
      }
    },
    mask: {
      enumerable: true,
      get: function() {
        return this._mask;
      },
      set: function(v) {
        this._mask = v;
        this._flagMask = true;
        if (_.isObject(v) && !v.clip) {
          v.clip = true;
        }
      }
    }
  };
  function replaceParent(child, newParent) {
    const parent = child.parent;
    let index;
    if (parent === newParent) {
      add();
      return;
    }
    if (parent && parent.children.ids[child.id]) {
      index = Array.prototype.indexOf.call(parent.children, child);
      parent.children.splice(index, 1);
      splice();
    }
    if (newParent) {
      add();
      return;
    }
    splice();
    if (parent._flagAdditions && parent.additions.length === 0) {
      parent._flagAdditions = false;
    }
    if (parent._flagSubtractions && parent.subtractions.length === 0) {
      parent._flagSubtractions = false;
    }
    delete child.parent;
    function add() {
      if (newParent.subtractions.length > 0) {
        index = Array.prototype.indexOf.call(newParent.subtractions, child);
        if (index >= 0) {
          newParent.subtractions.splice(index, 1);
        }
      }
      if (newParent.additions.length > 0) {
        index = Array.prototype.indexOf.call(newParent.additions, child);
        if (index >= 0) {
          newParent.additions.splice(index, 1);
        }
      }
      child.parent = newParent;
      newParent.additions.push(child);
      newParent._flagAdditions = true;
    }
    function splice() {
      index = Array.prototype.indexOf.call(parent.additions, child);
      if (index >= 0) {
        parent.additions.splice(index, 1);
      }
      index = Array.prototype.indexOf.call(parent.subtractions, child);
      if (index < 0) {
        parent.subtractions.push(child);
        parent._flagSubtractions = true;
      }
    }
  }

  // src/shapes/line.js
  var Line = class extends Path {
    constructor(x1, y1, x2, y2) {
      const points = [new Anchor(x1, y1), new Anchor(x2, y2)];
      super(points);
      for (let prop in proto22) {
        Object.defineProperty(this, prop, proto22[prop]);
      }
      this.vertices[0].command = Commands.move;
      this.vertices[1].command = Commands.line;
      this.automatic = false;
    }
  };
  __publicField(Line, "Properties", ["left", "right"]);
  var proto22 = {
    left: {
      enumerable: true,
      get: function() {
        return this.vertices[0];
      },
      set: function(v) {
        if (_.isObject(v)) {
          this.vertices.splice(0, 1, v);
        } else {
          const error = new TwoError("Two.Line.x argument is not an object.");
          console.warn(error.name, error.message);
        }
      }
    },
    right: {
      enumerable: true,
      get: function() {
        return this.vertices[1];
      },
      set: function(v) {
        if (_.isObject(v)) {
          this.vertices.splice(1, 1, v);
        } else {
          const error = new TwoError("Two.Line.y argument is not an object.");
          console.warn(error.name, error.message);
        }
      }
    }
  };

  // src/utils/interpret-svg.js
  var regex2 = {
    path: /[+-]?(?:\d*\.\d+|\d+)(?:[eE][+-]\d+)?/g,
    cssBackgroundImage: /url\(['"]?#([\w\d-_]*)['"]?\)/i,
    unitSuffix: /[a-zA-Z%]*/i
  };
  var alignments = {
    start: "left",
    middle: "center",
    end: "right"
  };
  var reservedAttributesToRemove = [
    "id",
    "class",
    "transform",
    "xmlns",
    "viewBox"
  ];
  var overwriteAttrs = ["x", "y", "width", "height", "href", "xlink:href"];
  function getAlignment(anchor2) {
    return alignments[anchor2];
  }
  function getBaseline(node) {
    const a = node.getAttribute("dominant-baseline");
    const b = node.getAttribute("alignment-baseline");
    return a || b;
  }
  function getTagName(tag) {
    return tag.replace(/svg:/gi, "").toLowerCase();
  }
  function applyTransformsToVector(transforms, vector3) {
    vector3.x += transforms.translateX;
    vector3.y += transforms.translateY;
    vector3.x *= transforms.scaleX;
    vector3.y *= transforms.scaleY;
    if (transforms.rotation !== 0) {
      const l = vector3.length();
      vector3.x = l * Math.cos(transforms.rotation);
      vector3.y = l * Math.sin(transforms.rotation);
    }
  }
  function extractCSSText(text, styles) {
    if (!styles) {
      styles = {};
    }
    const commands = text.split(";");
    for (let i = 0; i < commands.length; i++) {
      const command = commands[i].split(":");
      const name = command[0];
      const value = command[1];
      if (typeof name === "undefined" || typeof value === "undefined") {
        continue;
      }
      const trimmedName = name.replace(/\s/g, "");
      const trimmedValue = value.replace(/\s/g, "");
      styles[trimmedName] = trimmedValue;
    }
    return styles;
  }
  function getSvgStyles(node) {
    const styles = {};
    const attributes = getSvgAttributes(node);
    const length = Math.max(attributes.length, node.style.length);
    for (let i = 0; i < length; i++) {
      const command = node.style[i];
      const attribute = attributes[i];
      if (command) {
        styles[command] = node.style[command];
      }
      if (attribute) {
        styles[attribute] = node.getAttribute(attribute);
      }
    }
    return styles;
  }
  function getSvgAttributes(node) {
    const attributes = node.getAttributeNames();
    for (let i = 0; i < reservedAttributesToRemove.length; i++) {
      const keyword = reservedAttributesToRemove[i];
      const index = Array.prototype.indexOf.call(attributes, keyword);
      if (index >= 0) {
        attributes.splice(index, 1);
      }
    }
    return attributes;
  }
  function applySvgViewBox(node, value) {
    const elements = value.split(/[\s,]/);
    const x = -parseFloat(elements[0]);
    const y = -parseFloat(elements[1]);
    const width = parseFloat(elements[2]);
    const height = parseFloat(elements[3]);
    if (x && y) {
      for (let i = 0; i < node.children.length; i++) {
        const child = node.children[i];
        if ("translation" in child) {
          child.translation.add(x, y);
        } else if ("x" in child) {
          child.x = x;
        } else if ("y" in child) {
          child.y = y;
        }
      }
    }
    const xExists = typeof node.x === "number";
    const yExists = typeof node.y === "number";
    const widthExists = typeof node.width === "number";
    const heightExists = typeof node.height === "number";
    if (xExists) {
      node.translation.x += node.x;
    }
    if (yExists) {
      node.translation.y += node.y;
    }
    if (widthExists || heightExists) {
      node.scale = new Vector(1, 1);
    }
    if (widthExists) {
      node.scale.x = node.width / width;
    }
    if (heightExists) {
      node.scale.y = node.height / height;
    }
    node.mask = new Rectangle(0, 0, width, height);
    node.mask.origin.set(-width / 2, -height / 2);
    return node;
  }
  function applySvgAttributes(node, elem, parentStyles) {
    const styles = {}, attributes = {}, extracted = {};
    let i, m, key, value, prop, attr;
    let transforms, x, y;
    let id, scene, ref, tagName;
    let ca, cb, cc, error;
    if (node === null) {
      return styles;
    }
    if (root.getComputedStyle) {
      const computedStyles = root.getComputedStyle(node);
      i = computedStyles.length;
      while (i--) {
        key = computedStyles[i];
        value = computedStyles[key];
        if (typeof value !== "undefined") {
          styles[key] = value;
        }
      }
    }
    for (i = 0; i < node.attributes.length; i++) {
      attr = node.attributes[i];
      if (/style/i.test(attr.nodeName)) {
        extractCSSText(attr.value, extracted);
      } else {
        attributes[attr.nodeName] = attr.value;
      }
    }
    if (typeof styles.opacity !== "undefined") {
      styles["stroke-opacity"] = styles.opacity;
      styles["fill-opacity"] = styles.opacity;
      delete styles.opacity;
    }
    if (parentStyles) {
      _.defaults(styles, parentStyles);
    }
    _.extend(styles, extracted, attributes);
    styles.visible = !(typeof styles.display === "undefined" && /none/i.test(styles.display)) || typeof styles.visibility === "undefined" && /hidden/i.test(styles.visibility);
    for (key in styles) {
      value = styles[key];
      switch (key) {
        case "gradientTransform":
          if (/none/i.test(value))
            break;
          m = node.gradientTransform && node.gradientTransform.baseVal && node.gradientTransform.baseVal.length > 0 ? node.gradientTransform.baseVal[0].matrix : node.getCTM ? node.getCTM() : null;
          if (m === null)
            break;
          transforms = decomposeMatrix(m);
          switch (elem._renderer.type) {
            case "linear-gradient":
              applyTransformsToVector(transforms, elem.left);
              applyTransformsToVector(transforms, elem.right);
              break;
            case "radial-gradient":
              elem.center.x += transforms.translateX;
              elem.center.y += transforms.translateY;
              elem.focal.x += transforms.translateX;
              elem.focal.y += transforms.translateY;
              elem.radius *= Math.max(transforms.scaleX, transforms.scaleY);
              break;
          }
          break;
        case "transform":
          if (/none/i.test(value))
            break;
          m = node.transform && node.transform.baseVal && node.transform.baseVal.length > 0 ? node.transform.baseVal[0].matrix : node.getCTM ? node.getCTM() : null;
          if (m === null)
            break;
          if (Constants.AutoCalculateImportedMatrices) {
            transforms = decomposeMatrix(m);
            elem.translation.set(transforms.translateX, transforms.translateY);
            elem.rotation = Math.PI * (transforms.rotation / 180);
            elem.scale = new Vector(transforms.scaleX, transforms.scaleY);
            x = parseFloat((styles.x + "").replace("px"));
            y = parseFloat((styles.y + "").replace("px"));
            if (x) {
              elem.translation.x = x;
            }
            if (y) {
              elem.translation.y = y;
            }
          } else {
            m = node.getCTM();
            elem._matrix.manual = true;
            elem._matrix.set(m.a, m.b, m.c, m.d, m.e, m.f);
          }
          break;
        case "visible":
          if (elem instanceof Group) {
            elem._visible = value;
            break;
          }
          elem.visible = value;
          break;
        case "stroke-linecap":
          if (elem instanceof Group) {
            elem._cap = value;
            break;
          }
          elem.cap = value;
          break;
        case "stroke-linejoin":
          if (elem instanceof Group) {
            elem._join = value;
            break;
          }
          elem.join = value;
          break;
        case "stroke-miterlimit":
          if (elem instanceof Group) {
            elem._miter = value;
            break;
          }
          elem.miter = value;
          break;
        case "stroke-width":
          if (elem instanceof Group) {
            elem._linewidth = parseFloat(value);
            break;
          }
          elem.linewidth = parseFloat(value);
          break;
        case "opacity":
        case "stroke-opacity":
        case "fill-opacity":
          if (elem instanceof Group) {
            elem._opacity = parseFloat(value);
            break;
          }
          elem.opacity = parseFloat(value);
          break;
        case "clip-path":
          if (regex2.cssBackgroundImage.test(value)) {
            id = value.replace(regex2.cssBackgroundImage, "$1");
            if (read.defs.current && read.defs.current.contains(id)) {
              ref = read.defs.current.get(id);
              if (ref && ref.childNodes.length > 0) {
                ref = ref.childNodes[0];
                tagName = getTagName(ref.nodeName);
                elem.mask = read[tagName].call(this, ref, {});
                switch (elem._renderer.type) {
                  case "text":
                  case "path":
                    elem.position.add(elem.mask.position);
                    elem.mask.position.clear();
                    break;
                }
              }
            }
          }
          break;
        case "fill":
        case "stroke":
          prop = (elem instanceof Group ? "_" : "") + key;
          if (regex2.cssBackgroundImage.test(value)) {
            id = value.replace(regex2.cssBackgroundImage, "$1");
            if (read.defs.current && read.defs.current.contains(id)) {
              ref = read.defs.current.get(id);
              if (!ref.object) {
                tagName = getTagName(ref.nodeName);
                ref.object = read[tagName].call(this, ref, {});
              }
              ref = ref.object;
            } else {
              scene = getScene(this);
              ref = scene.getById(id);
            }
            elem[prop] = ref;
          } else {
            elem[prop] = value;
          }
          break;
        case "id":
          elem.id = value;
          break;
        case "class":
        case "className":
          elem.classList = value.split(" ");
          elem._flagClassName = true;
          break;
        case "x":
        case "y":
          ca = elem instanceof Gradient;
          cb = elem instanceof LinearGradient;
          cc = elem instanceof RadialGradient;
          if (ca || cb || cc) {
            break;
          }
          if (value.match("[a-z%]$") && !value.endsWith("px")) {
            error = new TwoError(
              "only pixel values are supported with the " + key + " attribute."
            );
            console.warn(error.name, error.message);
          }
          elem.translation[key] = parseFloat(value);
          break;
        case "font-family":
          if (elem instanceof Text) {
            elem.family = value;
          }
          break;
        case "font-size":
          if (elem instanceof Text) {
            if (value.match("[a-z%]$") && !value.endsWith("px")) {
              error = new TwoError(
                "only pixel values are supported with the " + key + " attribute."
              );
              console.warn(error.name, error.message);
            }
            elem.size = parseFloat(value);
          }
          break;
        case "font-weight":
          if (elem instanceof Text) {
            elem.weight = value;
          }
          break;
        case "font-style":
          if (elem instanceof Text) {
            elem.style = value;
          }
          break;
        case "text-decoration":
          if (elem instanceof Text) {
            elem.decoration = value;
          }
          break;
        case "line-height":
          if (elem instanceof Text) {
            elem.leading = value;
          }
          break;
      }
    }
    if (Object.keys(node.dataset).length)
      elem.dataset = node.dataset;
    return styles;
  }
  function updateDefsCache(node, defsCache) {
    for (let i = 0, l = node.childNodes.length; i < l; i++) {
      const n = node.childNodes[i];
      if (!n.id)
        continue;
      const tagName = getTagName(node.nodeName);
      if (tagName === "#text")
        continue;
      defsCache.add(n.id, n);
    }
  }
  function getScene(node) {
    while (node.parent) {
      node = node.parent;
    }
    return node.scene;
  }
  var read = {
    svg: function(node) {
      const defs = read.defs.current = new Registry();
      const elements = node.getElementsByTagName("defs");
      for (let i = 0; i < elements.length; i++) {
        updateDefsCache(elements[i], defs);
      }
      const svg2 = read.g.call(this, node);
      const viewBox = node.getAttribute("viewBox");
      const x = node.getAttribute("x");
      const y = node.getAttribute("y");
      const width = node.getAttribute("width");
      const height = node.getAttribute("height");
      svg2.defs = defs;
      const viewBoxExists = viewBox !== null;
      const xExists = x !== null;
      const yExists = y !== null;
      const widthExists = width !== null;
      const heightExists = height !== null;
      if (xExists) {
        svg2.x = parseFloat(x.replace(regex2.unitSuffix, ""));
      }
      if (yExists) {
        svg2.y = parseFloat(y.replace(regex2.unitSuffix, ""));
      }
      if (widthExists) {
        svg2.width = parseFloat(width.replace(regex2.unitSuffix, ""));
      }
      if (heightExists) {
        svg2.height = parseFloat(height.replace(regex2.unitSuffix, ""));
      }
      if (viewBoxExists) {
        applySvgViewBox(svg2, viewBox);
      }
      delete read.defs.current;
      return svg2;
    },
    defs: function(node) {
      return null;
    },
    use: function(node, styles) {
      let error;
      const href = node.getAttribute("href") || node.getAttribute("xlink:href");
      if (!href) {
        error = new TwoError("encountered <use /> with no href.");
        console.warn(error.name, error.message);
        return null;
      }
      const id = href.slice(1);
      if (!read.defs.current.contains(id)) {
        error = new TwoError(
          "unable to find element for reference " + href + "."
        );
        console.warn(error.name, error.message);
        return null;
      }
      const template = read.defs.current.get(id);
      const fullNode = template.cloneNode(true);
      for (let i = 0; i < node.attributes.length; i++) {
        const attr = node.attributes[i];
        const ca = overwriteAttrs.includes(attr.nodeName);
        const cb = !fullNode.hasAttribute(attr.nodeName);
        if (ca || cb) {
          fullNode.setAttribute(attr.nodeName, attr.value);
        }
      }
      const tagName = getTagName(fullNode.nodeName);
      return read[tagName].call(this, fullNode, styles);
    },
    g: function(node, parentStyles) {
      const group = new Group();
      applySvgAttributes.call(this, node, group, parentStyles);
      this.add(group);
      const styles = getSvgStyles.call(this, node);
      for (let i = 0, l = node.childNodes.length; i < l; i++) {
        const n = node.childNodes[i];
        const tag = n.nodeName;
        if (!tag)
          return;
        const tagName = getTagName(tag);
        if (tagName in read) {
          const o = read[tagName].call(group, n, styles);
          if (!!o && !o.parent) {
            group.add(o);
          }
        }
      }
      return group;
    },
    polygon: function(node, parentStyles) {
      let points;
      if (typeof node === "string") {
        points = node;
      } else {
        points = node.getAttribute("points");
      }
      const verts = [];
      points.replace(
        /(-?[\d.eE-]+)[,|\s](-?[\d.eE-]+)/g,
        function(match, p1, p2) {
          verts.push(new Anchor(parseFloat(p1), parseFloat(p2)));
        }
      );
      const poly = new Path(verts, true);
      poly.stroke = "none";
      poly.fill = "black";
      applySvgAttributes.call(this, node, poly, parentStyles);
      return poly;
    },
    polyline: function(node, parentStyles) {
      const poly = read.polygon.call(this, node, parentStyles);
      poly.closed = false;
      return poly;
    },
    path: function(node, parentStyles) {
      let path;
      if (typeof node === "string") {
        path = node;
        node = null;
      } else {
        path = node.getAttribute("d");
      }
      let points = [];
      let closed2 = false, relative = false;
      if (path) {
        let coord = new Anchor();
        let control, coords;
        let commands = path.match(/[a-df-z][^a-df-z]*/gi);
        const last = commands.length - 1;
        _.each(commands.slice(0), function(command, i) {
          const items = command.slice(1).trim().match(regex2.path);
          const type = command[0];
          const lower = type.toLowerCase();
          let bin, j, l, ct, times;
          const result = [];
          if (i === 0) {
            commands = [];
          }
          switch (lower) {
            case "h":
            case "v":
              if (items.length > 1) {
                bin = 1;
              }
              break;
            case "m":
            case "l":
            case "t":
              if (items.length > 2) {
                bin = 2;
              }
              break;
            case "s":
            case "q":
              if (items.length > 4) {
                bin = 4;
              }
              break;
            case "c":
              if (items.length > 6) {
                bin = 6;
              }
              break;
            case "a":
              if (items.length > 7) {
                bin = 7;
              }
              break;
          }
          if (bin) {
            for (j = 0, l = items.length, times = 0; j < l; j += bin) {
              ct = type;
              if (times > 0) {
                switch (type) {
                  case "m":
                    ct = "l";
                    break;
                  case "M":
                    ct = "L";
                    break;
                }
              }
              result.push(ct + items.slice(j, j + bin).join(" "));
              times++;
            }
            commands = Array.prototype.concat.apply(commands, result);
          } else {
            commands.push(command);
          }
        });
        _.each(commands, function(command, i) {
          let result, x, y;
          const type = command[0];
          const lower = type.toLowerCase();
          coords = command.slice(1).trim().match(regex2.path);
          relative = type === lower;
          let x1, y1, x2, y2, x3, y3, x4, y4, reflection;
          let a, b;
          let anchor2, rx, ry, xAxisRotation, largeArcFlag, sweepFlag;
          switch (lower) {
            case "z":
              if (i >= last) {
                closed2 = true;
              } else {
                x = coord.x;
                y = coord.y;
                result = new Anchor(
                  x,
                  y,
                  void 0,
                  void 0,
                  void 0,
                  void 0,
                  Commands.close
                );
                for (let j = points.length - 1; j >= 0; j--) {
                  const point = points[j];
                  if (/m/i.test(point.command)) {
                    coord = point;
                    break;
                  }
                }
              }
              break;
            case "m":
            case "l":
              control = void 0;
              x = parseFloat(coords[0]);
              y = parseFloat(coords[1]);
              result = new Anchor(
                x,
                y,
                void 0,
                void 0,
                void 0,
                void 0,
                /m/i.test(lower) ? Commands.move : Commands.line
              );
              if (relative) {
                result.addSelf(coord);
              }
              coord = result;
              break;
            case "h":
            case "v":
              a = /h/i.test(lower) ? "x" : "y";
              b = /x/i.test(a) ? "y" : "x";
              result = new Anchor(
                void 0,
                void 0,
                void 0,
                void 0,
                void 0,
                void 0,
                Commands.line
              );
              result[a] = parseFloat(coords[0]);
              result[b] = coord[b];
              if (relative) {
                result[a] += coord[a];
              }
              coord = result;
              break;
            case "c":
            case "s":
              x1 = coord.x;
              y1 = coord.y;
              if (!control) {
                control = new Vector();
              }
              if (/c/i.test(lower)) {
                x2 = parseFloat(coords[0]);
                y2 = parseFloat(coords[1]);
                x3 = parseFloat(coords[2]);
                y3 = parseFloat(coords[3]);
                x4 = parseFloat(coords[4]);
                y4 = parseFloat(coords[5]);
              } else {
                reflection = getReflection(coord, control, relative);
                x2 = reflection.x;
                y2 = reflection.y;
                x3 = parseFloat(coords[0]);
                y3 = parseFloat(coords[1]);
                x4 = parseFloat(coords[2]);
                y4 = parseFloat(coords[3]);
              }
              if (relative) {
                x2 += x1;
                y2 += y1;
                x3 += x1;
                y3 += y1;
                x4 += x1;
                y4 += y1;
              }
              coord.controls.right.set(x2 - coord.x, y2 - coord.y);
              result = new Anchor(
                x4,
                y4,
                x3 - x4,
                y3 - y4,
                void 0,
                void 0,
                Commands.curve
              );
              coord = result;
              control = result.controls.left;
              break;
            case "t":
            case "q":
              x1 = coord.x;
              y1 = coord.y;
              if (!control) {
                control = new Vector();
              }
              if (/q/i.test(lower)) {
                x2 = parseFloat(coords[0]);
                y2 = parseFloat(coords[1]);
                x3 = parseFloat(coords[0]);
                y3 = parseFloat(coords[1]);
                x4 = parseFloat(coords[2]);
                y4 = parseFloat(coords[3]);
              } else {
                reflection = getReflection(coord, control, relative);
                x2 = reflection.x;
                y2 = reflection.y;
                x3 = reflection.x;
                y3 = reflection.y;
                x4 = parseFloat(coords[0]);
                y4 = parseFloat(coords[1]);
              }
              if (relative) {
                x2 += x1;
                y2 += y1;
                x3 += x1;
                y3 += y1;
                x4 += x1;
                y4 += y1;
              }
              coord.controls.right.set(
                (x2 - coord.x) * 0.33,
                (y2 - coord.y) * 0.33
              );
              result = new Anchor(
                x4,
                y4,
                x3 - x4,
                y3 - y4,
                void 0,
                void 0,
                Commands.curve
              );
              coord = result;
              control = result.controls.left;
              break;
            case "a":
              x1 = coord.x;
              y1 = coord.y;
              rx = parseFloat(coords[0]);
              ry = parseFloat(coords[1]);
              xAxisRotation = parseFloat(coords[2]);
              largeArcFlag = parseFloat(coords[3]);
              sweepFlag = parseFloat(coords[4]);
              x4 = parseFloat(coords[5]);
              y4 = parseFloat(coords[6]);
              if (relative) {
                x4 += x1;
                y4 += y1;
              }
              anchor2 = new Anchor(x4, y4);
              anchor2.command = Commands.arc;
              anchor2.rx = rx;
              anchor2.ry = ry;
              anchor2.xAxisRotation = xAxisRotation;
              anchor2.largeArcFlag = largeArcFlag;
              anchor2.sweepFlag = sweepFlag;
              result = anchor2;
              coord = anchor2;
              control = void 0;
              break;
          }
          if (result) {
            if (Array.isArray(result)) {
              points = points.concat(result);
            } else {
              points.push(result);
            }
          }
        });
      }
      path = new Path(points, closed2, void 0, true);
      path.stroke = "none";
      path.fill = "black";
      const rect = path.getBoundingClientRect(true);
      rect.centroid = {
        x: rect.left + rect.width / 2,
        y: rect.top + rect.height / 2
      };
      _.each(path.vertices, function(v) {
        v.subSelf(rect.centroid);
      });
      applySvgAttributes.call(this, node, path, parentStyles);
      path.translation.addSelf(rect.centroid);
      return path;
    },
    circle: function(node, parentStyles) {
      const x = parseFloat(node.getAttribute("cx"));
      const y = parseFloat(node.getAttribute("cy"));
      const r = parseFloat(node.getAttribute("r"));
      const circle = new Circle(0, 0, r);
      circle.stroke = "none";
      circle.fill = "black";
      applySvgAttributes.call(this, node, circle, parentStyles);
      circle.translation.x = x;
      circle.translation.y = y;
      return circle;
    },
    ellipse: function(node, parentStyles) {
      const x = parseFloat(node.getAttribute("cx"));
      const y = parseFloat(node.getAttribute("cy"));
      const width = parseFloat(node.getAttribute("rx"));
      const height = parseFloat(node.getAttribute("ry"));
      const ellipse = new Ellipse(0, 0, width, height);
      ellipse.stroke = "none";
      ellipse.fill = "black";
      applySvgAttributes.call(this, node, ellipse, parentStyles);
      ellipse.translation.x = x;
      ellipse.translation.y = y;
      return ellipse;
    },
    rect: function(node, parentStyles) {
      const rx = parseFloat(node.getAttribute("rx"));
      const ry = parseFloat(node.getAttribute("ry"));
      if (!_.isNaN(rx) || !_.isNaN(ry)) {
        return read["rounded-rect"](node);
      }
      const width = parseFloat(node.getAttribute("width"));
      const height = parseFloat(node.getAttribute("height"));
      const w2 = width / 2;
      const h2 = height / 2;
      const rect = new Rectangle(0, 0, width, height);
      rect.stroke = "none";
      rect.fill = "black";
      applySvgAttributes.call(this, node, rect, parentStyles);
      rect.translation.x += w2;
      rect.translation.y += h2;
      return rect;
    },
    "rounded-rect": function(node, parentStyles) {
      const rx = parseFloat(node.getAttribute("rx")) || 0;
      const ry = parseFloat(node.getAttribute("ry")) || 0;
      const width = parseFloat(node.getAttribute("width"));
      const height = parseFloat(node.getAttribute("height"));
      const w2 = width / 2;
      const h2 = height / 2;
      const radius = new Vector(rx, ry);
      const rect = new RoundedRectangle(0, 0, width, height, radius);
      rect.stroke = "none";
      rect.fill = "black";
      applySvgAttributes.call(this, node, rect, parentStyles);
      rect.translation.x += w2;
      rect.translation.y += h2;
      return rect;
    },
    line: function(node, parentStyles) {
      const x1 = parseFloat(node.getAttribute("x1"));
      const y1 = parseFloat(node.getAttribute("y1"));
      const x2 = parseFloat(node.getAttribute("x2"));
      const y2 = parseFloat(node.getAttribute("y2"));
      const line = new Line(x1, y1, x2, y2).noFill();
      applySvgAttributes.call(this, node, line, parentStyles);
      return line;
    },
    lineargradient: function(node, parentStyles) {
      let units = node.getAttribute("gradientUnits");
      let spread = node.getAttribute("spreadMethod");
      if (!units) {
        units = "objectBoundingBox";
      }
      if (!spread) {
        spread = "pad";
      }
      let x1 = parseFloat(node.getAttribute("x1") || 0);
      let y1 = parseFloat(node.getAttribute("y1") || 0);
      let x2 = parseFloat(node.getAttribute("x2") || 0);
      let y2 = parseFloat(node.getAttribute("y2") || 0);
      const ox = (x2 + x1) / 2;
      const oy = (y2 + y1) / 2;
      if (/userSpaceOnUse/i.test(units)) {
        x1 -= ox;
        y1 -= oy;
        x2 -= ox;
        y2 -= oy;
      }
      const stops = [];
      for (let i = 0; i < node.children.length; i++) {
        const child = node.children[i];
        let offset = child.getAttribute("offset");
        if (/%/gi.test(offset)) {
          offset = parseFloat(offset.replace(/%/gi, "")) / 100;
        }
        offset = parseFloat(offset);
        let color = child.getAttribute("stop-color");
        let opacity = child.getAttribute("stop-opacity");
        let style = child.getAttribute("style");
        let matches;
        if (color === null) {
          matches = style ? style.match(/stop-color:\s?([#a-fA-F0-9]*)/) : false;
          color = matches && matches.length > 1 ? matches[1] : void 0;
        }
        if (opacity === null) {
          matches = style ? style.match(/stop-opacity:\s?([0-9.-]*)/) : false;
          opacity = matches && matches.length > 1 ? parseFloat(matches[1]) : 1;
        } else {
          opacity = parseFloat(opacity);
        }
        stops.push(new Stop(offset, color, opacity));
      }
      const gradient = new LinearGradient(x1, y1, x2, y2, stops);
      gradient.spread = spread;
      gradient.units = units;
      applySvgAttributes.call(this, node, gradient, parentStyles);
      return gradient;
    },
    radialgradient: function(node, parentStyles) {
      let units = node.getAttribute("gradientUnits");
      let spread = node.getAttribute("spreadMethod");
      if (!units) {
        units = "objectBoundingBox";
      }
      if (!spread) {
        spread = "pad";
      }
      let cx = parseFloat(node.getAttribute("cx")) || 0;
      let cy = parseFloat(node.getAttribute("cy")) || 0;
      let r = parseFloat(node.getAttribute("r"));
      let fx = parseFloat(node.getAttribute("fx"));
      let fy = parseFloat(node.getAttribute("fy"));
      if (_.isNaN(fx)) {
        fx = cx;
      }
      if (_.isNaN(fy)) {
        fy = cy;
      }
      const ox = Math.abs(cx + fx) / 2;
      const oy = Math.abs(cy + fy) / 2;
      if (/userSpaceOnUse/i.test(units)) {
        cx -= ox;
        cy -= oy;
        fx -= ox;
        fy -= oy;
      }
      const stops = [];
      for (let i = 0; i < node.children.length; i++) {
        const child = node.children[i];
        let offset = child.getAttribute("offset");
        if (/%/gi.test(offset)) {
          offset = parseFloat(offset.replace(/%/gi, "")) / 100;
        }
        offset = parseFloat(offset);
        let color = child.getAttribute("stop-color");
        let opacity = child.getAttribute("stop-opacity");
        let style = child.getAttribute("style");
        let matches;
        if (color === null) {
          matches = style ? style.match(/stop-color:\s?([#a-fA-F0-9]*)/) : false;
          color = matches && matches.length > 1 ? matches[1] : void 0;
        }
        if (opacity === null) {
          matches = style ? style.match(/stop-opacity:\s?([0-9.-]*)/) : false;
          opacity = matches && matches.length > 1 ? parseFloat(matches[1]) : 1;
        } else {
          opacity = parseFloat(opacity);
        }
        stops.push(new Stop(offset, color, opacity));
      }
      const gradient = new RadialGradient(cx, cy, r, stops, fx, fy);
      gradient.spread = spread;
      gradient.units = units;
      applySvgAttributes.call(this, node, gradient, parentStyles);
      return gradient;
    },
    text: function(node, parentStyles) {
      const alignment = getAlignment(node.getAttribute("text-anchor")) || "left";
      const baseline = getBaseline(node) || "baseline";
      let message = "";
      if (node.childNodes.length > 0 && node.childNodes[0].tagName === "TSPAN") {
        message = node.childNodes[0].textContent;
      } else {
        message = node.textContent;
      }
      const text = new Text(message);
      applySvgAttributes.call(this, node, text, parentStyles);
      text.alignment = alignment;
      text.baseline = baseline;
      return text;
    },
    clippath: function(node, parentStyles) {
      if (read.defs.current && !read.defs.current.contains(node.id)) {
        read.defs.current.add(node.id, node);
      }
      return null;
    },
    image: function(node, parentStyles) {
      let error;
      const href = node.getAttribute("href") || node.getAttribute("xlink:href");
      if (!href) {
        error = new TwoError("encountered <image /> with no href.");
        console.warn(error.name, error.message);
        return null;
      }
      const x = parseFloat(node.getAttribute("x")) || 0;
      const y = parseFloat(node.getAttribute("y")) || 0;
      const width = parseFloat(node.getAttribute("width"));
      const height = parseFloat(node.getAttribute("height"));
      const sprite = new Sprite(href, x, y);
      if (!_.isNaN(width)) {
        sprite.width = width;
      }
      if (!_.isNaN(height)) {
        sprite.height = height;
      }
      applySvgAttributes.call(this, node, sprite, parentStyles);
      return sprite;
    }
  };

  // src/utils/xhr.js
  function xhr(path, callback) {
    const xhr2 = new XMLHttpRequest();
    xhr2.open("GET", path);
    xhr2.onreadystatechange = function() {
      if (xhr2.readyState === 4 && xhr2.status === 200) {
        callback(xhr2.responseText);
      }
    };
    xhr2.send();
    return xhr2;
  }

  // src/effects/image-sequence.js
  var _ImageSequence = class extends Rectangle {
    _flagTextures = false;
    _flagFrameRate = false;
    _flagIndex = false;
    _amount = 1;
    _duration = 0;
    _index = 0;
    _startTime = 0;
    _playing = false;
    _firstFrame = 0;
    _lastFrame = 0;
    _loop = true;
    _textures = null;
    _frameRate = 0;
    _origin = null;
    constructor(paths, ox, oy, frameRate) {
      super(ox, oy, 0, 0);
      for (let prop in proto23) {
        Object.defineProperty(this, prop, proto23[prop]);
      }
      this._renderer.flagTextures = FlagTextures.bind(this);
      this._renderer.bindTextures = BindTextures.bind(this);
      this._renderer.unbindTextures = UnbindTextures.bind(this);
      this.noStroke();
      this.noFill();
      if (Array.isArray(paths)) {
        this.textures = paths.map(GenerateTexture.bind(this));
      } else {
        this.textures = [GenerateTexture(paths)];
      }
      this.origin = new Vector();
      this._update();
      if (typeof frameRate === "number") {
        this.frameRate = frameRate;
      } else {
        this.frameRate = _ImageSequence.DefaultFrameRate;
      }
      this.index = 0;
    }
    static fromObject(obj) {
      const sequence = new _ImageSequence().copy(obj);
      if ("id" in obj) {
        sequence.id = obj.id;
      }
      return sequence;
    }
    copy(imageSequence) {
      super.copy.call(this, imageSequence);
      for (let i = 0; i < _ImageSequence.Properties.length; i++) {
        const k = _ImageSequence.Properties[i];
        if (k in imageSequence) {
          this[k] = imageSequence[k];
        }
      }
      return this;
    }
    play(firstFrame, lastFrame, onLastFrame) {
      this._playing = true;
      this._firstFrame = 0;
      this._lastFrame = this.amount - 1;
      this._startTime = _.performance.now();
      if (typeof firstFrame === "number") {
        this._firstFrame = firstFrame;
      }
      if (typeof lastFrame === "number") {
        this._lastFrame = lastFrame;
      }
      if (typeof onLastFrame === "function") {
        this._onLastFrame = onLastFrame;
      } else {
        delete this._onLastFrame;
      }
      if (this._index !== this._firstFrame) {
        this._startTime -= 1e3 * Math.abs(this._index - this._firstFrame) / this._frameRate;
      }
      return this;
    }
    pause() {
      this._playing = false;
      return this;
    }
    stop() {
      this._playing = false;
      this._index = this._firstFrame;
      return this;
    }
    clone(parent) {
      const clone = new _ImageSequence(
        this.textures,
        this.translation.x,
        this.translation.y,
        this.frameRate
      );
      clone._loop = this._loop;
      if (this._playing) {
        clone.play();
      }
      if (parent) {
        parent.add(clone);
      }
      return clone;
    }
    toObject() {
      const object = super.toObject.call(this);
      object.textures = this.textures.map(function(texture) {
        return texture.toObject();
      });
      object.frameRate = this.frameRate;
      object.index = this.index;
      object.firstFrame = this.firstFrame;
      object.lastFrame = this.lastFrame;
      object.loop = this.loop;
      return object;
    }
    _update() {
      const effect = this._textures;
      let width, height, elapsed, amount, duration, texture;
      let index, frames;
      if (effect) {
        if (this._flagTextures) {
          this._amount = effect.length;
        }
        if (this._flagFrameRate) {
          this._duration = 1e3 * this._amount / this._frameRate;
        }
        if (this._playing && this._frameRate > 0) {
          amount = this._amount;
          if (_.isNaN(this._lastFrame)) {
            this._lastFrame = amount - 1;
          }
          elapsed = _.performance.now() - this._startTime;
          frames = this._lastFrame + 1;
          duration = 1e3 * (frames - this._firstFrame) / this._frameRate;
          if (this._loop) {
            elapsed = elapsed % duration;
          } else {
            elapsed = Math.min(elapsed, duration);
          }
          index = lerp(this._firstFrame, frames, elapsed / duration);
          index = Math.floor(index);
          if (index !== this._index) {
            this._index = index;
            texture = effect[this._index];
            if (texture.loaded) {
              width = texture.image.width;
              height = texture.image.height;
              if (this.width !== width) {
                this.width = width;
              }
              if (this.height !== height) {
                this.height = height;
              }
              this.fill = texture;
              if (index >= this._lastFrame - 1 && this._onLastFrame) {
                this._onLastFrame();
              }
            }
          }
        } else if (this._flagIndex || !(this.fill instanceof Texture)) {
          texture = effect[this._index];
          if (texture.loaded) {
            width = texture.image.width;
            height = texture.image.height;
            if (this.width !== width) {
              this.width = width;
            }
            if (this.height !== height) {
              this.height = height;
            }
          }
          this.fill = texture;
        }
      }
      super._update.call(this);
      return this;
    }
    flagReset() {
      this._flagTextures = this._flagFrameRate = false;
      super.flagReset.call(this);
      return this;
    }
  };
  var ImageSequence = _ImageSequence;
  __publicField(ImageSequence, "Properties", [
    "textures",
    "frameRate",
    "index",
    "firstFrame",
    "lastFrame",
    "loop"
  ]);
  __publicField(ImageSequence, "DefaultFrameRate", 30);
  var proto23 = {
    frameRate: {
      enumerable: true,
      get: function() {
        return this._frameRate;
      },
      set: function(v) {
        this._frameRate = v;
        this._flagFrameRate = true;
      }
    },
    index: {
      enumerable: true,
      get: function() {
        return this._index;
      },
      set: function(v) {
        this._index = v;
        this._flagIndex = true;
      }
    },
    textures: {
      enumerable: true,
      get: function() {
        return this._textures;
      },
      set: function(textures) {
        const bindTextures = this._renderer.bindTextures;
        const unbindTextures = this._renderer.unbindTextures;
        if (this._textures) {
          this._textures.unbind(Events.Types.insert, bindTextures).unbind(Events.Types.remove, unbindTextures);
        }
        this._textures = new Collection((textures || []).slice(0));
        this._textures.bind(Events.Types.insert, bindTextures).bind(Events.Types.remove, unbindTextures);
        bindTextures(this._textures);
      }
    },
    firstFrame: {
      enumerable: true,
      get: function() {
        return this._firstFrame;
      },
      set: function(v) {
        this._firstFrame = v;
      }
    },
    lastFrame: {
      enumerable: true,
      get: function() {
        return this._lastFrame;
      },
      set: function(v) {
        this._lastFrame = v;
      }
    },
    loop: {
      enumerable: true,
      get: function() {
        return this._loop;
      },
      set: function(v) {
        this._loop = !!v;
      }
    }
  };
  function FlagTextures() {
    this._flagTextures = true;
  }
  function BindTextures(items) {
    let i = items.length;
    while (i--) {
      items[i].bind(Events.Types.change, this._renderer.flagTextures);
    }
    this._renderer.flagTextures();
  }
  function UnbindTextures(items) {
    let i = items.length;
    while (i--) {
      items[i].unbind(Events.Types.change, this._renderer.flagTextures);
    }
    this._renderer.flagTextures();
  }
  function GenerateTexture(obj) {
    if (obj instanceof Texture) {
      return obj;
    } else if (typeof obj === "string") {
      return new Texture(obj);
    }
  }

  // src/renderers/canvas.js
  var emptyArray = [];
  var max4 = Math.max;
  var min4 = Math.min;
  var abs = Math.abs;
  var sin6 = Math.sin;
  var cos6 = Math.cos;
  var acos = Math.acos;
  var sqrt = Math.sqrt;
  var canvas2 = {
    isHidden: /(undefined|none|transparent)/i,
    alignments: {
      left: "start",
      middle: "center",
      right: "end"
    },
    baselines: {
      top: "top",
      middle: "middle",
      bottom: "bottom",
      baseline: "alphabetic"
    },
    getRendererType: function(type) {
      return type in canvas2 ? type : "path";
    },
    group: {
      renderChild: function(child) {
        const prop = canvas2.getRendererType(child._renderer.type);
        canvas2[prop].render.call(child, this.ctx, true, this.clip);
      },
      render: function(ctx) {
        if (!this._visible) {
          return this;
        }
        if (_.isFunction(this._renderer.onBeforeRender)) {
          this._renderer.onBeforeRender();
        }
        this._update();
        const matrix = this._matrix.elements;
        const parent = this.parent;
        this._renderer.opacity = this._opacity * (parent && parent._renderer ? parent._renderer.opacity : 1);
        const mask = this._mask;
        const defaultMatrix = isDefaultMatrix(matrix);
        const shouldIsolate = !defaultMatrix || !!mask;
        if (!this._renderer.context) {
          this._renderer.context = {};
        }
        this._renderer.context.ctx = ctx;
        if (shouldIsolate) {
          ctx.save();
          if (!defaultMatrix) {
            ctx.transform(
              matrix[0],
              matrix[3],
              matrix[1],
              matrix[4],
              matrix[2],
              matrix[5]
            );
          }
        }
        if (mask) {
          const prop = canvas2.getRendererType(mask._renderer.type);
          canvas2[prop].render.call(mask, ctx, true);
        }
        if (this._opacity > 0 && this._scale !== 0) {
          for (let i = 0; i < this.children.length; i++) {
            const child = this.children[i];
            const prop = canvas2.getRendererType(child._renderer.type);
            canvas2[prop].render.call(child, ctx);
          }
        }
        if (shouldIsolate) {
          ctx.restore();
        }
        if (_.isFunction(this._renderer.onAfterRender)) {
          this._renderer.onAfterRender();
        }
        return this.flagReset();
      }
    },
    path: {
      render: function(ctx, forced, parentClipped) {
        let matrix, stroke, linewidth, fill, opacity, visible, cap, join, miter, closed2, commands, length, last, prev, a, b, c, d, ux, uy, vx, vy, ar, bl, br, cl, x, y, mask, clip, defaultMatrix, isOffset, dashes, po;
        po = this.parent && this.parent._renderer ? this.parent._renderer.opacity : 1;
        mask = this._mask;
        clip = this._clip;
        opacity = this._opacity * (po || 1);
        visible = this._visible;
        if (!forced && (!visible || clip || opacity === 0)) {
          return this;
        }
        if (_.isFunction(this._renderer.onBeforeRender)) {
          this._renderer.onBeforeRender();
        }
        this._update();
        matrix = this._matrix.elements;
        stroke = this._stroke;
        linewidth = this._linewidth;
        fill = this._fill;
        cap = this._cap;
        join = this._join;
        miter = this._miter;
        closed2 = this._closed;
        commands = this._renderer.vertices;
        length = commands.length;
        last = length - 1;
        defaultMatrix = isDefaultMatrix(matrix);
        dashes = this.dashes;
        if (!defaultMatrix) {
          ctx.save();
          ctx.transform(
            matrix[0],
            matrix[3],
            matrix[1],
            matrix[4],
            matrix[2],
            matrix[5]
          );
        }
        if (mask) {
          const prop = canvas2.getRendererType(mask._renderer.type);
          canvas2[prop].render.call(mask, ctx, true);
        }
        if (fill) {
          if (typeof fill === "string") {
            ctx.fillStyle = fill;
          } else {
            const prop = canvas2.getRendererType(fill._renderer.type);
            canvas2[prop].render.call(fill, ctx, this);
            ctx.fillStyle = fill._renderer.effect;
          }
        }
        if (stroke) {
          if (typeof stroke === "string") {
            ctx.strokeStyle = stroke;
          } else {
            const prop = canvas2.getRendererType(stroke._renderer.type);
            canvas2[prop].render.call(stroke, ctx, this);
            ctx.strokeStyle = stroke._renderer.effect;
          }
          if (linewidth) {
            ctx.lineWidth = linewidth;
          }
          if (miter) {
            ctx.miterLimit = miter;
          }
          if (join) {
            ctx.lineJoin = join;
          }
          if (!closed2 && cap) {
            ctx.lineCap = cap;
          }
        }
        if (typeof opacity === "number") {
          ctx.globalAlpha = opacity;
        }
        if (dashes && dashes.length > 0) {
          ctx.lineDashOffset = dashes.offset || 0;
          ctx.setLineDash(dashes);
        }
        ctx.beginPath();
        let rx, ry, xAxisRotation, largeArcFlag, sweepFlag, ax, ay;
        for (let i = 0; i < length; i++) {
          b = commands[i];
          x = b.x;
          y = b.y;
          switch (b.command) {
            case Commands.close:
              ctx.closePath();
              break;
            case Commands.arc:
              rx = b.rx;
              ry = b.ry;
              xAxisRotation = b.xAxisRotation;
              largeArcFlag = b.largeArcFlag;
              sweepFlag = b.sweepFlag;
              prev = closed2 ? mod(i - 1, length) : max4(i - 1, 0);
              a = commands[prev];
              ax = a.x;
              ay = a.y;
              canvas2.renderSvgArcCommand(
                ctx,
                ax,
                ay,
                rx,
                ry,
                largeArcFlag,
                sweepFlag,
                xAxisRotation,
                x,
                y
              );
              break;
            case Commands.curve:
              prev = closed2 ? mod(i - 1, length) : Math.max(i - 1, 0);
              a = commands[prev];
              ar = a.controls && a.controls.right || Vector.zero;
              bl = b.controls && b.controls.left || Vector.zero;
              if (a._relative) {
                vx = ar.x + a.x;
                vy = ar.y + a.y;
              } else {
                vx = ar.x;
                vy = ar.y;
              }
              if (b._relative) {
                ux = bl.x + b.x;
                uy = bl.y + b.y;
              } else {
                ux = bl.x;
                uy = bl.y;
              }
              ctx.bezierCurveTo(vx, vy, ux, uy, x, y);
              if (i >= last && closed2) {
                c = d;
                br = b.controls && b.controls.right || Vector.zero;
                cl = c.controls && c.controls.left || Vector.zero;
                if (b._relative) {
                  vx = br.x + b.x;
                  vy = br.y + b.y;
                } else {
                  vx = br.x;
                  vy = br.y;
                }
                if (c._relative) {
                  ux = cl.x + c.x;
                  uy = cl.y + c.y;
                } else {
                  ux = cl.x;
                  uy = cl.y;
                }
                x = c.x;
                y = c.y;
                ctx.bezierCurveTo(vx, vy, ux, uy, x, y);
              }
              break;
            case Commands.line:
              ctx.lineTo(x, y);
              break;
            case Commands.move:
              d = b;
              ctx.moveTo(x, y);
              break;
          }
        }
        if (closed2) {
          ctx.closePath();
        }
        if (!clip && !parentClipped) {
          if (!canvas2.isHidden.test(fill)) {
            isOffset = fill._renderer && fill._renderer.offset;
            if (isOffset) {
              ctx.save();
              ctx.translate(-fill._renderer.offset.x, -fill._renderer.offset.y);
              ctx.scale(fill._renderer.scale.x, fill._renderer.scale.y);
            }
            ctx.fill();
            if (isOffset) {
              ctx.restore();
            }
          }
          if (!canvas2.isHidden.test(stroke)) {
            isOffset = stroke._renderer && stroke._renderer.offset;
            if (isOffset) {
              ctx.save();
              ctx.translate(
                -stroke._renderer.offset.x,
                -stroke._renderer.offset.y
              );
              ctx.scale(stroke._renderer.scale.x, stroke._renderer.scale.y);
              ctx.lineWidth = linewidth / stroke._renderer.scale.x;
            }
            ctx.stroke();
            if (isOffset) {
              ctx.restore();
            }
          }
        }
        if (!defaultMatrix) {
          ctx.restore();
        }
        if (clip && !parentClipped) {
          ctx.clip();
        }
        if (dashes && dashes.length > 0) {
          ctx.setLineDash(emptyArray);
        }
        if (_.isFunction(this._renderer.onAfterRender)) {
          this._renderer.onAfterRender();
        }
        return this.flagReset();
      }
    },
    points: {
      render: function(ctx, forced, parentClipped) {
        let me, stroke, linewidth, fill, opacity, visible, size, commands, length, b, x, y, defaultMatrix, isOffset, dashes, po;
        po = this.parent && this.parent._renderer ? this.parent._renderer.opacity : 1;
        opacity = this._opacity * (po || 1);
        visible = this._visible;
        if (!forced && (!visible || opacity === 0)) {
          return this;
        }
        if (_.isFunction(this._renderer.onBeforeRender)) {
          this._renderer.onBeforeRender();
        }
        this._update();
        me = this._matrix.elements;
        stroke = this._stroke;
        linewidth = this._linewidth;
        fill = this._fill;
        commands = this._renderer.collection;
        length = commands.length;
        defaultMatrix = isDefaultMatrix(me);
        dashes = this.dashes;
        size = this._size;
        if (!defaultMatrix) {
          ctx.save();
          ctx.transform(me[0], me[3], me[1], me[4], me[2], me[5]);
        }
        if (fill) {
          if (typeof fill === "string") {
            ctx.fillStyle = fill;
          } else {
            const prop = canvas2.getRendererType(fill._renderer.type);
            canvas2[prop].render.call(fill, ctx, this);
            ctx.fillStyle = fill._renderer.effect;
          }
        }
        if (stroke) {
          if (typeof stroke === "string") {
            ctx.strokeStyle = stroke;
          } else {
            const prop = canvas2.getRendererType(stroke._renderer.type);
            canvas2[prop].render.call(stroke, ctx, this);
            ctx.strokeStyle = stroke._renderer.effect;
          }
          if (linewidth) {
            ctx.lineWidth = linewidth;
          }
        }
        if (typeof opacity === "number") {
          ctx.globalAlpha = opacity;
        }
        if (dashes && dashes.length > 0) {
          ctx.lineDashOffset = dashes.offset || 0;
          ctx.setLineDash(dashes);
        }
        ctx.beginPath();
        let radius = size * 0.5, m;
        if (!this._sizeAttenuation) {
          m = this.worldMatrix.elements;
          m = decomposeMatrix(m[0], m[3], m[1], m[4], m[2], m[5]);
          radius /= Math.max(m.scaleX, m.scaleY);
        }
        for (let i = 0; i < length; i++) {
          b = commands[i];
          x = b.x;
          y = b.y;
          ctx.moveTo(x + radius, y);
          ctx.arc(x, y, radius, 0, TWO_PI);
        }
        if (!parentClipped) {
          if (!canvas2.isHidden.test(fill)) {
            isOffset = fill._renderer && fill._renderer.offset;
            if (isOffset) {
              ctx.save();
              ctx.translate(-fill._renderer.offset.x, -fill._renderer.offset.y);
              ctx.scale(fill._renderer.scale.x, fill._renderer.scale.y);
            }
            ctx.fill();
            if (isOffset) {
              ctx.restore();
            }
          }
          if (!canvas2.isHidden.test(stroke)) {
            isOffset = stroke._renderer && stroke._renderer.offset;
            if (isOffset) {
              ctx.save();
              ctx.translate(
                -stroke._renderer.offset.x,
                -stroke._renderer.offset.y
              );
              ctx.scale(stroke._renderer.scale.x, stroke._renderer.scale.y);
              ctx.lineWidth = linewidth / stroke._renderer.scale.x;
            }
            ctx.stroke();
            if (isOffset) {
              ctx.restore();
            }
          }
        }
        if (!defaultMatrix) {
          ctx.restore();
        }
        if (dashes && dashes.length > 0) {
          ctx.setLineDash(emptyArray);
        }
        if (_.isFunction(this._renderer.onAfterRender)) {
          this._renderer.onAfterRender();
        }
        return this.flagReset();
      }
    },
    text: {
      render: function(ctx, forced, parentClipped) {
        const po = this.parent && this.parent._renderer ? this.parent._renderer.opacity : 1;
        const opacity = this._opacity * po;
        const visible = this._visible;
        const mask = this._mask;
        const clip = this._clip;
        if (!forced && (!visible || clip || opacity === 0)) {
          return this;
        }
        if (_.isFunction(this._renderer.onBeforeRender)) {
          this._renderer.onBeforeRender();
        }
        this._update();
        const matrix = this._matrix.elements;
        const stroke = this._stroke;
        const linewidth = this._linewidth;
        const fill = this._fill;
        const decoration = this._decoration;
        const direction = this._direction;
        const defaultMatrix = isDefaultMatrix(matrix);
        const isOffset = fill._renderer && fill._renderer.offset && stroke._renderer && stroke._renderer.offset;
        const dashes = this.dashes;
        const alignment = canvas2.alignments[this._alignment] || this._alignment;
        const baseline = canvas2.baselines[this._baseline] || this._baseline;
        let a, b, c, d, e, sx, sy, x1, y1, x2, y2;
        if (!defaultMatrix) {
          ctx.save();
          ctx.transform(
            matrix[0],
            matrix[3],
            matrix[1],
            matrix[4],
            matrix[2],
            matrix[5]
          );
        }
        if (mask) {
          const prop = canvas2.getRendererType(mask._renderer.type);
          canvas2[prop].render.call(mask, ctx, true);
        }
        if (!isOffset) {
          ctx.font = [
            this._style,
            this._weight,
            this._size + "px/" + this._leading + "px",
            this._family
          ].join(" ");
        }
        ctx.textAlign = alignment;
        ctx.textBaseline = baseline;
        ctx.direction = direction;
        if (fill) {
          if (typeof fill === "string") {
            ctx.fillStyle = fill;
          } else {
            const prop = canvas2.getRendererType(fill._renderer.type);
            canvas2[prop].render.call(fill, ctx, this);
            ctx.fillStyle = fill._renderer.effect;
          }
        }
        if (stroke) {
          if (typeof stroke === "string") {
            ctx.strokeStyle = stroke;
          } else {
            const prop = canvas2.getRendererType(stroke._renderer.type);
            canvas2[prop].render.call(stroke, ctx, this);
            ctx.strokeStyle = stroke._renderer.effect;
          }
          if (linewidth) {
            ctx.lineWidth = linewidth;
          }
        }
        if (typeof opacity === "number") {
          ctx.globalAlpha = opacity;
        }
        if (dashes && dashes.length > 0) {
          ctx.lineDashOffset = dashes.offset || 0;
          ctx.setLineDash(dashes);
        }
        if (!clip && !parentClipped) {
          if (!canvas2.isHidden.test(fill)) {
            if (fill._renderer && fill._renderer.offset) {
              sx = fill._renderer.scale.x;
              sy = fill._renderer.scale.y;
              ctx.save();
              ctx.translate(-fill._renderer.offset.x, -fill._renderer.offset.y);
              ctx.scale(sx, sy);
              a = this._size / fill._renderer.scale.y;
              b = this._leading / fill._renderer.scale.y;
              ctx.font = [
                this._style,
                this._weight,
                a + "px/",
                b + "px",
                this._family
              ].join(" ");
              c = fill._renderer.offset.x / fill._renderer.scale.x;
              d = fill._renderer.offset.y / fill._renderer.scale.y;
              ctx.fillText(this.value, c, d);
              ctx.restore();
            } else {
              ctx.fillText(this.value, 0, 0);
            }
          }
          if (!canvas2.isHidden.test(stroke)) {
            if (stroke._renderer && stroke._renderer.offset) {
              sx = stroke._renderer.scale.x;
              sy = stroke._renderer.scale.y;
              ctx.save();
              ctx.translate(
                -stroke._renderer.offset.x,
                -stroke._renderer.offset.y
              );
              ctx.scale(sx, sy);
              a = this._size / stroke._renderer.scale.y;
              b = this._leading / stroke._renderer.scale.y;
              ctx.font = [
                this._style,
                this._weight,
                a + "px/",
                b + "px",
                this._family
              ].join(" ");
              c = stroke._renderer.offset.x / stroke._renderer.scale.x;
              d = stroke._renderer.offset.y / stroke._renderer.scale.y;
              e = linewidth / stroke._renderer.scale.x;
              ctx.lineWidth = e;
              ctx.strokeText(this.value, c, d);
              ctx.restore();
            } else {
              ctx.strokeText(this.value, 0, 0);
            }
          }
        }
        if (/(underline|strikethrough)/i.test(decoration)) {
          const metrics = ctx.measureText(this.value);
          let scalar = 1;
          switch (decoration) {
            case "underline":
              y1 = metrics.actualBoundingBoxDescent;
              y2 = metrics.actualBoundingBoxDescent;
              break;
            case "strikethrough":
              y1 = 0;
              y2 = 0;
              scalar = 0.5;
              break;
          }
          switch (baseline) {
            case "top":
              y1 += this._size * scalar;
              y2 += this._size * scalar;
              break;
            case "baseline":
            case "bottom":
              y1 -= this._size * scalar;
              y2 -= this._size * scalar;
              break;
          }
          switch (alignment) {
            case "left":
            case "start":
              x1 = 0;
              x2 = metrics.width;
              break;
            case "right":
            case "end":
              x1 = -metrics.width;
              x2 = 0;
              break;
            default:
              x1 = -metrics.width / 2;
              x2 = metrics.width / 2;
          }
          ctx.lineWidth = Math.max(Math.floor(this._size / 15), 1);
          ctx.strokeStyle = ctx.fillStyle;
          ctx.beginPath();
          ctx.moveTo(x1, y1);
          ctx.lineTo(x2, y2);
          ctx.stroke();
        }
        if (!defaultMatrix) {
          ctx.restore();
        }
        if (clip && !parentClipped) {
          ctx.clip();
        }
        if (dashes && dashes.length > 0) {
          ctx.setLineDash(emptyArray);
        }
        if (_.isFunction(this._renderer.onAfterRender)) {
          this._renderer.onAfterRender();
        }
        return this.flagReset();
      }
    },
    "linear-gradient": {
      render: function(ctx, parent) {
        if (!parent) {
          return;
        }
        if (_.isFunction(this._renderer.onBeforeRender)) {
          this._renderer.onBeforeRender();
        }
        this._update();
        if (!this._renderer.effect || this._flagEndPoints || this._flagStops || this._flagUnits) {
          let rect;
          let lx = this.left._x;
          let ly = this.left._y;
          let rx = this.right._x;
          let ry = this.right._y;
          if (/objectBoundingBox/i.test(this._units)) {
            rect = parent.getBoundingClientRect(true);
            lx = (lx - 0.5) * rect.width;
            ly = (ly - 0.5) * rect.height;
            rx = (rx - 0.5) * rect.width;
            ry = (ry - 0.5) * rect.height;
          }
          this._renderer.effect = ctx.createLinearGradient(lx, ly, rx, ry);
          for (let i = 0; i < this.stops.length; i++) {
            const stop = this.stops[i];
            this._renderer.effect.addColorStop(stop._offset, stop._color);
          }
        }
        if (_.isFunction(this._renderer.onAfterRender)) {
          this._renderer.onAfterRender();
        }
        return this.flagReset();
      }
    },
    "radial-gradient": {
      render: function(ctx, parent) {
        if (!parent) {
          return;
        }
        if (_.isFunction(this._renderer.onBeforeRender)) {
          this._renderer.onBeforeRender();
        }
        this._update();
        if (!this._renderer.effect || this._flagCenter || this._flagFocal || this._flagRadius || this._flagStops || this._flagUnits) {
          let rect;
          let cx = this.center._x;
          let cy = this.center._y;
          let fx = this.focal._x;
          let fy = this.focal._y;
          let radius = this._radius;
          if (/objectBoundingBox/i.test(this._units)) {
            rect = parent.getBoundingClientRect(true);
            cx = (cx - 0.5) * rect.width * 0.5;
            cy = (cy - 0.5) * rect.height * 0.5;
            fx = (fx - 0.5) * rect.width * 0.5;
            fy = (fy - 0.5) * rect.height * 0.5;
            radius *= Math.min(rect.width, rect.height);
          }
          this._renderer.effect = ctx.createRadialGradient(
            cx,
            cy,
            0,
            fx,
            fy,
            radius
          );
          for (let i = 0; i < this.stops.length; i++) {
            const stop = this.stops[i];
            this._renderer.effect.addColorStop(stop._offset, stop._color);
          }
        }
        if (_.isFunction(this._renderer.onAfterRender)) {
          this._renderer.onAfterRender();
        }
        return this.flagReset();
      }
    },
    texture: {
      render: function(ctx) {
        if (_.isFunction(this._renderer.onBeforeRender)) {
          this._renderer.onBeforeRender();
        }
        this._update();
        const image = this.image;
        if (!this._renderer.effect || (this._flagLoaded || this._flagImage || this._flagVideo || this._flagRepeat) && this.loaded) {
          this._renderer.effect = ctx.createPattern(this.image, this._repeat);
        }
        if (this._flagOffset || this._flagLoaded || this._flagScale) {
          if (!(this._renderer.offset instanceof Vector)) {
            this._renderer.offset = new Vector();
          }
          this._renderer.offset.x = -this._offset.x;
          this._renderer.offset.y = -this._offset.y;
          if (image) {
            this._renderer.offset.x += image.width / 2;
            this._renderer.offset.y += image.height / 2;
            if (this._scale instanceof Vector) {
              this._renderer.offset.x *= this._scale.x;
              this._renderer.offset.y *= this._scale.y;
            } else {
              this._renderer.offset.x *= this._scale;
              this._renderer.offset.y *= this._scale;
            }
          }
        }
        if (this._flagScale || this._flagLoaded) {
          if (!(this._renderer.scale instanceof Vector)) {
            this._renderer.scale = new Vector();
          }
          if (this._scale instanceof Vector) {
            this._renderer.scale.copy(this._scale);
          } else {
            this._renderer.scale.set(this._scale, this._scale);
          }
        }
        if (_.isFunction(this._renderer.onAfterRender)) {
          this._renderer.onAfterRender();
        }
        return this.flagReset();
      }
    },
    renderSvgArcCommand: function(ctx, ax, ay, rx, ry, largeArcFlag, sweepFlag, xAxisRotation, x, y) {
      xAxisRotation = xAxisRotation * Math.PI / 180;
      rx = abs(rx);
      ry = abs(ry);
      const dx2 = (ax - x) / 2;
      const dy2 = (ay - y) / 2;
      const x1p = cos6(xAxisRotation) * dx2 + sin6(xAxisRotation) * dy2;
      const y1p = -sin6(xAxisRotation) * dx2 + cos6(xAxisRotation) * dy2;
      const x1ps = x1p * x1p;
      const y1ps = y1p * y1p;
      let rxs = rx * rx;
      let rys = ry * ry;
      const cr = x1ps / rxs + y1ps / rys;
      if (cr > 1) {
        const s = sqrt(cr);
        rx = s * rx;
        ry = s * ry;
        rxs = rx * rx;
        rys = ry * ry;
      }
      const dq = rxs * y1ps + rys * x1ps;
      const pq = (rxs * rys - dq) / dq;
      let q = sqrt(max4(0, pq));
      if (largeArcFlag === sweepFlag)
        q = -q;
      const cxp = q * rx * y1p / ry;
      const cyp = -q * ry * x1p / rx;
      const cx = cos6(xAxisRotation) * cxp - sin6(xAxisRotation) * cyp + (ax + x) / 2;
      const cy = sin6(xAxisRotation) * cxp + cos6(xAxisRotation) * cyp + (ay + y) / 2;
      const startAngle = svgAngle(1, 0, (x1p - cxp) / rx, (y1p - cyp) / ry);
      const delta = svgAngle(
        (x1p - cxp) / rx,
        (y1p - cyp) / ry,
        (-x1p - cxp) / rx,
        (-y1p - cyp) / ry
      ) % TWO_PI;
      const endAngle = startAngle + delta;
      const clockwise = sweepFlag === 0;
      renderArcEstimate(
        ctx,
        cx,
        cy,
        rx,
        ry,
        startAngle,
        endAngle,
        clockwise,
        xAxisRotation
      );
    }
  };
  var Renderer = class extends Events {
    constructor(params) {
      super();
      const smoothing = params.smoothing !== false;
      this.domElement = params.domElement || document.createElement("canvas");
      this.ctx = this.domElement.getContext("2d");
      this.overdraw = params.overdraw || false;
      if (typeof this.ctx.imageSmoothingEnabled !== "undefined") {
        this.ctx.imageSmoothingEnabled = smoothing;
      }
      this.scene = new Group();
      this.scene.parent = this;
    }
    setSize(width, height, ratio) {
      this.width = width;
      this.height = height;
      this.ratio = typeof ratio === "undefined" ? getRatio(this.ctx) : ratio;
      this.domElement.width = width * this.ratio;
      this.domElement.height = height * this.ratio;
      if (this.domElement.style) {
        _.extend(this.domElement.style, {
          width: width + "px",
          height: height + "px"
        });
      }
      return this.trigger(Events.Types.resize, width, height, ratio);
    }
    render() {
      const isOne = this.ratio === 1;
      if (!isOne) {
        this.ctx.save();
        this.ctx.scale(this.ratio, this.ratio);
      }
      if (!this.overdraw) {
        this.ctx.clearRect(0, 0, this.width, this.height);
      }
      canvas2.group.render.call(this.scene, this.ctx);
      if (!isOne) {
        this.ctx.restore();
      }
      return this;
    }
  };
  __publicField(Renderer, "Utils", canvas2);
  function renderArcEstimate(ctx, ox, oy, rx, ry, startAngle, endAngle, clockwise, xAxisRotation) {
    const delta = endAngle - startAngle;
    const epsilon = Curve.Tolerance.epsilon;
    const samePoints = Math.abs(delta) < epsilon;
    let deltaAngle = mod(delta, TWO_PI);
    if (deltaAngle < epsilon) {
      if (samePoints) {
        deltaAngle = 0;
      } else {
        deltaAngle = TWO_PI;
      }
    }
    if (clockwise === true && !samePoints) {
      if (deltaAngle === TWO_PI) {
        deltaAngle = -TWO_PI;
      } else {
        deltaAngle = deltaAngle - TWO_PI;
      }
    }
    for (let i = 0; i < Constants.Resolution; i++) {
      const t = i / (Constants.Resolution - 1);
      const angle = startAngle + t * deltaAngle;
      let x = ox + rx * Math.cos(angle);
      let y = oy + ry * Math.sin(angle);
      if (xAxisRotation !== 0) {
        const cos7 = Math.cos(xAxisRotation);
        const sin7 = Math.sin(xAxisRotation);
        const tx = x - ox;
        const ty = y - oy;
        x = tx * cos7 - ty * sin7 + ox;
        y = tx * sin7 + ty * cos7 + oy;
      }
      ctx.lineTo(x, y);
    }
  }
  function svgAngle(ux, uy, vx, vy) {
    const dot = ux * vx + uy * vy;
    const len = sqrt(ux * ux + uy * uy) * sqrt(vx * vx + vy * vy);
    let ang = acos(max4(-1, min4(1, dot / len)));
    if (ux * vy - uy * vx < 0) {
      ang = -ang;
    }
    return ang;
  }
  function isDefaultMatrix(m) {
    return m[0] == 1 && m[3] == 0 && m[1] == 0 && m[4] == 1 && m[2] == 0 && m[5] == 0;
  }

  // src/renderers/svg.js
  var svg = {
    version: 1.1,
    ns: "http://www.w3.org/2000/svg",
    xlink: "http://www.w3.org/1999/xlink",
    alignments: {
      left: "start",
      center: "middle",
      right: "end"
    },
    baselines: {
      top: "hanging",
      middle: "middle",
      bottom: "ideographic",
      baseline: "alphabetic"
    },
    createElement: function(name, attrs) {
      const tag = name;
      const elem = document.createElementNS(svg.ns, tag);
      if (tag === "svg") {
        attrs = _.defaults(attrs || {}, {
          version: svg.version
        });
      }
      if (attrs && Object.keys(attrs).length > 0) {
        svg.setAttributes(elem, attrs);
      }
      return elem;
    },
    setAttributes: function(elem, attrs) {
      const keys = Object.keys(attrs);
      for (let i = 0; i < keys.length; i++) {
        if (/href/.test(keys[i])) {
          elem.setAttributeNS(svg.xlink, keys[i], attrs[keys[i]]);
        } else {
          elem.setAttribute(keys[i], attrs[keys[i]]);
        }
      }
      return this;
    },
    removeAttributes: function(elem, attrs) {
      for (let key in attrs) {
        elem.removeAttribute(key);
      }
      return this;
    },
    toString: function(points, closed2) {
      let l = points.length, last = l - 1, d, string = "";
      for (let i = 0; i < l; i++) {
        const b = points[i];
        const prev = closed2 ? mod(i - 1, l) : Math.max(i - 1, 0);
        const a = points[prev];
        let command, c;
        let vx, vy, ux, uy, ar, bl, br, cl;
        let rx, ry, xAxisRotation, largeArcFlag, sweepFlag;
        let x = toFixed(b.x);
        let y = toFixed(b.y);
        switch (b.command) {
          case Commands.close:
            command = Commands.close;
            break;
          case Commands.arc:
            rx = b.rx;
            ry = b.ry;
            xAxisRotation = b.xAxisRotation;
            largeArcFlag = b.largeArcFlag;
            sweepFlag = b.sweepFlag;
            command = Commands.arc + " " + rx + " " + ry + " " + xAxisRotation + " " + largeArcFlag + " " + sweepFlag + " " + x + " " + y;
            break;
          case Commands.curve:
            ar = a.controls && a.controls.right || Vector.zero;
            bl = b.controls && b.controls.left || Vector.zero;
            if (a.relative) {
              vx = toFixed(ar.x + a.x);
              vy = toFixed(ar.y + a.y);
            } else {
              vx = toFixed(ar.x);
              vy = toFixed(ar.y);
            }
            if (b.relative) {
              ux = toFixed(bl.x + b.x);
              uy = toFixed(bl.y + b.y);
            } else {
              ux = toFixed(bl.x);
              uy = toFixed(bl.y);
            }
            command = (i === 0 ? Commands.move : Commands.curve) + " " + vx + " " + vy + " " + ux + " " + uy + " " + x + " " + y;
            break;
          case Commands.move:
            d = b;
            command = Commands.move + " " + x + " " + y;
            break;
          default:
            command = b.command + " " + x + " " + y;
        }
        if (i >= last && closed2) {
          if (b.command === Commands.curve) {
            c = d;
            br = b.controls && b.controls.right || b;
            cl = c.controls && c.controls.left || c;
            if (b.relative) {
              vx = toFixed(br.x + b.x);
              vy = toFixed(br.y + b.y);
            } else {
              vx = toFixed(br.x);
              vy = toFixed(br.y);
            }
            if (c.relative) {
              ux = toFixed(cl.x + c.x);
              uy = toFixed(cl.y + c.y);
            } else {
              ux = toFixed(cl.x);
              uy = toFixed(cl.y);
            }
            x = toFixed(c.x);
            y = toFixed(c.y);
            command += " C " + vx + " " + vy + " " + ux + " " + uy + " " + x + " " + y;
          }
          if (b.command !== Commands.close) {
            command += " Z";
          }
        }
        string += command + " ";
      }
      return string;
    },
    pointsToString: function(points, size) {
      let string = "";
      const r = size * 0.5;
      for (let i = 0; i < points.length; i++) {
        const x = points[i].x;
        const y = points[i].y - r;
        string += Commands.move + " " + x + " " + y + " ";
        string += "a " + r + " " + r + " 0 1 0 0.001 0 Z";
      }
      return string;
    },
    getClip: function(shape, domElement) {
      let clip = shape._renderer.clip;
      if (!clip) {
        clip = shape._renderer.clip = svg.createElement("clipPath", {
          "clip-rule": "nonzero"
        });
      }
      if (clip.parentNode === null) {
        domElement.defs.appendChild(clip);
      }
      return clip;
    },
    getRendererType: function(type) {
      return type in svg ? type : "path";
    },
    defs: {
      update: function(domElement) {
        const { defs } = domElement;
        if (defs._flagUpdate) {
          const children = Array.prototype.slice.call(defs.children, 0);
          for (let i = 0; i < children.length; i++) {
            const child = children[i];
            const id = child.id;
            const selector = `[fill="url(#${id})"],[stroke="url(#${id})"],[clip-path="url(#${id})"]`;
            const exists = domElement.querySelector(selector);
            if (!exists) {
              defs.removeChild(child);
            }
          }
          defs._flagUpdate = false;
        }
      }
    },
    group: {
      appendChild: function(object) {
        const elem = object._renderer.elem;
        if (!elem) {
          return;
        }
        const tag = elem.nodeName;
        if (!tag || /(radial|linear)gradient/i.test(tag) || object._clip) {
          return;
        }
        this.elem.appendChild(elem);
      },
      removeChild: function(object) {
        const elem = object._renderer.elem;
        if (!elem || elem.parentNode != this.elem) {
          return;
        }
        const tag = elem.nodeName;
        if (!tag) {
          return;
        }
        if (object._clip) {
          return;
        }
        this.elem.removeChild(elem);
      },
      orderChild: function(object) {
        this.elem.appendChild(object._renderer.elem);
      },
      renderChild: function(child) {
        const prop = svg.getRendererType(child._renderer.type);
        svg[prop].render.call(child, this);
      },
      render: function(domElement) {
        if (!this._visible && !this._flagVisible || this._opacity === 0 && !this._flagOpacity) {
          return this;
        }
        if (_.isFunction(this._renderer.onBeforeRender)) {
          this._renderer.onBeforeRender();
        }
        this._update();
        if (!this._renderer.elem) {
          this._renderer.elem = svg.createElement("g", {
            id: this.id
          });
          domElement.appendChild(this._renderer.elem);
        }
        const flagMatrix = this._matrix.manual || this._flagMatrix;
        const context = {
          domElement,
          elem: this._renderer.elem
        };
        if (flagMatrix) {
          this._renderer.elem.setAttribute(
            "transform",
            "matrix(" + this._matrix.toString() + ")"
          );
        }
        for (let i = 0; i < this.children.length; i++) {
          const child = this.children[i];
          const prop = svg.getRendererType(child._renderer.type);
          svg[prop].render.call(child, domElement);
        }
        if (this._flagId) {
          this._renderer.elem.setAttribute("id", this._id);
        }
        if (this._flagOpacity) {
          this._renderer.elem.setAttribute("opacity", this._opacity);
        }
        if (this._flagVisible) {
          this._renderer.elem.setAttribute(
            "display",
            this._visible ? "inline" : "none"
          );
        }
        if (this._flagClassName) {
          this._renderer.elem.setAttribute("class", this.classList.join(" "));
        }
        if (this._flagAdditions) {
          this.additions.forEach(svg.group.appendChild, context);
        }
        if (this._flagSubtractions) {
          this.subtractions.forEach(svg.group.removeChild, context);
        }
        if (this._flagOrder) {
          this.children.forEach(svg.group.orderChild, context);
        }
        if (this._flagMask) {
          if (this._mask) {
            const prop = svg.getRendererType(this._mask._renderer.type);
            svg[prop].render.call(this._mask, domElement);
            this._renderer.elem.setAttribute(
              "clip-path",
              "url(#" + this._mask.id + ")"
            );
          } else {
            this._renderer.elem.removeAttribute("clip-path");
          }
        }
        if (this.dataset) {
          Object.assign(this._renderer.elem.dataset, this.dataset);
        }
        if (_.isFunction(this._renderer.onAfterRender)) {
          this._renderer.onAfterRender();
        }
        return this.flagReset();
      }
    },
    path: {
      render: function(domElement) {
        if (this._opacity === 0 && !this._flagOpacity) {
          return this;
        }
        if (_.isFunction(this._renderer.onBeforeRender)) {
          this._renderer.onBeforeRender();
        }
        this._update();
        const changed = {};
        const flagMatrix = this._matrix.manual || this._flagMatrix;
        if (flagMatrix) {
          changed.transform = "matrix(" + this._matrix.toString() + ")";
        }
        if (this._flagId) {
          changed.id = this._id;
        }
        if (this._flagVertices) {
          const vertices = svg.toString(this._renderer.vertices, this._closed);
          changed.d = vertices;
        }
        if (this._fill && this._fill._renderer) {
          this._renderer.hasFillEffect = true;
          this._fill._update();
          const prop = svg.getRendererType(this._fill._renderer.type);
          svg[prop].render.call(this._fill, domElement, true);
        }
        if (this._flagFill) {
          changed.fill = this._fill && this._fill.id ? "url(#" + this._fill.id + ")" : this._fill;
          if (this._renderer.hasFillEffect && typeof this._fill.id === "undefined") {
            domElement.defs._flagUpdate = true;
            delete this._renderer.hasFillEffect;
          }
        }
        if (this._stroke && this._stroke._renderer) {
          this._renderer.hasStrokeEffect = true;
          this._stroke._update();
          const prop = svg.getRendererType(this._stroke._renderer.type);
          svg[prop].render.call(this._stroke, domElement, true);
        }
        if (this._flagStroke) {
          changed.stroke = this._stroke && this._stroke.id ? "url(#" + this._stroke.id + ")" : this._stroke;
          if (this._renderer.hasStrokeEffect && typeof this._stroke.id === "undefined") {
            domElement.defs._flagUpdate = true;
            delete this._renderer.hasStrokeEffect;
          }
        }
        if (this._flagLinewidth) {
          changed["stroke-width"] = this._linewidth;
        }
        if (this._flagOpacity) {
          changed["stroke-opacity"] = this._opacity;
          changed["fill-opacity"] = this._opacity;
        }
        if (this._flagClassName) {
          changed["class"] = this.classList.join(" ");
        }
        if (this._flagVisible) {
          changed.visibility = this._visible ? "visible" : "hidden";
        }
        if (this._flagCap) {
          changed["stroke-linecap"] = this._cap;
        }
        if (this._flagJoin) {
          changed["stroke-linejoin"] = this._join;
        }
        if (this._flagMiter) {
          changed["stroke-miterlimit"] = this._miter;
        }
        if (this.dashes && this.dashes.length > 0) {
          changed["stroke-dasharray"] = this.dashes.join(" ");
          changed["stroke-dashoffset"] = this.dashes.offset || 0;
        }
        if (!this._renderer.elem) {
          changed.id = this._id;
          this._renderer.elem = svg.createElement("path", changed);
          domElement.appendChild(this._renderer.elem);
        } else {
          svg.setAttributes(this._renderer.elem, changed);
        }
        if (this._flagClip) {
          const clip = svg.getClip(this, domElement);
          const elem = this._renderer.elem;
          if (this._clip) {
            elem.removeAttribute("id");
            clip.setAttribute("id", this.id);
            clip.appendChild(elem);
          } else {
            clip.removeAttribute("id");
            elem.setAttribute("id", this.id);
            this.parent._renderer.elem.appendChild(elem);
          }
        }
        if (this._flagMask) {
          if (this._mask) {
            const prop = svg.getRendererType(this._mask._renderer.type);
            svg[prop].render.call(this._mask, domElement);
            this._renderer.elem.setAttribute(
              "clip-path",
              "url(#" + this._mask.id + ")"
            );
          } else {
            this._renderer.elem.removeAttribute("clip-path");
          }
        }
        if (_.isFunction(this._renderer.onAfterRender)) {
          this._renderer.onAfterRender();
        }
        return this.flagReset();
      }
    },
    points: {
      render: function(domElement) {
        if (this._opacity === 0 && !this._flagOpacity) {
          return this;
        }
        if (_.isFunction(this._renderer.onBeforeRender)) {
          this._renderer.onBeforeRender();
        }
        this._update();
        const changed = {};
        const flagMatrix = this._matrix.manual || this._flagMatrix;
        if (flagMatrix) {
          changed.transform = "matrix(" + this._matrix.toString() + ")";
        }
        if (this._flagId) {
          changed.id = this._id;
        }
        if (this._flagVertices || this._flagSize || this._flagSizeAttenuation) {
          let size = this._size;
          if (!this._sizeAttenuation) {
            const me = this.worldMatrix.elements;
            const m = decomposeMatrix(me[0], me[3], me[1], me[4], me[2], me[5]);
            size /= Math.max(m.scaleX, m.scaleY);
          }
          const vertices = svg.pointsToString(this._renderer.collection, size);
          changed.d = vertices;
        }
        if (this._fill && this._fill._renderer) {
          this._renderer.hasFillEffect = true;
          this._fill._update();
          const prop = svg.getRendererType(this._fill._renderer.type);
          svg[prop].render.call(this._fill, domElement, true);
        }
        if (this._flagFill) {
          changed.fill = this._fill && this._fill.id ? "url(#" + this._fill.id + ")" : this._fill;
          if (this._renderer.hasFillEffect && typeof this._fill.id === "undefined") {
            domElement.defs._flagUpdate = true;
            delete this._renderer.hasFillEffect;
          }
        }
        if (this._stroke && this._stroke._renderer) {
          this._renderer.hasStrokeEffect = true;
          this._stroke._update();
          const prop = svg.getRendererType(this._stroke._renderer.type);
          svg[prop].render.call(this._stroke, domElement, true);
        }
        if (this._flagStroke) {
          changed.stroke = this._stroke && this._stroke.id ? "url(#" + this._stroke.id + ")" : this._stroke;
          if (this._renderer.hasStrokeEffect && typeof this._stroke.id === "undefined") {
            domElement.defs._flagUpdate = true;
            delete this._renderer.hasStrokeEffect;
          }
        }
        if (this._flagLinewidth) {
          changed["stroke-width"] = this._linewidth;
        }
        if (this._flagOpacity) {
          changed["stroke-opacity"] = this._opacity;
          changed["fill-opacity"] = this._opacity;
        }
        if (this._flagClassName) {
          changed["class"] = this.classList.join(" ");
        }
        if (this._flagVisible) {
          changed.visibility = this._visible ? "visible" : "hidden";
        }
        if (this.dashes && this.dashes.length > 0) {
          changed["stroke-dasharray"] = this.dashes.join(" ");
          changed["stroke-dashoffset"] = this.dashes.offset || 0;
        }
        if (!this._renderer.elem) {
          changed.id = this._id;
          this._renderer.elem = svg.createElement("path", changed);
          domElement.appendChild(this._renderer.elem);
        } else {
          svg.setAttributes(this._renderer.elem, changed);
        }
        if (_.isFunction(this._renderer.onAfterRender)) {
          this._renderer.onAfterRender();
        }
        return this.flagReset();
      }
    },
    text: {
      render: function(domElement) {
        this._update();
        const changed = {};
        const flagMatrix = this._matrix.manual || this._flagMatrix;
        if (flagMatrix) {
          changed.transform = "matrix(" + this._matrix.toString() + ")";
        }
        if (this._flagId) {
          changed.id = this._id;
        }
        if (this._flagFamily) {
          changed["font-family"] = this._family;
        }
        if (this._flagSize) {
          changed["font-size"] = this._size;
        }
        if (this._flagLeading) {
          changed["line-height"] = this._leading;
        }
        if (this._flagAlignment) {
          changed["text-anchor"] = svg.alignments[this._alignment] || this._alignment;
        }
        if (this._flagBaseline) {
          changed["dominant-baseline"] = svg.baselines[this._baseline] || this._baseline;
        }
        if (this._flagStyle) {
          changed["font-style"] = this._style;
        }
        if (this._flagWeight) {
          changed["font-weight"] = this._weight;
        }
        if (this._flagDecoration) {
          changed["text-decoration"] = this._decoration;
        }
        if (this._flagDirection) {
          changed["direction"] = this._direction;
        }
        if (this._fill && this._fill._renderer) {
          this._renderer.hasFillEffect = true;
          this._fill._update();
          const prop = svg.getRendererType(this._fill._renderer.type);
          svg[prop].render.call(this._fill, domElement, true);
        }
        if (this._flagFill) {
          changed.fill = this._fill && this._fill.id ? "url(#" + this._fill.id + ")" : this._fill;
          if (this._renderer.hasFillEffect && typeof this._fill.id === "undefined") {
            domElement.defs._flagUpdate = true;
            delete this._renderer.hasFillEffect;
          }
        }
        if (this._stroke && this._stroke._renderer) {
          this._renderer.hasStrokeEffect = true;
          this._stroke._update();
          const prop = svg.getRendererType(this._stroke._renderer.type);
          svg[prop].render.call(this._stroke, domElement, true);
        }
        if (this._flagStroke) {
          changed.stroke = this._stroke && this._stroke.id ? "url(#" + this._stroke.id + ")" : this._stroke;
          if (this._renderer.hasStrokeEffect && typeof this._stroke.id === "undefined") {
            domElement.defs._flagUpdate = true;
            delete this._renderer.hasStrokeEffect;
          }
        }
        if (this._flagLinewidth) {
          changed["stroke-width"] = this._linewidth;
        }
        if (this._flagOpacity) {
          changed.opacity = this._opacity;
        }
        if (this._flagClassName) {
          changed["class"] = this.classList.join(" ");
        }
        if (this._flagVisible) {
          changed.visibility = this._visible ? "visible" : "hidden";
        }
        if (this.dashes && this.dashes.length > 0) {
          changed["stroke-dasharray"] = this.dashes.join(" ");
          changed["stroke-dashoffset"] = this.dashes.offset || 0;
        }
        if (!this._renderer.elem) {
          changed.id = this._id;
          this._renderer.elem = svg.createElement("text", changed);
          domElement.appendChild(this._renderer.elem);
        } else {
          svg.setAttributes(this._renderer.elem, changed);
        }
        if (this._flagClip) {
          const clip = svg.getClip(this, domElement);
          const elem = this._renderer.elem;
          if (this._clip) {
            elem.removeAttribute("id");
            clip.setAttribute("id", this.id);
            clip.appendChild(elem);
          } else {
            clip.removeAttribute("id");
            elem.setAttribute("id", this.id);
            this.parent._renderer.elem.appendChild(elem);
          }
        }
        if (this._flagMask) {
          if (this._mask) {
            const prop = svg.getRendererType(this._mask._renderer.type);
            svg[prop].render.call(this._mask, domElement);
            this._renderer.elem.setAttribute(
              "clip-path",
              "url(#" + this._mask.id + ")"
            );
          } else {
            this._renderer.elem.removeAttribute("clip-path");
          }
        }
        if (this._flagValue) {
          this._renderer.elem.textContent = this._value;
        }
        return this.flagReset();
      }
    },
    "linear-gradient": {
      render: function(domElement, silent) {
        if (_.isFunction(this._renderer.onBeforeRender)) {
          this._renderer.onBeforeRender();
        }
        if (!silent) {
          this._update();
        }
        const changed = {};
        if (this._flagId) {
          changed.id = this._id;
        }
        if (this._flagEndPoints) {
          changed.x1 = this.left._x;
          changed.y1 = this.left._y;
          changed.x2 = this.right._x;
          changed.y2 = this.right._y;
        }
        if (this._flagSpread) {
          changed.spreadMethod = this._spread;
        }
        if (this._flagUnits) {
          changed.gradientUnits = this._units;
        }
        if (!this._renderer.elem) {
          changed.id = this._id;
          this._renderer.elem = svg.createElement("linearGradient", changed);
        } else {
          svg.setAttributes(this._renderer.elem, changed);
        }
        if (this._renderer.elem.parentNode === null) {
          domElement.defs.appendChild(this._renderer.elem);
        }
        if (this._flagStops) {
          const lengthChanged = this._renderer.elem.childNodes.length !== this.stops.length;
          if (lengthChanged) {
            while (this._renderer.elem.lastChild) {
              this._renderer.elem.removeChild(this._renderer.elem.lastChild);
            }
          }
          for (let i = 0; i < this.stops.length; i++) {
            const stop = this.stops[i];
            const attrs = {};
            if (stop._flagOffset) {
              attrs.offset = 100 * stop._offset + "%";
            }
            if (stop._flagColor) {
              attrs["stop-color"] = stop._color;
            }
            if (stop._flagOpacity) {
              attrs["stop-opacity"] = stop._opacity;
            }
            if (!stop._renderer.elem) {
              stop._renderer.elem = svg.createElement("stop", attrs);
            } else {
              svg.setAttributes(stop._renderer.elem, attrs);
            }
            if (lengthChanged) {
              this._renderer.elem.appendChild(stop._renderer.elem);
            }
            stop.flagReset();
          }
        }
        if (_.isFunction(this._renderer.onAfterRender)) {
          this._renderer.onAfterRender();
        }
        return this.flagReset();
      }
    },
    "radial-gradient": {
      render: function(domElement, silent) {
        if (_.isFunction(this._renderer.onBeforeRender)) {
          this._renderer.onBeforeRender();
        }
        if (!silent) {
          this._update();
        }
        const changed = {};
        if (this._flagId) {
          changed.id = this._id;
        }
        if (this._flagCenter) {
          changed.cx = this.center._x;
          changed.cy = this.center._y;
        }
        if (this._flagFocal) {
          changed.fx = this.focal._x;
          changed.fy = this.focal._y;
        }
        if (this._flagRadius) {
          changed.r = this._radius;
        }
        if (this._flagSpread) {
          changed.spreadMethod = this._spread;
        }
        if (this._flagUnits) {
          changed.gradientUnits = this._units;
        }
        if (!this._renderer.elem) {
          changed.id = this._id;
          this._renderer.elem = svg.createElement("radialGradient", changed);
        } else {
          svg.setAttributes(this._renderer.elem, changed);
        }
        if (this._renderer.elem.parentNode === null) {
          domElement.defs.appendChild(this._renderer.elem);
        }
        if (this._flagStops) {
          const lengthChanged = this._renderer.elem.childNodes.length !== this.stops.length;
          if (lengthChanged) {
            while (this._renderer.elem.lastChild) {
              this._renderer.elem.removeChild(this._renderer.elem.lastChild);
            }
          }
          for (let i = 0; i < this.stops.length; i++) {
            const stop = this.stops[i];
            const attrs = {};
            if (stop._flagOffset) {
              attrs.offset = 100 * stop._offset + "%";
            }
            if (stop._flagColor) {
              attrs["stop-color"] = stop._color;
            }
            if (stop._flagOpacity) {
              attrs["stop-opacity"] = stop._opacity;
            }
            if (!stop._renderer.elem) {
              stop._renderer.elem = svg.createElement("stop", attrs);
            } else {
              svg.setAttributes(stop._renderer.elem, attrs);
            }
            if (lengthChanged) {
              this._renderer.elem.appendChild(stop._renderer.elem);
            }
            stop.flagReset();
          }
        }
        if (_.isFunction(this._renderer.onAfterRender)) {
          this._renderer.onAfterRender();
        }
        return this.flagReset();
      }
    },
    texture: {
      render: function(domElement, silent) {
        if (_.isFunction(this._renderer.onBeforeRender)) {
          this._renderer.onBeforeRender();
        }
        if (!silent) {
          this._update();
        }
        const changed = {};
        const styles = { x: 0, y: 0 };
        const image = this.image;
        if (this._flagId) {
          changed.id = this._id;
        }
        if (this._flagLoaded && this.loaded) {
          switch (image.nodeName.toLowerCase()) {
            case "canvas":
              styles.href = styles["xlink:href"] = image.toDataURL("image/png");
              break;
            case "img":
            case "image":
              styles.href = styles["xlink:href"] = this.src;
              break;
          }
        }
        if (this._flagOffset || this._flagLoaded || this._flagScale) {
          changed.x = this._offset.x;
          changed.y = this._offset.y;
          if (image) {
            changed.x -= image.width / 2;
            changed.y -= image.height / 2;
            if (this._scale instanceof Vector) {
              changed.x *= this._scale.x;
              changed.y *= this._scale.y;
            } else {
              changed.x *= this._scale;
              changed.y *= this._scale;
            }
          }
          if (changed.x > 0) {
            changed.x *= -1;
          }
          if (changed.y > 0) {
            changed.y *= -1;
          }
        }
        if (this._flagScale || this._flagLoaded || this._flagRepeat) {
          changed.width = 0;
          changed.height = 0;
          if (image) {
            changed.width = image.width;
            changed.height = image.height;
            switch (this._repeat) {
              case "no-repeat":
                changed.width += 1;
                changed.height += 1;
                break;
            }
            if (this._scale instanceof Vector) {
              changed.width *= this._scale.x;
              changed.height *= this._scale.y;
            } else {
              changed.width *= this._scale;
              changed.height *= this._scale;
            }
            styles.width = changed.width;
            styles.height = changed.height;
          }
        }
        if (this._flagScale || this._flagLoaded) {
          if (!this._renderer.image) {
            this._renderer.image = svg.createElement("image", styles);
          } else {
            svg.setAttributes(this._renderer.image, styles);
          }
        }
        if (!this._renderer.elem) {
          changed.id = this._id;
          changed.patternUnits = "userSpaceOnUse";
          this._renderer.elem = svg.createElement("pattern", changed);
        } else if (Object.keys(changed).length !== 0) {
          svg.setAttributes(this._renderer.elem, changed);
        }
        if (this._renderer.elem.parentNode === null) {
          domElement.defs.appendChild(this._renderer.elem);
        }
        if (this._renderer.elem && this._renderer.image && !this._renderer.appended) {
          this._renderer.elem.appendChild(this._renderer.image);
          this._renderer.appended = true;
        }
        if (_.isFunction(this._renderer.onAfterRender)) {
          this._renderer.onAfterRender();
        }
        return this.flagReset();
      }
    }
  };
  var Renderer2 = class extends Events {
    constructor(params) {
      super();
      this.domElement = params.domElement || svg.createElement("svg");
      this.scene = new Group();
      this.scene.parent = this;
      this.defs = svg.createElement("defs");
      this.defs._flagUpdate = false;
      this.domElement.appendChild(this.defs);
      this.domElement.defs = this.defs;
      this.domElement.style.overflow = "hidden";
    }
    setSize(width, height) {
      this.width = width;
      this.height = height;
      svg.setAttributes(this.domElement, {
        width,
        height
      });
      return this.trigger(Events.Types.resize, width, height);
    }
    render() {
      svg.group.render.call(this.scene, this.domElement);
      svg.defs.update(this.domElement);
      return this;
    }
  };
  __publicField(Renderer2, "Utils", svg);

  // src/utils/shaders.js
  var shaders = {
    create: function(gl, source, type) {
      const shader = gl.createShader(gl[type]);
      gl.shaderSource(shader, source);
      gl.compileShader(shader);
      const compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
      if (!compiled) {
        const error = gl.getShaderInfoLog(shader);
        gl.deleteShader(shader);
        throw new TwoError("unable to compile shader " + shader + ": " + error);
      }
      return shader;
    },
    types: {
      vertex: "VERTEX_SHADER",
      fragment: "FRAGMENT_SHADER"
    },
    path: {
      vertex: `
      precision mediump float;
      attribute vec2 a_position;

      uniform mat3 u_matrix;
      uniform vec2 u_resolution;
      uniform vec4 u_rect;

      varying vec2 v_textureCoords;

      void main() {
        vec2 rectCoords = (a_position * (u_rect.zw - u_rect.xy)) + u_rect.xy;
        vec2 projected = (u_matrix * vec3(rectCoords, 1.0)).xy;
        vec2 normal = projected / u_resolution;
        vec2 clipspace = (normal * 2.0) - 1.0;

        gl_Position = vec4(clipspace * vec2(1.0, -1.0), 0.0, 1.0);
        v_textureCoords = a_position;
      }
    `,
      fragment: `
      precision mediump float;

      uniform sampler2D u_image;
      varying vec2 v_textureCoords;

      void main() {
        vec4 texel = texture2D(u_image, v_textureCoords);
        if (texel.a == 0.0) {
          discard;
        }
        gl_FragColor = texel;
      }
    `
    },
    points: {
      vertex: `
      precision mediump float;
      attribute vec2 a_position;

      uniform float u_size;
      uniform mat3 u_matrix;
      uniform vec2 u_resolution;

      varying vec2 v_textureCoords;

      void main() {
        vec2 projected = (u_matrix * vec3(a_position, 1.0)).xy;
        vec2 normal = projected / u_resolution;
        vec2 clipspace = (normal * 2.0) - 1.0;

        gl_PointSize = u_size;
        gl_Position = vec4(clipspace * vec2(1.0, -1.0), 0.0, 1.0);
        v_textureCoords = a_position;
      }
    `,
      fragment: `
      precision mediump float;

      uniform sampler2D u_image;

      void main() {
        vec4 texel = texture2D(u_image, gl_PointCoord);
        if (texel.a == 0.0) {
          discard;
        }
        gl_FragColor = texel;
      }
    `
    }
  };

  // src/renderers/webgl.js
  var multiplyMatrix = Matrix2.Multiply;
  var identity = [1, 0, 0, 0, 1, 0, 0, 0, 1];
  var transformation = new NumArray(9);
  var CanvasUtils = Renderer.Utils;
  var vector2 = new Vector();
  var quad = new NumArray([0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1]);
  var webgl = {
    precision: 0.9,
    isHidden: /(undefined|none|transparent)/i,
    canvas: root.document ? root.document.createElement("canvas") : { getContext: function() {
    } },
    alignments: {
      left: "start",
      middle: "center",
      right: "end"
    },
    matrix: new Matrix2(),
    group: {
      removeChild: function(child, gl) {
        if (child.children) {
          for (let i = 0; i < child.children.length; i++) {
            webgl.group.removeChild(child.children[i], gl);
          }
        }
        if (child._renderer.texture) {
          gl.deleteTexture(child._renderer.texture);
          delete child._renderer.texture;
        }
        if (child._renderer.positionBuffer) {
          gl.deleteBuffer(child._renderer.positionBuffer);
          delete child._renderer.positionBuffer;
        }
      },
      render: function(gl, programs) {
        if (!this._visible) {
          return;
        }
        if (_.isFunction(this._renderer.onBeforeRender)) {
          this._renderer.onBeforeRender();
        }
        this._update();
        const parent = this.parent;
        const flagParentMatrix = parent._matrix && parent._matrix.manual || parent._flagMatrix;
        const flagMatrix = this._matrix.manual || this._flagMatrix;
        if (flagParentMatrix || flagMatrix) {
          if (!this._renderer.matrix) {
            this._renderer.matrix = new NumArray(9);
          }
          this._matrix.toTransformArray(true, transformation);
          multiplyMatrix(
            transformation,
            parent._renderer.matrix,
            this._renderer.matrix
          );
          if (!(this._renderer.scale instanceof Vector)) {
            this._renderer.scale = new Vector();
          }
          if (this._scale instanceof Vector) {
            this._renderer.scale.x = this._scale.x;
            this._renderer.scale.y = this._scale.y;
          } else {
            this._renderer.scale.x = this._scale;
            this._renderer.scale.y = this._scale;
          }
          if (!/renderer/i.test(parent._renderer.type)) {
            this._renderer.scale.x *= parent._renderer.scale.x;
            this._renderer.scale.y *= parent._renderer.scale.y;
          }
          if (flagParentMatrix) {
            this._flagMatrix = true;
          }
        }
        if (this._mask) {
          gl.clear(gl.STENCIL_BUFFER_BIT);
          gl.enable(gl.STENCIL_TEST);
          gl.stencilFunc(gl.ALWAYS, 1, 0);
          gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE);
          gl.colorMask(false, false, false, false);
          const prop = Renderer.Utils.getRendererType(
            this._mask._renderer.type
          );
          webgl[prop].render.call(this._mask, gl, programs, this);
          gl.stencilFunc(gl.EQUAL, 1, 255);
          gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
          gl.colorMask(true, true, true, true);
        }
        this._flagOpacity = parent._flagOpacity || this._flagOpacity;
        this._renderer.opacity = this._opacity * (parent && parent._renderer ? parent._renderer.opacity : 1);
        let i;
        if (this._flagSubtractions) {
          for (i = 0; i < this.subtractions.length; i++) {
            webgl.group.removeChild(this.subtractions[i], gl);
          }
        }
        for (i = 0; i < this.children.length; i++) {
          const child = this.children[i];
          const prop = Renderer.Utils.getRendererType(child._renderer.type);
          webgl[prop].render.call(child, gl, programs);
        }
        if (this._mask) {
          gl.disable(gl.STENCIL_TEST);
        }
        if (_.isFunction(this._renderer.onAfterRender)) {
          this._renderer.onAfterRender();
        }
        return this.flagReset();
      }
    },
    path: {
      updateCanvas: function(gl, elem) {
        let prev, a, c, ux, uy, vx, vy, ar, bl, br, cl, x, y;
        let isOffset;
        const commands = elem._renderer.vertices;
        const canvas3 = this.canvas;
        const ctx = this.ctx;
        const ratio = gl.renderer.ratio;
        const scale = vector2.copy(elem._renderer.scale).multiply(ratio);
        const stroke = elem._stroke;
        const linewidth = elem._linewidth;
        const fill = elem._fill;
        const opacity = elem._renderer.opacity || elem._opacity;
        const cap = elem._cap;
        const join = elem._join;
        const miter = elem._miter;
        const closed2 = elem._closed;
        const dashes = elem.dashes;
        const length = commands.length;
        const last = length - 1;
        canvas3.width = Math.max(
          Math.ceil(elem._renderer.rect.width * scale.x),
          1
        );
        canvas3.height = Math.max(
          Math.ceil(elem._renderer.rect.height * scale.y),
          1
        );
        const centroid = elem._renderer.rect.centroid;
        const cx = centroid.x;
        const cy = centroid.y;
        ctx.clearRect(0, 0, canvas3.width, canvas3.height);
        if (fill) {
          if (typeof fill === "string") {
            ctx.fillStyle = fill;
          } else {
            const prop = Renderer.Utils.getRendererType(
              fill._renderer.type
            );
            webgl[prop].render.call(fill, ctx, elem);
            ctx.fillStyle = fill._renderer.effect;
          }
        }
        if (stroke) {
          if (typeof stroke === "string") {
            ctx.strokeStyle = stroke;
          } else {
            const prop = Renderer.Utils.getRendererType(
              stroke._renderer.type
            );
            webgl[prop].render.call(stroke, ctx, elem);
            ctx.strokeStyle = stroke._renderer.effect;
          }
          if (linewidth) {
            ctx.lineWidth = linewidth;
          }
          if (miter) {
            ctx.miterLimit = miter;
          }
          if (join) {
            ctx.lineJoin = join;
          }
          if (!closed2 && cap) {
            ctx.lineCap = cap;
          }
        }
        if (typeof opacity === "number") {
          ctx.globalAlpha = opacity;
        }
        if (dashes && dashes.length > 0) {
          ctx.lineDashOffset = dashes.offset || 0;
          ctx.setLineDash(dashes);
        }
        let d, rx, ry, xAxisRotation, largeArcFlag, sweepFlag, ax, ay;
        ctx.save();
        ctx.scale(scale.x, scale.y);
        ctx.translate(cx, cy);
        ctx.beginPath();
        for (let i = 0; i < commands.length; i++) {
          const b = commands[i];
          x = b.x;
          y = b.y;
          switch (b.command) {
            case Commands.close:
              ctx.closePath();
              break;
            case Commands.arc:
              rx = b.rx;
              ry = b.ry;
              xAxisRotation = b.xAxisRotation;
              largeArcFlag = b.largeArcFlag;
              sweepFlag = b.sweepFlag;
              prev = closed2 ? mod(i - 1, length) : Math.max(i - 1, 0);
              a = commands[prev];
              ax = a.x;
              ay = a.y;
              CanvasUtils.renderSvgArcCommand(
                ctx,
                ax,
                ay,
                rx,
                ry,
                largeArcFlag,
                sweepFlag,
                xAxisRotation,
                x,
                y
              );
              break;
            case Commands.curve:
              prev = closed2 ? mod(i - 1, length) : Math.max(i - 1, 0);
              a = commands[prev];
              ar = a.controls && a.controls.right || Vector.zero;
              bl = b.controls && b.controls.left || Vector.zero;
              if (a._relative) {
                vx = ar.x + a.x;
                vy = ar.y + a.y;
              } else {
                vx = ar.x;
                vy = ar.y;
              }
              if (b._relative) {
                ux = bl.x + b.x;
                uy = bl.y + b.y;
              } else {
                ux = bl.x;
                uy = bl.y;
              }
              ctx.bezierCurveTo(vx, vy, ux, uy, x, y);
              if (i >= last && closed2) {
                c = d;
                br = b.controls && b.controls.right || Vector.zero;
                cl = c.controls && c.controls.left || Vector.zero;
                if (b._relative) {
                  vx = br.x + b.x;
                  vy = br.y + b.y;
                } else {
                  vx = br.x;
                  vy = br.y;
                }
                if (c._relative) {
                  ux = cl.x + c.x;
                  uy = cl.y + c.y;
                } else {
                  ux = cl.x;
                  uy = cl.y;
                }
                x = c.x;
                y = c.y;
                ctx.bezierCurveTo(vx, vy, ux, uy, x, y);
              }
              break;
            case Commands.line:
              ctx.lineTo(x, y);
              break;
            case Commands.move:
              d = b;
              ctx.moveTo(x, y);
              break;
          }
        }
        if (closed2) {
          ctx.closePath();
        }
        if (!webgl.isHidden.test(fill)) {
          isOffset = fill._renderer && fill._renderer.offset;
          if (isOffset) {
            ctx.save();
            ctx.translate(-fill._renderer.offset.x, -fill._renderer.offset.y);
            ctx.scale(fill._renderer.scale.x, fill._renderer.scale.y);
          }
          ctx.fill();
          if (isOffset) {
            ctx.restore();
          }
        }
        if (!webgl.isHidden.test(stroke)) {
          isOffset = stroke._renderer && stroke._renderer.offset;
          if (isOffset) {
            ctx.save();
            ctx.translate(-stroke._renderer.offset.x, -stroke._renderer.offset.y);
            ctx.scale(stroke._renderer.scale.x, stroke._renderer.scale.y);
            ctx.lineWidth = linewidth / stroke._renderer.scale.x;
          }
          ctx.stroke();
          if (isOffset) {
            ctx.restore();
          }
        }
        ctx.restore();
      },
      getBoundingClientRect: function(vertices, border, rect) {
        let left = Infinity, right = -Infinity, top = Infinity, bottom = -Infinity, width, height;
        vertices.forEach(function(v) {
          const x = v.x, y = v.y, controls = v.controls;
          let a, b, c, d, cl, cr;
          top = Math.min(y, top);
          left = Math.min(x, left);
          right = Math.max(x, right);
          bottom = Math.max(y, bottom);
          if (!v.controls) {
            return;
          }
          cl = controls.left;
          cr = controls.right;
          if (!cl || !cr) {
            return;
          }
          a = v._relative ? cl.x + x : cl.x;
          b = v._relative ? cl.y + y : cl.y;
          c = v._relative ? cr.x + x : cr.x;
          d = v._relative ? cr.y + y : cr.y;
          if (!a || !b || !c || !d) {
            return;
          }
          top = Math.min(b, d, top);
          left = Math.min(a, c, left);
          right = Math.max(a, c, right);
          bottom = Math.max(b, d, bottom);
        });
        if (typeof border === "number") {
          top -= border;
          left -= border;
          right += border;
          bottom += border;
        }
        width = right - left;
        height = bottom - top;
        rect.top = top;
        rect.left = left;
        rect.right = right;
        rect.bottom = bottom;
        rect.width = width;
        rect.height = height;
        if (!rect.centroid) {
          rect.centroid = {};
        }
        rect.centroid.x = -left;
        rect.centroid.y = -top;
      },
      render: function(gl, programs, forcedParent) {
        if (!this._visible || !this._opacity) {
          return this;
        }
        if (_.isFunction(this._renderer.onBeforeRender)) {
          this._renderer.onBeforeRender();
        }
        this._update();
        const parent = forcedParent || this.parent;
        const prop = Renderer.Utils.getRendererType(this._renderer.type);
        const program = programs[prop];
        const flagParentMatrix = parent._matrix.manual || parent._flagMatrix;
        const flagMatrix = this._matrix.manual || this._flagMatrix;
        const parentChanged = this._renderer.parent !== parent;
        const flagTexture = this._flagVertices || this._flagFill || this._fill instanceof LinearGradient && (this._fill._flagSpread || this._fill._flagStops || this._fill._flagEndPoints) || this._fill instanceof RadialGradient && (this._fill._flagSpread || this._fill._flagStops || this._fill._flagRadius || this._fill._flagCenter || this._fill._flagFocal) || this._fill instanceof Texture && (this._fill._flagLoaded && this._fill.loaded || this._fill._flagImage || this._fill._flagVideo || this._fill._flagRepeat || this._fill._flagOffset || this._fill._flagScale) || this._stroke instanceof LinearGradient && (this._stroke._flagSpread || this._stroke._flagStops || this._stroke._flagEndPoints) || this._stroke instanceof RadialGradient && (this._stroke._flagSpread || this._stroke._flagStops || this._stroke._flagRadius || this._stroke._flagCenter || this._stroke._flagFocal) || this._stroke instanceof Texture && (this._stroke._flagLoaded && this._stroke.loaded || this._stroke._flagImage || this._stroke._flagVideo || this._stroke._flagRepeat || this._stroke._flagOffset || this._fill._flagScale) || this._flagStroke || this._flagLinewidth || this._flagOpacity || parent._flagOpacity || this._flagVisible || this._flagCap || this._flagJoin || this._flagMiter || this._flagScale || this.dashes && this.dashes.length > 0 || !this._renderer.texture;
        if (flagParentMatrix || flagMatrix || parentChanged) {
          if (!this._renderer.matrix) {
            this._renderer.matrix = new NumArray(9);
          }
          this._matrix.toTransformArray(true, transformation);
          multiplyMatrix(
            transformation,
            parent._renderer.matrix,
            this._renderer.matrix
          );
          if (!(this._renderer.scale instanceof Vector)) {
            this._renderer.scale = new Vector();
          }
          let sx, sy;
          if (this._scale instanceof Vector) {
            sx = this._scale.x * parent._renderer.scale.x;
            sy = this._scale.y * parent._renderer.scale.y;
          } else {
            sx = this._scale * parent._renderer.scale.x;
            sy = this._scale * parent._renderer.scale.y;
          }
          this._renderer.scale.x = sx < 0 ? -sx : sx;
          this._renderer.scale.y = sy < 0 ? -sy : sy;
          if (parentChanged) {
            this._renderer.parent = parent;
          }
        }
        if (this._mask) {
          gl.clear(gl.STENCIL_BUFFER_BIT);
          gl.enable(gl.STENCIL_TEST);
          gl.stencilFunc(gl.ALWAYS, 1, 0);
          gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE);
          gl.colorMask(false, false, false, false);
          const prop2 = Renderer.Utils.getRendererType(
            this._mask._renderer.type
          );
          webgl[prop2].render.call(this._mask, gl, programs, this);
          gl.stencilFunc(gl.EQUAL, 1, 255);
          gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
          gl.colorMask(true, true, true, true);
        }
        if (flagTexture) {
          if (!this._renderer.rect) {
            this._renderer.rect = {};
          }
          this._renderer.opacity = this._opacity * parent._renderer.opacity;
          webgl.path.getBoundingClientRect(
            this._renderer.vertices,
            this._linewidth,
            this._renderer.rect
          );
          webgl.updateTexture.call(webgl, gl, this);
        } else {
          if (this._fill && this._fill._update) {
            this._fill._update();
          }
          if (this._stroke && this._stroke._update) {
            this._stroke._update();
          }
        }
        if (this._clip && !forcedParent || !this._renderer.texture) {
          return this;
        }
        if (programs.current !== program) {
          gl.useProgram(program);
          gl.bindBuffer(gl.ARRAY_BUFFER, programs.buffers.position);
          gl.vertexAttribPointer(program.position, 2, gl.FLOAT, false, 0, 0);
          gl.enableVertexAttribArray(program.position);
          gl.bufferData(gl.ARRAY_BUFFER, quad, gl.STATIC_DRAW);
          if (!programs.resolution.flagged) {
            gl.uniform2f(
              gl.getUniformLocation(program, "u_resolution"),
              programs.resolution.width,
              programs.resolution.height
            );
          }
          programs.current = program;
        }
        if (programs.resolution.flagged) {
          gl.uniform2f(
            gl.getUniformLocation(program, "u_resolution"),
            programs.resolution.width,
            programs.resolution.height
          );
        }
        gl.bindTexture(gl.TEXTURE_2D, this._renderer.texture);
        const rect = this._renderer.rect;
        gl.uniformMatrix3fv(program.matrix, false, this._renderer.matrix);
        gl.uniform4f(program.rect, rect.left, rect.top, rect.right, rect.bottom);
        gl.drawArrays(gl.TRIANGLES, 0, 6);
        if (this._mask) {
          gl.disable(gl.STENCIL_TEST);
        }
        if (_.isFunction(this._renderer.onAfterRender)) {
          this._renderer.onAfterRender();
        }
        return this.flagReset();
      }
    },
    points: {
      updateCanvas: function(gl, elem) {
        let isOffset;
        const canvas3 = this.canvas;
        const ctx = this.ctx;
        const ratio = gl.renderer.ratio;
        const stroke = elem._stroke;
        const linewidth = elem._linewidth;
        const fill = elem._fill;
        const opacity = elem._renderer.opacity || elem._opacity;
        const dashes = elem.dashes;
        const size = elem._size * ratio;
        let dimension = size;
        if (!webgl.isHidden.test(stroke)) {
          dimension += linewidth;
        }
        canvas3.width = getPoT(dimension);
        canvas3.height = canvas3.width;
        const aspect = dimension / canvas3.width;
        const cx = canvas3.width / 2;
        const cy = canvas3.height / 2;
        ctx.clearRect(0, 0, canvas3.width, canvas3.height);
        if (fill) {
          if (typeof fill === "string") {
            ctx.fillStyle = fill;
          } else {
            const prop = Renderer.Utils.getRendererType(
              fill._renderer.type
            );
            webgl[prop].render.call(fill, ctx, elem);
            ctx.fillStyle = fill._renderer.effect;
          }
        }
        if (stroke) {
          if (typeof stroke === "string") {
            ctx.strokeStyle = stroke;
          } else {
            const prop = Renderer.Utils.getRendererType(
              stroke._renderer.type
            );
            webgl[prop].render.call(stroke, ctx, elem);
            ctx.strokeStyle = stroke._renderer.effect;
          }
          if (linewidth) {
            ctx.lineWidth = linewidth / aspect;
          }
        }
        if (typeof opacity === "number") {
          ctx.globalAlpha = opacity;
        }
        if (dashes && dashes.length > 0) {
          ctx.lineDashOffset = dashes.offset || 0;
          ctx.setLineDash(dashes);
        }
        ctx.save();
        ctx.translate(cx, cy);
        ctx.scale(webgl.precision, webgl.precision);
        ctx.beginPath();
        ctx.arc(0, 0, size / aspect * 0.5, 0, TWO_PI);
        ctx.restore();
        if (closed) {
          ctx.closePath();
        }
        if (!webgl.isHidden.test(fill)) {
          isOffset = fill._renderer && fill._renderer.offset;
          if (isOffset) {
            ctx.save();
            ctx.translate(-fill._renderer.offset.x, -fill._renderer.offset.y);
            ctx.scale(fill._renderer.scale.x, fill._renderer.scale.y);
          }
          ctx.fill();
          if (isOffset) {
            ctx.restore();
          }
        }
        if (!webgl.isHidden.test(stroke)) {
          isOffset = stroke._renderer && stroke._renderer.offset;
          if (isOffset) {
            ctx.save();
            ctx.translate(-stroke._renderer.offset.x, -stroke._renderer.offset.y);
            ctx.scale(stroke._renderer.scale.x, stroke._renderer.scale.y);
            ctx.lineWidth = linewidth / stroke._renderer.scale.x;
          }
          ctx.stroke();
          if (isOffset) {
            ctx.restore();
          }
        }
      },
      render: function(gl, programs, forcedParent) {
        if (!this._visible || !this._opacity) {
          return this;
        }
        if (_.isFunction(this._renderer.onBeforeRender)) {
          this._renderer.onBeforeRender();
        }
        this._update();
        let size = this._size;
        const parent = forcedParent || this.parent;
        const program = programs[this._renderer.type];
        const sizeAttenuation = this._sizeAttenuation;
        const stroke = this._stroke;
        const linewidth = this._linewidth;
        const flagParentMatrix = parent._matrix.manual || parent._flagMatrix;
        const flagMatrix = this._matrix.manual || this._flagMatrix;
        const parentChanged = this._renderer.parent !== parent;
        const commands = this._renderer.vertices;
        const length = this._renderer.collection.length;
        const flagVertices = this._flagVertices;
        const flagTexture = this._flagFill || this._fill instanceof LinearGradient && (this._fill._flagSpread || this._fill._flagStops || this._fill._flagEndPoints) || this._fill instanceof RadialGradient && (this._fill._flagSpread || this._fill._flagStops || this._fill._flagRadius || this._fill._flagCenter || this._fill._flagFocal) || this._fill instanceof Texture && (this._fill._flagLoaded && this._fill.loaded || this._fill._flagImage || this._fill._flagVideo || this._fill._flagRepeat || this._fill._flagOffset || this._fill._flagScale) || this._stroke instanceof LinearGradient && (this._stroke._flagSpread || this._stroke._flagStops || this._stroke._flagEndPoints) || this._stroke instanceof RadialGradient && (this._stroke._flagSpread || this._stroke._flagStops || this._stroke._flagRadius || this._stroke._flagCenter || this._stroke._flagFocal) || this._stroke instanceof Texture && (this._stroke._flagLoaded && this._stroke.loaded || this._stroke._flagImage || this._stroke._flagVideo || this._stroke._flagRepeat || this._stroke._flagOffset || this._fill._flagScale) || this._flagStroke || this._flagLinewidth || this._flagOpacity || parent._flagOpacity || this._flagVisible || this._flagScale || this.dashes && this.dashes.length > 0 || !this._renderer.texture;
        if (flagParentMatrix || flagMatrix || parentChanged) {
          if (!this._renderer.matrix) {
            this._renderer.matrix = new NumArray(9);
          }
          this._matrix.toTransformArray(true, transformation);
          multiplyMatrix(
            transformation,
            parent._renderer.matrix,
            this._renderer.matrix
          );
          if (!(this._renderer.scale instanceof Vector)) {
            this._renderer.scale = new Vector();
          }
          let sx, sy;
          if (this._scale instanceof Vector) {
            sx = this._scale.x * parent._renderer.scale.x;
            sy = this._scale.y * parent._renderer.scale.y;
          } else {
            sx = this._scale * parent._renderer.scale.x;
            sy = this._scale * parent._renderer.scale.y;
          }
          this._renderer.scale.x = sx < 0 ? -sx : sx;
          this._renderer.scale.y = sy < 0 ? -sy : sy;
          if (parentChanged) {
            this._renderer.parent = parent;
          }
        }
        if (flagVertices) {
          const positionBuffer = this._renderer.positionBuffer;
          if (positionBuffer) {
            gl.deleteBuffer(positionBuffer);
          }
          this._renderer.positionBuffer = gl.createBuffer();
          gl.bindBuffer(gl.ARRAY_BUFFER, this._renderer.positionBuffer);
          gl.vertexAttribPointer(program.position, 2, gl.FLOAT, false, 0, 0);
          gl.enableVertexAttribArray(program.position);
          gl.bufferData(gl.ARRAY_BUFFER, commands, gl.STATIC_DRAW);
        }
        if (flagTexture) {
          this._renderer.opacity = this._opacity * parent._renderer.opacity;
          webgl.updateTexture.call(webgl, gl, this);
        } else {
          if (this._fill && this._fill._update) {
            this._fill._update();
          }
          if (this._stroke && this._stroke._update) {
            this._stroke._update();
          }
        }
        if (this._clip && !forcedParent || !this._renderer.texture) {
          return this;
        }
        if (!webgl.isHidden.test(stroke)) {
          size += linewidth;
        }
        size /= webgl.precision;
        if (sizeAttenuation) {
          size *= Math.max(this._renderer.scale.x, this._renderer.scale.y);
        }
        if (programs.current !== program) {
          gl.useProgram(program);
          if (!programs.resolution.flagged) {
            gl.uniform2f(
              gl.getUniformLocation(program, "u_resolution"),
              programs.resolution.width,
              programs.resolution.height
            );
          }
          programs.current = program;
        }
        if (programs.resolution.flagged) {
          gl.uniform2f(
            gl.getUniformLocation(program, "u_resolution"),
            programs.resolution.width,
            programs.resolution.height
          );
        }
        gl.bindTexture(gl.TEXTURE_2D, this._renderer.texture);
        gl.uniformMatrix3fv(program.matrix, false, this._renderer.matrix);
        gl.uniform1f(program.size, size * programs.resolution.ratio);
        gl.drawArrays(gl.POINTS, 0, length);
        if (_.isFunction(this._renderer.onAfterRender)) {
          this._renderer.onAfterRender();
        }
        return this.flagReset();
      }
    },
    text: {
      updateCanvas: function(gl, elem) {
        const canvas3 = this.canvas;
        const ctx = this.ctx;
        const ratio = gl.renderer.ratio;
        const scale = vector2.copy(elem._renderer.scale).multiply(ratio);
        const stroke = elem._stroke;
        const linewidth = elem._linewidth;
        const fill = elem._fill;
        const opacity = elem._renderer.opacity || elem._opacity;
        const dashes = elem.dashes;
        const decoration = elem._decoration;
        const direction = elem._direction;
        canvas3.width = Math.max(
          Math.ceil(elem._renderer.rect.width * scale.x),
          1
        );
        canvas3.height = Math.max(
          Math.ceil(elem._renderer.rect.height * scale.y),
          1
        );
        const centroid = elem._renderer.rect.centroid;
        const cx = centroid.x;
        const cy = centroid.y;
        let a, b, c, d, e, sx, sy, x1, y1, x2, y2;
        const isOffset = fill._renderer && fill._renderer.offset && stroke._renderer && stroke._renderer.offset;
        ctx.clearRect(0, 0, canvas3.width, canvas3.height);
        if (!isOffset) {
          ctx.font = [
            elem._style,
            elem._weight,
            elem._size + "px/" + elem._leading + "px",
            elem._family
          ].join(" ");
        }
        ctx.textAlign = "center";
        ctx.textBaseline = "middle";
        ctx.textDirection = direction;
        if (fill) {
          if (typeof fill === "string") {
            ctx.fillStyle = fill;
          } else {
            const prop = Renderer.Utils.getRendererType(
              fill._renderer.type
            );
            webgl[prop].render.call(fill, ctx, elem);
            ctx.fillStyle = fill._renderer.effect;
          }
        }
        if (stroke) {
          if (typeof stroke === "string") {
            ctx.strokeStyle = stroke;
          } else {
            const prop = Renderer.Utils.getRendererType(
              stroke._renderer.type
            );
            webgl[prop].render.call(stroke, ctx, elem);
            ctx.strokeStyle = stroke._renderer.effect;
          }
          if (linewidth) {
            ctx.lineWidth = linewidth;
          }
        }
        if (typeof opacity === "number") {
          ctx.globalAlpha = opacity;
        }
        if (dashes && dashes.length > 0) {
          ctx.lineDashOffset = dashes.offset || 0;
          ctx.setLineDash(dashes);
        }
        ctx.save();
        ctx.scale(scale.x, scale.y);
        ctx.translate(cx, cy);
        if (!webgl.isHidden.test(fill)) {
          if (fill._renderer && fill._renderer.offset) {
            sx = fill._renderer.scale.x;
            sy = fill._renderer.scale.y;
            ctx.save();
            ctx.translate(-fill._renderer.offset.x, -fill._renderer.offset.y);
            ctx.scale(sx, sy);
            a = elem._size / fill._renderer.scale.y;
            b = elem._leading / fill._renderer.scale.y;
            ctx.font = [
              elem._style,
              elem._weight,
              a + "px/",
              b + "px",
              elem._family
            ].join(" ");
            c = fill._renderer.offset.x / fill._renderer.scale.x;
            d = fill._renderer.offset.y / fill._renderer.scale.y;
            ctx.fillText(elem.value, c, d);
            ctx.restore();
          } else {
            ctx.fillText(elem.value, 0, 0);
          }
        }
        if (!webgl.isHidden.test(stroke)) {
          if (stroke._renderer && stroke._renderer.offset) {
            sx = stroke._renderer.scale.x;
            sy = stroke._renderer.scale.y;
            ctx.save();
            ctx.translate(-stroke._renderer.offset.x, -stroke._renderer.offset.y);
            ctx.scale(sx, sy);
            a = elem._size / stroke._renderer.scale.y;
            b = elem._leading / stroke._renderer.scale.y;
            ctx.font = [
              elem._style,
              elem._weight,
              a + "px/",
              b + "px",
              elem._family
            ].join(" ");
            c = stroke._renderer.offset.x / stroke._renderer.scale.x;
            d = stroke._renderer.offset.y / stroke._renderer.scale.y;
            e = linewidth / stroke._renderer.scale.x;
            ctx.lineWidth = e;
            ctx.strokeText(elem.value, c, d);
            ctx.restore();
          } else {
            ctx.strokeText(elem.value, 0, 0);
          }
        }
        if (/(underline|strikethrough)/i.test(decoration)) {
          const metrics = ctx.measureText(elem.value);
          switch (decoration) {
            case "underline":
              y1 = metrics.actualBoundingBoxDescent;
              y2 = metrics.actualBoundingBoxDescent;
              break;
            case "strikethrough":
              y1 = 0;
              y2 = 0;
              break;
          }
          x1 = -metrics.width / 2;
          x2 = metrics.width / 2;
          ctx.lineWidth = Math.max(Math.floor(elem._size / 15), 1);
          ctx.strokeStyle = ctx.fillStyle;
          ctx.beginPath();
          ctx.moveTo(x1, y1);
          ctx.lineTo(x2, y2);
          ctx.stroke();
        }
        ctx.restore();
      },
      getBoundingClientRect: function(elem, rect) {
        const ctx = webgl.ctx;
        ctx.font = [
          elem._style,
          elem._weight,
          elem._size + "px/" + elem._leading + "px",
          elem._family
        ].join(" ");
        ctx.textAlign = "center";
        ctx.textBaseline = Renderer.Utils.baselines[elem._baseline] || elem._baseline;
        const metrics = ctx.measureText(elem._value);
        let width = metrics.width;
        let height = 1.15 * (metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent);
        if (this._linewidth && !webgl.isHidden.test(this._stroke)) {
          width += this._linewidth * 2;
          height += this._linewidth * 2;
        }
        const w = width / 2;
        const h = height / 2;
        switch (webgl.alignments[elem._alignment] || elem._alignment) {
          case webgl.alignments.left:
            if (elem.direction === "ltr") {
              rect.left = 0;
              rect.right = width;
            } else {
              rect.left = -width;
              rect.right = 0;
            }
            break;
          case webgl.alignments.right:
            if (elem.direction === "ltr") {
              rect.left = -width;
              rect.right = 0;
            } else {
              rect.left = 0;
              rect.right = width;
            }
            break;
          default:
            rect.left = -w;
            rect.right = w;
        }
        switch (elem._baseline) {
          case "bottom":
            rect.top = -height;
            rect.bottom = 0;
            break;
          case "top":
            rect.top = 0;
            rect.bottom = height;
            break;
          case "baseline":
            rect.top = -h * 1.5;
            rect.bottom = h * 0.5;
            break;
          default:
            rect.top = -h;
            rect.bottom = h;
        }
        rect.width = width;
        rect.height = height;
        if (!rect.centroid) {
          rect.centroid = {};
        }
        rect.centroid.x = w;
        rect.centroid.y = h;
      },
      render: function(gl, programs, forcedParent) {
        if (!this._visible || !this._opacity) {
          return this;
        }
        if (_.isFunction(this._renderer.onBeforeRender)) {
          this._renderer.onBeforeRender();
        }
        this._update();
        const parent = forcedParent || this.parent;
        const program = programs[this._renderer.type];
        const flagParentMatrix = parent._matrix.manual || parent._flagMatrix;
        const flagMatrix = this._matrix.manual || this._flagMatrix;
        const parentChanged = this._renderer.parent !== parent;
        const flagTexture = this._flagVertices || this._flagFill || this._fill instanceof LinearGradient && (this._fill._flagSpread || this._fill._flagStops || this._fill._flagEndPoints) || this._fill instanceof RadialGradient && (this._fill._flagSpread || this._fill._flagStops || this._fill._flagRadius || this._fill._flagCenter || this._fill._flagFocal) || this._fill instanceof Texture && (this._fill._flagLoaded && this._fill.loaded || this._fill._flagImage || this._fill._flagVideo || this._fill._flagRepeat || this._fill._flagOffset || this._fill._flagScale) || this._stroke instanceof LinearGradient && (this._stroke._flagSpread || this._stroke._flagStops || this._stroke._flagEndPoints) || this._stroke instanceof RadialGradient && (this._stroke._flagSpread || this._stroke._flagStops || this._stroke._flagRadius || this._stroke._flagCenter || this._stroke._flagFocal) || this._stroke instanceof Texture && (this._stroke._flagLoaded && this._stroke.loaded || this._stroke._flagImage || this._stroke._flagVideo || this._stroke._flagRepeat || this._stroke._flagOffset || this._fill._flagScale) || this._flagStroke || this._flagLinewidth || this._flagOpacity || parent._flagOpacity || this._flagVisible || this._flagScale || this._flagValue || this._flagFamily || this._flagSize || this._flagLeading || this._flagAlignment || this._flagBaseline || this._flagStyle || this._flagWeight || this._flagDecoration || this.dashes && this.dashes.length > 0 || !this._renderer.texture;
        if (flagParentMatrix || flagMatrix || parentChanged) {
          if (!this._renderer.matrix) {
            this._renderer.matrix = new NumArray(9);
          }
          this._matrix.toTransformArray(true, transformation);
          multiplyMatrix(
            transformation,
            parent._renderer.matrix,
            this._renderer.matrix
          );
          if (!(this._renderer.scale instanceof Vector)) {
            this._renderer.scale = new Vector();
          }
          let sx, sy;
          if (this._scale instanceof Vector) {
            sx = this._scale.x * parent._renderer.scale.x;
            sy = this._scale.y * parent._renderer.scale.y;
          } else {
            sx = this._scale * parent._renderer.scale.x;
            sy = this._scale * parent._renderer.scale.y;
          }
          this._renderer.scale.x = sx < 0 ? -sx : sx;
          this._renderer.scale.y = sy < 0 ? -sy : sy;
          if (parentChanged) {
            this._renderer.parent = parent;
          }
        }
        if (this._mask) {
          gl.clear(gl.STENCIL_BUFFER_BIT);
          gl.enable(gl.STENCIL_TEST);
          gl.stencilFunc(gl.ALWAYS, 1, 0);
          gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE);
          gl.colorMask(false, false, false, false);
          const prop = Renderer.Utils.getRendererType(
            this._mask._renderer.type
          );
          webgl[prop].render.call(this._mask, gl, programs, this);
          gl.stencilFunc(gl.EQUAL, 1, 255);
          gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
          gl.colorMask(true, true, true, true);
        }
        if (flagTexture) {
          if (!this._renderer.rect) {
            this._renderer.rect = {};
          }
          this._renderer.opacity = this._opacity * parent._renderer.opacity;
          webgl.text.getBoundingClientRect(this, this._renderer.rect);
          webgl.updateTexture.call(webgl, gl, this);
        } else {
          if (this._fill && this._fill._update) {
            this._fill._update();
          }
          if (this._stroke && this._stroke._update) {
            this._stroke._update();
          }
        }
        if (this._clip && !forcedParent || !this._renderer.texture) {
          return this;
        }
        if (programs.current !== program) {
          gl.useProgram(program);
          gl.bindBuffer(gl.ARRAY_BUFFER, programs.buffers.position);
          gl.vertexAttribPointer(program.position, 2, gl.FLOAT, false, 0, 0);
          gl.enableVertexAttribArray(program.position);
          gl.bufferData(gl.ARRAY_BUFFER, quad, gl.STATIC_DRAW);
          if (!programs.resolution.flagged) {
            gl.uniform2f(
              gl.getUniformLocation(program, "u_resolution"),
              programs.resolution.width,
              programs.resolution.height
            );
          }
          programs.current = program;
        }
        if (programs.resolution.flagged) {
          gl.uniform2f(
            gl.getUniformLocation(program, "u_resolution"),
            programs.resolution.width,
            programs.resolution.height
          );
        }
        gl.bindTexture(gl.TEXTURE_2D, this._renderer.texture);
        const rect = this._renderer.rect;
        gl.uniformMatrix3fv(program.matrix, false, this._renderer.matrix);
        gl.uniform4f(program.rect, rect.left, rect.top, rect.right, rect.bottom);
        gl.drawArrays(gl.TRIANGLES, 0, 6);
        if (this._mask) {
          gl.disable(gl.STENCIL_TEST);
        }
        if (_.isFunction(this._renderer.onAfterRender)) {
          this._renderer.onAfterRender();
        }
        return this.flagReset();
      }
    },
    "linear-gradient": {
      render: function(ctx, parent) {
        if (!ctx.canvas.getContext("2d") || !parent) {
          return;
        }
        if (_.isFunction(this._renderer.onBeforeRender)) {
          this._renderer.onBeforeRender();
        }
        this._update();
        if (!this._renderer.effect || this._flagEndPoints || this._flagStops || this._flagUnits) {
          let rect;
          let lx = this.left._x;
          let ly = this.left._y;
          let rx = this.right._x;
          let ry = this.right._y;
          if (/objectBoundingBox/i.test(this._units)) {
            rect = parent.getBoundingClientRect(true);
            lx = (lx - 0.5) * rect.width;
            ly = (ly - 0.5) * rect.height;
            rx = (rx - 0.5) * rect.width;
            ry = (ry - 0.5) * rect.height;
          }
          this._renderer.effect = ctx.createLinearGradient(lx, ly, rx, ry);
          for (let i = 0; i < this.stops.length; i++) {
            const stop = this.stops[i];
            this._renderer.effect.addColorStop(stop._offset, stop._color);
          }
        }
        if (_.isFunction(this._renderer.onAfterRender)) {
          this._renderer.onAfterRender();
        }
        return this.flagReset();
      }
    },
    "radial-gradient": {
      render: function(ctx, parent) {
        if (!ctx.canvas.getContext("2d") || !parent) {
          return;
        }
        if (_.isFunction(this._renderer.onBeforeRender)) {
          this._renderer.onBeforeRender();
        }
        this._update();
        if (!this._renderer.effect || this._flagCenter || this._flagFocal || this._flagRadius || this._flagStops || this._flagUnits) {
          let rect;
          let cx = this.center._x;
          let cy = this.center._y;
          let fx = this.focal._x;
          let fy = this.focal._y;
          let radius = this._radius;
          if (/objectBoundingBox/i.test(this._units)) {
            rect = parent.getBoundingClientRect(true);
            cx = (cx - 0.5) * rect.width * 0.5;
            cy = (cy - 0.5) * rect.height * 0.5;
            fx = (fx - 0.5) * rect.width * 0.5;
            fy = (fy - 0.5) * rect.height * 0.5;
            radius *= Math.min(rect.width, rect.height);
          }
          this._renderer.effect = ctx.createRadialGradient(
            cx,
            cy,
            0,
            fx,
            fy,
            radius
          );
          for (let i = 0; i < this.stops.length; i++) {
            const stop = this.stops[i];
            this._renderer.effect.addColorStop(stop._offset, stop._color);
          }
        }
        if (_.isFunction(this._renderer.onAfterRender)) {
          this._renderer.onAfterRender();
        }
        return this.flagReset();
      }
    },
    texture: {
      render: function(ctx, elem) {
        if (!ctx.canvas.getContext("2d")) {
          return;
        }
        if (_.isFunction(this._renderer.onBeforeRender)) {
          this._renderer.onBeforeRender();
        }
        this._update();
        const image = this.image;
        if ((this._flagLoaded || this._flagImage || this._flagVideo || this._flagRepeat) && this.loaded) {
          this._renderer.effect = ctx.createPattern(image, this._repeat);
        } else if (!this._renderer.effect) {
          return this.flagReset();
        }
        if (this._flagOffset || this._flagLoaded || this._flagScale) {
          if (!(this._renderer.offset instanceof Vector)) {
            this._renderer.offset = new Vector();
          }
          this._renderer.offset.x = -this._offset.x;
          this._renderer.offset.y = -this._offset.y;
          if (image) {
            this._renderer.offset.x += image.width / 2;
            this._renderer.offset.y += image.height / 2;
            if (this._scale instanceof Vector) {
              this._renderer.offset.x *= this._scale.x;
              this._renderer.offset.y *= this._scale.y;
            } else {
              this._renderer.offset.x *= this._scale;
              this._renderer.offset.y *= this._scale;
            }
          }
        }
        if (this._flagScale || this._flagLoaded) {
          if (!(this._renderer.scale instanceof Vector)) {
            this._renderer.scale = new Vector();
          }
          let sx, sy;
          if (this._scale instanceof Vector) {
            sx = this._scale.x;
            sy = this._scale.y;
          } else {
            sx = this._scale;
            sy = this._scale;
          }
          this._renderer.scale.x = sx < 0 ? -sx : sx;
          this._renderer.scale.y = sy < 0 ? -sy : sy;
        }
        if (_.isFunction(this._renderer.onAfterRender)) {
          this._renderer.onAfterRender();
        }
        return this.flagReset();
      }
    },
    updateTexture: function(gl, elem) {
      const prop = Renderer.Utils.getRendererType(elem._renderer.type);
      this[prop].updateCanvas.call(webgl, gl, elem);
      if (this.canvas.width <= 0 || this.canvas.height <= 0) {
        if (elem._renderer.texture) {
          gl.deleteTexture(elem._renderer.texture);
        }
        delete elem._renderer.texture;
        return;
      }
      if (!elem._renderer.texture) {
        elem._renderer.texture = gl.createTexture();
      }
      gl.bindTexture(gl.TEXTURE_2D, elem._renderer.texture);
      gl.texImage2D(
        gl.TEXTURE_2D,
        0,
        gl.RGBA,
        gl.RGBA,
        gl.UNSIGNED_BYTE,
        this.canvas
      );
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    },
    program: {
      create: function(gl, shaders2) {
        let program, linked, error;
        program = gl.createProgram();
        _.each(shaders2, function(s) {
          gl.attachShader(program, s);
        });
        gl.linkProgram(program);
        linked = gl.getProgramParameter(program, gl.LINK_STATUS);
        if (!linked) {
          error = gl.getProgramInfoLog(program);
          gl.deleteProgram(program);
          throw new TwoError("unable to link program: " + error);
        }
        return program;
      }
    },
    extensions: {
      init: function(gl) {
        const extensions = {};
        const names = [
          "EXT_texture_filter_anisotropic",
          "WEBGL_compressed_texture_s3tc",
          "OES_texture_float_linear",
          "WEBGL_multisampled_render_to_texture"
        ];
        for (let i = 0; i < names.length; i++) {
          const name = names[i];
          extensions[name] = webgl.extensions.get(gl, name);
        }
        return extensions;
      },
      get: function(gl, name) {
        return gl.getExtension(name) || gl.getExtension(`MOZ_${name}`) || gl.getExtension(`WEBKIT_${name}`);
      }
    },
    TextureRegistry: new Registry()
  };
  webgl.ctx = webgl.canvas.getContext("2d");
  var Renderer3 = class extends Events {
    constructor(params) {
      super();
      let gl, program, vs, fs;
      this.domElement = params.domElement || document.createElement("canvas");
      if (typeof params.offscreenElement !== "undefined") {
        webgl.canvas = params.offscreenElement;
        webgl.ctx = webgl.canvas.getContext("2d");
      }
      this.scene = new Group();
      this.scene.parent = this;
      this._renderer = {
        type: "renderer",
        matrix: new NumArray(identity),
        scale: 1,
        opacity: 1
      };
      this._flagMatrix = true;
      params = _.defaults(params || {}, {
        antialias: false,
        alpha: true,
        premultipliedAlpha: true,
        stencil: true,
        preserveDrawingBuffer: true,
        overdraw: false
      });
      this.overdraw = params.overdraw;
      gl = this.ctx = this.domElement.getContext("webgl", params) || this.domElement.getContext("experimental-webgl", params);
      if (!this.ctx) {
        throw new TwoError(
          "unable to create a webgl context. Try using another renderer."
        );
      }
      vs = shaders.create(gl, shaders.path.vertex, shaders.types.vertex);
      fs = shaders.create(gl, shaders.path.fragment, shaders.types.fragment);
      this.programs = {
        current: null,
        buffers: {
          position: gl.createBuffer()
        },
        resolution: {
          width: 0,
          height: 0,
          ratio: 1,
          flagged: false
        }
      };
      program = this.programs.path = webgl.program.create(gl, [vs, fs]);
      this.programs.text = this.programs.path;
      gl.extensions = webgl.extensions.init(gl);
      gl.renderer = this;
      program.position = gl.getAttribLocation(program, "a_position");
      program.matrix = gl.getUniformLocation(program, "u_matrix");
      program.rect = gl.getUniformLocation(program, "u_rect");
      const positionBuffer = gl.createBuffer();
      gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
      gl.vertexAttribPointer(program.position, 2, gl.FLOAT, false, 0, 0);
      gl.enableVertexAttribArray(program.position);
      gl.bufferData(gl.ARRAY_BUFFER, quad, gl.STATIC_DRAW);
      vs = shaders.create(gl, shaders.points.vertex, shaders.types.vertex);
      fs = shaders.create(gl, shaders.points.fragment, shaders.types.fragment);
      program = this.programs.points = webgl.program.create(gl, [vs, fs]);
      program.position = gl.getAttribLocation(program, "a_position");
      program.matrix = gl.getUniformLocation(program, "u_matrix");
      program.size = gl.getUniformLocation(program, "u_size");
      gl.enable(gl.BLEND);
      gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
      gl.blendEquation(gl.FUNC_ADD);
      gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
    }
    setSize(width, height, ratio) {
      let w, h;
      const ctx = this.ctx;
      this.width = width;
      this.height = height;
      this.ratio = typeof ratio === "undefined" ? getRatio(ctx) : ratio;
      this.domElement.width = width * this.ratio;
      this.domElement.height = height * this.ratio;
      if (_.isObject(this.domElement.style)) {
        _.extend(this.domElement.style, {
          width: width + "px",
          height: height + "px"
        });
      }
      this._renderer.matrix[0] = this._renderer.matrix[4] = this._renderer.scale = this.ratio;
      this._flagMatrix = true;
      w = width * this.ratio;
      h = height * this.ratio;
      ctx.viewport(0, 0, w, h);
      this.programs.resolution.width = w;
      this.programs.resolution.height = h;
      this.programs.resolution.ratio = this.ratio;
      this.programs.resolution.flagged = true;
      return this.trigger(Events.Types.resize, width, height, ratio);
    }
    render() {
      const gl = this.ctx;
      if (!this.overdraw) {
        gl.clear(gl.COLOR_BUFFER_BIT);
      }
      webgl.group.render.call(this.scene, gl, this.programs);
      this._flagMatrix = false;
      this.programs.resolution.flagged = true;
      return this;
    }
  };
  __publicField(Renderer3, "Utils", webgl);

  // src/two.js
  var Utils = _.extend(
    {
      Error: TwoError,
      getRatio,
      read,
      xhr
    },
    _,
    CanvasPolyfill,
    curves_exports,
    math_exports
  );
  var _Two = class {
    _events = new Events();
    get _bound() {
      return this._events._bound;
    }
    set _bound(v) {
      this._events._bound = v;
    }
    addEventListener() {
      return this._events.addEventListener.apply(this, arguments);
    }
    on() {
      return this._events.addEventListener.apply(this, arguments);
    }
    bind() {
      return this._events.addEventListener.apply(this, arguments);
    }
    removeEventListener() {
      return this._events.removeEventListener.apply(this, arguments);
    }
    off() {
      return this._events.removeEventListener.apply(this, arguments);
    }
    unbind() {
      return this._events.removeEventListener.apply(this, arguments);
    }
    dispatchEvent() {
      return this._events.dispatchEvent.apply(this, arguments);
    }
    trigger() {
      return this._events.dispatchEvent.apply(this, arguments);
    }
    listen() {
      return this._events.listen.apply(this, arguments);
    }
    ignore() {
      return this._events.ignore.apply(this, arguments);
    }
    type = "";
    renderer = null;
    scene = null;
    width = 0;
    height = 0;
    frameCount = 0;
    timeDelta = 0;
    playing = false;
    constructor(options) {
      const params = _.defaults(options || {}, {
        fullscreen: false,
        fitted: false,
        width: 640,
        height: 480,
        type: _Two.Types.svg,
        autostart: false
      });
      _.each(
        params,
        function(v, k) {
          if (/fullscreen/i.test(k) || /autostart/i.test(k)) {
            return;
          }
          this[k] = v;
        },
        this
      );
      if (_.isElement(params.domElement)) {
        const tagName = params.domElement.tagName.toLowerCase();
        if (!/^(CanvasRenderer-canvas|WebGLRenderer-canvas|SVGRenderer-svg)$/.test(
          this.type + "-" + tagName
        )) {
          this.type = _Two.Types[tagName];
        }
      }
      this.renderer = new _Two[this.type](this);
      this.setPlaying(params.autostart);
      this.frameCount = 0;
      if (params.fullscreen) {
        this.fit = fitToWindow.bind(this);
        this.fit.domElement = window;
        this.fit.attached = true;
        _.extend(document.body.style, {
          overflow: "hidden",
          margin: 0,
          padding: 0,
          top: 0,
          left: 0,
          right: 0,
          bottom: 0,
          position: "fixed"
        });
        _.extend(this.renderer.domElement.style, {
          display: "block",
          top: 0,
          left: 0,
          right: 0,
          bottom: 0,
          position: "fixed"
        });
        dom.bind(this.fit.domElement, "resize", this.fit);
        this.fit();
      } else if (params.fitted) {
        this.fit = fitToParent.bind(this);
        _.extend(this.renderer.domElement.style, {
          display: "block"
        });
      } else if (typeof params.width === "number" && typeof params.height === "number") {
        this.renderer.setSize(params.width, params.height, this.ratio);
        this.width = params.width;
        this.height = params.height;
      }
      this.renderer.bind(Events.Types.resize, updateDimensions.bind(this));
      this.scene = this.renderer.scene;
      _Two.Instances.push(this);
      if (params.autostart) {
        raf.init();
      }
    }
    appendTo(elem) {
      elem.appendChild(this.renderer.domElement);
      if (this.fit) {
        if (this.fit.domElement !== window) {
          this.fit.domElement = elem;
          this.fit.attached = false;
        }
        this.update();
      }
      return this;
    }
    play() {
      this.playing = true;
      raf.init();
      return this.trigger(Events.Types.play);
    }
    pause() {
      this.playing = false;
      return this.trigger(Events.Types.pause);
    }
    setPlaying(p) {
      this.playing = p;
    }
    release(obj) {
      let i, v, child;
      if (typeof obj === "undefined") {
        return this.release(this.scene);
      }
      if (typeof obj.unbind === "function") {
        obj.unbind();
      }
      if (typeof obj.fill === "object" && "unbind" in obj.fill) {
        obj.fill.unbind();
      }
      if (typeof obj.stroke === "object" && "unbind" in obj.stroke) {
        obj.stroke.unbind();
      }
      if (obj.vertices) {
        if (typeof obj.vertices.unbind === "function") {
          obj.vertices.unbind();
        }
        for (i = 0; i < obj.vertices.length; i++) {
          v = obj.vertices[i];
          if (typeof v.unbind === "function") {
            v.unbind();
          }
          if (v.controls) {
            if (v.controls.left && typeof v.controls.left.unbind === "function") {
              v.controls.left.unbind();
            }
            if (v.controls.right && typeof v.controls.right.unbind === "function") {
              v.controls.right.unbind();
            }
          }
        }
      }
      if (obj.children) {
        for (i = 0; i < obj.children.length; i++) {
          child = obj.children[i];
          this.release(child);
        }
        if (typeof obj.children.unbind === "function") {
          obj.children.unbind();
        }
      }
      return obj;
    }
    update() {
      const animated = !!this._lastFrame;
      const now = _.performance.now();
      if (animated) {
        this.timeDelta = parseFloat((now - this._lastFrame).toFixed(3));
      }
      this._lastFrame = now;
      if (this.fit && this.fit.domElement && !this.fit.attached) {
        dom.bind(this.fit.domElement, "resize", this.fit);
        this.fit.attached = true;
        this.fit();
      }
      const width = this.width;
      const height = this.height;
      const renderer = this.renderer;
      if (width !== renderer.width || height !== renderer.height) {
        renderer.setSize(width, height, this.ratio);
      }
      this.trigger(Events.Types.update, this.frameCount, this.timeDelta);
      return this.render();
    }
    render() {
      this.renderer.render();
      return this.trigger(Events.Types.render, this.frameCount++);
    }
    add(objects) {
      if (!(objects instanceof Array)) {
        objects = Array.prototype.slice.call(arguments);
      }
      this.scene.add(objects);
      return this;
    }
    remove(objects) {
      if (!(objects instanceof Array)) {
        objects = Array.prototype.slice.call(arguments);
      }
      this.scene.remove(objects);
      return this;
    }
    clear() {
      this.scene.remove(this.scene.children);
      return this;
    }
    makeLine(x1, y1, x2, y2) {
      const line = new Line(x1, y1, x2, y2);
      this.scene.add(line);
      return line;
    }
    makeArrow(x1, y1, x2, y2, size) {
      const headlen = typeof size === "number" ? size : 10;
      const angle = Math.atan2(y2 - y1, x2 - x1);
      const vertices = [
        new Anchor(
          x1,
          y1,
          void 0,
          void 0,
          void 0,
          void 0,
          Commands.move
        ),
        new Anchor(
          x2,
          y2,
          void 0,
          void 0,
          void 0,
          void 0,
          Commands.line
        ),
        new Anchor(
          x2 - headlen * Math.cos(angle - Math.PI / 4),
          y2 - headlen * Math.sin(angle - Math.PI / 4),
          void 0,
          void 0,
          void 0,
          void 0,
          Commands.line
        ),
        new Anchor(
          x2,
          y2,
          void 0,
          void 0,
          void 0,
          void 0,
          Commands.move
        ),
        new Anchor(
          x2 - headlen * Math.cos(angle + Math.PI / 4),
          y2 - headlen * Math.sin(angle + Math.PI / 4),
          void 0,
          void 0,
          void 0,
          void 0,
          Commands.line
        )
      ];
      const path = new Path(vertices, false, false, true);
      path.noFill();
      path.cap = "round";
      path.join = "round";
      this.scene.add(path);
      return path;
    }
    makeRectangle(x, y, width, height) {
      const rect = new Rectangle(x, y, width, height);
      this.scene.add(rect);
      return rect;
    }
    makeRoundedRectangle(x, y, width, height, sides) {
      const rect = new RoundedRectangle(x, y, width, height, sides);
      this.scene.add(rect);
      return rect;
    }
    makeCircle(x, y, radius, resolution) {
      const circle = new Circle(x, y, radius, resolution);
      this.scene.add(circle);
      return circle;
    }
    makeEllipse(x, y, rx, ry, resolution) {
      const ellipse = new Ellipse(x, y, rx, ry, resolution);
      this.scene.add(ellipse);
      return ellipse;
    }
    makeStar(x, y, outerRadius, innerRadius, sides) {
      const star = new Star(x, y, outerRadius, innerRadius, sides);
      this.scene.add(star);
      return star;
    }
    makeCurve(points) {
      const l = arguments.length;
      if (!Array.isArray(points)) {
        points = [];
        for (let i = 0; i < l; i += 2) {
          const x = arguments[i];
          if (typeof x !== "number") {
            break;
          }
          const y = arguments[i + 1];
          points.push(new Anchor(x, y));
        }
      }
      const last = arguments[l - 1];
      const curve = new Path(
        points,
        !(typeof last === "boolean" ? last : void 0),
        true
      );
      const rect = curve.getBoundingClientRect();
      curve.center().translation.set(rect.left + rect.width / 2, rect.top + rect.height / 2);
      this.scene.add(curve);
      return curve;
    }
    makePolygon(x, y, radius, sides) {
      const poly = new Polygon(x, y, radius, sides);
      this.scene.add(poly);
      return poly;
    }
    makeArcSegment(x, y, innerRadius, outerRadius, startAngle, endAngle, resolution) {
      const arcSegment = new ArcSegment(
        x,
        y,
        innerRadius,
        outerRadius,
        startAngle,
        endAngle,
        resolution
      );
      this.scene.add(arcSegment);
      return arcSegment;
    }
    makePoints(p) {
      const l = arguments.length;
      let vertices = p;
      if (!Array.isArray(p)) {
        vertices = [];
        for (let i = 0; i < l; i += 2) {
          const x = arguments[i];
          if (typeof x !== "number") {
            break;
          }
          const y = arguments[i + 1];
          vertices.push(new Vector(x, y));
        }
      }
      const points = new Points(vertices);
      this.scene.add(points);
      return points;
    }
    makePath(p) {
      const l = arguments.length;
      let points = p;
      if (!Array.isArray(p)) {
        points = [];
        for (let i = 0; i < l; i += 2) {
          const x = arguments[i];
          if (typeof x !== "number") {
            break;
          }
          const y = arguments[i + 1];
          points.push(new Anchor(x, y));
        }
      }
      const last = arguments[l - 1];
      const path = new Path(
        points,
        !(typeof last === "boolean" ? last : void 0)
      );
      const rect = path.getBoundingClientRect();
      if (typeof rect.top === "number" && typeof rect.left === "number" && typeof rect.right === "number" && typeof rect.bottom === "number") {
        path.center().translation.set(
          rect.left + rect.width / 2,
          rect.top + rect.height / 2
        );
      }
      this.scene.add(path);
      return path;
    }
    makeText(message, x, y, styles) {
      const text = new Text(message, x, y, styles);
      this.add(text);
      return text;
    }
    makeLinearGradient(x1, y1, x2, y2) {
      const stops = Array.prototype.slice.call(arguments, 4);
      const gradient = new LinearGradient(x1, y1, x2, y2, stops);
      this.add(gradient);
      return gradient;
    }
    makeRadialGradient(x1, y1, radius) {
      const stops = Array.prototype.slice.call(arguments, 3);
      const gradient = new RadialGradient(x1, y1, radius, stops);
      this.add(gradient);
      return gradient;
    }
    makeSprite(pathOrTexture, x, y, columns, rows, frameRate, autostart) {
      const sprite = new Sprite(pathOrTexture, x, y, columns, rows, frameRate);
      if (autostart) {
        sprite.play();
      }
      this.add(sprite);
      return sprite;
    }
    makeImageSequence(pathsOrTextures, x, y, frameRate, autostart) {
      const imageSequence = new ImageSequence(pathsOrTextures, x, y, frameRate);
      if (autostart) {
        imageSequence.play();
      }
      this.add(imageSequence);
      return imageSequence;
    }
    makeTexture(pathOrSource, callback) {
      const texture = new Texture(pathOrSource, callback);
      return texture;
    }
    makeGroup(objects) {
      if (!(objects instanceof Array)) {
        objects = Array.prototype.slice.call(arguments);
      }
      const group = new Group();
      this.scene.add(group);
      group.add(objects);
      return group;
    }
    interpret(svg2, shallow, add) {
      const tag = svg2.tagName.toLowerCase();
      add = typeof add !== "undefined" ? add : true;
      if (!(tag in read)) {
        return null;
      }
      const node = read[tag].call(this, svg2);
      if (add) {
        this.add(shallow && node instanceof Group ? node.children : node);
      } else if (node.parent) {
        node.remove();
      }
      return node;
    }
    load(pathOrSVGContent, callback) {
      const group = new Group();
      let elem, i, child;
      const attach = function(data) {
        dom.temp.innerHTML = data;
        for (i = 0; i < dom.temp.children.length; i++) {
          elem = dom.temp.children[i];
          child = this.interpret(elem, false, false);
          if (child !== null) {
            group.add(child);
          }
        }
        if (typeof callback === "function") {
          const svg2 = dom.temp.children.length <= 1 ? dom.temp.children[0] : dom.temp.children;
          callback(group, svg2);
        }
      }.bind(this);
      if (/\.svg$/i.test(pathOrSVGContent)) {
        xhr(pathOrSVGContent, attach);
        return group;
      }
      attach(pathOrSVGContent);
      return group;
    }
  };
  var Two = _Two;
  __publicField(Two, "NextFrameId", Constants.NextFrameId);
  __publicField(Two, "Types", Constants.Types);
  __publicField(Two, "Version", Constants.Version);
  __publicField(Two, "PublishDate", Constants.PublishDate);
  __publicField(Two, "Identifier", Constants.Identifier);
  __publicField(Two, "Resolution", Constants.Resolution);
  __publicField(Two, "AutoCalculateImportedMatrices", Constants.AutoCalculateImportedMatrices);
  __publicField(Two, "Instances", Constants.Instances);
  __publicField(Two, "uniqueId", Constants.uniqueId);
  __publicField(Two, "Anchor", Anchor);
  __publicField(Two, "Collection", Collection);
  __publicField(Two, "Events", Events);
  __publicField(Two, "Group", Group);
  __publicField(Two, "Matrix", Matrix2);
  __publicField(Two, "Path", Path);
  __publicField(Two, "Registry", Registry);
  __publicField(Two, "Element", Element);
  __publicField(Two, "Shape", Shape);
  __publicField(Two, "Text", Text);
  __publicField(Two, "Vector", Vector);
  __publicField(Two, "Gradient", Gradient);
  __publicField(Two, "ImageSequence", ImageSequence);
  __publicField(Two, "LinearGradient", LinearGradient);
  __publicField(Two, "RadialGradient", RadialGradient);
  __publicField(Two, "Sprite", Sprite);
  __publicField(Two, "Stop", Stop);
  __publicField(Two, "Texture", Texture);
  __publicField(Two, "ArcSegment", ArcSegment);
  __publicField(Two, "Circle", Circle);
  __publicField(Two, "Ellipse", Ellipse);
  __publicField(Two, "Line", Line);
  __publicField(Two, "Points", Points);
  __publicField(Two, "Polygon", Polygon);
  __publicField(Two, "Rectangle", Rectangle);
  __publicField(Two, "RoundedRectangle", RoundedRectangle);
  __publicField(Two, "Star", Star);
  __publicField(Two, "CanvasRenderer", Renderer);
  __publicField(Two, "SVGRenderer", Renderer2);
  __publicField(Two, "WebGLRenderer", Renderer3);
  __publicField(Two, "Commands", Commands);
  __publicField(Two, "Utils", Utils);
  function fitToWindow() {
    const wr = document.body.getBoundingClientRect();
    const width = this.width = wr.width;
    const height = this.height = wr.height;
    this.renderer.setSize(width, height, this.ratio);
  }
  function fitToParent() {
    const parent = this.renderer.domElement.parentElement;
    if (!parent) {
      console.warn("Two.js: Attempting to fit to parent, but no parent found.");
      return;
    }
    const wr = parent.getBoundingClientRect();
    const width = this.width = wr.width;
    const height = this.height = wr.height;
    this.renderer.setSize(width, height, this.ratio);
  }
  function updateDimensions(width, height) {
    this.width = width;
    this.height = height;
    this.trigger(Events.Types.resize, width, height);
  }
  var raf = dom.getRequestAnimationFrame();
  function loop() {
    for (let i = 0; i < Two.Instances.length; i++) {
      const t = Two.Instances[i];
      if (t.playing) {
        t.update();
      }
    }
    Two.NextFrameId = raf(loop);
  }
  raf.init = function() {
    loop();
    raf.init = function() {
    };
  };
  return __toCommonJS(two_exports);
})().default;

(function(){if(typeof exports==='object'&&typeof module!=='undefined'){module.exports=Two}})()