The Mapbox SDK includes a camera system for navigating the map with mouse and touch input. There are two camera modes, each suited to different use cases.
The camera moves through 3D space while the map stays in place. Best for:
- 3D city exploration
- Games and simulations
- Scenes where the camera needs to orbit around a point of interest
The camera orbits a target point on the map. Panning moves the camera, zooming adjusts how far the camera is from the ground, and rotation orbits around the target.
The camera stays in a fixed position while the map moves underneath. Best for:
- Traditional 2D map interfaces
- Navigation and routing views
- Data visualization overlays
- AR/VR applications where the camera is controlled by head tracking
Panning shifts the map's geographic center. Zooming changes the map's scale level. The camera itself doesn't move — the world moves under it.
- Your scene needs a MapboxMapBehaviour on a GameObject (this is the map itself).
- Add a camera behaviour component to any GameObject in the scene:
- Moving3dCameraBehaviour for 3D camera, or
- SlippyMapCameraBehaviour for slippy map camera
- Assign the Map Behaviour field to the GameObject that has MapboxMapBehaviour.
- Assign the Camera field to the scene camera used for rendering. If left empty, the main camera is used automatically.
The camera will initialize itself once the map is ready. No additional setup is required.
| Setting | Description |
|---|---|
| Pitch | Camera tilt angle. 90 = looking straight down, 15 = near the horizon. |
| Bearing | Camera rotation in degrees. 0 = north is up. |
| Camera Curve | An animation curve that controls how camera height changes with zoom level. The X axis is zoom, Y axis is distance from the ground. |
| Distance Scale | Multiplier on the camera curve output. Increase to raise the camera without re-editing the curve. Default: 2. |
| Zoom Sensitivity | How much each scroll step changes the zoom level. Default: 0.25. |
| Rotation Speed | How fast right-click drag rotates the camera. Default: 50. |
| Setting | Description |
|---|---|
| Center Latitude Longitude | Initial map center as a geographic coordinate. Example: 40.7128, -74.0060 for New York. |
| Pitch | Camera tilt angle. 90 = looking straight down, 15 = near the horizon. |
| Bearing | Camera rotation in degrees. 0 = north is up. |
| Camera Distance | How far the camera is from the ground target. Typical range: 100 to 1000 depending on your map's scale. Default: 200. |
| Pan Enabled | Toggle left-click / single-finger drag to pan the map. |
Rotation Settings (nested):
| Setting | Description |
|---|---|
| Enabled | Toggle right-click drag to rotate. |
| Speed | Rotation sensitivity. Default: 50. |
| Rotation Mode | Rotate The Camera orbits the camera around the map. Rotate The Map keeps the camera fixed and rotates the map underneath — useful for navigation-style views. |
| Map Root | The root transform of the map. Auto-detected if left empty. |
Zoom Settings (nested):
| Setting | Description |
|---|---|
| Enabled | Toggle scroll wheel / pinch zoom. |
| Speed | Zoom sensitivity per step. Default: 0.25. |
| Zoom At Cursor | When enabled, the map zooms toward the cursor or pinch position. When disabled, zoom is always centered on the map. |
Both cameras support mouse and touch input. The controls are:
| Action | Mouse | Touch |
|---|---|---|
| Pan | Left-click drag | Single-finger drag |
| Rotate | Right-click drag | Not available via touch |
| Zoom | Scroll wheel | Two-finger pinch |
| Tilt | Not available via mouse | Two-finger vertical drag |
When using two fingers, the system automatically detects whether you are pinching (zoom) or dragging vertically (tilt) and applies the dominant gesture. Both gestures will not activate at the same time.
Zoom at cursor works with both mouse and touch — when using pinch, the zoom centers on the midpoint between your two fingers.
The cameras work with both Unity's legacy Input Manager and the new Input System package. The active path is selected at compile time:
- Default (no Input System package installed) — uses the legacy
UnityEngine.InputAPI. No action needed. - With
com.unity.inputsysteminstalled — the example asmdef declares aversionDefinesentry that automatically definesMAPBOX_NEW_INPUT_SYSTEM. The new-input branch activates and reads pointer state viaMouse.current/Touch.activeTouches.
The Input System package is not a hard dependency of the SDK — projects that don't install it keep the legacy path with no extra setup. Projects that set Active Input Handling to "Input System Package (New)" only must install the package; otherwise UnityEngine.Input is unavailable at runtime.
If neither camera mode fits your needs, you can create your own by writing a class that extends MapInput and a MonoBehaviour that extends MapCameraBehaviour<T>.
Your custom camera class needs to implement one method — UpdateCamera — where you handle input and return camera state (center, zoom, pitch, bearing, scale). The base class provides ready-made helpers for input detection, coordinate conversion, and value clamping.
The behaviour wrapper handles initialization and communicating changes to the map automatically. A minimal custom camera behaviour only needs a few lines of code beyond the camera logic itself.
As of v3.1.0, the SDK supports parenting the map under an external transform — an ARAnchor, an XR rig, or any rotated/translated parent — and having the entire map (terrain tiles, buildings, roads, areas) compose correctly with that parent transform. This makes it possible to place the map on a real-world surface in AR, anchor it to a tracked plane, or rotate the whole map as a unit.
- Translating
MapRootin world space — the whole map moves as a unit. - Rotating
MapRootaround any axis — terrain and vector content follow. - Parenting
MapRootunder anARAnchor, anXROriginchild, or any custom rig — the parent's translation and rotation propagate.
All of this works because tile placement and vector-content placement are done in local space relative to MapRoot, and runtime-created roots use SetParent(parent, worldPositionStays: false) so they don't pin themselves to world coordinates.
-
Non-unit
MapRoot.localScale. The quadtree LOD math (UnityTileProvider.ShouldSplit) reads the camera's world-space position and compares against tile bounds derived fromMapInformation.Scale. ScalingMapRootdoesn't propagate to that math, so the LOD will pick zoom levels appropriate for the unscaled tile size, not the visible one.Use
MapInformation.Scaleto drive map size instead. AScaleof 1000 means each Web Mercator unit is rendered as 1000 Unity units. For a tabletop-size diorama, setScaleto a small value (e.g. 0.01) — the LOD math will follow. For an animated tabletop → world-size transition, theDynamicScalingMapInformationclass drivesScalefrom an animation curve indexed by zoom.
For AR/MR apps you generally want:
-
Replace the built-in camera behaviours.
SlippyMapCameraBehaviourandMoving3dCameraBehaviourboth write directly toCamera.transformevery frame (and in Rotate The Map mode,SlippyMapCamerawrites toMapRoot.rotation). In an AR/MR setup ARKit/ARCore is already driving the camera transform; you don't want the SDK fighting it. Remove these components from the scene. -
Write a thin custom
MapCameraBehaviour<T>that does the inverse: instead of moving the camera based on input, it reads the AR-tracked camera's pose and pushes the relevant state intoMapboxMap.ChangeView(...). You typically only need to pushCenter(lat/lon) andScale— pitch and bearing can stay at their initial values since the AR camera handles its own orientation. -
Let the quadtree LOD see the AR camera.
UnityTileProvider.Settings.Cameracan be set explicitly via theUnityTileProviderBehaviourinspector. Point it at your AR camera. The tile cover will frustum-cull against the AR camera's actual view. -
Animate scale, not transform. For a "diorama grows to world size" effect, lerp
MapInformation.Scaleover time. The visualizer reacts toWorldScaleChangedand re-lays-out tiles without re-fetching as long as zoom is held constant. Pre-warm the cache for the destination zoom range if you cross zoom boundaries during the animation.
This is the first release with AR-style parent transforms supported architecturally. It hasn't been validated against a full ARKit / ARCore sample, and it has not been profiled on AR-class devices. Treat it as early access: the bones are in place, but expect to do your own integration work and report rough edges.