Building a 3D Elevation Photo Diary with deck.gl
During a recent two-week vacation in Nerja, Spain, I took hundreds of photos with my phone. Many of them captured GPS coordinates and altitude data. Instead of letting that metadata sit unused, I decided to build an interactive 3D visualization that plots each photo on the actual terrain where it was taken.
Quick demo of the interactive viewer
The Concept
The idea was simple: create a chronological journey through my vacation photos, where each photo appears on a 3D terrain map at its location. As you navigate through the photos, the camera flies to each spot, showing the landscape in 3D.
Tech Stack
deck.gl for 3D Visualization
I chose deck.gl for rendering the 3D terrain and photo markers. It's a WebGL-powered framework that handles complex 3D visualizations with impressive performance. Two key layers made this possible:
TerrainLayer - Renders the 3D elevation map using Terrarium-format tiles from AWS:
const terrain = new TerrainLayer({
id: 'terrain',
elevationData: 'https://s3.amazonaws.com/elevation-tiles-prod/terrarium/{z}/{x}/{y}.png',
texture: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
...
});
ScatterplotLayer - Displays photo locations as 3D points on the terrain. I used two layers: one for visited photos (gray, smaller) and one for the current photo (orange, larger).
Data Processing
The photos' EXIF data provided latitude, longitude, altitude, and timestamps. I extracted this into a CSV file with entries sorted chronologically:
filestem,latitude,longitude,altitude,timestamp
IMG_20260106_132810881,36.78705,-3.883663888888889,197.6,2026:01:06 13:28:12
...
Key Features
Smooth Camera Transitions
When navigating between photos, the camera smoothly flies to the new location using deck.gl's FlyToInterpolator:
deckInstance.setProps({
initialViewState: {
longitude: currentPhoto.longitude,
latitude: currentPhoto.latitude,
zoom: 15,
bearing: 180,
pitch: 40,
transitionDuration: 2000,
transitionInterpolator: new deck.FlyToInterpolator()
}
});
Progressive Trail Visualization
As you move through the photos, previously visited locations remain visible in gray, creating a visual trail of your journey. The current photo is highlighted in orange.
Responsive Layout
The interface adapts to different screen sizes:
- Landscape: Map takes 60-70% of width, photo/controls on the right
- Portrait: Map takes 60% of height, photo/controls below
@media (max-aspect-ratio: 1/1) {
#app-container {
flex-direction: column;
}
#map-container {
flex: 0 0 60%;
}
...
}
Keyboard Navigation
Keyboard shortcuts for quick navigation:
- Arrow keys: Previous/Next photo
- Home/End: First/Last photo
- Spacebar: Play/Pause auto-advance
Auto-Play Journey
A play button advances through photos automatically (3 seconds each), creating a cinematic journey through the vacation.
Challenges & Solutions
GPS Altitude Accuracy
Phone GPS altitude data can be unreliable, especially near sea level. I added a note in the info modal about this limitation. In future versions, I might cross-reference with the terrain elevation data to improve accuracy.
Photo Loading Performance
I selected 300 of the photos that had GPS data and created smaller web-optimized versions using wim to ensure quick loading without sacrificing too much quality.
Mobile Layout
Getting the controls to fit on small portrait screens required careful tweaking of photo max-height and padding values. The final solution uses a compact info display (icons instead of labels) and reduced button spacing.
What I Learned
- deck.gl is powerful but has a learning curve - The layer system is elegant once you understand it, but proper coordinate handling and view state management took some experimentation.
- GPS metadata opens creative possibilities - This project barely scratches the surface of what's possible with GPS metadata from photos.
- Responsive 3D is tricky - Balancing the 3D visualization with UI controls across different screen sizes required more iteration than expected.
- Small touches matter - The smooth camera transitions, progressive trail effect, and keyboard shortcuts help make the experience more engaging.
Try It Yourself
The project is built with vanilla JavaScript and deck.gl - no frameworks needed. If you have GPS-tagged photos from a trip, you could adapt this code to create your own elevation diary.
Have you built something similar or have ideas for improvements? Drop a comment below!
Tech Used:
- deck.gl - 3D visualization
- wim - Image optimization
- AWS Terrain Tiles - Elevation data
- Esri World Imagery - Satellite imagery
Featured Merch
Latest Posts
- Thunderbird Keeps Threading Emails? Here's the Fix
- Social Media Dimensions Cheat Sheet 2025
- How Limiting My Internet Usage Changed the Way I Work and Live
- Practical Tips to Reduce Data Usage on Phones, Tablets, and Computers
Featured Book

Subscribe to RSS Feed
Published by Ramiro Gómez on . Subscribe to the Geeksta RSS feed to be informed about new posts.
Tags: spain visualization map web development javascript
Disclosure: External links on this website may contain affiliate IDs, which means that I earn a commission if you make a purchase using these links. This allows me to offer hopefully valuable content for free while keeping this website sustainable. For more information, please see the disclosure section on the about page.