import {
  State,
  clamp,
  convertAiaToTurn,
  lerp,
  mod,
  sidesShiftMapper,
  uvsTransformerPresets
} from "./chunk-YIK32INT.js";
import {
  Cubie,
  M44,
  Program,
  Quaternion,
  Transform,
  V2,
  V3,
  V4
} from "./chunk-ROHLD3FA.js";
import {
  __privateAdd,
  __privateGet,
  __privateMethod,
  __privateSet,
  __publicField
} from "./chunk-HPRLEMBT.js";

// node_modules/rubiks-js/src/ui/camera.js
var _position, _lookAt, _forward, _right, _up, _fov, _aspect, _width, _height, _near, _far, _projectionMatrix, _worldToCameraMatrix, _projectionMatrixInverse, _cameraToWorldMatrix, _worldProjectionMatrix;
var Camera = class {
  /**
   * @param {V3} position
   * @param {V3} lookAt
   * @param {V3} up
   * @param {number} fov
   * @param {number} width
   * @param {number} height
   * @param {number} near
   * @param {number} far
   */
  constructor(position, lookAt, up, fov, width, height, near, far) {
    /** @type {V3} */
    __privateAdd(this, _position);
    /** @type {V3} */
    __privateAdd(this, _lookAt);
    /** @type {V3} */
    __privateAdd(this, _forward);
    /** @type {V3} */
    __privateAdd(this, _right);
    /** @type {V3} */
    __privateAdd(this, _up);
    /** @type {number} */
    __privateAdd(this, _fov);
    /** @type {number} */
    __privateAdd(this, _aspect);
    /** @type {number} */
    __privateAdd(this, _width);
    /** @type {number} */
    __privateAdd(this, _height);
    /** @type {number} */
    __privateAdd(this, _near);
    /** @type {number} */
    __privateAdd(this, _far);
    /** @type {M44} */
    __privateAdd(this, _projectionMatrix);
    /** @type {M44} */
    __privateAdd(this, _worldToCameraMatrix);
    /** @type {M44} */
    __privateAdd(this, _projectionMatrixInverse);
    /** @type {M44} */
    __privateAdd(this, _cameraToWorldMatrix);
    /** @type {M44} */
    __privateAdd(this, _worldProjectionMatrix);
    __privateSet(this, _position, position);
    __privateSet(this, _lookAt, lookAt);
    __privateSet(this, _up, up);
    __privateSet(this, _fov, fov);
    __privateSet(this, _width, width);
    __privateSet(this, _height, height);
    __privateSet(this, _aspect, width / height);
    __privateSet(this, _near, near);
    __privateSet(this, _far, far);
    this.calcCameraDirections();
    this.calcWorldToCameraMatrix();
    this.calcProjectionMatrix();
  }
  /** @param {V3} value */
  set position(value) {
    __privateSet(this, _position, value);
    this.calcCameraDirections();
    this.calcWorldToCameraMatrix();
  }
  /** @param {V3} value */
  set lookAt(value) {
    __privateSet(this, _lookAt, value);
    this.calcCameraDirections();
    this.calcWorldToCameraMatrix();
  }
  /** @param {V3} value */
  set up(value) {
    __privateSet(this, _up, value);
    this.calcCameraDirections();
    this.calcWorldToCameraMatrix();
  }
  get position() {
    return __privateGet(this, _position);
  }
  get lookAt() {
    return __privateGet(this, _lookAt);
  }
  get up() {
    return __privateGet(this, _up);
  }
  get forward() {
    return __privateGet(this, _forward);
  }
  get right() {
    return __privateGet(this, _right);
  }
  /** @param {number} value */
  set fov(value) {
    __privateSet(this, _fov, value);
    this.calcProjectionMatrix();
  }
  /** @param {number} value */
  set near(value) {
    __privateSet(this, _near, value);
    this.calcProjectionMatrix();
  }
  /** @param {number} value */
  set far(value) {
    __privateSet(this, _far, value);
    this.calcProjectionMatrix();
  }
  get fov() {
    return __privateGet(this, _fov);
  }
  get aspect() {
    return __privateGet(this, _aspect);
  }
  get near() {
    return __privateGet(this, _near);
  }
  get far() {
    return __privateGet(this, _far);
  }
  get width() {
    return __privateGet(this, _width);
  }
  get height() {
    return __privateGet(this, _height);
  }
  /**
   * @param {number} width
   * @param {number} height
   */
  screenSize(width, height) {
    __privateSet(this, _width, width);
    __privateSet(this, _height, height);
    __privateSet(this, _aspect, width / height);
    this.calcProjectionMatrix();
  }
  get projectionMatrix() {
    return __privateGet(this, _projectionMatrix);
  }
  get projectionMatrixInverse() {
    return __privateGet(this, _projectionMatrixInverse);
  }
  get worldToCameraMatrix() {
    return __privateGet(this, _worldToCameraMatrix);
  }
  get cameraToWorldMatrix() {
    return __privateGet(this, _cameraToWorldMatrix);
  }
  get worldProjectionMatrix() {
    return __privateGet(this, _worldProjectionMatrix);
  }
  /** @param {V3} v */
  worldToScreen({ x, y, z }) {
    const point4d = this.worldProjectionMatrix.mult(new V4(x, y, z, 1));
    const screenPoint = point4d.toV3().scale(1 / point4d.w).toV2().add(new V2(1, 1)).scale(0.5).mult(new V2(this.width, this.height));
    return screenPoint;
  }
  // worldDirectionToScreen({x, y, z}: V3) {
  //   // const rotationTransform = this.cameraToWorldMatrix.transpose
  //   const cameraPoint = this.worldToCameraMatrix.mult(new V4(x, y, z, 1))
  //   const projectedPoint = this.projectionMatrix.mult(cameraPoint)
  //   const viewportPoint = projectedPoint.toV3().scale(1 / projectedPoint.w).toV2()
  //   const screenPoint = viewportPoint.add(new V2(1, 1)).scale(.5).mult(new V2(this.width, this.height))
  //   // console.log(this.projectionMatrix)
  //   console.table({cameraPoint, projectedPoint, viewportPoint, screenPoint})
  //   return screenPoint
  // }
  calcProjectionMatrix() {
    var _a3;
    __privateSet(this, _projectionMatrix, M44.perspective(__privateGet(this, _fov) * Math.PI / 180, __privateGet(this, _aspect), __privateGet(this, _near), __privateGet(this, _far)));
    __privateSet(this, _projectionMatrixInverse, __privateGet(this, _projectionMatrix).inverse);
    __privateSet(this, _worldProjectionMatrix, (_a3 = __privateGet(this, _projectionMatrix)) == null ? void 0 : _a3.mult(__privateGet(this, _worldToCameraMatrix)));
  }
  calcWorldToCameraMatrix() {
    var _a3;
    __privateSet(this, _worldToCameraMatrix, M44.lookAt(__privateGet(this, _position), __privateGet(this, _lookAt), __privateGet(this, _up)));
    __privateSet(this, _cameraToWorldMatrix, __privateGet(this, _worldToCameraMatrix).inverse);
    __privateSet(this, _worldProjectionMatrix, (_a3 = __privateGet(this, _projectionMatrix)) == null ? void 0 : _a3.mult(__privateGet(this, _worldToCameraMatrix)));
  }
  calcCameraDirections() {
    __privateSet(this, _forward, __privateGet(this, _lookAt).sub(__privateGet(this, _position)).normalized);
    __privateSet(this, _right, __privateGet(this, _up).cross(__privateGet(this, _forward)).normalized);
  }
};
_position = new WeakMap();
_lookAt = new WeakMap();
_forward = new WeakMap();
_right = new WeakMap();
_up = new WeakMap();
_fov = new WeakMap();
_aspect = new WeakMap();
_width = new WeakMap();
_height = new WeakMap();
_near = new WeakMap();
_far = new WeakMap();
_projectionMatrix = new WeakMap();
_worldToCameraMatrix = new WeakMap();
_projectionMatrixInverse = new WeakMap();
_cameraToWorldMatrix = new WeakMap();
_worldProjectionMatrix = new WeakMap();

