Module Architecture Overview¶
Introduction¶
MINE (Machinestalk Indoor Navigation Engine) is a production-ready Android SDK built with Jetpack Compose that delivers high-performance indoor navigation experiences. The module architecture follows a layered approach, building upon industry-standard 3D rendering technologies to provide a declarative, customizable navigation system.
-
Layered Architecture
Clean separation between rendering, UI, and business logic for maintainability
-
Compose-First
Built from the ground up for Jetpack Compose with declarative UI patterns
-
Modular Design
Each component is independently testable and replaceable
-
Highly Customizable
Theme every aspect from materials to UI components
Architecture Stack¶
Layered View¶
flowchart TB
subgraph UI["UI Layer (Compose)"]
A[IndoorNavigationScene]
B[FloorPicker]
C[SearchBar]
D[POIOverlays]
end
subgraph Core["Core Navigation Layer"]
E[MapLoader]
F[PathFinder]
G[CameraController]
H[ThemeManager]
end
subgraph Rendering["Rendering Layer"]
I[SceneView Wrapper]
J[Material System]
K[Entity Manager]
end
subgraph Foundation["Foundation Layer"]
L[SceneView Library]
M[Filament Engine]
N[OpenGL/Vulkan]
end
A --> E
B --> G
C --> F
D --> K
E --> I
F --> I
G --> I
H --> J
I --> L
J --> L
K --> L
L --> M
M --> N
style UI fill:#3b82f6,stroke:#2563eb,color:#fff
style Core fill:#8b5cf6,stroke:#7c3aed,color:#fff
style Rendering fill:#06b6d4,stroke:#0891b2,color:#fff
style Foundation fill:#64748b,stroke:#475569,color:#fff
Technology Stack¶
flowchart BT
F[Filament 1.46.0<br/>Physical-Based Renderer] -->|3D Engine| S[SceneView 2.0<br/>3D/AR View Library]
S -->|Compose Integration| M[MINE SDK<br/>Indoor Navigation]
M -->|Declarative UI| A[Your Android App<br/>Jetpack Compose]
style F fill:#e06c75,stroke:#c678dd,color:#fff
style S fill:#61afef,stroke:#56b6c2,color:#fff
style M fill:#98c379,stroke:#10b981,color:#fff
style A fill:#d19a66,stroke:#f59e0b,color:#fff
Core Components¶
1. Foundation Layer: Filament¶
Filament is Google's physically-based rendering (PBR) engine written in C++, providing:
- High Performance: 60+ FPS on mid-range devices
- Mobile Optimized: Small binary size (~2MB), low memory footprint
- PBR Materials: Realistic lighting and surface properties
- Cross-Platform: Consistent rendering across devices
// Filament handles low-level rendering
val engine = Engine.create()
val scene = engine.createScene()
val renderer = engine.createRenderer()
2. Rendering Layer: SceneView¶
SceneView is an open-source 3D/AR view library that wraps Filament, offering:
- Compose Integration: Native support for Jetpack Compose
- AR Capabilities: ARCore integration (optional)
- Scene Management: Simplified entity and node management
- Camera Controls: Built-in gestures for pan, zoom, rotate
// SceneView simplifies Filament usage
Scene(
modifier = Modifier.fillMaxSize(),
engine = engine,
modelLoader = modelLoader,
cameraNode = cameraNode,
onGestureListener = gestureListener
)
3. Core Layer: MINE Navigation¶
MINE builds upon SceneView to provide indoor-specific features:
data class MapBuild(
val floors: List<Floor>,
val pois: List<PointOfInterest>,
val routes: List<Route>,
val metadata: VenueMetadata
)
class MapLoader {
suspend fun loadFromAssets(context: Context, filename: String): MapBuild
suspend fun loadFromUrl(url: String): MapBuild
fun loadFromJson(json: String): MapBuild
}
interface PathFinder {
fun findPath(
start: Position,
end: Position,
preferences: NavigationPreferences = Default
): Path
fun findAccessiblePath(
start: Position,
end: Position
): Path
}
data class Path(
val waypoints: List<Waypoint>,
val distance: Float,
val estimatedTime: Duration,
val floorChanges: List<FloorTransition>
)
class CameraController(private val cameraNode: Node) {
fun animateToFloor(floor: Int, duration: Long = 500)
fun animateToPOI(poi: PointOfInterest, duration: Long = 800)
fun setZoomLevel(level: Float)
fun setBearing(degrees: Float)
fun resetToDefault()
}
sealed class MapTheme {
object Light : MapTheme()
object Dark : MapTheme()
data class Custom(
val floorMaterial: MaterialConfig,
val wallMaterial: MaterialConfig,
val poiColors: Map<PoiType, Color>,
val routeColor: Color
) : MapTheme()
}
4. UI Layer: Compose Components¶
MINE provides composable UI elements:
@Composable
fun IndoorNavigationScene(
mapBuild: MapBuild,
theme: MapTheme = MapTheme.Dark,
cameraConfig: CameraConfig = CameraConfig.Default,
onPOIClick: (PointOfInterest) -> Unit = {},
onFloorChange: (Int) -> Unit = {}
) {
// Renders the 3D map scene
}
@Composable
fun FloorPicker(
floors: List<Floor>,
currentFloor: Int,
onFloorSelected: (Int) -> Unit
) {
// Floor selection UI
}
@Composable
fun POISearchBar(
pois: List<PointOfInterest>,
onPOISelected: (PointOfInterest) -> Unit
) {
// Search functionality
}
Data Flow¶
sequenceDiagram
participant App as Your App
participant UI as MINE UI Layer
participant Core as Core Layer
participant Scene as SceneView
participant Fil as Filament
App->>UI: IndoorNavigationScene(mapBuild)
UI->>Core: MapLoader.load(mapBuild)
Core->>Core: Parse JSON, validate
Core->>Scene: Create entities for floors/POIs
Scene->>Fil: Create renderables
Fil->>Scene: Render frames
Scene->>UI: Display 3D scene
UI->>App: Rendered view
App->>UI: User clicks POI
UI->>Core: PathFinder.findPath(current, target)
Core->>Core: A* algorithm
Core->>Scene: Draw route polyline
Scene->>Fil: Update scene
Fil->>UI: Render with route
Module Dependencies¶
Gradle Configuration¶
dependencies {
// Core MINE SDK
implementation("com.machinestalk:indoornavigationengine:1.0.0")
// Required dependencies (automatically included)
// - SceneView: io.github.sceneview:sceneview:2.0.0
// - Filament: com.google.android.filament:filament-android:1.46.0
// - Compose UI: androidx.compose.ui:ui:1.6.0
// Optional: ARCore support
implementation("com.google.ar:core:1.41.0")
}
Module Structure¶
com.machinestalk.indoornavigationengine
βββ components/ # UI Composables
β βββ IndoorNavigationScene.kt
β βββ FloorPicker.kt
β βββ POISearchBar.kt
β βββ RouteOverlay.kt
βββ models/ # Data classes
β βββ MapBuild.kt
β βββ Floor.kt
β βββ PointOfInterest.kt
β βββ Route.kt
βββ resources/ # Resource management
β βββ MapLoader.kt
β βββ MaterialManager.kt
β βββ TextureCache.kt
βββ ui/ # UI utilities
β βββ ThemeManager.kt
β βββ CameraController.kt
β βββ GestureHandler.kt
βββ util/ # Helpers
βββ JsonUtil.kt
βββ MathUtil.kt
βββ Extensions.kt
Performance Characteristics¶
Memory Footprint¶
| Component | RAM Usage | Notes |
|---|---|---|
| MINE Core | ~8MB | Base SDK without maps |
| SceneView | ~12MB | Includes scene graph |
| Filament Engine | ~15MB | Rendering engine |
| Map Data (5 floors) | ~25MB | Uncompressed JSON + textures |
| GPU Memory | ~120MB | Renderable entities |
| Total | ~180MB | Typical venue |
Initialization Time¶
// Benchmark on Pixel 4a (Android 12)
measureTimeMillis {
val mapBuild = MapLoader.loadFromAssets(context, "venue.json")
// ~280ms
}
measureTimeMillis {
IndoorNavigationScene(mapBuild)
// ~380ms (first render)
}
// Total cold start: ~660ms
// Subsequent renders: <16ms (60 FPS)
Architecture Benefits¶
β Separation of Concerns¶
Each layer has a clear responsibility:
- Filament: Low-level rendering
- SceneView: Scene management & Compose integration
- MINE Core: Indoor navigation logic
- UI Components: User interaction
β Testability¶
Layers can be tested independently:
@Test
fun `PathFinder calculates optimal route`() {
val pathFinder = PathFinder(mockGraph)
val path = pathFinder.findPath(start, end)
assertEquals(5, path.waypoints.size)
assertTrue(path.distance < 100f)
}
β Extensibility¶
Easy to extend without modifying core:
// Custom POI renderer
class CustomPOIRenderer : POIRenderer {
override fun render(poi: PointOfInterest, scene: Scene) {
// Custom rendering logic
}
}
IndoorNavigationScene(
mapBuild = mapBuild,
poiRenderer = CustomPOIRenderer()
)
β Performance¶
Optimized at each layer:
- Filament: GPU-accelerated rendering
- SceneView: Frustum culling, LOD management
- MINE: Cached path calculations, entity pooling
Integration Example¶
Full Implementation¶
@Composable
fun VenueNavigationScreen(venueId: String) {
// State management
var mapBuild by remember { mutableStateOf<MapBuild?>(null) }
var currentFloor by remember { mutableIntStateOf(0) }
var selectedPOI by remember { mutableStateOf<PointOfInterest?>(null) }
// Load map on composition
LaunchedEffect(venueId) {
mapBuild = MapLoader.loadFromAssets(
context = context,
filename = "venues/$venueId.json"
)
}
mapBuild?.let { map ->
Box(modifier = Modifier.fillMaxSize()) {
// Main 3D scene
IndoorNavigationScene(
mapBuild = map,
theme = MapTheme.Dark,
cameraConfig = CameraConfig(
initialFloor = currentFloor,
zoomLevel = 15f
),
onPOIClick = { poi -> selectedPOI = poi },
onFloorChange = { floor -> currentFloor = floor }
)
// Overlay: Floor picker
FloorPicker(
floors = map.floors,
currentFloor = currentFloor,
onFloorSelected = { floor -> currentFloor = floor },
modifier = Modifier
.align(Alignment.CenterEnd)
.padding(16.dp)
)
// Overlay: Search bar
POISearchBar(
pois = map.pois.filter { it.floor == currentFloor },
onPOISelected = { poi -> selectedPOI = poi },
modifier = Modifier
.align(Alignment.TopCenter)
.padding(16.dp)
)
// Overlay: POI details
selectedPOI?.let { poi ->
POIDetailCard(
poi = poi,
onNavigate = { /* Start navigation */ },
onDismiss = { selectedPOI = null },
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(16.dp)
)
}
}
}
}
Comparison with Alternatives¶
| Feature | MINE | Google Maps Indoor | Mapbox | Custom Solution |
|---|---|---|---|---|
| 3D Rendering | β Filament PBR | β 2D tiles | β οΈ Limited 3D | π§ DIY |
| Offline Support | β Full | β οΈ Cached only | β οΈ Cached only | π§ DIY |
| Compose Native | β Yes | β Views only | β Views only | π§ DIY |
| Path Finding | β Built-in | β οΈ Limited | β οΈ API-based | π§ DIY |
| Customization | β Full control | β Limited | β οΈ Style only | β Full |
| Setup Time | β±οΈ <15 min | β±οΈ Hours | β±οΈ Hours | β±οΈ Weeks |
| Cost | π° One-time | π°π° Per-use | π°π° Per-use | π°π°π° Dev time |
Advanced Topics¶
Custom Material System¶
// Extend ThemeManager for venue-specific materials
class VenueMaterialManager(engine: Engine) {
private val carpetMaterial = loadMaterial("carpet.filamat")
private val marbleMaterial = loadMaterial("marble.filamat")
fun applyToZone(zone: Zone): MaterialInstance {
return when (zone.type) {
ZoneType.HALLWAY -> carpetMaterial
ZoneType.LOBBY -> marbleMaterial
else -> defaultMaterial
}
}
}
State Management Integration¶
// With ViewModel
class NavigationViewModel : ViewModel() {
private val _mapState = MutableStateFlow<MapState>(MapState.Loading)
val mapState = _mapState.asStateFlow()
fun loadMap(venueId: String) {
viewModelScope.launch {
_mapState.value = MapState.Loading
val map = mapRepository.fetchMap(venueId)
_mapState.value = MapState.Success(map)
}
}
}
@Composable
fun NavigationScreen(viewModel: NavigationViewModel) {
val mapState by viewModel.mapState.collectAsState()
when (val state = mapState) {
is MapState.Loading -> LoadingIndicator()
is MapState.Success -> IndoorNavigationScene(state.mapBuild)
is MapState.Error -> ErrorView(state.message)
}
}
Resources¶
-
Filament Details
Deep dive into the rendering engine
-
SceneView API
Learn about the 3D scene wrapper
-
Theme System
Customize materials and colors
-
Component Reference
Full API documentation
FAQ¶
Can I use MINE with existing View-based UI?
Yes, while MINE is Compose-first, you can wrap composables in ComposeView:
val composeView = ComposeView(context).apply {
setContent {
IndoorNavigationScene(mapBuild)
}
}
viewGroup.addView(composeView)
Does MINE support AR features?
MINE focuses on indoor navigation. For AR, you can integrate ARCore separately and use SceneView's AR capabilities alongside MINE's navigation logic.
What's the minimum Android version?
Android 7.0 (API 24) for basic functionality. Some features like Vulkan backend require API 28+.
How do I update maps without app releases?
Use MapLoader.loadFromUrl() to fetch maps from your CDN:
val mapBuild = MapLoader.loadFromUrl(
"https://cdn.example.com/venues/${venueId}.json"
)
Next Steps¶
- Quick Start Guide - Get MINE running in 15 minutes
- SceneView API Reference - Understand the 3D scene component
- Map Loading - Learn about map data formats
- UI Components - Explore composable widgets
Last updated: December 2024 | MINE SDK v1.0.0 | SceneView 2.0 | Filament 1.46.0