declare module "gl-matrix" {
  declare type Vec2 = [number, number];

  declare type Vec3 = [number, number, number];

  declare type Vec4 = [number, number, number, number];

  declare type Quat = [number, number, number, number];

  declare type Mat2d = [number, number, number, number, number, number];

  declare type Mat2 = [number, number, number, number];

  declare type Mat3 = [
    number,
    number,
    number,
    number,
    number,
    number,
    number,
    number,
    number
  ];

  declare type Mat4 = [
    number,
    number,
    number,
    number,
    number,
    number,
    number,
    number,
    number,
    number,
    number,
    number,
    number,
    number,
    number,
    number
  ];

  declare var vec2: {
    create(): Vec2,
    clone(a: Vec2): Vec2,
    fromValues(x: number, y: number): Vec2,
    copy(out: Vec2, a: Vec2): Vec2,
    set(out: Vec2, x: number, y: number): Vec2,
    add(out: Vec2, a: Vec2, b: Vec2): Vec2,
    subtract(out: Vec2, a: Vec2, b: Vec2): Vec2,
    sub(out: Vec2, a: Vec2, b: Vec2): Vec2,
    multiply(out: Vec2, a: Vec2, b: Vec2): Vec2,
    mul(out: Vec2, a: Vec2, b: Vec2): Vec2,
    divide(out: Vec2, a: Vec2, b: Vec2): Vec2,
    div(out: Vec2, a: Vec2, b: Vec2): Vec2,
    ceil(out: Vec2, a: Vec2): Vec2,
    floor(out: Vec2, a: Vec2): Vec2,
    min(out: Vec2, a: Vec2, b: Vec2): Vec2,
    max(out: Vec2, a: Vec2, b: Vec2): Vec2,
    round(out: Vec2, a: Vec2): Vec2,
    scale(out: Vec2, a: Vec2, b: number): Vec2,
    scaleAndAdd(out: Vec2, a: Vec2, b: Vec2, scale: number): Vec2,
    distance(a: Vec2, b: Vec2): number,
    dist(a: Vec2, b: Vec2): number,
    squaredDistance(a: Vec2, b: Vec2): number,
    sqrDist(a: Vec2, b: Vec2): number,
    length(a: Vec2): number,
    len(a: Vec2): number,
    squaredLength(a: Vec2): number,
    sqrLen(a: Vec2): number,
    negate(out: Vec2, a: Vec2): Vec2,
    inverse(out: Vec2, a: Vec2): Vec2,
    normalize(out: Vec2, a: Vec2): Vec2,
    dot(a: Vec2, b: Vec2): number,
    cross(out: Vec3, a: Vec2, b: Vec2): Vec3,
    lerp(out: Vec2, a: Vec2, b: Vec2, t: number): Vec2,
    random(out: Vec2, scale?: number): Vec2,
    transformMat2(out: Vec2, a: Vec2, m: Mat2): Vec2,
    transformMat2d(out: Vec2, a: Vec2, m: Mat2d): Vec2,
    transformMat3(out: Vec2, a: Vec2, m: Mat3): Vec2,
    transformMat4(out: Vec2, a: Vec2, m: Mat4): Vec2,
    str(a: Vec2): string,
    exactEquals(a: Vec2, b: Vec2): boolean,
    equals(a: Vec2, b: Vec2): boolean
  };