// node_modules/rubiks-js/src/ui/rubiks.js
var rotationAxis = [
  V3.getRotationAxis(0),
  V3.getRotationAxis(1),
  V3.getRotationAxis(2)
];
var cubeRotationOnMiddle = {
  0: {
    2: 90,
    3: -90,
    4: -90,
    5: 90
  },
  1: {
    0: -90,
    1: 90,
    4: 90,
    5: -90
  },
  2: {
    0: 90,
    1: -90,
    2: -90,
    3: 90
  }
};
var uvsTransformers = {
  0: {
    0: uvsTransformerPresets.rcR2Rcc,
    1: uvsTransformerPresets.rcR2Rcc,
    2: uvsTransformerPresets.flipV23,
    3: uvsTransformerPresets.flipV23,
    4: uvsTransformerPresets.flipV12,
    5: uvsTransformerPresets.flipV12
  },
  1: {
    0: uvsTransformerPresets.rcfhFvRcc,
    1: uvsTransformerPresets.rcfhFvRcc,
    2: uvsTransformerPresets.rcR2Rcc,
    3: uvsTransformerPresets.rcR2Rcc,
    4: uvsTransformerPresets.rcFhRcfh,
    5: uvsTransformerPresets.rcFhRcfh
  },
  2: {
    0: uvsTransformerPresets.flipH23,
    1: uvsTransformerPresets.flipH23,
    2: uvsTransformerPresets.flipH12,
    3: uvsTransformerPresets.flipH12,
    4: uvsTransformerPresets.rcR2Rcc,
    5: uvsTransformerPresets.rcR2Rcc
  }
};
var shouldInvertAngle = (axis, side) => {
  return side === 0 || side === 2 && axis === 0 || side === 3 && axis === 2 || side === 5;
};
var RubiksTransform = class extends Transform {
  /**
   * @param {V3} position
   * @param {Quaternion} rotation
   */
  constructor(position, rotation) {
    super(position, rotation, null);
    /** @type {[V3, V3, V3]} */
    __publicField(this, "rotationAxis");
    this.setTransforms();
  }
  /** @property */
  setTransforms() {
    super.setTransforms();
    this.rotationAxis = /** @type {[V3, V3, V3]} */
    rotationAxis.map((axis) => {
      return this.apply(axis);
    });
  }
};
var _turnCallback, _axisDeltasMap, _Rubiks_instances, turn_fn, swapOuterFacelets_fn, swapInnerFacelets_fn, _rotatingCubies, _rotationAxis, _rotationCenter, _currentAngle, _initialAngle, _rotatingAutomatic, _turnProgress, _turnSpeed, _targetAngle, _rotationIndex, _rotationAxisIndex, _side;
var _Rubiks = class _Rubiks {
  /**
   * @param {Quaternion} rotation
   * @param {number[][][]} uvs
   * @param {V3[]} hoveringColors
   * @param {TurnCallback} turnCallback
   */
  constructor(rotation, uvs, hoveringColors, turnCallback) {
    __privateAdd(this, _Rubiks_instances);
    /** @type {RubiksTransform} */
    __publicField(this, "transform");
    /** @type {Cubie[]} */
    __publicField(this, "cubies");
    /** @type {TurnCallback} */
    __privateAdd(this, _turnCallback);
    // manual rotation
    /** @type {Array<{cubie: Cubie, backupPosition: V3, backupRotation: Quaternion, directionFromCenter: V3}>} */
    __privateAdd(this, _rotatingCubies, []);
    __privateAdd(this, _rotationAxis, V3.zero);
    __privateAdd(this, _rotationCenter, V3.zero);
    __privateAdd(this, _currentAngle, 0);
    // automatic rotation
    __privateAdd(this, _initialAngle, 0);
    __privateAdd(this, _rotatingAutomatic, false);
    __privateAdd(this, _turnProgress, 0);
    __privateAdd(this, _turnSpeed, 4);
    __privateAdd(this, _targetAngle, 0);
    __privateAdd(this, _rotationIndex, 0);
    __privateAdd(this, _rotationAxisIndex, 0);
    __privateAdd(this, _side, 0);
    __privateSet(this, _turnCallback, turnCallback);
    this.transform = new RubiksTransform(V3.zero, rotation);
    this.cubies = [];
    for (let i = 0; i < 27; i++) {
      const cubie = new Cubie(
        i,
        uvs,
        hoveringColors,
        this
      );
      this.cubies.push(cubie);
      this.transform.children.push(cubie);
    }
  }
  /**
   * @param {import('./program').Program} program
   * @param {WebGL2RenderingContext} gl
   * @param {WebGLBuffer} uvsVbo
   */
  render(program, gl, uvsVbo) {
    this.cubies.forEach((cubie) => cubie.render(program, gl, uvsVbo));
  }
  /**
   * @param {number} axis
   * @param {number} index
   * @returns {Cubie[]}
   */
  getPlane(axis, index) {
    const [d1, d2] = __privateGet(_Rubiks, _axisDeltasMap)[axis];
    const initial = Math.pow(3, axis) * index;
    const cubies = [];
    for (let i = 0; i < 3; i++) {
      for (let j = 0; j < 3; j++) {
        const index2 = initial + i * d1 + j * d2;
        const cubie = this.cubies[index2];
        cubies.push(cubie);
      }
    }
    return cubies;
  }
  /**
   * @param {Cubie[]} cubies
   * @param {V3} axis
   */
  startRotation(cubies, axis) {
    __privateSet(this, _rotationAxis, axis);
    __privateSet(this, _rotationCenter, cubies[4].transform.position);
    __privateSet(this, _rotatingCubies, cubies.map((cubie) => {
      return {
        cubie,
        backupPosition: cubie.transform.position,
        backupRotation: cubie.transform.rotation,
        directionFromCenter: cubie.transform.position.sub(__privateGet(this, _rotationCenter))
      };
    }));
  }
  /** @param {number} angle */
  rotateManual(angle) {
    const rotation = Quaternion.fromAngle(__privateGet(this, _rotationAxis), -angle);
    __privateSet(this, _currentAngle, angle);
    __privateGet(this, _rotatingCubies).forEach(({ cubie, backupRotation, directionFromCenter }) => {
      const rotatedDirectionFromCenter = rotation.rotate(directionFromCenter);
      const newPosition = __privateGet(this, _rotationCenter).add(rotatedDirectionFromCenter);
      cubie.transform.position = newPosition;
      cubie.transform.rotation = backupRotation;
      cubie.transform.rotate(__privateGet(this, _rotationAxis), angle);
    });
  }
  /**
   * @param {number} axis
   * @param {number} index
   * @param {number} angle
   * @param {number} side
   */
  finishRotation(axis, index, angle, side) {
    __privateSet(this, _rotatingAutomatic, true);
    __privateSet(this, _turnProgress, 0);
    __privateSet(this, _targetAngle, angle);
    __privateSet(this, _initialAngle, __privateGet(this, _currentAngle));
    __privateSet(this, _rotationIndex, index);
    __privateSet(this, _rotationAxisIndex, axis);
    __privateSet(this, _side, side);
  }
  /** @param {number} delta */
  update(delta) {
    if (!__privateGet(this, _rotatingAutomatic)) {
      return;
    }
    __privateSet(this, _turnProgress, __privateGet(this, _turnProgress) + delta * __privateGet(this, _turnSpeed));
    if (__privateGet(this, _turnProgress) >= 1) {
      __privateSet(this, _rotatingAutomatic, false);
      __privateGet(this, _rotatingCubies).forEach(({ cubie, backupPosition, backupRotation }) => {
        cubie.transform.position = backupPosition;
        cubie.transform.rotation = backupRotation;
      });
      __privateMethod(this, _Rubiks_instances, turn_fn).call(this, __privateGet(this, _rotationAxisIndex), __privateGet(this, _rotationIndex), __privateGet(this, _targetAngle), __privateGet(this, _side), __privateGet(this, _rotatingCubies).map(({ cubie }) => cubie));
      return;
    }
    const currentAngle = lerp(__privateGet(this, _initialAngle), __privateGet(this, _targetAngle) * 90, __privateGet(this, _turnProgress));
    const rotation = Quaternion.fromAngle(__privateGet(this, _rotationAxis), -currentAngle);
    __privateGet(this, _rotatingCubies).forEach(({ cubie, backupRotation, directionFromCenter }) => {
      cubie.transform.rotation = backupRotation.mult(Quaternion.fromAngle(__privateGet(this, _rotationAxis), currentAngle));
      const rotatedDirectionFromCenter = rotation.rotate(directionFromCenter);
      const newPosition = __privateGet(this, _rotationCenter).add(rotatedDirectionFromCenter);
      cubie.transform.position = newPosition;
    });
  }
  get isTurning() {
    return __privateGet(this, _rotatingAutomatic);
  }
};
_turnCallback = new WeakMap();
_axisDeltasMap = new WeakMap();
_Rubiks_instances = new WeakSet();
/**
* @param {number} axis
* @param {number} index
* @param {number} angle
* @param {number} side
* @param {Cubie[]} plane
*/
turn_fn = function(axis, index, angle, side, plane) {
  angle = mod(angle, 4);
  if (angle === 0) {
    return;
  }
  if (index === 1) {
    __privateMethod(this, _Rubiks_instances, turn_fn).call(this, axis, 0, -angle, side, this.getPlane(axis, 0));
    __privateMethod(this, _Rubiks_instances, turn_fn).call(this, axis, 2, -angle, side, this.getPlane(axis, 2));
    this.transform.rotate(this.transform.rotationAxis[axis], angle * cubeRotationOnMiddle[axis][side]);
    return;
  }
  if (shouldInvertAngle(axis, side)) {
    angle = mod(-angle, 4);
  }
  __privateMethod(this, _Rubiks_instances, swapOuterFacelets_fn).call(this, plane, axis, angle);
  __privateMethod(this, _Rubiks_instances, swapInnerFacelets_fn).call(this, plane, axis, index, angle);
  __privateGet(this, _turnCallback).call(this, { axis, index, angle });
};
/**
 * @param {Cubie[]} plane
 * @param {number} axis
 * @param {number} angle
 */
