Problem Statement / Feature Objective
The utility dashboard renders thousands of spatially distributed assets (meters, valves, substations) on a 2D Mapbox canvas. Operators need an immersive 3D view to assess vertical clearance, conduit overlap, and infrastructure density in urban corridors. A Three.js overlay must be composited on top of the Mapbox WebGL context using a shared render loop, with a QuadTree-based Level-of-Detail (LOD) system that swaps detailed 3D models for impostor sprites beyond 500 meters camera distance. The overlay must track Mapbox camera synch (latitude, longitude, altitude, heading, pitch) every animation frame.
Technical Invariants & Bounds
- Maximum drawable assets: 20,000 per viewport before LOD culling. Beyond that, batch culling to 10,000 via off-screen frustum check.
- LOD distances: LOD 0 (full mesh) at 0-100m, LOD 1 (simplified mesh) at 100-300m, LOD 2 (impostor sprite) at 300-500m, culled beyond 500m.
- QuadTree depth: 8 levels, covering a 100 km x 100 km region. Leaf nodes hold asset references; internal nodes hold aggregated bounding spheres.
- Camera sync: Mapbox provides mercatorCoordinate and worldToCameraMatrix. These must be extracted via map.transform on every frame and fed to the Three.js camera.
- Compositing: Three.js renderer uses alpha: true, a custom WebGLRenderTarget, or overlay approach via CSS pointer-events: none on a Three.js canvas absolutely positioned over the Mapbox canvas.
- Performance budget: Three.js frame must complete within 8 ms (120 fps target) on a laptop GPU (Intel Iris Xe) and 16 ms (60 fps) on a field tablet.
Codebase Navigation Guide
- src/components/map/ThreeOverlay.tsx - React component that initializes Three.js scene, renderer, and camera. Manages the overlay canvas lifecycle.
- src/components/map/lod/QuadTree.ts - QuadTree spatial index: insert, queryFrustum, getLODLevel.
- src/components/map/lod/AssetMesh.ts - Three.js Mesh factory: creates LOD0 mesh, LOD1 simplified mesh, LOD2 sprite from asset type template.
- src/components/map/shaders/assetInstancing.vert - Instance vertex shader for rendering many identical meshes with per-instance position/rotation/scale.
- src/hooks/useMapCameraSync.ts - Hook that reads map.transform each requestAnimationFrame and updates the Three.js camera matrix.
- src/types/spatial.ts - Spatial types: Coordinate3D, AABB, FrustumPlane, LODLevel, AssetInstance.
Implementation Blueprint
- In ThreeOverlay.tsx, create a Three.js WebGLRenderer with alpha: true and set its DOM element to position: absolute over the Mapbox container. Set pointer-events: none on the canvas so Mapbox handles interactions.
- Create the QuadTree in QuadTree.ts: subdivide the 100 km region into 4 quadrants per level. Insert(asset: AssetInstance) traverses to the appropriate leaf. QueryFrustum(frustum: FrustumPlane[]) returns all visible assets at appropriate LOD.
- In useMapCameraSync, read map.transform._center, _elevation, _heading, _pitch each frame via requestAnimationFrame. Compute Three.js camera matrix using mercator projection. Post the frustum planes to the QuadTree query.
- AssetMesh.ts defines LOD meshes using THREE.LOD: LOD0 is a detailed GLTF (loaded via GLTFLoader from public/models/), LOD1 is a BoxGeometry with material, LOD2 is a SpriteMaterial with a circular texture. Use THREE.InstancedMesh for identical asset types to reduce draw calls.
- LOD selection: for each queried asset, compute camera distance, select LOD level, apply via LOD.update(). For LOD2 sprites, billboard the sprite toward the camera.
- Optimize culling: run frustum query in a Web Worker (src/workers/frustumCull.worker.ts) to avoid blocking the render thread. The worker returns visible asset IDs and their LOD levels.
- Add a memory watchdog: if ThreeOverlay detects GPU memory usage > 512 MB (via renderer.info), degrade max LOD0 distance to 50m and increase sprite threshold.
Problem Statement / Feature Objective
The utility dashboard renders thousands of spatially distributed assets (meters, valves, substations) on a 2D Mapbox canvas. Operators need an immersive 3D view to assess vertical clearance, conduit overlap, and infrastructure density in urban corridors. A Three.js overlay must be composited on top of the Mapbox WebGL context using a shared render loop, with a QuadTree-based Level-of-Detail (LOD) system that swaps detailed 3D models for impostor sprites beyond 500 meters camera distance. The overlay must track Mapbox camera synch (latitude, longitude, altitude, heading, pitch) every animation frame.
Technical Invariants & Bounds
Codebase Navigation Guide
Implementation Blueprint