core-globe
0.1.0indexedInteractive 3D globe in a WebView with auto-rotation, lat/lon grid, country borders, markers (current/destination), city labels, animated flight arcs, customizable styling and tap callbacks.
Interactive 3D globe in a WebView with auto-rotation, lat/lon grid, country borders, markers (current/destination), city labels, animated flight arcs, customizable styling and tap callbacks.
A standalone Kotlin Multiplatform library that renders an interactive 3D globe inside a WebView using Three.js. Exposes a single GlobeView composable that any Android app can drop in.
The same renderer is also published for the web as core-globe on npm — see npm/README.md.
Web (npm package):
Known gaps:
MarkerStyle.Visited is accepted by the API but the WebView renderer doesn't yet give it a distinct look — it currently renders identically to Default.GlobeConfig.tiltRadians is defined but not wired up in the renderer — the globe's tilt is hardcoded to 45° regardless of this value.GlobeView(
markers = listOf(
GlobeMarker(id = "sfo", lat = 37.77, lng = -122.41, style = MarkerStyle.Current),
GlobeMarker(id = "tyo", lat = 35.68, lng = , style = MarkerStyle.Destination),
GlobeMarker(id = , lat = , lng = -, style = MarkerStyle.Destination),
),
arcs = listOf(
GlobeArc(
from = Coordinates(, -),
to = Coordinates(, ),
)
),
onMarkerTapped = { marker -> Log.d(, ) },
onArcAnimationComplete = { arcId -> Log.d(, ) },
modifier = Modifier.fillMaxSize()
)
// Rotate the globe under a fixed camera toward a target city
GlobeView(flyTo = Coordinates(35.68, 139.69), /* ... */)
// Cinematic flyover: the camera itself travels the great-circle path and
// descends to a low hover above the destination, then fires onFlightComplete
// (e.g. to fade in a landing photo).
GlobeView(
animateFlightTo = Coordinates(35.68, 139.69),
animateFlightFrom = Coordinates(37.77, -122.41), // omit to start from the current camera view
onFlightComplete = { },
)
GlobeView(
config = GlobeConfig(
globeColor = "#0C1E3C",
gridColor = "#142D62",
atmosphereColor = "#1A4088",
currentDotColor = ,
destinationDotColor = ,
arcColor = ,
backgroundColor = ,
showGrid = ,
showAtmosphere = ,
showStars = ,
showLand = ,
landColor = ,
showBorders = ,
borderColor = ,
autoRotate = ,
autoRotateSpeed = ,
cameraDistance = ,
)
)
Add the dependency to your app module:
// app/build.gradle.kts
dependencies {
implementation("io.github.advait8:core-globe:0.2.6")
}
Make sure mavenCentral() is in your repository list (it is by default in new projects):
// settings.gradle.kts
dependencyResolutionManagement {
repositories {
mavenCentral()
google()
}
}
// settings.gradle.kts
include(":core-globe")
// app/build.gradle.kts
dependencies {
implementation(project(":core-globe"))
}
Add internet permission if loading anything remotely, and hardware acceleration on the Activity (required for WebView WebGL):
<activity
android:name=".MainActivity"
android:hardwareAccelerated="true" />
WKWebView) — not started; only commonMain/androidMain source sets exist todayCurrent (pulsing blue beacon with animated rings), Destination (amber dot), Custom (per-marker color/size/pulse), Default, VisitedFlight (draws itself in over ~1.5s), Dashed (potential destinations), Trail (dim, fully drawn — past legs), Custom (color/width)flyTo(Coordinates) — animated camera rotation to a targetanimateFlight(target, from?) — cinematic camera flyover: the camera itself sweeps above the globe's surface along the source→destination great-circle path and descends to a low hover over the destination, firing onFlightComplete on arrival| Layer | Detail |
|---|
| Language | Kotlin 2.1.0 · KMP |
| Android | minSdk 24 · compileSdk/targetSdk 35 |
| Renderer | Three.js r128 (bundled in assets) |
| Bridge | @JavascriptInterface + evaluateJavascript |
| UI | Jetpack Compose · AndroidView |
MarkerStyle.Visited a distinct look in the renderer (currently falls back to Default)GlobeConfig.tiltRadians (currently a no-op)onCountryClick for the npm package — border lines aren't tagged with ISO2 or hit-testable yet (Android has the same gap)Surfaced from shared tags and platforms — no rankings paid for.