All work
2025ENGINEERLive

DC Map – Interactive 3D Visualization

A game-like map app for exploring Washington D.C. with 3D building visualizations and a fly-through mode.

DC Map – Interactive 3D Visualization

Stack

TypeScript · Mapbox GL JS

Result

Immersive 3D Fly Mode

Year

2025

Status

Live ↗

HighlightsImmersive 3D Fly ModeInteractive VisualizationHigh PerformanceGame-like Experience

Gallery

DC Map – Interactive 3D Visualization screenshot 1
1 / 5

Google Maps is functional. It's also soulless.

I live in DC and genuinely love exploring it: the museums, the monuments, the parks, the neighborhoods. But the way most people navigate a city is either staring at Google Maps or getting lost. Neither felt like the right way to experience a place as visually rich and historically layered as Washington D.C.

I wanted something that made the city feel like a world to explore rather than a set of directions to follow. Something closer to a game than a navigation app. So I built one.

A map you actually want to open

DC Map is a 3D interactive map of Washington D.C. designed to be fun to use rather than purely functional. The core idea: what if you could explore the city from your browser the way you'd explore a game world? Discover landmarks, learn about museums, fly over the National Mall, watch the trees change color with the seasons.

The map uses Mapbox GL JS with 3D building extrusions. Real elevation data, real building geometry, rendered with a slightly stylized aesthetic that makes it feel designed rather than like a raw satellite view. You can zoom, pan, rotate, and tilt freely. The whole screen is the map.

The design decisions that made it feel right

The aesthetic choice (stylized rather than photorealistic) was made early and shaped everything downstream. Photorealistic maps look like infrastructure tools. They signal: this is for getting somewhere. The slightly stylized buildings with their extrusions, the muted but intentional color palette, the clean rendering of geometry: these signal something different. This is a place you'd want to spend time in. That distinction matters because the whole premise of the project depends on the user being willing to wander. If the map looks like a navigation app, people will use it like a navigation app.

The information cards on landmarks and museums are deliberately minimal: a name, one sentence of context, and a search link if you want more. This was a considered choice, not a shortcut. A detailed card creates a reading task. It makes you feel like you need to finish it before moving on. A brief card does something different: it tells you just enough to be curious, then gets out of the way. The design choice changes what the user does next. With a dense card, they read and close. With a minimal card, they look up, look around at the map, and start thinking about what's nearby. That's the behavior the whole project is trying to produce.

The layer controls give users independent toggles for landmarks, museums, trees, and parks rather than a single "show all POIs" switch. This was about respecting that people explore differently. Someone who wants to understand DC's green space doesn't need landmark pins cluttering the view. Someone doing a museum tour doesn't need seasonal tree data. A single toggle flattens those different modes into one experience. Independent layers let the user compose their own map, which turns out to be closer to how people actually think about a city, as a set of overlapping systems rather than one undifferentiated set of things to look at.

The XP system deserves the same explanation. It's easy to dismiss as a gamification layer added for engagement, but that's not what it's doing. The specific mechanic (you earn points by getting within 50 meters of a landmark, not by clicking on it from any distance) is the whole design. It requires physical navigation. You have to move toward the thing to get credit. That changes the mental model from "looking at a map" to "moving through a city." The XP number is almost incidental. What matters is the behavior the mechanic requires: proximity, attention, intentional movement. That's the experience.

The city in layers

The city is organized into layers you can toggle independently: landmarks, museums, trees, parks. Each layer has its own visual language on the map.

The tree layer uses real DMV tree inventory data, thousands of actual trees plotted across DC. You can change the tree colors by season: spring greens, summer deep green, autumn reds and oranges, winter grey. It's a small thing but it changes how the whole city reads on screen. Parks layer in with their own seasonal coloring on top.

Landmarks and museums are the exploration layer. DC has 10 major iconic landmarks and 36+ museums catalogued from Open Data DC. Click on any of them and you get a small information card about the place. What it is, a bit of context. If you want to go deeper, there's a search icon that opens a Google search for more. The goal wasn't to replace Wikipedia; it was to give you just enough to be curious and orient yourself.

