function createFramebufferInfo(gl, attachments, width, height) {
  var target = FRAMEBUFFER;
  var fb = gl.createFramebuffer();
  gl.bindFramebuffer(target, fb);
  width = width || gl.drawingBufferWidth;
  height = height || gl.drawingBufferHeight;
  attachments = attachments || defaultAttachments;
  var colorAttachmentCount = 0;
  var framebufferInfo = {
    framebuffer: fb,
    attachments: [],
    width: width,
    height: height
  };
  attachments.forEach(function (attachmentOptions) {
    var attachment = attachmentOptions.attachment;
    var format = attachmentOptions.format;
    var attachmentPoint = getAttachmentPointForFormat(format);

    if (!attachmentPoint) {
      attachmentPoint = COLOR_ATTACHMENT0 + colorAttachmentCount++;
    }

    if (!attachment) {
      if (isRenderbufferFormat(format)) {
        attachment = gl.createRenderbuffer();
        gl.bindRenderbuffer(RENDERBUFFER, attachment);
        gl.renderbufferStorage(RENDERBUFFER, format, width, height);
      } else {
        var textureOptions = Object.assign({}, attachmentOptions);
        textureOptions.width = width;
        textureOptions.height = height;

        if (textureOptions.auto === undefined) {
          textureOptions.auto = false;
          textureOptions.min = textureOptions.min || textureOptions.minMag || LINEAR;
          textureOptions.mag = textureOptions.mag || textureOptions.minMag || LINEAR;
          textureOptions.wrapS = textureOptions.wrapS || textureOptions.wrap || CLAMP_TO_EDGE;
          textureOptions.wrapT = textureOptions.wrapT || textureOptions.wrap || CLAMP_TO_EDGE;
        }

        attachment = textures.createTexture(gl, textureOptions);
      }
    }

    if (helper.isRenderbuffer(gl, attachment)) {
      gl.framebufferRenderbuffer(target, attachmentPoint, RENDERBUFFER, attachment);
    } else if (helper.isTexture(gl, attachment)) {
      if (attachmentOptions.layer !== undefined) {
        gl.framebufferTextureLayer(target, attachmentPoint, attachment, attachmentOptions.level || 0, attachmentOptions.layer);
      } else {
        gl.framebufferTexture2D(target, attachmentPoint, attachmentOptions.texTarget || TEXTURE_2D, attachment, attachmentOptions.level || 0);
      }
    } else {
      throw new Error('unknown attachment type');
    }

    framebufferInfo.attachments.push(attachment);
  });
  return framebufferInfo;
}
Creates a framebuffer and attachments.

This returns a {@link module:twgl.FramebufferInfo} because it needs to return the attachments as well as the framebuffer.

The simplest usage

    // create an RGBA/UNSIGNED_BYTE texture and DEPTH_STENCIL renderbuffer
    const fbi = twgl.createFramebufferInfo(gl);

More complex usage

    // create an RGB565 renderbuffer and a STENCIL_INDEX8 renderbuffer
    const attachments = [
      { format: RGB565, mag: NEAREST },
      { format: STENCIL_INDEX8 },
    ]
    const fbi = twgl.createFramebufferInfo(gl, attachments);

Passing in a specific size

    const width = 256;
    const height = 256;
    const fbi = twgl.createFramebufferInfo(gl, attachments, width, height);

**Note!!** It is up to you to check if the framebuffer is renderable by calling `gl.checkFramebufferStatus`.
[WebGL1 only guarantees 3 combinations of attachments work](https://www.khronos.org/registry/webgl/specs/latest/1.0/#6.6).

@param {WebGLRenderingContext} gl the WebGLRenderingContext
@param {module:twgl.AttachmentOptions[]} [attachments] which attachments to create. If not provided the default is a framebuffer with an
   `RGBA`, `UNSIGNED_BYTE` texture `COLOR_ATTACHMENT0` and a `DEPTH_STENCIL` renderbuffer `DEPTH_STENCIL_ATTACHMENT`.
@param {number} [width] the width for the attachments. Default = size of drawingBuffer
@param {number} [height] the height for the attachments. Default = size of drawingBuffer
@return {module:twgl.FramebufferInfo} the framebuffer and attachments.
@memberOf module:twgl/framebuffers