  declare var vec3: {
    create(): Vec3,
    clone(a: Vec3): Vec3,
    fromValues(x: number, y: number, z: number): Vec3,
    copy(out: Vec3, a: Vec3): Vec3,
    set(out: Vec3, x: number, y: number, z: number): Vec3,
    add(out: Vec3, a: Vec3, b: Vec3): Vec3,
    subtract(out: Vec3, a: Vec3, b: Vec3): Vec3,
    sub(out: Vec3, a: Vec3, b: Vec3): Vec3,
    multiply(out: Vec3, a: Vec3, b: Vec3): Vec3,
    mul(out: Vec3, a: Vec3, b: Vec3): Vec3,
    divide(out: Vec3, a: Vec3, b: Vec3): Vec3,
    div(out: Vec3, a: Vec3, b: Vec3): Vec3,
    ceil(out: Vec3, a: Vec3): Vec3,
    floor(out: Vec3, a: Vec3): Vec3,
    min(out: Vec3, a: Vec3, b: Vec3): Vec3,
    max(out: Vec3, a: Vec3, b: Vec3): Vec3,
    round(out: Vec3, a: Vec3): Vec3,
    scale(out: Vec3, a: Vec3, b: number): Vec3,
    scaleAndAdd(out: Vec3, a: Vec3, b: Vec3, scale: number): Vec3,
    distance(a: Vec3, b: Vec3): number,
    dist(a: Vec3, b: Vec3): number,
    squaredDistance(a: Vec3, b: Vec3): number,
    sqrDist(a: Vec3, b: Vec3): number,
    length(a: Vec3): number,
    len(a: Vec3): number,
    squaredLength(a: Vec3): number,
    sqrLen(a: Vec3): number,
    negate(out: Vec3, a: Vec3): Vec3,
    inverse(out: Vec3, a: Vec3): Vec3,
    normalize(out: Vec3, a: Vec3): Vec3,
    dot(a: Vec3, b: Vec3): number,
    cross(out: Vec3, a: Vec3, b: Vec3): Vec3,
    lerp(out: Vec3, a: Vec3, b: Vec3, t: number): Vec3,
    hermite(out: Vec3, a: Vec3, b: Vec3, c: Vec3, d: Vec3, t: number): Vec3,
    bezier(out: Vec3, a: Vec3, b: Vec3, c: Vec3, d: Vec3, t: number): Vec3,
    random(out: Vec3, scale?: number): Vec3,
    transformMat4(out: Vec3, a: Vec3, m: Mat4): Vec3,
    transformMat3(out: Vec3, a: Vec3, m: Mat4): Vec3,
    transformQuat(out: Vec3, a: Vec3, q: Quat): Vec3,
    rotateX(out: Vec3, a: Vec3, b: Vec3, c: number): Vec3,
    rotateY(out: Vec3, a: Vec3, b: Vec3, c: number): Vec3,
    rotateZ(out: Vec3, a: Vec3, b: Vec3, c: number): Vec3,
    forEach<T, U>(
      arr: Array<Vec3>,
      stride: number,
      offset: number,
      count: number,
      fn: (a: Vec3, arg: T) => U,
      arg: T
    ): Array<U>,
    angle(a: Vec3, b: Vec3): number,
    str(a: Vec3): string,
    exactEquals(a: Vec3, b: Vec3): boolean,
    equals(a: Vec3, b: Vec3): boolean
  };

  declare var vec4: {
    create(): Vec4,
    clone(a: Vec4): Vec4,
    fromValues(x: number, y: number, z: number, w: number): Vec4,
    copy(out: Vec4, a: Vec4): Vec4,
    set(out: Vec4, x: number, y: number, z: number, w: number): Vec4,
    add(out: Vec4, a: Vec4, b: Vec4): Vec4,
    subtract(out: Vec4, a: Vec4, b: Vec4): Vec4,
    sub(out: Vec4, a: Vec4, b: Vec4): Vec4,
    multiply(out: Vec4, a: Vec4, b: Vec4): Vec4,
    mul(out: Vec4, a: Vec4, b: Vec4): Vec4,
    divide(out: Vec4, a: Vec4, b: Vec4): Vec4,
    div(out: Vec4, a: Vec4, b: Vec4): Vec4,
    ceil(out: Vec4, a: Vec4): Vec4,
    floor(out: Vec4, a: Vec4): Vec4,
    min(out: Vec4, a: Vec4, b: Vec4): Vec4,
    max(out: Vec4, a: Vec4, b: Vec4): Vec4,
    round(out: Vec4, a: Vec4): Vec4,
    scale(out: Vec4, a: Vec4, b: number): Vec4,
    scaleAndAdd(out: Vec4, a: Vec4, b: Vec4, scale: number): Vec4,
    distance(a: Vec4, b: Vec4): number,
    dist(a: Vec4, b: Vec4): number,
    squaredDistance(a: Vec4, b: Vec4): number,
    sqrDist(a: Vec4, b: Vec4): number,
    length(a: Vec4): number,
    len(a: Vec4): number,
    squaredLength(a: Vec4): number,
    sqrLen(a: Vec4): number,
    negate(out: Vec4, a: Vec4): Vec4,
    inverse(out: Vec4, a: Vec4): Vec4,
    normalize(out: Vec4, a: Vec4): Vec4,
    dot(a: Vec4, b: Vec4): number,
    lerp(out: Vec4, a: Vec4, b: Vec4, t: number): Vec4,
    random(out: Vec4, scale?: number): Vec4,
    transformMat4(out: Vec4, a: Vec4, m: Mat4): Vec4,
    transformQuat(out: Vec4, a: Vec4, q: Quat): Vec4,
    str(a: Vec4): string,
    exactEquals(a: Vec4, b: Vec4): boolean,
    equals(a: Vec4, b: Vec4): boolean
  };

