mapbox / mapbox/mapbox-maps-android
Flicker of CircleLayer and 3D Model when tilting/rotating camera (Mapbox Android SDK 11.17.0)
Nobody has claimed this yet.
- Dominant language
- Kotlin
- Stars
- 578
- Forks
- 161
- PR merge metrics
- No merged PRs in 30d
Description
## Environment
- Android OS version: 15
- Devices affected: Nothing Phone 2 (also Xiaomi MI 9T on Android 10)
- Maps SDK Version: com.mapbox.maps:android:11.7.0
## Observed behavior and steps to reproduce
When the camera is pitched/tilted or moved quickly the on-screen circle and a 3D glb model briefly flicker. This is reproducible with this code:
```kotlin
package com.example.mapduck
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.example.mapduck.databinding.ActivityMainBinding
import com.mapbox.geojson.Point
import com.mapbox.maps.CameraOptions
import com.mapbox.maps.Style
import com.mapbox.maps.extension.style.expressions.generated.Expression
import com.mapbox.maps.extension.style.layers.generated.circleLayer
import com.mapbox.maps.extension.style.layers.generated.modelLayer
import com.mapbox.maps.extension.style.layers.properties.generated.CirclePitchAlignment
import com.mapbox.maps.extension.style.layers.properties.generated.CirclePitchScale
import com.mapbox.maps.extension.style.layers.properties.generated.CircleTranslateAnchor
import com.mapbox.maps.extension.style.layers.addLayer
import com.mapbox.maps.extension.style.model.addModel
import com.mapbox.maps.extension.style.model.model
import com.mapbox.maps.extension.style.sources.addSource
import com.mapbox.maps.extension.style.sources.generated.geoJsonSource
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private val duckCenter = Point.fromLngLat(8.81645, 45.557)
private val circleCenter = Point.fromLngLat(8.819, 45.559)
private val duckModelId = "duck"
private val duckModelUrl =
"https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0/Duck/glTF-Binary/Duck.glb"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val mapView = binding.mapView
val mapboxMap = mapView.mapboxMap
mapboxMap.setCamera(
CameraOptions.Builder()
.center(duckCenter)
.zoom(17.0)
.pitch(60.0)
.build()
)
mapboxMap.loadStyle(Style.STANDARD) { style ->
addDuckModel(style)
addCircle(style)
}
}
private fun addDuckModel(style: Style) {
// Model source
style.addSource(
geoJsonSource("duck-model-source") {
geometry(duckCenter)
}
)
// Register the remote model asset so the layer can reference it
style.addModel(
model(duckModelId) {
uri(duckModelUrl)
}
)
style.addLayer(
modelLayer("duck-model-layer", "duck-model-source") {
modelId(duckModelId)
modelScale(listOf(50.0, 50.0, 50.0))
modelRotation(listOf(0.0, 0.0, 0.0))
}
)
}
private fun addCircle(style: Style) {
style.addSource(
geoJsonSource("circle-source") {
geometry(circleCenter)
}
)
style.addLayer(
circleLayer("user-location-ring-layer", "circle-source") {
circleRadius(40.0)
circleColor("rgba(30, 136, 229, 0.25)")
circleOpacity(0.7)
circleStrokeWidth(2.0)
circleStrokeColor("rgba(30, 136, 229, 0.5)")
circlePitchAlignment(CirclePitchAlignment.VIEWPORT)
circlePitchScale(CirclePitchScale.VIEWPORT)
circleTranslateAnchor(CircleTranslateAnchor.VIEWPORT)
circleSortKey(9999.0)
}
)
style.addLayer(
circleLayer("user-location-dot-layer", "circle-source") {
circleRadius(6.0)
circleColor("#1E88E5")
circleStrokeWidth(2.0)
circleStrokeColor("#FFFFFF")
circlePitchAlignment(CirclePitchAlignment.VIEWPORT)
circlePitchScale(CirclePitchScale.VIEWPORT)
circleTranslateAnchor(CircleTranslateAnchor.VIEWPORT)
circleSortKey(10000.0)
}
)
}
override fun onStart() {
super.onStart()
binding.mapView.onStart()
}
override fun onStop() {
super.onStop()
binding.mapView.onStop()
}
override fun onLowMemory() {
super.onLowMemory()
binding.mapView.onLowMemory()
}
override fun onDestroy() {
super.onDestroy()
binding.mapView.onDestroy()
}
}
```
This video shows the glitch:
https://github.com/user-attachments/assets/3a2a4467-ce45-40a7-88a7-96bd2e2885bf
## Expected behavior
That flicker should not happen.
## Notes / preliminary analysis
It looks like the flicker happens when "loaded: false":
`12-11 18:36:40.826 341 341 D MapDebug: SourceDataLoaded: [sourceId: composite, type: Tile, loaded: false, tileId: [z: 12, x: 2148, y: 1465], dataId: , timeInterval: [begin: Thu Dec 11 18:36:40 GMT+01:00 2025, end: Thu Dec 11 18:36:40 GMT+01:00 2025]]`
I have no idea why this happens. If this could help, I also tried with rnmapbox in react native and the same behaviour happens. Thank you for your time.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Reproduce the issue with the provided Kotlin MainActivity, using the rapid camera tilt or rotation on the listed Android devices and SDK version. Observe the circle, 3D GLB model, and SourceDataLoaded log during movement; done means the flicker no longer occurs.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- android, kotlin
- Domain
- computer-graphics, mobile-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100