swapOuterFacelets_fn = function(plane, axis, angle) {
  const [s0, s1, s2, s3] = sidesShiftMapper[axis];
  const facelets = [
    plane[0].getFaceletOfSide(s0),
    plane[1].getFaceletOfSide(s0),
    plane[2].getFaceletOfSide(s0),
    plane[2].getFaceletOfSide(s1),
    plane[5].getFaceletOfSide(s1),
    plane[8].getFaceletOfSide(s1),
    plane[8].getFaceletOfSide(s2),
    plane[7].getFaceletOfSide(s2),
    plane[6].getFaceletOfSide(s2),
    plane[6].getFaceletOfSide(s3),
    plane[3].getFaceletOfSide(s3),
    plane[0].getFaceletOfSide(s3)
  ];
  const shiftedUvs = [];
  for (let index = 0; index < 12; index++) {
    const shiftedIndex = mod(index + 3 * angle, 12);
    const { uvs } = facelets[shiftedIndex];
    const facelet = facelets[index];
    const transformer = uvsTransformers[axis][facelet.side][angle];
    shiftedUvs[index] = transformer(uvs);
  }
  for (let index = 0; index < 12; index++) {
    facelets[index].uvs = shiftedUvs[index];
  }
};
/**
 * @param {Cubie[]} plane
 * @param {number} axis
 * @param {number} index
 * @param {number} angle
 */
swapInnerFacelets_fn = function(plane, axis, index, angle) {
  const side = axis * 2 + Math.sign(index);
  const facelets = [
    plane[0].getFaceletOfSide(side),
    plane[1].getFaceletOfSide(side),
    plane[2].getFaceletOfSide(side),
    plane[5].getFaceletOfSide(side),
    plane[8].getFaceletOfSide(side),
    plane[7].getFaceletOfSide(side),
    plane[6].getFaceletOfSide(side),
    plane[3].getFaceletOfSide(side)
  ];
  const shiftedUvs = [];
  const transformer = uvsTransformers[axis][side][angle];
  for (let index2 = 0; index2 < 8; index2++) {
    const shiftedIndex = mod(index2 + 2 * angle, 8);
    const { uvs } = facelets[shiftedIndex];
    shiftedUvs[index2] = transformer(uvs);
  }
  for (let index2 = 0; index2 < 8; index2++) {
    facelets[index2].uvs = shiftedUvs[index2];
  }
  const center = plane[4].getFaceletOfSide(side);
  center.uvs = transformer(center.uvs);
};
_rotatingCubies = new WeakMap();
_rotationAxis = new WeakMap();
_rotationCenter = new WeakMap();
_currentAngle = new WeakMap();
_initialAngle = new WeakMap();
_rotatingAutomatic = new WeakMap();
_turnProgress = new WeakMap();
_turnSpeed = new WeakMap();
_targetAngle = new WeakMap();
_rotationIndex = new WeakMap();
_rotationAxisIndex = new WeakMap();
_side = new WeakMap();
/** @type {[number, number][]} */
__privateAdd(_Rubiks, _axisDeltasMap, [
  [3, 9],
  [1, 9],
  [1, 3]
]);
var Rubiks = _Rubiks;

// node_modules/rubiks-js/src/ui/ray.js
var _origin, _direction, _Ray_instances, intersectCube_fn;
var Ray = class {
  /**
   * @param {import('./camera').Camera} camera
   * @param {number} x
   * @param {number} y
   * @param {number} width
   * @param {number} height
   */
  constructor(camera, x, y, width, height) {
    __privateAdd(this, _Ray_instances);
    /** @type {V3} */
    __privateAdd(this, _origin);
    /** @type {V3} */
    __privateAdd(this, _direction);
    const u = (x + 0.5) / width * 2 - 1;
    const v = (height - y + 0.5) / height * 2 - 1;
    __privateSet(this, _origin, camera.cameraToWorldMatrix.mult(new V4(0, 0, 0, 1)).toV3());
    const d1 = camera.projectionMatrixInverse.mult(new V4(u, v, 0, 1));
    const d2 = camera.cameraToWorldMatrix.mult(new V4(d1.x, d1.y, d1.z, 0));
    __privateSet(this, _direction, d2.toV3().normalized);
  }
  /** @param {import('./rubiks').Rubiks} rubiks */
  intersectRubiks(rubiks) {
    return rubiks.cubies.map((cubie) => __privateMethod(this, _Ray_instances, intersectCube_fn).call(this, cubie)).flat(1);
  }
  /**
   * @param {import('./facelet').Facelet} facelet
   * @returns {{
   *  inside: false
   * } | {
   *  inside: true,
   *  facelet: import('./facelet').Facelet,
   *  d: number
   * }}
   */
  intersectFacelet(facelet) {
    const { normal, top, left, topLeft, bottomRight } = facelet.transform;
    const denom = __privateGet(this, _direction).dot(normal);
    if (denom === 0) {
      return { inside: false };
    }
    const d = topLeft.sub(__privateGet(this, _origin)).dot(normal) / denom;
    const intersection = __privateGet(this, _origin).add(__privateGet(this, _direction).scale(d));
    const fromTopLeft = intersection.sub(topLeft).normalized;
    const fromBottomRight = intersection.sub(bottomRight).normalized;
    const dot1 = fromTopLeft.dot(left);
    const dot2 = fromTopLeft.dot(top);
    const dot3 = fromBottomRight.dot(left.negate);
    const dot4 = fromBottomRight.dot(top.negate);
    const inside = dot1 <= 1 && dot1 >= 0 && dot2 <= 1 && dot2 >= 0 && dot3 <= 1 && dot3 >= 0 && dot4 <= 1 && dot4 >= 0;
    if (!inside) {
      return { inside: false };
    }
    return {
      inside,
      facelet,
      d
    };
  }
};
_origin = new WeakMap();
_direction = new WeakMap();
_Ray_instances = new WeakSet();
/** @param {import('./cubie').Cubie} cubie */
intersectCube_fn = function(cubie) {
  return cubie.facelets.reduce((acc, facelet) => {
    const hit = this.intersectFacelet(facelet);
    if (hit.inside) {
      acc.push({ facelet: hit.facelet, d: hit.d });
    }
    return acc;
  }, []);
};

