text: 'use strict';
  
  module.exports = function(timestamp) {
  	var wasWindowIdled = timestamp - this.previousTimeStamp > 100;
  	var isLoop = this.states[this.activeState].loop !== undefined ? this.states[this.activeState].loop : true;
  	var progressPercent, isLooping, nextGradient;
  
  	// If tab was inactive then resumed, reset the previous timestamp
  	if (this.previousTimeStamp === null || wasWindowIdled) {
  		this.previousTimeStamp = timestamp;
  	}
  
  	// Compute progress and save the timestamp
  	this.progress = this.progress + (timestamp - this.previousTimeStamp);
  	progressPercent = (this.progress / this.activetransitionSpeed * 100).toFixed(2);
  	this.previousTimeStamp = timestamp;
  
  	// Set the new gradient colors in a property
  	this.refreshColorsAndPos(progressPercent);
  
  	// Continue the animation or prepare for the next one
  	if (progressPercent < 100) {
  		this.animation = requestAnimationFrame(this.animateColors.bind(this));
  
  	} else {
  		// if the current animation index is inferior to the penultimate gradient
  		// or to the last gradient with the loop mode activated
  		if (this.channelsIndex < this.states[this.activeState].gradients.length - 2 || isLoop) {
  
  			// Set the active transition speed to the active state one after changing state
  			if (this.isChangingState) {
  				this.activetransitionSpeed = this.states[this.activeState].transitionSpeed || 5000;
  				this.isChangingState = false;
  			}
  
  			// Resetting properties
  			this.previousTimeStamp = null;
  			this.progress = 0;
  			this.channelsIndex++;
  			isLooping = false;
  
  			// If it's going to loop or if it's the transition after the loop
  			if (this.channelsIndex === this.states[this.activeState].gradients.length - 1) {
  				isLooping = true;
  				
  			} else if (this.channelsIndex === this.states[this.activeState].gradients.length) {
  				this.channelsIndex = 0;
  			}
  
  			// Checking the next gradient to send in args of an event and a callback
  			nextGradient = this.states[this.activeState].gradients[this.channelsIndex + 1] === undefined ?
  				this.states[this.activeState].gradients[0] :
  				this.states[this.activeState].gradients[this.channelsIndex + 1];
  
  			// Compute the colors for the transition and render a new frame
  			this.setColors();
  			this.animation = requestAnimationFrame(this.animateColors.bind(this));
  			
  			// Callback and Event
  			if (this.callbacks.onGradientChange) {
  				this.callbacks.onGradientChange({
  					isLooping: isLooping,
  					colorsFrom: this.states[this.activeState].gradients[this.channelsIndex],
  					colorsTo: nextGradient,
  					activeState: this.activeState
  				});
  			}
  
  			this.canvas.dispatchEvent(this.events.gradientChange({
  				isLooping: isLooping,
  				colorsFrom: this.states[this.activeState].gradients[this.channelsIndex],
  				colorsTo: nextGradient,
  				activeState: this.activeState
  			}));
  
  		// Else if it was the last gradient on the list and the loop mode is off
  		} else {
  			cancelAnimationFrame(this.animation);
  
  			// Callback and Event
  			if (this.callbacks.onEnd) this.callbacks.onEnd();
  			this.canvas.dispatchEvent(new CustomEvent('granim:end'));
  		}
  	}
  };
  