Points for wandering

This is the part I enjoyed building most. There's a progression system built into the exploration.

When you move close to a landmark or museum, within 50 meters, you discover it. Discovering a landmark earns 50 XP. A tree is 10 XP. The XP accumulates into a level system (100 XP per level), with achievement unlocks along the way. Progress is saved locally so your discoveries persist between sessions.

The tip on the map reads: "Click on landmarks to discover them and earn points." It's lightweight, this isn't a full game, but it changes the mental model from passive browsing to active exploration. You're not just looking at a map, you're moving through it.

This one took the longest to feel right

Fly mode lets you leave the map plane entirely and navigate DC as a first-person flyover, moving through the 3D building geometry with WASD controls and mouse look, like a free camera in a game engine.

Getting this to feel right took iteration. Camera movement with momentum and easing feels cinematic; without it, it feels like a broken drone. The fly mode has physics-based momentum so the movement has weight to it. There's also collision-aware navigation so you don't clip through buildings arbitrarily.

Feel matters in interaction design in a way that's hard to argue for in a spec but immediately obvious in use. The physics-based momentum isn't decoration. It's the difference between a camera that feels like a tool and one that feels like it's fighting you. Too much acceleration and the movement feels twitchy, impossible to aim. Too little and it feels sluggish, like dragging something through water. I went through multiple iterations of easing curves, acceleration rates, and turn sensitivity before it landed in the range where it felt responsive but not nervous, cinematic but controllable. The target feel was a free-roaming camera in a game engine, something that has weight and follows your intent without overreacting to it.

The WASD controls are a deliberate choice about who this is for. WASD navigation is a convention that comes from PC gaming. If you know it, it's immediately intuitive. If you don't, it's not the right interface for you, and that's fine. This is a web app, not a mobile-first product, and the fly mode in particular is designed for people who are comfortable enough with computers to have that muscle memory. That's not an oversight; it's a scope decision. Making fly mode work well for the people who will love it is more valuable than making it awkward for everyone by trying to accommodate every possible input model.

Flying along the Potomac, banking over the Mall with the Washington Monument on one side and the Capitol on the other. That's what I was going for. It might not be perfect, but it's there and it works.

Real data, real trees, real roads

Most of the interesting technical work was in the data layer. DC Map uses several static GeoJSON datasets: landmark locations (manually curated), museum locations from Open Data DC, the full DMV tree inventory, DC's walkable road network, and a navigation graph built from road data for pathfinding.

The road network data needed preprocessing. I built a custom walk-graph generation script that converts the raw road data into a format usable for navigation. Turf.js handles the geospatial calculations: proximity detection for the discovery system, distance calculations, point-in-polygon checks for boundary warnings.

The architecture runs through a centralized StateManager that coordinates game state, landmark tracking, museum progress, XP, fly controls, and map state through custom hooks and providers. Everything that matters, discoveries, level, achievements, persists to localStorage.

Maps can be fun. Here's proof.

Navigation apps are optimized for getting you from A to B efficiently. That's useful. But there's a different mode, exploration, curiosity, wandering, that deserves its own interface.

DC is a beautiful, walkable, historically dense city that a lot of people only experience as a sequence of tourist checkpoints. DC Map is for the other kind of visit: the one where you wander, discover something you didn't plan to find, and come away with a better sense of the place as a whole.

What I keep adding in my head

The landmark and museum data is currently static. When a new museum opens or a landmark changes, that's a manual update. I'd connect to the Open Data DC API directly so the data stays current automatically. I'd also build out the discovery cards with more depth. Right now they're intentionally brief, but there's room for richer content without breaking the lightweight feel. A guided tour mode, where the map flies you through a scripted sequence of landmarks, is something I've had in mind since the beginning.

Built with

TypeScriptMapbox GL JSNext.jsReactTailwind CSS