The Javascript web becomes really slow on Firefox

I have received the following code from codepen (I do not remember the pen anymore). I recently used it for a project and I noticed that it works fine on Chrome, but that is ridiculously slow on Firefox. Is there anything I can do? or is it just how Firefox makes?

https://jsfiddle.net/Lyukg7sr/

HTML:

CSS:

# container {
position: relative;
width: 100%;
height: 480px;
background color: # 000;
}

# container-inner {
position: absolute;
above: 0;
left: 0;
right: 0;
bottom: 0;
}

JS:

(a function () {

var pi = Math.PI;
var pi2 = 2 * Math.PI;

this.Waves = function (owner, options) {
var Waves = this;

Waves.options = extend (options || {}, {
resize: false,
rotation: 45,
waves: 5,
width: 100,
color: [11, 14],
amplitude: 0.5
background: true,
preload: true,
speed: [0.004, 0.008],
debug: false,
fps: false,
});

Waves.waves = [];

Waves.holder = document.querySelector (owner);
Waves.canvas = document.createElement (& # 39; canvas & # 39;);
Waves.ctx = Waves.canvas.getContext (2d & # 39;);
Waves.holder.appendChild (Waves.canvas);

Waves.hue = Waves.options.hue[0];
Waves.hueFw = true;
Waves.stats = new Stats ();

Waves.resize ();
Waves.init (Waves.options.preload);

if (Waves.options.resize)
window.addEventListener (& # 39; resize & # 39 ;, function () {
Waves.resize ();
}, false);

};

Waves.prototype.init = function (preload) {
var Waves = this;
var options = Waves.options;

for (var i = 0; i <options.waves; i ++)
Waves.waves[i] = new wave (waves);

if (precharge) Waves.preload ();
};

Waves.prototype.preload = function () {
var Waves = this;
var options = Waves.options;

for (var i = 0; i <options.waves; i ++) {
Waves.updateColor ();
for (var j = 0; j < options.width; j++) {
        Waves.waves[i].update();
      }
    }
  };

  Waves.prototype.render = function () {
    var Waves = this;
    var ctx = Waves.ctx;
    var options = Waves.options;

    Waves.updateColor();
    Waves.clear();

    if (Waves.options.debug) {
      ctx.beginPath();
      ctx.strokeStyle = '#f00';
      ctx.arc(Waves.centerX, Waves.centerY, Waves.radius, 0, pi2);
      ctx.stroke();
    }

    if (Waves.options.background) {
      Waves.background();
    }

    each(Waves.waves, function (wave, i) {
      wave.update();
      wave.draw();
    });
  };

  Waves.prototype.animate = function () {
    var Waves = this;

    Waves.render();

    if (Waves.options.fps) {
      Waves.stats.log();
      Waves.ctx.font = '12px Arial';
      Waves.ctx.fillStyle = '#fff';
      Waves.ctx.fillText(Waves.stats.fps() + ' FPS', 10, 22);
    }

    window.requestAnimationFrame(Waves.animate.bind(Waves));
  };

  Waves.prototype.clear = function () {
    var Waves = this;
    Waves.ctx.clearRect(0, 0, Waves.width, Waves.height);
  };

  Waves.prototype.background = function () {
    var Waves = this;
    var ctx = Waves.ctx;

    var gradient = Waves.ctx.createLinearGradient(0, 0, 0, Waves.height);
    gradient.addColorStop(0, '#000');
    gradient.addColorStop(1, Waves.color);

    ctx.fillStyle = gradient;
    ctx.fillRect(0, 0, Waves.width, Waves.height);
  };

  Waves.prototype.resize = function () {
    var Waves = this;
    var width = Waves.holder.offsetWidth;
    var height = Waves.holder.offsetHeight;
    Waves.scale = window.devicePixelRatio || 1;
    Waves.width = width * Waves.scale;
    Waves.height = height * Waves.scale;
    Waves.canvas.width = Waves.width;
    Waves.canvas.height = Waves.height;
    Waves.canvas.style.width = width + 'px';
    Waves.canvas.style.height = height + 'px';
    Waves.radius = Math.sqrt(Math.pow(Waves.width, 2) + Math.pow(Waves.height, 2)) / 2;
    Waves.centerX = Waves.width / 2;
    Waves.centerY = Waves.height / 2;
    //Waves.radius /= 2; // REMOVE FOR FULLSREEN
  };

  Waves.prototype.updateColor = function () {
    var Waves = this;

    Waves.hue += (Waves.hueFw) ? 0.01 : -0.01;

    if (Waves.hue > Waves.options.hue[1] && Waves.hueFw) {
Waves.hue = Waves.options.hue[1];
Waves.Waves = false;
} else if (Waves.hue < Waves.options.hue[0] && !Waves.hueFw) {
      Waves.hue = Waves.options.hue[0];
      Waves.Waves = true;
    }

    var a = Math.floor(127 * Math.sin(0.3 * Waves.hue + 0) + 128);
    var b = Math.floor(127 * Math.sin(0.3 * Waves.hue + 2) + 128);
    var c = Math.floor(127 * Math.sin(0.3 * Waves.hue + 4) + 128);

    Waves.color = 'rgba(' + a + ',' + b + ',' + c + ', 0.1)';
  };

  function Wave(Waves) {
    var Wave = this;
    var speed = Waves.options.speed;

    Wave.Waves = Waves;
    Wave.Lines = [];

    Wave.angle = [
      rnd(pi2),
      rnd(pi2),
      rnd(pi2),
      rnd(pi2)
    ];

    Wave.speed = [
      rnd(speed[0], speed[1]) * rnd_sign(),
      rnd(speed[0], speed[1]) * rnd_sign(),
      rnd(speed[0], speed[1]) * rnd_sign(),
      rnd(speed[0], speed[1]) * rnd_sign(),
    ];

    return Wave;
  }

  Wave.prototype.update = function () {
    var Wave = this;
    var Lines = Wave.Lines;
    var color = Wave.Waves.color;

    Lines.push(new Line(Wave, color));

    if (Lines.length > Wave.Waves.options.width) {
Lines.shift ();
}
};

Wave.prototype.draw = function () {
var Wave = this;
var Waves = Wave.Waves;

var ctx = Waves.ctx;
var radius = Waves.radius;
var radius3 = radius / 3;
var x = Waves.centerX;
var y = Waves.centerY;
var rotation = dtr (Waves.options.rotation);
var amplitude = Waves.options.amplitude;
var debug = Waves.options.debug;

var Lines = Wave.Lines;

each (lines, function (line, i) {
if (debug && i> 0) returns;

var angle = line.angle;

var x1 = x - radius * Math.cos (angle[0] * amplitude + rotation);
var y1 = y - radius * Math.sin (angle[0] * amplitude + rotation);
var x2 = x + radius * Math.cos (angle[3] * amplitude + rotation);
var y2 = y + radius * Math.sin (angle[3] * amplitude + rotation);
var cpx1 = x - radius3 * Math.cos (angle[1] * amplitude * 2);
var cpy1 = y - radius3 * Math.sin (angle[1] * amplitude * 2);
var cpx2 = x + radius3 * Math.cos (angle[2] * amplitude * 2);
var cpy2 = y + radius3 * Math.sin (angle[2] * amplitude * 2);

ctx.strokeStyle = (debugging)? & # 39; # fff: line.color;

ctx.beginPath ();
ctx.moveTo (x1, y1);
ctx.bezierCurveTo (cpx1, cpy1, cpx2, cpy2, x2, y2);
ctx.stroke ();

if (debugging) {
ctx.strokeStyle = # fff & # 39 ;;
ctxglobalAlpha = 0.3;

ctx.beginPath ();
ctx.moveTo (x1, y1);
ctx.lineTo (cpx1, cpy1);
ctx.stroke ();
ctx.beginPath ();
ctx.moveTo (x2, y2);
ctx.lineTo (cpx2, cpy2);
ctx.stroke ();

ctx.globalAlpha = 1;
}
});
};

Line function (Wave, color) {
var Line = this;

var angle = Wave.angle;
var speed = Wave.speed;

Line.angle =[
Math.sin (angle[0] + = speed[0])
Math.sin (angle[1] + = speed[1])
Math.sin (angle[2] + = speed[2])
Math.sin (angle[3] + = speed[3])
];

Line.color = color;
}

Statistics function () {
this.data = [];
}

Stats.prototype.time = function () {
return (performance || Date)
.now();
};

Stats.prototype.log = function () {
if (! this.last) {
this.last = this.time ();
returns 0;
}

this.new = this.time ();
this.delta = this.new - this.last;
this.last = this.new;

this.data.push (this.delta);
if (this.data.length> 10)
this.data.shift ();
};

Stats.prototype.fps = function () {
var fps = 0;
each (this.data, function (data, i) {
fps + = data;
});

return Math.round (1000 / (fps / this.data.length));
};

function each (elements, reminder) {
for (var i = 0; i < items.length; i++) {
      callback(items[i], i);
    }
  }

  function extend(options, defaults) {
    for (var key in options)
      if (defaults.hasOwnProperty(key))
        defaults[key] = options[key];
    return defaults;
  }

  function dtr(deg) {
    return deg * pi / 180;
  }

  function rtd(rad) {
    return rad * 180 / pi;
  }

  function diagonal_angle(w, h) {
    var a = Math.atan2(h, w) * 1.27325;
    return a;
  }

  function rnd(a, b) {
    if (arguments.length == 1)
      return Math.random() * a;
    return a + Math.random() * (b - a);
  }

  function rnd_sign() {
    return (Math.random() > 0.5)? 1: -1;
}

}) ();

var waves = new Waves (# container-inner & # 39;
fps: false,
resize: true,
waves: 3,
width: 239,
});

wave.animate ();