Building a 3D Geo-Viz Engine in Vanilla Three.js: 12 Pitfalls from GeoJSON to Shader Flylines
Chart libraries like ECharts abstract away the geometry, shaders, and coordinate systems that make custom 3D map effects possible. This engine's 12 documented pitfalls—especially the global UV rewrite, TubeGeometry vertex layout, and coordinate-system rotation—are the exact problems a developer hits when breaking free of those abstractions, and the solutions apply to any Three.js geographic project.
Starting from a single HTML file, the LockScope engine renders GeoJSON as extruded 3D city blocks with a continuous satellite texture, conical light pillars mapped to economic data, and flowing flylines animated via custom fragment shaders. A CSS variable and JS color dual-track system enables hot-switching between three color presets without a page reload. The entire stack avoids npm, frameworks, and build tools, shipping as a directory of static files that runs on any HTTP server. The project's 12-version iteration surfaced a dozen concrete pitfalls in Three.js, from ExtrudeGeometry UV fragmentation and TubeGeometry vertex structure to strict-mode recursion and memory leaks during scene rebuilding. Each pitfall is documented with its root cause and the specific fix applied, forming a practical reference for anyone building custom 3D map visualizations outside the constraints of charting libraries.
ExtrudeGeometry's per-Shape UV generation is a documented but underappreciated trap: the fix requires understanding the geometry's vertex layout well enough to walk rings and rewrite the UV buffer by hand.
The TubeGeometry vertex-count detail (radialSegments + 1) is easy to miss because the constructor parameter is named radialSegments, not verticesPerRing, and the docs don't emphasize the +1.
Hardcoding flyline color to a single gold that works across all three color presets is a pragmatic design choice that avoids the complexity of per-scheme Shader uniform updates.
Shipping as a directory of static files with zero build steps is a deliberate constraint that forces simplicity; it also makes the engine trivially deployable in air-gapped or restricted environments common for government data dashboards.
The 12 pitfalls are not generic debugging anecdotes—each is a Three.js API behavior that is either counterintuitive or poorly documented, making the list a useful pre-flight checklist for similar projects.