// node_modules/rubiks-js/src/ui/inputHandler.js
var _a, _b, _c, _d, _e, _canvas, _rubiks, _camera, _maxZoom, _minZoom, _pointers, _action, _InputHandler_instances, setAction_fn, _pointerDown, _InputHandler_static, getPointerDown_fn, _pointerMove, getPointerMove_fn, _pointerUp, getPointerUp_fn, _pointerLeave, getPointerLeave_fn, _wheel, getWheel_fn, startActionRotatingSide_fn, actionRotatingSide_fn, startActionRotatingCube_fn, actionRotatingCube_fn, startActionGesture_fn, actionGesture_fn, actionHovering_fn, getTurnDirection_fn, rotateSide_fn, rotateCube_fn, zoomCube_fn, getZoom_fn;
var _InputHandler = class _InputHandler {
  /**
   * @param {HTMLCanvasElement} canvas
   * @param {import('./rubiks').Rubiks} rubiks
   * @param {import('./camera').Camera} camera
   */
  constructor(canvas, rubiks, camera) {
    __privateAdd(this, _InputHandler_instances);
    /** @type {HTMLCanvasElement} */
    __privateAdd(this, _canvas);
    /** @type {import('./rubiks').Rubiks} */
    __privateAdd(this, _rubiks);
    /** @type {import('./camera').Camera} */
    __privateAdd(this, _camera);
    /** @readonly */
    __privateAdd(this, _maxZoom, 40);
    /** @readonly */
    __privateAdd(this, _minZoom, 10);
    /** @type {Map<number, PointerEvent>} */
    __privateAdd(this, _pointers, /* @__PURE__ */ new Map());
    /** @type {import('../types').Action} */
    __privateAdd(this, _action, { type: "none" });
    // event handlers
    __privateAdd(this, _pointerDown, __privateMethod(_a = _InputHandler, _InputHandler_static, getPointerDown_fn).call(_a, this));
    __privateAdd(this, _pointerMove, __privateMethod(_b = _InputHandler, _InputHandler_static, getPointerMove_fn).call(_b, this));
    __privateAdd(this, _pointerUp, __privateMethod(_c = _InputHandler, _InputHandler_static, getPointerUp_fn).call(_c, this));
    __privateAdd(this, _pointerLeave, __privateMethod(_d = _InputHandler, _InputHandler_static, getPointerLeave_fn).call(_d, this));
    __privateAdd(this, _wheel, __privateMethod(_e = _InputHandler, _InputHandler_static, getWheel_fn).call(_e, this));
    __privateSet(this, _canvas, canvas);
    __privateSet(this, _rubiks, rubiks);
    __privateSet(this, _camera, camera);
  }
  addEventListeners() {
    __privateGet(this, _canvas).addEventListener("pointermove", __privateGet(this, _pointerMove));
    __privateGet(this, _canvas).addEventListener("pointerdown", __privateGet(this, _pointerDown));
    __privateGet(this, _canvas).addEventListener("pointerup", __privateGet(this, _pointerUp));
    __privateGet(this, _canvas).addEventListener("pointerleave", __privateGet(this, _pointerLeave));
    __privateGet(this, _canvas).addEventListener("wheel", __privateGet(this, _wheel));
  }
  removeEventListeners() {
    __privateGet(this, _canvas).removeEventListener("pointermove", __privateGet(this, _pointerMove));
    __privateGet(this, _canvas).removeEventListener("pointerdown", __privateGet(this, _pointerDown));
    __privateGet(this, _canvas).removeEventListener("pointerup", __privateGet(this, _pointerUp));
    __privateGet(this, _canvas).removeEventListener("pointerleave", __privateGet(this, _pointerLeave));
    __privateGet(this, _canvas).removeEventListener("wheel", __privateGet(this, _wheel));
  }
};
_canvas = new WeakMap();
_rubiks = new WeakMap();
_camera = new WeakMap();
_maxZoom = new WeakMap();
_minZoom = new WeakMap();
_pointers = new WeakMap();
_action = new WeakMap();
_InputHandler_instances = new WeakSet();
/** @param {import('../types').Action} action */
setAction_fn = function(action) {
  if (__privateGet(this, _action).type === "hovering") {
    __privateGet(this, _action).facelet.hovering = false;
  }
  if (action.type === "hovering") {
    action.facelet.hovering = true;
  }
  if (__privateGet(this, _action).type === "rotatingSide" && __privateGet(this, _action).side) {
    const info = __privateGet(this, _action)[__privateGet(this, _action).side];
    const angle = Math.round(info.angle / 90);
    __privateGet(this, _rubiks).finishRotation(info.axis, info.index, angle, __privateGet(this, _action).facelet.side);
  }
  __privateSet(this, _action, action);
};
_pointerDown = new WeakMap();
_InputHandler_static = new WeakSet();
getPointerDown_fn = function(inputHandler) {
  return (event) => {
    var _a3, _b2, _c2, _d2, _e2;
    const { offsetX, offsetY, pointerId } = event;
    if (event.button === 0) {
      __privateGet(inputHandler, _pointers).set(pointerId, event);
    } else if (event.button === 1) {
      __privateGet(inputHandler, _pointers).set(pointerId, event);
      __privateMethod(_a3 = inputHandler, _InputHandler_instances, setAction_fn).call(_a3, {
        type: "rotatingCube",
        mouse: new V2(offsetX, offsetY)
      });
      return;
    }
    if (__privateGet(inputHandler, _pointers).size === 1) {
      if (__privateGet(inputHandler, _rubiks).isTurning) {
        return;
      }
      if (__privateGet(inputHandler, _action).type === "none") {
        __privateMethod(_b2 = inputHandler, _InputHandler_instances, actionHovering_fn).call(_b2, offsetX, offsetY);
      }
      if (__privateGet(inputHandler, _action).type === "hovering") {
        __privateMethod(_c2 = inputHandler, _InputHandler_instances, startActionRotatingSide_fn).call(_c2, offsetX, offsetY, __privateGet(inputHandler, _action).facelet);
        return;
      }
      __privateMethod(_d2 = inputHandler, _InputHandler_instances, startActionRotatingCube_fn).call(_d2, offsetX, offsetY);
    } else if (__privateGet(inputHandler, _pointers).size === 2) {
      __privateMethod(_e2 = inputHandler, _InputHandler_instances, startActionGesture_fn).call(_e2);
    }
  };
};
_pointerMove = new WeakMap();
getPointerMove_fn = function(inputHandler) {
  return (event) => {
    var _a3, _b2, _c2, _d2;
    const { offsetX, offsetY } = event;
    if (__privateGet(inputHandler, _pointers).size === 0) {
      __privateMethod(_a3 = inputHandler, _InputHandler_instances, actionHovering_fn).call(_a3, offsetX, offsetY);
      return;
    }
    __privateGet(inputHandler, _pointers).set(event.pointerId, event);
    __privateMethod(_b2 = inputHandler, _InputHandler_instances, actionRotatingSide_fn).call(_b2, offsetX, offsetY);
    __privateMethod(_c2 = inputHandler, _InputHandler_instances, actionRotatingCube_fn).call(_c2, offsetX, offsetY);
    __privateMethod(_d2 = inputHandler, _InputHandler_instances, actionGesture_fn).call(_d2);
  };
};
_pointerUp = new WeakMap();
getPointerUp_fn = function(inputHandler) {
  return () => {
    var _a3;
    __privateGet(inputHandler, _pointers).clear();
    __privateMethod(_a3 = inputHandler, _InputHandler_instances, setAction_fn).call(_a3, {
      type: "none"
    });
  };
};
_pointerLeave = new WeakMap();
getPointerLeave_fn = function(inputHandler) {
  return () => {
    var _a3;
    __privateGet(inputHandler, _pointers).clear();
    __privateMethod(_a3 = inputHandler, _InputHandler_instances, setAction_fn).call(_a3, {
      type: "none"
    });
  };
};
_wheel = new WeakMap();
getWheel_fn = function(inputHandler) {
  return ({ deltaY, deltaMode }) => {
    var _a3;
    if (deltaMode !== WheelEvent.DOM_DELTA_PIXEL) {
      return;
    }
    const d = clamp(deltaY / 102, -1, 1) * 0.1;
    __privateMethod(_a3 = inputHandler, _InputHandler_instances, zoomCube_fn).call(_a3, d);
  };
};
// actions
// rotating side
/**
 * @param {number} offsetX
 * @param {number} offsetY
 * @param {import('./facelet').Facelet} hovering
 */
