docs: function setupGui(cameras) {
    const gui = new dat.GUI({width: 300});
  
    gui.add(guiState, 'camera', toCameraOptions(cameras))
        .onChange(async function(cameraLabel) {
          state.changingCamera = true;
  
          await loadVideo(cameraLabel);
  
          state.changingCamera = false;
        });
  
    gui.add(guiState, 'flipHorizontal');
  
    // Architecture: there are a few BodyPix models varying in size and
    // accuracy. 1.00 is the largest, but will be the slowest. 0.25 is the
    // fastest, but least accurate.
    gui.add(
           guiState.input, 'mobileNetArchitecture',
           ['1.00', '0.75', '0.50', '0.25'])
        .onChange(async function(architecture) {
          state.changingArchitecture = true;
          // Important to purge variables and free
          // up GPU memory
          state.net.dispose();
  
          // Load the PoseNet model weights for
          // either the 0.50, 0.75, 1.00, or 1.01
          // version
          state.net = await bodyPix.load(+architecture);
  
          state.changingArchitecture = false;
        });
  
    // Output stride:  Internally, this parameter affects the height and width
    // of the layers in the neural network. The lower the value of the output
    // stride the higher the accuracy but slower the speed, the higher the value
    // the faster the speed but lower the accuracy.
    gui.add(guiState.input, 'outputStride', [8, 16, 32]);
  
    const estimateController =
        gui.add(guiState, 'estimate', ['segmentation', 'partmap']);
  
    let segmentation = gui.addFolder('Segmentation');
    segmentation.add(guiState.segmentation, 'segmentationThreshold', 0.0, 1.0);
    const segmentationEffectController =
        segmentation.add(guiState.segmentation, 'effect', ['mask', 'bokeh']);
  
    segmentation.open();
  
    let darknessLevel;
    let bokehBlurAmount;
    let edgeBlurAmount;
    let maskBlurAmount;
    let maskBackground;
  
    segmentationEffectController.onChange(function(effectType) {
      if (effectType === 'mask') {
        if (bokehBlurAmount) {
          bokehBlurAmount.remove();
        }
        if (edgeBlurAmount) {
          edgeBlurAmount.remove();
        }
        darknessLevel =
            segmentation.add(guiState.segmentation, 'opacity', 0.0, 1.0);
        maskBlurAmount = segmentation.add(guiState.segmentation, 'maskBlurAmount')
                             .min(0)
                             .max(20)
                             .step(1);
        maskBackground =
            segmentation.add(guiState.segmentation, 'maskBackground');
      } else if (effectType === 'bokeh') {
        if (darknessLevel) {
          darknessLevel.remove();
        }
        if (maskBlurAmount) {
          maskBlurAmount.remove();
        }
        if (maskBackground) {
          maskBackground.remove();
        }
        bokehBlurAmount = segmentation
                              .add(
                                  guiState.segmentation,
                                  'backgroundBlurAmount',
                                  )
                              .min(1)
                              .max(20)
                              .step(1);
        edgeBlurAmount = segmentation.add(guiState.segmentation, 'edgeBlurAmount')
                             .min(0)
                             .max(20)
                             .step(1);
      }
    });
  
    // manually set the effect so that the options are shown.
    segmentationEffectController.setValue(guiState.segmentation.effect);
  
    let partMap = gui.addFolder('Part Map');
    partMap.add(guiState.partMap, 'segmentationThreshold', 0.0, 1.0);
    partMap.add(guiState.partMap, 'applyPixelation');
    partMap.add(guiState.partMap, 'opacity', 0.0, 1.0);
    partMap.add(guiState.partMap, 'colorScale', Object.keys(partColorScales))
        .onChange(colorScale => {
          setShownPartColorScales(colorScale);
        });
    setShownPartColorScales(guiState.partMap.colorScale);
  
    estimateController.onChange(function(estimationType) {
      if (estimationType === 'segmentation') {
        segmentation.open();
        partMap.close();
        document.getElementById('colors').style.display = 'none';
      } else {
        segmentation.close();
        partMap.open();
        document.getElementById('colors').style.display = 'inline-block';
      }
    });
  
    gui.add(guiState, 'showFps').onChange(showFps => {
      if (showFps) {
        document.body.appendChild(stats.dom);
      } else {
        document.body.removeChild(stats.dom);
      }
    })
  }