zoomToFit = ({ controls, camera, entities }) => {
  // our camera.fov is already in radian, no need to convert
  const { zoomToFit } = controls
  if (zoomToFit.targets !== 'all') {
    return { controls, camera }
  }

  if (entities.length === 0) return { controls, camera }

  // compute the overall bounds
  const geometries = entities.map((entity) => entity.geometry)
  const bounds = computeBounds(geometries)

  // fixme: for now , we only use the first item
  const { fov, target, position } = camera
  const { tightness } = Object.assign({}, zoomToFit, controlsProps.zoomToFit)
  /*
    - x is scaleForIdealDistance
    - currentDistance is fixed
    - how many times currentDistance * x = idealDistance
    So
    x = idealDistance / currentDistance
  */
  const idealDistanceFromCamera = (bounds.dia * tightness) / Math.tan(fov / 2.0)
  const currentDistance = vec3.distance(target, position)
  const scaleForIdealDistance = idealDistanceFromCamera / currentDistance

  return {
    camera: { target: bounds.center },
    controls: { scale: scaleForIdealDistance }
  }
}
compute camera state to 'fit' an object on screen
Note1: this is a non optimal but fast & easy implementation
@param {Object} controls the controls data/state
@param {Object} camera the camera data/state
@param {Array} entities - an array of entities (see entitiesFromSolids)
@return {Object} the updated camera data/state