startActionRotatingSide_fn = function(offsetX, offsetY, hovering) {
  const { left, top, topLeft } = hovering.transform;
  const screenTopLeft = __privateGet(this, _camera).worldToScreen(topLeft);
  const screenBottomLeft = __privateGet(this, _camera).worldToScreen(topLeft.add(left));
  const screenTopRight = __privateGet(this, _camera).worldToScreen(topLeft.add(top));
  const rightDir = screenTopRight.sub(screenTopLeft).normalized;
  const downDir = screenBottomLeft.sub(screenTopLeft).normalized;
  const rubiksRotation = __privateGet(this, _rubiks).transform;
  const side = hovering.side;
  const currentAxis = Math.floor(side / 2);
  const cubie = hovering.transform.parent;
  const [axis1, axis2] = [0, 1, 2].filter((axis) => axis !== currentAxis).map((axis) => {
    const rotationAxis2 = V3.getRotationAxis(axis);
    const rubiksRotationAxis = rubiksRotation.apply(rotationAxis2);
    const index = Math.floor(cubie.index / Math.pow(3, axis)) % 3;
    const info = {
      default: rubiksRotationAxis,
      inverted: rubiksRotationAxis.negate,
      axis,
      index
    };
    return info;
  });
  const sideInvertMap = [
    false,
    true,
    true,
    false,
    false,
    true
  ];
  const invert = sideInvertMap[hovering.side];
  const mouse = new V2(offsetX, __privateGet(this, _canvas).height - offsetY);
  if (Math.abs(axis1.default.dot(top)) > 0.99) {
    __privateMethod(this, _InputHandler_instances, setAction_fn).call(this, {
      type: "rotatingSide",
      mouse,
      down: __privateMethod(this, _InputHandler_instances, getTurnDirection_fn).call(this, axis1, top, downDir, true !== invert),
      right: __privateMethod(this, _InputHandler_instances, getTurnDirection_fn).call(this, axis2, left, rightDir, false !== invert),
      side: null,
      facelet: hovering
    });
  } else {
    __privateMethod(this, _InputHandler_instances, setAction_fn).call(this, {
      type: "rotatingSide",
      mouse,
      down: __privateMethod(this, _InputHandler_instances, getTurnDirection_fn).call(this, axis2, top, downDir, true !== invert),
      right: __privateMethod(this, _InputHandler_instances, getTurnDirection_fn).call(this, axis1, left, rightDir, false !== invert),
      side: null,
      facelet: hovering
    });
  }
};
/**
 * @param {number} offsetX
 * @param {number} offsetY
 */
actionRotatingSide_fn = function(offsetX, offsetY) {
  if (__privateGet(this, _action).type !== "rotatingSide") {
    return;
  }
  const mouse = new V2(offsetX, __privateGet(this, _canvas).height - offsetY);
  if (__privateGet(this, _action).mouse.sub(mouse).mag < 10) {
    return;
  }
  const initialMouse = __privateGet(this, _action).mouse;
  if (__privateGet(this, _action).side) {
    __privateMethod(this, _InputHandler_instances, rotateSide_fn).call(this, mouse, __privateGet(this, _action)[__privateGet(this, _action).side], initialMouse);
    return;
  }
  const { right, down } = __privateGet(this, _action);
  const mouseDir = mouse.sub(initialMouse).normalized;
  const rightDot = right.dir.dot(mouseDir);
  const downDot = down.dir.dot(mouseDir);
  if (Math.abs(rightDot) > Math.abs(downDot)) {
    __privateGet(this, _action).side = "right";
    __privateGet(this, _rubiks).startRotation(right.cubies, right.rotationAxis);
    __privateMethod(this, _InputHandler_instances, rotateSide_fn).call(this, mouse, right, initialMouse);
  } else {
    __privateGet(this, _action).side = "down";
    __privateGet(this, _rubiks).startRotation(down.cubies, down.rotationAxis);
    __privateMethod(this, _InputHandler_instances, rotateSide_fn).call(this, mouse, down, initialMouse);
  }
};
// rotating cube
/**
 * @param {number} offsetX
 * @param {number} offsetY
 */
startActionRotatingCube_fn = function(offsetX, offsetY) {
  __privateMethod(this, _InputHandler_instances, setAction_fn).call(this, {
    type: "rotatingCube",
    mouse: new V2(offsetX, offsetY)
  });
};
/**
 * @param {number} offsetX
 * @param {number} offsetY
 */
actionRotatingCube_fn = function(offsetX, offsetY) {
  if (__privateGet(this, _action).type !== "rotatingCube") {
    return;
  }
  const mouse = new V2(offsetX, offsetY);
  const delta = mouse.sub(__privateGet(this, _action).mouse);
  __privateGet(this, _action).mouse = mouse;
  __privateMethod(this, _InputHandler_instances, rotateCube_fn).call(this, delta);
};
// two pointer gesture
startActionGesture_fn = function() {
  const [e1, e2] = __privateGet(this, _pointers).values();
  const dx = e1.screenX - e2.screenX;
  const dy = e1.screenY - e2.screenY;
  __privateMethod(this, _InputHandler_instances, setAction_fn).call(this, {
    type: "gesture",
    distance: dx * dx + dy * dy,
    center: new V2(e1.screenX + e2.screenX, e1.screenY + e2.screenY).scale(0.5)
  });
};
actionGesture_fn = function() {
  if (__privateGet(this, _action).type !== "gesture") {
    return;
  }
  const [e1, e2] = __privateGet(this, _pointers).values();
  const dx = e1.screenX - e2.screenX;
  const dy = e1.screenY - e2.screenY;
  const distance = dx * dx + dy * dy;
  const deltaDistance = distance - __privateGet(this, _action).distance;
  __privateGet(this, _action).distance = distance;
  const d = clamp(deltaDistance / 1e3, -1, 1) * -0.02;
  __privateMethod(this, _InputHandler_instances, zoomCube_fn).call(this, d);
  const center = new V2(e1.screenX + e2.screenX, e1.screenY + e2.screenY).scale(0.5);
  const deltaCenter = center.sub(__privateGet(this, _action).center);
  __privateGet(this, _action).center = center;
  __privateMethod(this, _InputHandler_instances, rotateCube_fn).call(this, deltaCenter);
};
// hovering
/**
 * @param {number} offsetX
 * @param {number} offsetY
 */
