function mergeFrames(records, options, frameDimensions) {
  return new Promise(function (resolve, reject) {
    // The number of frames
    var framesCount = records.length;
    
    // Track execution time
    var start = Date.now();

    // Used for the step option
    var stepsCounter = 0;

    // Create a progress bar
    var progressBar = getProgressBar(
      "Merging",
      Math.ceil(framesCount / options.step)
    );

    // The gif image
    var gif = new di.GIFEncoder(frameDimensions.width, frameDimensions.height, {
      highWaterMark: 5 * 1024 * 1024,
    });

    // Pipe
    gif.pipe(di.fs.createWriteStream(options.outputFile));

    // Quality
    gif.setQuality(101 - options.quality);

    // Repeat
    gif.setRepeat(options.repeat);

    // Write the headers
    gif.writeHeader();

    di.async.eachOfSeries(
      records,
      function (frame, index, callback) {
        if (stepsCounter != 0) {
          stepsCounter = (stepsCounter + 1) % options.step;
          return callback();
        }

        stepsCounter = (stepsCounter + 1) % options.step;

        // The path of the rendered frame
        var framePath = di.path.join(renderDir, index + ".png");

        // Read and parse the rendered frame
        loadPNG(framePath)
          .then(function (png) {
            progressBar.tick();

            // Set the duration (the delay of the next frame)
            // The % is used to take the delay of the first frame
            // as the duration of the last frame
            gif.setDelay(records[(index + 1) % framesCount].delay);

            // Add frames
            gif.addFrame(png.data);

            // Next
            callback();
          })
          .catch(function (error) {
            callback(error);
          });
      },
      function (error) {
        if (error) {
          return reject(error);
        }

        // Write the footer
        gif.finish();

        // Finish
        console.log(di.chalk.green('[merge] Process successfully completed in ' + (Date.now() - start) + 'ms.'));
        resolve();
      }
    );
  });
}
Merge the rendered frames into an animated GIF image

@param  {Array}   records         [{delay, content}, ...]
@param  {Object}  options         {quality, repeat, step, outputFile}
@param  {Object}  frameDimensions {width, height}
@return {Promise}