code: function Renderer(opts) {
    this.entities = []
    this.root = this.entity()
  
    // check if we passed gl context or options object
    opts = opts.texture2D ? { ctx: opts } : opts
  
    const ctx = (this._ctx = opts.ctx)
  
    const gl = opts.ctx.gl
    gl.getExtension('OES_standard_derivatives')
  
    this._dummyTexture2D = ctx.texture2D({ width: 4, height: 4 })
    this._dummyTextureCube = ctx.textureCube({ width: 4, height: 4 })
  
    this._debug = false
    this._programCacheMap = {
      values: [],
      getValue: function(flags, vert, frag) {
        for (var i = 0; i < this.values.length; i++) {
          var v = this.values[i]
          if (v.frag === frag && v.vert === vert) {
            if (v.flags.length === flags.length) {
              var found = true
              for (var j = 0; j < flags.length; j++) {
                if (v.flags[j] !== flags[j]) {
                  found = false
                  break
                }
              }
              if (found) {
                return v.program
              }
            }
          }
        }
        return false
      },
      setValue: function(flags, vert, frag, program) {
        this.values.push({ flags, vert, frag, program })
      }
    }
  
    if (opts.profile) {
      State.profiler = createProfiler(opts.ctx, this)
      State.profiler.flush = opts.profileFlush
    }
  
    if (opts.pauseOnBlur && isBrowser) {
      window.addEventListener('focus', () => {
        State.paused = false
      })
      window.addEventListener('blur', () => {
        State.paused = true
      })
    }
  
    // TODO: move from State object to internal probs and renderer({ opts }) setter?
    Object.assign(State, opts)
    this._state = State
  
    this.shaders = {
      chunks: SHADERS_CHUNKS,
      pipeline: {
        material: {
          vert: PBR_VERT,
          frag: PBR_FRAG
        }
      }
    }
  }
docs: opts = Context opts = { ctx: Context, width: Number, height: Number, profile: Boolean }