actionHovering_fn = function(offsetX, offsetY) {
  const ray = new Ray(__privateGet(this, _camera), offsetX, offsetY, window.innerWidth, window.innerHeight);
  const facelets = ray.intersectRubiks(__privateGet(this, _rubiks));
  if (facelets.length) {
    facelets.sort((a, b) => a.d - b.d);
    __privateMethod(this, _InputHandler_instances, setAction_fn).call(this, {
      type: "hovering",
      facelet: facelets[0].facelet
    });
  } else {
    __privateMethod(this, _InputHandler_instances, setAction_fn).call(this, {
      type: "none"
    });
  }
};
// action helpers
// rotating side
/**
 * @param {import('../types').AxisInfo} axisInfo
 * @param {V3} vector
 * @param {V2} dir
 * @param {boolean} invert
 * @returns {import('../types').SideInfo}
 */
getTurnDirection_fn = function(axisInfo, vector, dir, invert) {
  if (axisInfo.default.dot(vector) > 0.99)
    return {
      dir,
      angle: 0,
      axis: axisInfo.axis,
      rotationAxis: V3.getRotationAxis(axisInfo.axis).scale(invert ? -1 : 1),
      index: axisInfo.index,
      cubies: __privateGet(this, _rubiks).getPlane(axisInfo.axis, axisInfo.index)
    };
  return {
    dir,
    angle: 0,
    axis: axisInfo.axis,
    rotationAxis: V3.getRotationAxis(axisInfo.axis).scale(invert ? 1 : -1),
    index: axisInfo.index,
    cubies: __privateGet(this, _rubiks).getPlane(axisInfo.axis, axisInfo.index)
  };
};
/**
 * @param {V2} mouse
 * @param {import('../types').SideInfo} info
 * @param {V2} initialMouse
 */
rotateSide_fn = function(mouse, info, initialMouse) {
  const length = info.dir.dot(initialMouse.sub(mouse));
  const zoom = __privateMethod(this, _InputHandler_instances, getZoom_fn).call(this);
  info.angle = length / (3 - zoom * 2);
  __privateGet(this, _rubiks).rotateManual(info.angle);
};
// rotating cube
/** @param {V2} delta */
rotateCube_fn = function(delta) {
  if (delta.x === 0 && delta.y === 0) {
    return;
  }
  const n = __privateGet(this, _camera).up.scale(delta.y).add(__privateGet(this, _camera).right.scale(delta.x));
  const axis = __privateGet(this, _camera).forward.cross(n);
  const zoom = __privateMethod(this, _InputHandler_instances, getZoom_fn).call(this);
  const angle = Math.sqrt(delta.x * delta.x + delta.y * delta.y) * 0.3 + 2 * zoom;
  __privateGet(this, _rubiks).transform.rotate(axis, angle);
};
// zooming camera
/** @param {number} d */
zoomCube_fn = function(d) {
  const { position } = __privateGet(this, _camera);
  __privateGet(this, _camera).position = new V3(0, 0, clamp(position.z * (1 + d), -__privateGet(this, _maxZoom), -__privateGet(this, _minZoom)));
};
getZoom_fn = function() {
  const zoom = -__privateGet(this, _camera).position.z;
  const minZoom = __privateGet(this, _minZoom);
  const maxZoom = __privateGet(this, _maxZoom);
  return (zoom - minZoom) / (maxZoom - minZoom);
};
__privateAdd(_InputHandler, _InputHandler_static);
var InputHandler = _InputHandler;

// node_modules/rubiks-js/src/ui/debugger.js
var _ctx, _canvas2, _strokeColor, _fillColor, _Debugger_static, flipVector_fn;
var _Debugger = class _Debugger {
  /**
   * @param {Element?} canvas
   */
  constructor(canvas) {
    /** @type {CanvasRenderingContext2D?} */
    __privateAdd(this, _ctx);
    /** @type {HTMLCanvasElement?} */
    __privateAdd(this, _canvas2);
    __privateAdd(this, _strokeColor, "white");
    __privateAdd(this, _fillColor, "white");
    if (!canvas) {
      return;
    }
    if (!(canvas instanceof HTMLCanvasElement)) {
      throw new Error(`rubiks cube debugger is not a canvas, it is a <${canvas.tagName}>`);
    }
    __privateSet(this, _canvas2, canvas);
    const ctx = canvas.getContext("2d");
    if (!ctx)
      throw new Error("cannot create 2d context for rubiks cube debugger");
    __privateSet(this, _ctx, ctx);
  }
  clear() {
    if (__privateGet(this, _ctx) && __privateGet(this, _canvas2)) {
      __privateGet(this, _ctx).clearRect(0, 0, __privateGet(this, _canvas2).width, __privateGet(this, _canvas2).height);
    }
  }
  /** @param {string} color */
  stroke(color) {
    __privateSet(this, _strokeColor, color);
  }
  /** @param {string} color */
  fill(color) {
    __privateSet(this, _fillColor, color);
  }
  /**
   * @param {V2} from
   * @param {V2} to
   */
  line(from, to) {
    var _a3, _b2;
    if (__privateGet(this, _ctx) && __privateGet(this, _canvas2)) {
      __privateGet(this, _ctx).strokeStyle = __privateGet(this, _strokeColor);
      __privateGet(this, _ctx).lineWidth = 3;
      const fromF = __privateMethod(_a3 = _Debugger, _Debugger_static, flipVector_fn).call(_a3, from, __privateGet(this, _canvas2));
      const toF = __privateMethod(_b2 = _Debugger, _Debugger_static, flipVector_fn).call(_b2, to, __privateGet(this, _canvas2));
      __privateGet(this, _ctx).beginPath();
      __privateGet(this, _ctx).moveTo(fromF.x, fromF.y);
      __privateGet(this, _ctx).lineTo(toF.x, toF.y);
      __privateGet(this, _ctx).stroke();
    }
  }
  /**
   * @param {V2} origin
   * @param {V2} direction
   * @param {number} [length=1]
   */
  vector(origin, direction, length = 1) {
    this.line(origin, origin.add(direction.scale(length)));
  }
  /**
   * @param {number} width
   * @param {number} height
   */
  setSize(width, height) {
    if (__privateGet(this, _canvas2)) {
      __privateGet(this, _canvas2).width = width;
      __privateGet(this, _canvas2).height = height;
    }
  }
  /**
   * @param {V2} pos
   * @param {string} text
   */
  text(pos, text) {
    if (__privateGet(this, _ctx)) {
      __privateGet(this, _ctx).fillStyle = __privateGet(this, _fillColor);
      __privateGet(this, _ctx).fillText(text, pos.x, pos.y);
    }
  }
};
_ctx = new WeakMap();
_canvas2 = new WeakMap();
_strokeColor = new WeakMap();
_fillColor = new WeakMap();
_Debugger_static = new WeakSet();
flipVector_fn = function({ x, y }, canvas) {
  return new V2(x, canvas.height - y);
};
__privateAdd(_Debugger, _Debugger_static);
var Debugger = _Debugger;
var debugger_default = new Debugger(document.querySelector("[data-rubiks-cube-debug]"));

