var ul = Object.defineProperty;
var Yl = (c, l, b) => l in c ? ul(c, l, { enumerable: !0, configurable: !0, writable: !0, value: b }) : c[l] = b;
var F = (c, l, b) => (Yl(c, typeof l != "symbol" ? l + "" : l, b), b), g = (c, l, b) => {
  if (!l.has(c))
    throw TypeError("Cannot " + b);
};
var W = (c, l, b) => (g(c, l, "read from private field"), b ? b.call(c) : l.get(c)), Y = (c, l, b) => {
  if (l.has(c))
    throw TypeError("Cannot add the same private member more than once");
  l instanceof WeakSet ? l.add(c) : l.set(c, b);
}, i = (c, l, b, d) => (g(c, l, "write to private field"), d ? d.call(c, b) : l.set(c, b), b);
var o = (c, l, b, d) => ({
  set _(X) {
    i(c, l, X, b);
  },
  get _() {
    return W(c, l, d);
  }
}), v = (c, l, b) => (g(c, l, "access private method"), b);
function Jl(c) {
  const { selector: l, id: b } = c;
  let d = document.body, X = document.createElement("canvas");
  if (X.id = b, X.classList.add("dice-box-canvas"), l) {
    if (typeof l != "string")
      throw new Error("You must provide a DOM selector as the first argument in order to render the Dice Box");
    if (d = document.querySelector(l), !(d != null && d.nodeName))
      throw new Error(`DiceBox target DOM node: '${l}' not found or not available yet. Try invoking inside a DOMContentLoaded event`);
  }
  return d.appendChild(X), X;
}
const ml = "[encoded data, 182128 characters]", Xl = typeof window < "u" && window.Blob && new Blob([atob(ml)], { type: "text/javascript;charset=utf-8" });
function il() {
  let c;
  try {
    if (c = Xl && (window.URL || window.webkitURL).createObjectURL(Xl), !c)
      throw "";
    return new Worker(c);
  } catch {
    return new Worker("data:application/javascript;base64," + ml);
  } finally {
    c && (window.URL || window.webkitURL).revokeObjectURL(c);
  }
}
const pl = (c) => {
  let l;
  return function() {
    let b = this, d = arguments;
    l && window.cancelAnimationFrame(l), l = window.requestAnimationFrame(function() {
      c.apply(b, d);
    });
  };
}, hl = (c = { dedupe: !1 }) => {
  const { dedupe: l } = c;
  let b = [], d;
  const X = (m) => (l && (b = []), b.push(m), d || (d = Z()), d.finally(() => {
    d = void 0;
  })), Z = async () => {
    const m = [];
    for (; b.length; ) {
      const V = b.shift();
      m.push(await V());
    }
    return m;
  };
  return { push: X, queue: b, flush: () => d || Promise.resolve([]) };
}, yl = (c) => JSON.parse(JSON.stringify(c));
class Zl {
  /**
   * Generate a random number between 0 (inclusive) and 1 (exclusive).
   * A drop in replacement for Math.random()
   * @return {number}
   */
  static value() {
    const l = window.crypto || window.msCrypto, b = new Uint32Array(1);
    return l.getRandomValues(b)[0] / 2 ** 32;
  }
  /**
   * Generate a very good random number between min (inclusive) and max (exclusive) by using crypto.getRandomValues() twice.
   * @param  {number} min
   * @param  {number} max
   * @return {number}
   */
  static range(l, b) {
    return Math.floor(Math.pow(10, 14) * this.value() * this.value()) % (b - l + 1) + l;
  }
}
const al = (c) => {
  let l = !1, b = c.slice(c.startsWith("#") ? 1 : 0);
  b.length === 3 ? b = [...b].map((X) => X + X).join("") : b.length === 8 && (l = !0), b = parseInt(b, 16);
  let d = {
    r: b >>> 16,
    g: (b & 65280) >>> 8,
    b: b & 255
  };
  return l && (d.r = b >>> 24, d.g = (b & 16711680) >>> 16, d.b = (b & 65280) >>> 8, d.a = b & 255), d;
};
function nl() {
  try {
    const c = document.createElement("canvas");
    return !!window.WebGLRenderingContext && (c.getContext("webgl") || c.getContext("experimental-webgl"));
  } catch {
    return !1;
  }
}
const sl = {
  id: `dice-canvas-${Date.now()}`,
  // set the canvas id
  container: null,
  enableShadows: !0,
  // do dice cast shadows onto DiceBox mesh?
  shadowTransparency: 0.8,
  lightIntensity: 1,
  delay: 10,
  // delay between dice being generated - 0 causes stuttering and physics popping
  scale: 5,
  // scale the dice
  theme: "default",
  // can be a hex color or a pre-defined theme such as 'purpleRock'
  preloadThemes: [],
  externalThemes: {},
  // point to CDN paths
  themeColor: "#2e8555",
  // used for color values or named theme variants - not fully implemented yet // green: #2e8555 // yellow: #feea03
  offscreen: !0,
  // use offscreen canvas browser feature for performance improvements - will fallback to false based on feature detection
  assetPath: "/assets/dice-box/",
  // path to 'ammo', 'themes' folders and web workers
  // origin: location.origin,
  origin: typeof window < "u" ? window.location.origin : "",
  suspendSimulation: !1
};
var f, x, C, B, u, w, U, p, K, k, y, I, cl, E, Gl, T, Wl, Q, D, P, r;
class vl {
  constructor(l = {}) {
    // Load the BabylonJS World
    Y(this, I);
    // Load the AmmoJS physics world
    Y(this, E);
    Y(this, T);
    // used by both .add and .roll - .roll clears the box and .add does not
    Y(this, Q);
    Y(this, P);
    F(this, "rollCollectionData", {});
    F(this, "rollGroupData", {});
    F(this, "rollDiceData", {});
    F(this, "themeData", []);
    F(this, "themesLoadedData", {});
    Y(this, f, 0);
    Y(this, x, 0);
    Y(this, C, 0);
    Y(this, B, 0);
    Y(this, u, {});
    Y(this, w, void 0);
    Y(this, U, void 0);
    Y(this, p, void 0);
    Y(this, K, void 0);
    Y(this, k, void 0);
    Y(this, y, !0);
    F(this, "noop", () => {
    });
    if (arguments.length === 2 && typeof (arguments[0] === "string") && typeof (arguments[1] === "object") && (console.warn("You are using the old API. Dicebox constructor accepts a config object as it's only argument. Please read the v1.1.0 docs at https://fantasticdice.games/docs/usage/config"), l = arguments[1], l.container = arguments[0]), typeof l != "object")
      throw new Error("Config options should be an object. Config reference: https://fantasticdice.games/docs/usage/config#configuration-options");
    const { onBeforeRoll: b, onDieComplete: d, onRollComplete: X, onRemoveComplete: Z, onThemeConfigLoaded: m, onThemeLoaded: V, ...G } = l;
    this.config = { ...sl, ...G }, this.onBeforeRoll = l.onBeforeRoll || this.noop, this.onDieComplete = l.onDieComplete || this.noop, this.onRollComplete = l.onRollComplete || this.noop, this.onRemoveComplete = l.onRemoveComplete || this.noop, this.onThemeLoaded = l.onThemeLoaded || this.noop, this.onThemeConfigLoaded = l.onThemeConfigLoaded || this.noop, nl() ? (this.canvas = Jl({
      selector: this.config.container,
      id: this.config.id
    }), this.isVisible = !0) : i(this, y, !1), this.loadThemeQueue = hl();
  }
  resizeWorld() {
    const b = pl(() => {
      W(this, u).resize({ width: this.canvas.clientWidth, height: this.canvas.clientHeight }), W(this, p) && W(this, p).postMessage({ action: "resize", width: this.canvas.clientWidth, height: this.canvas.clientHeight });
    });
    window.addEventListener("resize", b);
  }
  async init() {
    return W(this, y) ? v(this, E, Gl).call(this) : i(this, K, Promise.resolve()), await v(this, I, cl).call(this), this.resizeWorld(), W(this, u).onRollResult = (l) => {
      const b = this.rollDiceData[l.rollId], d = this.rollGroupData[b.groupId], X = this.rollCollectionData[b.collectionId];
      d.rolls[b.rollId].value = l.value, X.completedRolls++, X.completedRolls == X.rolls.length && X.resolve(Object.values(X.rolls).map(({ collectionId: G, id: J, meshName: R, ...N }) => N));
      const { collectionId: Z, id: m, ...V } = b;
      this.onDieComplete(V);
    }, W(this, u).onRollComplete = () => {
      this.onRollComplete(this.getRollResults());
    }, W(this, u).onDieRemoved = (l) => {
      let b = this.rollDiceData[l];
      const d = this.rollCollectionData[b.removeCollectionId];
      d.completedRolls++, delete this.rollDiceData[b.rollId];
      const X = this.rollGroupData[b.groupId];
      delete X.rolls[b.rollId];
      const Z = v(this, P, r).call(this, b.groupId);
      X.value = Z.value, X.qty = Z.rollsArray.length, d.completedRolls == d.rolls.length && d.resolve(Object.values(d.rolls).map(({ id: N, ...L }) => L));
      const { collectionId: m, id: V, removeCollectionId: G, meshName: J, ...R } = b;
      this.onRemoveComplete(R);
    }, await Promise.all([W(this, w), W(this, K)]), W(this, p) && v(this, T, Wl).call(this), await this.loadThemeQueue.push(() => this.loadTheme(this.config.theme)), this.config.preloadThemes.forEach((async function(l) {
      await this.loadThemeQueue.push(() => this.loadTheme(l));
    }).bind(this)), this;
  }
  // fetch the theme config and return a themeData object
  async getThemeConfig(l) {
    let b = `${this.config.origin}${this.config.assetPath}themes/${l}`;
    this.config.externalThemes[l] && (b = this.config.externalThemes[l]);
    let d = await fetch(`${b}/theme.config.json`).then((m) => {
      if (m.ok) {
        const V = m.headers.get("content-type");
        if (V && V.indexOf("application/json") !== -1)
          return m.json();
        if (m.type && m.type === "basic")
          return m.json();
        throw new Error(`Incorrect contentType: ${V}. Expected "application/json" or "basic"`);
      } else
        throw new Error(`Unable to fetch config file for theme: '${l}'. Request rejected with status ${m.status}: ${m.statusText}`);
    }).catch((m) => console.error(m));
    if (!d)
      throw new Error("No theme config data to work with.");
    let X = "default", Z = `${this.config.origin}${this.config.assetPath}themes/default/default.json`;
    if (d.hasOwnProperty("meshFile") && (X = d.meshFile.replace(/(.*)\..{2,4}$/, "$1"), Z = `${b}/${d.meshFile}`), !d.hasOwnProperty("diceAvailable"))
      throw new Error('A theme must indicate which dice are available by defining "diceAvailable".');
    if (d.hasOwnProperty("extends")) {
      const m = await this.loadTheme(d.extends).catch((G) => console.error(G));
      if (m.hasOwnProperty("extends"))
        throw new Error("Cannot extend a theme that extends another theme.");
      const V = {};
      d.diceAvailable.forEach((G) => {
        V[G] = d.systemName;
      }), m.diceExtended = { ...m.diceExtended, ...V }, this.config.theme = d.extends;
    }
    return Object.assign(
      d,
      {
        basePath: b,
        meshFilePath: Z,
        meshName: X,
        theme: l
      }
    ), d;
  }
  async loadTheme(l) {
    if (this.themesLoadedData[l])
      return this.themesLoadedData[l];
    const b = this.themesLoadedData[l] = await this.getThemeConfig(l).catch((d) => console.error(d));
    if (this.onThemeConfigLoaded(b), !!b)
      return await W(this, u).loadTheme(b).catch((d) => console.error(d)), this.onThemeLoaded(b), b;
  }
  // TODO: use getter and setter
  // change config options
  async updateConfig(l) {
    const b = { ...this.config, ...l };
    if (this.config = b, b.theme) {
      const X = (await this.loadThemeQueue.push(() => this.loadTheme(b.theme))).at(-1);
      X.hasOwnProperty("extends") && (this.config.theme = X.extends);
    }
    return W(this, u).updateConfig(b), W(this, p) && W(this, p).postMessage({
      action: "updateConfig",
      options: b
    }), this;
  }
  clear() {
    return i(this, f, 0), i(this, x, 0), i(this, C, 0), i(this, B, 0), this.rollCollectionData = {}, this.rollGroupData = {}, this.rollDiceData = {}, W(this, u).clear(), W(this, p) && W(this, p).postMessage({ action: "clearDice" }), this;
  }
  hide(l) {
    return l ? (this.canvas.dataset.hideClass = l, this.canvas.classList.add(l)) : this.canvas.style.display = "none", this.isVisible = !1, this;
  }
  show() {
    var b;
    const l = (b = this.canvas.dataset) == null ? void 0 : b.hideClass;
    return l ? (delete this.canvas.dataset.hideClass, this.canvas.classList.remove(l)) : this.canvas.style.display = "block", this.isVisible = !0, this.resizeWorld(), this;
  }
  // TODO: pass data with roll - such as roll name. Passed back at the end in the results
  roll(l, { theme: b = this.config.theme, themeColor: d = this.config.themeColor, newStartPoint: X = !0 } = {}) {
    this.clear();
    const Z = o(this, f)._++;
    this.rollCollectionData[Z] = new M({
      id: Z,
      notation: l,
      theme: b,
      themeColor: d,
      newStartPoint: X
    });
    const m = this.createNotationArray(l, this.themesLoadedData[b].diceAvailable);
    return v(this, Q, D).call(this, m, Z), this.rollCollectionData[Z].promise;
  }
  add(l, { theme: b = this.config.theme, themeColor: d = this.config.themeColor, newStartPoint: X = !0 } = {}) {
    const Z = o(this, f)._++;
    this.rollCollectionData[Z] = new M({
      id: Z,
      notation: l,
      theme: b,
      themeColor: d,
      newStartPoint: X
    });
    const m = this.createNotationArray(l, this.themesLoadedData[b].diceAvailable);
    return v(this, Q, D).call(this, m, Z), this.rollCollectionData[Z].promise;
  }
  reroll(l, { remove: b = !1, hide: d = !1, newStartPoint: X = !0 } = {}) {
    const m = (Array.isArray(l) ? l : [l]).map(({ value: V, ...G }) => G);
    return b === !0 && this.remove(m, { hide: d }), this.add(m, { newStartPoint: X });
  }
  remove(l, { hide: b = !1 } = {}) {
    const d = Array.isArray(l) ? l : [l], X = o(this, f)._++;
    return this.rollCollectionData[X] = new M({
      id: X,
      notation: l,
      rolls: d
    }), d.map((Z) => {
      this.rollDiceData[Z.rollId].removeCollectionId = X;
      let m = this.rollDiceData[Z.rollId].id;
      W(this, u).remove({ id: m, rollId: Z.rollId }), W(this, p) && W(this, p).postMessage({ action: "removeDie", id: m });
    }), this.rollCollectionData[X].promise;
  }
  // accepts simple notations eg: 4d6
  // accepts array of notations eg: ['4d6','2d10']
  // accepts object {sides:int, qty:int}
  // accepts array of objects eg: [{sides:int, qty:int, mods:[]}]
  createNotationArray(l, b) {
    const d = Array.isArray(l) ? l : [l];
    let X = [];
    const Z = (G) => {
      if (G.hasOwnProperty("qty") || (G.qty = 1), G.hasOwnProperty("sides"))
        return G.sides === "100" && (G.sides = 100, G.data = "single"), !0;
      {
        const J = "Roll notation is missing sides";
        throw new Error(J);
      }
    }, m = (G) => {
      G = G.toString();
      let J = G.split(".");
      return J[1] ? J[1] = parseInt(J[1]) + 1 : J[1] = 1, J[0] + "." + J[1];
    }, V = (G) => {
      G.hasOwnProperty("rollId") && this.rollDiceData.hasOwnProperty(G.rollId) && (G.rollId = m(G.rollId)), G.hasOwnProperty("modifier") || (G.modifier = 0);
    };
    return d.forEach((G) => {
      typeof G == "string" ? X.push(this.parse(G, b)) : typeof d == "object" && (V(G), Z(G) && X.push(G));
    }), X;
  }
  // parse text die notation such as 2d10+3 => {number:2, type:6, modifier:3}
  // taken from https://github.com/ChapelR/dice-notation
  parse(l, b) {
    const d = /(\d+)([dD]{1}\d+)(.*)$/i, X = /(\d+)[dD](00|%)(.*)$/i, Z = /(\d+)[dD](f+[ate]*)(.*)$/i, m = /(\d+)[dD]([\d\w]+)([+-]{0,1}\d+)?/i, V = /([+-])(\d+)/, G = l.trim().replace(/\s+/g, ""), J = (h, S) => {
      if (h = Number(h), Number.isNaN(h) || !Number.isInteger(h) || h < 1)
        throw new Error(S);
      return h;
    }, R = G.match(X) || G.match(d) || G.match(Z) || G.match(m);
    let N = 0;
    const L = "Invalid notation: " + l;
    if (!R || !R.length || R.length < 3)
      throw new Error(L);
    if (R[3] && V.test(R[3])) {
      const h = R[3].match(V);
      let S = J(h[2], L);
      h[1].trim() === "-" && (S *= -1), N = S;
    }
    const s = {
      qty: J(R[1], L),
      modifier: N
    };
    return G.match(X) ? (s.sides = "d100", s.data = "single") : G.match(Z) ? s.sides = "fate" : (b.includes(G.match(m)[2]), s.sides = R[2]), s;
  }
  getRollResults() {
    return Object.entries(this.rollGroupData).map(([l, b]) => {
      const d = v(this, P, r).call(this, l);
      b.value = d.value, b.qty = d.rollsArray.length;
      const X = { ...b };
      return X.rolls = d.rollsArray, X;
    });
  }
}
f = new WeakMap(), x = new WeakMap(), C = new WeakMap(), B = new WeakMap(), u = new WeakMap(), w = new WeakMap(), U = new WeakMap(), p = new WeakMap(), K = new WeakMap(), k = new WeakMap(), y = new WeakMap(), I = new WeakSet(), cl = async function() {
  i(this, w, new Promise((b, d) => {
    i(this, U, b);
  }));
  const l = () => {
    W(this, U).call(this);
  };
  if (W(this, y))
    if ("OffscreenCanvas" in window && "transferControlToOffscreen" in this.canvas && this.config.offscreen) {
      const b = await import("./world.offscreen.js").then((d) => d.default);
      i(this, u, new b({
        canvas: this.canvas,
        options: this.config,
        onInitComplete: l
      }));
    } else {
      this.config.offscreen && (console.warn("This browser does not support OffscreenCanvas. Using standard canvas fallback."), this.config.offscreen = !1);
      const b = await import("./world.onscreen.js").then((d) => d.default);
      i(this, u, new b({
        canvas: this.canvas,
        options: this.config,
        onInitComplete: l
      }));
    }
  else {
    console.warn("This browser does not support WebGL which is required for 3D rendering. Falling back to random number generator");
    const b = await import("./world.none.js").then((d) => d.default);
    i(this, u, new b({
      canvas: this.canvas,
      options: this.config,
      onInitComplete: l
    }));
  }
}, E = new WeakSet(), Gl = function() {
  i(this, p, new il()), i(this, K, new Promise((l, b) => {
    i(this, k, l);
  })), W(this, p).onmessage = (l) => {
    switch (l.data.action) {
      case "init-complete":
        W(this, k).call(this);
    }
  }, W(this, p).postMessage({
    action: "init",
    width: this.canvas.clientWidth,
    height: this.canvas.clientHeight,
    options: this.config
  });
}, T = new WeakSet(), Wl = function() {
  const l = new MessageChannel();
  W(this, u).connect(l.port1), W(this, p).postMessage({
    action: "connect"
  }, [l.port2]);
}, Q = new WeakSet(), D = async function(l, b) {
  this.onBeforeRoll(l);
  const d = this.rollCollectionData[b];
  let X = d.newStartPoint;
  l.forEach(async (Z) => {
    var q, $, _, ll, bl, dl;
    if (!Z.sides)
      throw new Error("Improper dice notation or unable to parse notation");
    let m = Z.theme || d.theme || this.config.theme;
    const V = Z.themeColor || d.themeColor || this.config.themeColor, G = {}, J = Z.groupId !== void 0;
    let R;
    const N = () => this.loadTheme(m);
    await this.loadThemeQueue.push(N);
    let L = this.themesLoadedData[m].meshName, s = (q = this.themesLoadedData[m]) == null ? void 0 : q.diceAvailable, h = this.themesLoadedData[m].diceExtended || {}, S = (_ = ($ = this.themesLoadedData[m]) == null ? void 0 : $.material) == null ? void 0 : _.type;
    const t = Object.keys(h);
    if (t && t.includes(Z.sides)) {
      m = h[Z.sides];
      const e = () => this.loadTheme(m);
      this.loadThemeQueue.push(e), L = this.themesLoadedData[m].meshName, s = (ll = this.themesLoadedData[m]) == null ? void 0 : ll.diceAvailable, S = (dl = (bl = this.themesLoadedData[m]) == null ? void 0 : bl.material) == null ? void 0 : dl.type;
    }
    let O = "", j;
    S === "color" && (j = al(V), O = j.r * 0.299 + j.g * 0.587 + j.b * 0.114 > 175 ? "_dark" : "_light");
    for (var A = 0, Vl = Z.qty; A < Vl; A++) {
      let e = Z.rollId !== void 0 ? Z.rollId : o(this, C)._++, Rl = Z.id !== void 0 ? Z.id : o(this, B)._++;
      R = J ? Z.groupId : W(this, x);
      const H = Number.isInteger(Z.sides) ? `d${Z.sides}` : Z.sides;
      /^d[1-9]{1}[0-9]{0,1}0?$/.test(Z.sides) && (Z.sides = parseInt(Z.sides.replace("d", "")));
      const a = {
        sides: Z.sides,
        data: Z.data,
        dieType: H,
        groupId: R,
        collectionId: d.id,
        rollId: e,
        id: Rl,
        theme: m,
        themeColor: V,
        meshName: L
      };
      if (G[e] = a, this.rollDiceData[e] = a, d.rolls.push(this.rollDiceData[e]), a.sides === "fate" && !s.includes(H) && !t.includes(H) || a.sides === "fate" && !W(this, y)) {
        console.warn(`fate die unavailable in '${m}' theme. Using fallback.`);
        const n = -1, z = 1;
        a.value = Zl.range(n, z), W(this, u).addNonDie(a);
      } else if (this.config.suspendSimulation || !s.includes(H) && !t.includes(H) || !W(this, y)) {
        const n = W(this, y) ? this.config.suspendSimulation ? "3D simulation suspended. Using fallback." : `${a.sides} die unavailable in '${m}' theme. Using fallback.` : "This browser does not support webGL. Using random number fallback.";
        console.warn(n);
        const z = Number.isInteger(a.sides) ? a.sides : parseInt(a.sides.replace(/\D/g, ""));
        a.value = Zl.range(1, z), W(this, u).addNonDie(a);
      } else {
        let n;
        if (t.includes(H)) {
          const z = h[H];
          n = this.themesLoadedData[z];
        }
        W(this, u).add({
          ...a,
          newStartPoint: X,
          theme: (n == null ? void 0 : n.systemName) || m,
          meshName: (n == null ? void 0 : n.meshName) || L,
          colorSuffix: O
        });
      }
      X = !1;
    }
    J ? Object.assign(this.rollGroupData[R].rolls, G) : (Z.rolls = G, Z.id = R, this.rollGroupData[R] = Z, ++o(this, x)._);
  });
}, P = new WeakSet(), r = function(l) {
  const b = this.rollGroupData[l], d = Object.values(b.rolls).map(({ collectionId: Z, id: m, meshName: V, ...G }) => G);
  let X = d.reduce((Z, m) => {
    const V = isNaN(m.value) ? 0 : m.value;
    return Z + V;
  }, 0);
  return X += b.modifier ? b.modifier : 0, { value: X, rollsArray: d };
};
class M {
  constructor(l) {
    Object.assign(this, l), this.rolls = l.rolls || [], this.completedRolls = 0;
    const b = this;
    this.promise = new Promise((d, X) => {
      b.resolve = d, b.reject = X;
    });
  }
}
export {
  yl as d,
  vl as default
};
//# sourceMappingURL=dice-box.es.js.map