  declare var quat: {
    create(): Quat,
    rotationTo(out: Quat, a: Vec3, b: Vec3): Quat,
    setAxes(out: Quat, view: Vec3, right: Vec3, up: Vec3): Quat,
    clone(a: Quat): Quat,
    fromValues(x: number, y: number, z: number, w: number): Quat,
    copy(out: Quat, a: Quat): Quat,
    set(out: Quat, x: number, y: number, z: number, w: number): Quat,
    identity(out: Quat): Quat,
    setAxisAngle(out: Quat, axis: Vec3, rad: number): Quat,
    getAxisAngle(out_axis: Vec3, q: Quat): number,
    add(out: Quat, a: Quat, b: Quat): Quat,
    multiply(out: Quat, a: Quat, b: Quat): Quat,
    mul(out: Quat, a: Quat, b: Quat): Quat,
    scale(out: Quat, a: Quat, b: number): Quat,
    rotateX(out: Quat, a: Quat, rad: number): Quat,
    rotateY(out: Quat, a: Quat, rad: number): Quat,
    rotateZ(out: Quat, a: Quat, rad: number): Quat,
    calculateW(out: Quat, a: Quat): Quat,
    dot(a: Quat, b: Quat): number,
    lerp(out: Quat, a: Quat, b: Quat, t: number): Quat,
    slerp(out: Quat, a: Quat, b: Quat, t: number): Quat,
    sqlerp(out: Quat, a: Quat, b: Quat, d: Quat, d: Quat, t: number): Quat,
    invert(out: Quat, a: Quat): Quat,
    conjugate(out: Quat, a: Quat): Quat,
    length(a: Quat): number,
    len(a: Quat): number,
    squaredLength(a: Quat): number,
    sqrLen(a: Quat): number,
    normalize(out: Quat, a: Quat): Quat,
    fromMat3(out: Quat, m: Mat3): Quat,
    str(a: Quat): string,
    exactEquals(a: Quat, b: Quat): boolean,
    equals(a: Quat, b: Quat): boolean
  };

  declare var mat2: {
    create(): Mat2,
    clone(a: Mat2): Mat2,
    copy(out: Mat2, a: Mat2): Mat2,
    identity(out: Mat2): Mat2,
    fromValues(m00: number, m01: number, m10: number, m11: number): Mat2,
    set(out: Mat2, m00: number, m01: number, m10: number, m11: number): Mat2,
    transpose(out: Mat2, a: Mat2): Mat2,
    invert(out: Mat2, a: Mat2): Mat2,
    adjoint(out: Mat2, a: Mat2): Mat2,
    determinant(a: Mat2): number,
    multiply(out: Mat2, a: Mat2, b: Mat2): Mat2,
    mul(out: Mat2, a: Mat2, b: Mat2): Mat2,
    rotate(out: Mat2, a: Mat2, rad: number): Mat2,
    scale(out: Mat2, a: Mat2, v: Vec2): Mat2,
    fromRotation(out: Mat2, rad: number): Mat2,
    fromScaling(out: Mat2, v: Vec2): Mat2,
    str(a: Mat2): string,
    frob(a: Mat2): number,
    LDU(L: Mat2, D: Mat2, U: Mat2, a: Mat2): [Mat2, Mat2, Mat2],
    add(out: Mat2, a: Mat2, b: Mat2): Mat2,
    subtract(out: Mat2, a: Mat2, b: Mat2): Mat2,
    sub(out: Mat2, a: Mat2, b: Mat2): Mat2,
    exactEquals(a: Mat2, b: Mat2): boolean,
    equals(a: Mat2, b: Mat2): boolean,
    multiplyScalar(out: Mat2, a: Mat2, b: number): Mat2,
    multiplyScalarAndAdd(out: Mat2, a: Mat2, b: Mat2, scale: number): Mat2
  };

