`cameraForBounds` accepts `pitch` in its options but ignores it when fitting
User Story
As a developer fitting a route or bounding box on a pitched map, I can pass pitch to cameraForBounds / fitBounds and get a center and zoom that keep the whole box on screen, so that the result does not depend on the map being flat.
Rationale
CameraForBoundsOptions extends CameraOptions, so pitch type-checks today. But cameraForBoxAndBearing only rotates the Mercator corners by bearing and scales the rotated extent into the padded viewport. Pitch never enters the calculation. When the caller then applies the result together with a pitch (fitBounds({..., pitch: 45}), or easeTo with the returned center/zoom plus a pitch), perspective compresses the far edge of the box toward the horizon while the near edge widens and spills out of the sides and bottom of the viewport.
MapLibre Native's cameraForLatLngBounds, cameraForLatLngs, and cameraForGeometry take optional bearing and pitch and account for both in the fit. The two engines therefore return different cameras for the same inputs, which shows up in any wrapper that targets both (MapLibre Compose tracks this in maplibre/maplibre-compose#1399).
Impact
Without this, fitBounds and cameraForBounds silently produce a wrong fit whenever the map is pitched, and the pitch option in CameraForBoundsOptions remains accepted but meaningless. Apps that pitch the camera (navigation, 3D buildings, terrain) have to keep the map flat during the fit or reimplement the fit outside the library.
AI Assistance
Fable 5.1 helped audit the GL JS and MapLibre Native sources and draft this text. I reviewed and edited it.
Source: maplibre/maplibre-gl-js