// node_modules/rubiks-js/src/shaders/facelet.glsl.js
var vertex = `#version 300 es

layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aUV;

out vec2 uv;
out vec2 pos;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
    gl_Position = projection * view * model * vec4(aPos, 1.0);
    uv = aUV;
    pos = aPos.yz;
}`;
var fragment = `#version 300 es

precision mediump float;

in vec2 uv;
in vec2 pos;

out vec4 FragColor;

uniform sampler2D tex;
uniform vec3 colorMult;

vec3 rime = vec3(0.07);
float outer = 0.45;
float inner = 0.44;

float map(float value, float min1, float max1, float min2, float max2)
{
    return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
}

void main()
{
    float x = abs(pos.x);
    float y = abs(pos.y);
    if (x > outer || y > outer) {
        FragColor = vec4(rime, 1.0);
        return;
    }
    vec3 color = texture(tex, uv).rgb * colorMult;
    if (x > inner || y > inner) {
        float t = smoothstep(0.0, 1.0, map(max(x, y), outer, inner, 0.0, 1.0));
        vec3 c = color * t + rime * (1.0 - t);
        FragColor = vec4(c, 1.0);
        return;
    }
    FragColor = vec4(color, 1.0);
}`;

// node_modules/rubiks-js/src/events.js
var ChangeEvent = class {
  /**
   * @param {number} axis
   * @param {number} index
   * @param {number} angle
   * @param {import('./state/types').Turn} turn
   * @param {import('./state').StateInfo} state
   */
  constructor(axis, index, angle, turn, state) {
    /**
     * Axis that was turned around
     * 
     * 0 => x-axis (from right to left)
     * 
     * 1 => y-axis (from bottom to top)
     * 
     * 2 => z-axis (from front to back)
     * @type {0 | 1 | 2}
     */
    __publicField(this, "axis");
    /**
     * The slice on the axis. Example using axis = 0:
     * 
     * 0 => Left slice
     * 
     * 2 => Right slice
     * 
     * The middle layer is never turned. Instead both outer layers are turn
     * in the opposite direction. This has the same effect.
     * That way the centers always stay in the same position.
     * @type {0 | 2}
     */
    __publicField(this, "index");
    /**
     * Important: The angle is always clockwise around the axis and not
     * clockwise around the turning side. This means that R and L' both
     * have an angle of 1
     * @type {1 | 2 | 3}
     */
    __publicField(this, "angle");
    /**
     * @type {import('./state/types').Turn}
     */
    __publicField(this, "turn");
    /**
     * @type {import('./state').StateInfo}
     */
    __publicField(this, "state");
    this.axis = /** @type {0 | 1 | 2} */
    axis;
    this.index = /** @type {0 | 2} */
    index;
    this.angle = /** @type {1 | 2 | 3} */
    angle;
    this.turn = turn;
    this.state = state;
  }
};