  declare var mat2d: {
    create(): Mat2d,
    clone(a: Mat2d): Mat2d,
    copy(out: Mat2d, a: Mat2d): Mat2d,
    identity(out: Mat2d): Mat2d,
    fromValues(
      a: number,
      b: number,
      c: number,
      d: number,
      tx: number,
      ty: number
    ): Mat2d,
    set(
      out: Mat2d,
      a: number,
      b: number,
      c: number,
      d: number,
      tx: number,
      ty: number
    ): Mat2d,
    invert(out: Mat2d, a: Mat2d): Mat2d,
    determinant(a: Mat2d): number,
    multiply(out: Mat2d, a: Mat2d, b: Mat2d): Mat2d,
    mul(out: Mat2d, a: Mat2d, b: Mat2d): Mat2d,
    rotate(out: Mat2d, a: Mat2d, rad: number): Mat2d,
    scale(out: Mat2d, a: Mat2d, v: Vec2): Mat2d,
    translate(out: Mat2d, a: Mat2d, v: Vec2): Mat2d,
    fromRotation(out: Mat2d, rad: number): Mat2d,
    fromScaling(out: Mat2d, v: Vec2): Mat2d,
    fromTranslation(out: Mat2d, v: Vec2): Mat2d,
    str(a: Mat2d): string,
    frob(a: Mat2d): number,
    add(out: Mat2d, a: Mat2d, b: Mat2d): Mat2d,
    subtract(out: Mat2d, a: Mat2d, b: Mat2d): Mat2d,
    sub(out: Mat2d, a: Mat2d, b: Mat2d): Mat2d,
    multiplyScalar(out: Mat2d, a: Mat2d, b: number): Mat2d,
    multiplyScalarAndAdd(out: Mat2d, a: Mat2d, b: Mat2d, scale: number): Mat2d,
    exactEquals(a: Mat2d, b: Mat2d): boolean,
    equals(a: Mat2d, b: Mat2d): boolean
  };

  declare var mat3: {
    create(): Mat3,
    fromMat4(out: Mat3, a: Mat4): Mat3,
    clone(a: Mat3): Mat3,
    copy(out: Mat3, a: Mat3): Mat3,
    fromValues(
      m00: number,
      m01: number,
      m02: number,
      m10: number,
      m11: number,
      m12: number,
      m20: number,
      m21: number,
      m22: number
    ): Mat3,
    set(
      out: Mat3,
      m00: number,
      m01: number,
      m02: number,
      m10: number,
      m11: number,
      m12: number,
      m20: number,
      m21: number,
      m22: number
    ): Mat3,
    identity(out: Mat3): Mat3,
    transpose(out: Mat3, a: Mat3): Mat3,
    invert(out: Mat3, a: Mat3): Mat3,
    adjoint(out: Mat3, a: Mat3): Mat3,
    determinant(a: Mat3): number,
    multiply(out: Mat3, a: Mat3, b: Mat3): Mat3,
    mul(out: Mat3, a: Mat3, b: Mat3): Mat3,
    translate(out: Mat3, a: Mat3, v: Vec2): Mat3,
    rotate(out: Mat3, a: Mat3, rad: number): Mat3,
    scale(out: Mat3, a: Mat3, v: Vec2): Mat3,
    fromTranslation(out: Mat3, v: Vec2): Mat3,
    fromRotation(out: Mat3, rad: number): Mat3,
    fromScaling(out: Mat3, v: Vec2): Mat3,
    fromMat2d(out: Mat3, a: Mat2d): Mat3,
    fromQuat(out: Mat3, q: Quat): Mat3,
    normalFromMat4(out: Mat3, a: Mat4): Mat3,
    str(a: Mat3): string,
    frob(a: Mat3): number,
    add(out: Mat3, a: Mat3, b: Mat3): Mat3,
    subtract(out: Mat3, a: Mat3, b: Mat3): Mat3,
    sub(out: Mat3, a: Mat3, b: Mat3): Mat3,
    multiplyScalar(out: Mat3, a: Mat3, b: number): Mat3,
    multiplyScalarAndAdd(out: Mat3, a: Mat3, b: Mat3, scale: number): Mat3,
    exactEquals(a: Mat3, b: Mat3): boolean,
    equals(a: Mat3, b: Mat3): boolean
  };

  declare var mat4: {
    create(): Mat4,
    clone(a: Mat4): Mat4,
    copy(out: Mat4, a: Mat4): Mat4,
    fromValues(
      m00: number,
      m01: number,
      m02: number,
      m03: number,
      m10: number,
      m11: number,
      m12: number,
      m13: number,
      m20: number,
      m21: number,
      m22: number,
      m23: number,
      m30: number,
      m31: number,
      m32: number,
      m33: number
    ): Mat4,
    set(
      out: Mat4,
      m00: number,
      m01: number,
      m02: number,
      m03: number,
      m10: number,
      m11: number,
      m12: number,
      m13: number,
      m20: number,
      m21: number,
      m22: number,
      m23: number,
      m30: number,
      m31: number,
      m32: number,
      m33: number
    ): Mat4,
    identity(out: Mat4): Mat4,
    determinant(a: Mat4): number,
    rotate(out: Mat4, a: Mat4, rad: number, axis: Vec3): Mat4,
    fromTranslation(out: Mat4, v: Vec3): Mat4,
    fromScaling(out: Mat4, v: Vec3): Mat4,
    fromRotation(out: Mat4, rad: number, axis: Vec3): Mat4,
    fromXRotation(out: Mat4, rad: number): Mat4,
    fromYRotation(out: Mat4, rad: number): Mat4,
    fromZRotation(out: Mat4, rad: number): Mat4,
    fromRotationTranslation(out: Mat4, q: Quat, v: Vec3): Mat4,
    getTranslation(out: Vec3, mat: Mat4): Vec3,
    getScaling(out: Vec3, mat: Mat4): Vec3,
    getRotation(out: Quat, mat: Mat4): Quat,
    fromRotationTranslationScale(out: Mat4, q: Quat, v: Vec3, s: Vec3): Mat4,
    fromRotationTranslationScaleOrigin(
      out: Mat4,
      q: Quat,
      v: Vec3,
      s: Vec3,
      o: Vec3
    ): Mat4,
    fromQuat(out: Mat4, q: Quat): Mat4,
    frustum(
      out: Mat4,
      left: number,
      right: number,
      bottom: number,
      top: number,
      near: number,
      far: number
    ): Mat4,
    perspective(
      out: Mat4,
      fovy: number,
      aspect: number,
      near: number,
      far: number
    ): Mat4,
    perspectiveFromFieldOfView(
      out: Mat4,
      fov: {
        upDegrees: number,
        downDegrees: number,
        leftDegrees: number,
        rightDegrees: number
      },
      near: number,
      far: number
    ): Mat4,
    ortho(
      out: Mat4,
      left: number,
      right: number,
      bottom: number,
      top: number,
      near: number,
      far: number
    ): Mat4,
    lookAt(out: Mat4, eye: Vec3, center: Vec3, up: Vec3): Mat4,
    str(a: Mat4): string,
    frob(a: Mat4): number,
    add(out: Mat4, a: Mat4, b: Mat4): Mat4,
    subtract(out: Mat4, a: Mat4, b: Mat4): Mat4,
    sub(out: Mat4, a: Mat4, b: Mat4): Mat4,
    mul(out: Mat4, a: Mat4, b: Mat4): Mat4,
    multiplyScalar(out: Mat4, a: Mat4, b: number): Mat4,
    multiplyScalarAndAdd(out: Mat4, a: Mat4, b: Mat4, scale: number): Mat4,
    exactEquals(a: Mat4, b: Mat4): boolean,
    equals(a: Mat4, b: Mat4): boolean,

    transpose(out: Mat4, a: Mat4): Mat4,
    invert(out: Mat4, a: Mat4): Mat4,
    adjoint(out: Mat4, a: Mat4): Mat4,
    multiply(out: Mat4, a: Mat4, b: Mat4): Mat4,
    translate(out: Mat4, a: Mat4, v: Vec3): Mat4,
    scale(out: Mat4, a: Mat4, v: Vec3): Mat4,
    rotateX(out: Mat4, a: Mat4, rad: number): Mat4,
    rotateY(out: Mat4, a: Mat4, rad: number): Mat4,
    rotateZ(out: Mat4, a: Mat4, rad: number): Mat4,

    SIMD: {
      transpose(out: Mat4, a: Mat4): Mat4,
      invert(out: Mat4, a: Mat4): Mat4,
      adjoint(out: Mat4, a: Mat4): Mat4,
      multiply(out: Mat4, a: Mat4, b: Mat4): Mat4,
      translate(out: Mat4, a: Mat4, v: Vec3): Mat4,
      scale(out: Mat4, a: Mat4, v: Vec3): Mat4,
      rotateX(out: Mat4, a: Mat4, rad: number): Mat4,
      rotateY(out: Mat4, a: Mat4, rad: number): Mat4,
      rotateZ(out: Mat4, a: Mat4, rad: number): Mat4
    },

    scalar: {
      transpose(out: Mat4, a: Mat4): Mat4,
      invert(out: Mat4, a: Mat4): Mat4,
      adjoint(out: Mat4, a: Mat4): Mat4,
      multiply(out: Mat4, a: Mat4, b: Mat4): Mat4,
      translate(out: Mat4, a: Mat4, v: Vec3): Mat4,
      scale(out: Mat4, a: Mat4, v: Vec3): Mat4,
      rotateX(out: Mat4, a: Mat4, rad: number): Mat4,
      rotateY(out: Mat4, a: Mat4, rad: number): Mat4,
      rotateZ(out: Mat4, a: Mat4, rad: number): Mat4
    }
  };
}