// node_modules/rubiks-js/src/rubiksCube.js
var _a2, _initialized, _gl, _canvas3, _program, _vao, _uvsVbo, _texture, _camera2, _rubiks2, _inputHandler, _state, _trackCenters, _frame, _resizeHandler, _canvasData, _image, _uvs, _hoveringColors, _RubiksCube_static, getResizeHandler_fn, _RubiksCube_instances, initialize_fn, _listeners, turnHandler_fn;
var _RubiksCube = class _RubiksCube {
  /**
   * @param {string} canvasData
   * @param {ImageData | HTMLImageElement} image
   * @param {number[][][]} uvs
   * @param {number[][]} hoveringColors
    * @param {boolean} trackCenters
   */
  constructor(canvasData, image, uvs, hoveringColors, trackCenters) {
    __privateAdd(this, _RubiksCube_instances);
    __privateAdd(this, _initialized, false);
    /** @type {WebGL2RenderingContext} */
    __privateAdd(this, _gl);
    /** @type {HTMLCanvasElement} */
    __privateAdd(this, _canvas3);
    /** @type {Program} */
    __privateAdd(this, _program);
    /** @type {WebGLVertexArrayObject} */
    __privateAdd(this, _vao);
    /** @type {WebGLBuffer} */
    __privateAdd(this, _uvsVbo);
    /** @type {WebGLTexture} */
    __privateAdd(this, _texture);
    /** @type {Camera} */
    __privateAdd(this, _camera2);
    /** @type {Rubiks} */
    __privateAdd(this, _rubiks2);
    /** @type {InputHandler} */
    __privateAdd(this, _inputHandler);
    /** @type {State} */
    __privateAdd(this, _state);
    /** @type {boolean} */
    __privateAdd(this, _trackCenters);
    __privateAdd(this, _frame, 0);
    __privateAdd(this, _resizeHandler, __privateMethod(_a2 = _RubiksCube, _RubiksCube_static, getResizeHandler_fn).call(_a2, this));
    /** @type {string} */
    __privateAdd(this, _canvasData);
    /** @type {ImageData | HTMLImageElement} */
    __privateAdd(this, _image);
    /** @type {number[][][]} */
    __privateAdd(this, _uvs);
    /** @type {number[][]} */
    __privateAdd(this, _hoveringColors);
    /** @type {Map<keyof Events, Set<(event: any) => void>>} */
    __privateAdd(this, _listeners, /* @__PURE__ */ new Map());
    __privateSet(this, _canvasData, canvasData);
    __privateSet(this, _image, image);
    __privateSet(this, _uvs, uvs);
    __privateSet(this, _hoveringColors, hoveringColors);
    __privateSet(this, _trackCenters, trackCenters);
  }
  /**
   * Starts rendering the cube and listening for user inputs.
   * Automaticly initializes webgl and pointer event listeners.
   */
  start() {
    if (!__privateGet(this, _initialized)) {
      __privateMethod(this, _RubiksCube_instances, initialize_fn).call(this);
      __privateSet(this, _initialized, true);
    }
    __privateGet(this, _inputHandler).addEventListeners();
    window.addEventListener("resize", __privateGet(this, _resizeHandler));
    __privateGet(this, _resizeHandler).call(this);
    __privateGet(this, _program).use();
    __privateGet(this, _gl).bindVertexArray(__privateGet(this, _vao));
    __privateGet(this, _gl).activeTexture(__privateGet(this, _gl).TEXTURE0);
    __privateGet(this, _gl).bindTexture(__privateGet(this, _gl).TEXTURE_2D, __privateGet(this, _texture));
    __privateGet(this, _program).uniform("tex", {
      setUniform: (gl, location) => gl.uniform1i(location, 0)
    });
    let lastTime = Date.now();
    const loop = () => {
      const currentTime = Date.now();
      const deltaTime = (currentTime - lastTime) / 1e3;
      lastTime = currentTime;
      __privateGet(this, _gl).clear(__privateGet(this, _gl).COLOR_BUFFER_BIT | __privateGet(this, _gl).DEPTH_BUFFER_BIT);
      __privateGet(this, _program).uniform("view", __privateGet(this, _camera2).worldToCameraMatrix);
      __privateGet(this, _program).uniform("projection", __privateGet(this, _camera2).projectionMatrix);
      __privateGet(this, _rubiks2).render(__privateGet(this, _program), __privateGet(this, _gl), __privateGet(this, _uvsVbo));
      __privateGet(this, _rubiks2).update(deltaTime);
      __privateSet(this, _frame, requestAnimationFrame(loop));
    };
    __privateSet(this, _frame, requestAnimationFrame(loop));
  }
  /**
   * Stops rendering the cube and removes all listeners.
   */
  stop() {
    window.removeEventListener("resize", __privateGet(this, _resizeHandler));
    cancelAnimationFrame(__privateGet(this, _frame));
    __privateGet(this, _inputHandler).removeEventListeners();
  }
  /**
   * Resets the internal state and applys it to the cube.
   */
  reset() {
    __privateGet(this, _state).reset();
    __privateGet(this, _state).applyState(__privateGet(this, _uvs), __privateGet(this, _rubiks2));
  }
  /**
   * @param {string} stateStr a base46 representation
   * @returns {boolean} false if `stateStr` was invalid
   */
  setState(stateStr) {
    if (!__privateGet(this, _initialized)) {
      __privateMethod(this, _RubiksCube_instances, initialize_fn).call(this);
      __privateSet(this, _initialized, true);
    }
    if (!__privateGet(this, _state).decode(stateStr)) {
      return false;
    }
    __privateGet(this, _state).applyState(__privateGet(this, _uvs), __privateGet(this, _rubiks2));
    return true;
  }
  get transform() {
    return __privateGet(this, _rubiks2).transform;
  }
  /**
   * @template {keyof Events} Name
   * @param {Name} name
   * @param {(event: Events[Name]) => void} callback
   */
  on(name, callback) {
    const set = __privateGet(this, _listeners).get(name) ?? /* @__PURE__ */ new Set();
    set.add(callback);
    __privateGet(this, _listeners).set(name, set);
  }
};
_initialized = new WeakMap();
_gl = new WeakMap();
_canvas3 = new WeakMap();
_program = new WeakMap();
_vao = new WeakMap();
_uvsVbo = new WeakMap();
_texture = new WeakMap();
_camera2 = new WeakMap();
_rubiks2 = new WeakMap();
_inputHandler = new WeakMap();
_state = new WeakMap();
_trackCenters = new WeakMap();
_frame = new WeakMap();
_resizeHandler = new WeakMap();
_canvasData = new WeakMap();
_image = new WeakMap();
_uvs = new WeakMap();
_hoveringColors = new WeakMap();
_RubiksCube_static = new WeakSet();
getResizeHandler_fn = function(rubiksCube) {
  return () => {
    const width = window.innerWidth;
    const height = window.innerHeight;
    debugger_default.setSize(width, height);
    __privateGet(rubiksCube, _canvas3).width = width;
    __privateGet(rubiksCube, _canvas3).height = height;
    __privateGet(rubiksCube, _gl).viewport(0, 0, width, height);
    __privateGet(rubiksCube, _camera2).screenSize(width, height);
  };
};
_RubiksCube_instances = new WeakSet();
initialize_fn = function() {
  const canvas = document.querySelector(`[${__privateGet(this, _canvasData)}]`);
  if (!canvas) {
    throw new Error(`<canvas ${__privateGet(this, _canvasData)}> does not exist`);
  }
  if (!(canvas instanceof HTMLCanvasElement)) {
    throw new Error(`<canvas ${__privateGet(this, _canvasData)}> is not a canvas, it is a <${canvas.tagName}>`);
  }
  __privateSet(this, _canvas3, canvas);
  const gl = canvas.getContext("webgl2");
  if (!gl) {
    throw new Error(`cannot create webgl2 context`);
  }
  __privateSet(this, _gl, gl);
  gl.enable(gl.DEPTH_TEST);
  gl.depthFunc(gl.LESS);
  __privateSet(this, _program, new Program("rubiksCube/shaders/facelet.glsl", vertex, fragment, gl));
  const vao = gl.createVertexArray();
  if (!vao) {
    throw new Error("could not create a webgl vertex array object");
  }
  __privateSet(this, _vao, vao);
  gl.bindVertexArray(vao);
  const vertices = [
    0,
    -0.5,
    -0.5,
    0,
    -0.5,
    0.5,
    0,
    0.5,
    0.5,
    0,
    0.5,
    -0.5
  ];
  const verticesBuffer = new Float32Array(vertices);
  const verticesVbo = gl.createBuffer();
  const indices = [
    0,
    1,
    3,
    1,
    3,
    2
  ];
  const indicesBuffer = new Int8Array(indices);
  const ebo = gl.createBuffer();
  const uvsVbo = gl.createBuffer();
  if (!verticesVbo || !ebo || !uvsVbo) {
    throw new Error("could not create a vertex buffer objects");
  }
  __privateSet(this, _uvsVbo, uvsVbo);
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ebo);
  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indicesBuffer, gl.STATIC_DRAW);
  gl.bindBuffer(gl.ARRAY_BUFFER, verticesVbo);
  gl.bufferData(gl.ARRAY_BUFFER, verticesBuffer, gl.STATIC_DRAW);
  gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 12, 0);
  gl.enableVertexAttribArray(0);
  gl.enableVertexAttribArray(1);
  gl.bindVertexArray(null);
  const texture = gl.createTexture();
  if (!texture) {
    throw new Error("could not create a texture");
  }
  __privateSet(this, _texture, texture);
  gl.bindTexture(gl.TEXTURE_2D, texture);
  gl.texImage2D(
    gl.TEXTURE_2D,
    0,
    gl.RGBA,
    gl.RGBA,
    gl.UNSIGNED_BYTE,
    __privateGet(this, _image)
  );
  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_MIN_FILTER, gl.NEAREST);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
  gl.bindTexture(gl.TEXTURE_2D, null);
  const hoveringColors = __privateGet(this, _hoveringColors).map(([r, g, b]) => new V3(r, g, b));
  __privateSet(this, _camera2, new Camera(new V3(0, 0, -10), V3.zero, V3.up, 45, window.innerWidth, window.innerHeight, 0.1, 100));
  __privateSet(this, _rubiks2, new Rubiks(Quaternion.identity, __privateGet(this, _uvs), hoveringColors, __privateMethod(this, _RubiksCube_instances, turnHandler_fn).bind(this)));
  __privateSet(this, _inputHandler, new InputHandler(canvas, __privateGet(this, _rubiks2), __privateGet(this, _camera2)));
  __privateSet(this, _state, new State(__privateGet(this, _trackCenters)));
};
_listeners = new WeakMap();
/**
 * @param {import('./types').AIA} aia
 */
turnHandler_fn = function(aia) {
  const turn = convertAiaToTurn(aia);
  __privateGet(this, _state).applyTurn(turn);
  const changeHandlers = __privateGet(this, _listeners).get("change");
  if (changeHandlers) {
    const event = new ChangeEvent(
      aia.axis,
      aia.index,
      aia.angle,
      turn,
      __privateGet(this, _state).stateInfo
    );
    for (const callback of changeHandlers) {
      callback(event);
    }
  }
};
__privateAdd(_RubiksCube, _RubiksCube_static);
var RubiksCube = _RubiksCube;

// node_modules/rubiks-js/src/index.js
var defaultTexture = new ImageData(new Uint8ClampedArray([
  0,
  0,
  255,
  255,
  0,
  255,
  0,
  255,
  255,
  255,
  0,
  255,
  255,
  255,
  255,
  255,
  255,
  0,
  0,
  255,
  255,
  127,
  0,
  255
]), 1, 6);
var defaultUVs = Array(6).fill(null).map((_, index) => {
  return Array(9).fill([
    0,
    (index + 0) / 6,
    1,
    (index + 0) / 6,
    1,
    (index + 1) / 6,
    0,
    (index + 1) / 6
  ]);
});
var defaultHovorvingColors = Array(6).fill(Array(3).fill(0.7));
export {
  RubiksCube,
  defaultHovorvingColors,
  defaultTexture,
  defaultUVs
};
//# sourceMappingURL=rubiks-js.js.map
