Library / SDK
r-follador/CubeTrek avatar
r-follador/CubeTrek

CubeTrek turns a GPS track into a 3D terrain model

Home for all your GPS Tracks: Visualize, share and manage your GPS tracks.

563 stars35 forksHTMLGPL-2.0

At a glance

What is it?
CubeTrek is a self-hosted web application for managing outdoor activity tracks, and the thing it does that other tools do not is build a 3D model of the terrain around your route. Upload a FIT or GPX file and the server downsamples it, cross-checks the elevation against a NASA SRTM model, guesses the activity name from the highest point, and stores the result in PostGIS.
Who is it for?
Adopt CubeTrek if you keep GPS tracks from Garmin, Polar or Coros devices and want to see the shape of a route rather than a line on a flat map, since the 3D model and the elevation cross-check are the reason it exists. Skip it if you only want a map and statistics, since a general activity tracker already does that, and if you cannot run a Java service with PostGIS and a map tile provider.
Can I use it commercially?
Yes, with conditions. GPL-2.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 11 days ago.
What is it written in?
Mainly HTML, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The pitch is that a 2D map hides the interesting part

CubeTrek is a home for your GPS tracks, where you can visualise, share and manage them, and the opening argument is about why flat maps are a poor fit for mountain sports.

Topography is what makes skiing, hiking, trail running and mountain biking so exciting. You conquer those vertical distances with a lot of sweat and effort, but your tracking software only shows a boring 2D map.

That framing explains the whole project. A track recorded on a watch is a sequence of points with latitude, longitude, time and elevation, and rendering it on a 2D map discards the one thing that makes those sports what they are. CubeTrek's answer is to build an actual 3D model of the terrain the route crosses and draw the track on it.

The service is a sign-up web application at CubeTrek.com, and you connect your Garmin, Polar or Coros watch to it. The releases suggest the device support grew over time, with v5.3 titled Coros Syncing and v5.2 titled Improved handling of sensitive data.

The visible features are the three you would expect from that pitch. An interactive 3D topology view using Babylon.js. TrekMapper, a heatmap of all your activities on one map. And a large set of statistics, including yearly activity views that the README describes as GitHub inspired activity stats, and matching activities, which is automatic matching and comparing of similar activities.

The example given is a ski route to the Mattijsch Horn, and the link to it is a view of a specific activity, so the sharing model is per activity rather than per account.

The project is Java with a JavaScript front end, GPL-2.0 licensed, with the last push on 2026-10-12 and releases v5.4 from 2025-01-10, v5.3 from 2024-10-19 and v5.2 from 2024-02-15.

The import pipeline is where the interesting decisions are

The processing chain is described step by step, and each step answers a question the raw file does not.

When you upload a FIT or GPX file, the server reads the tracks, downsamples them to a reasonable resolution, and calculates descriptive values such as the geographical bounding box, distance and time.

Then the elevation data is cross-checked with the elevation model on the server. The stated purpose is to check if the device's height sensors were properly calibrated, and a simple correction is applied if necessary. And if elevation data is completely absent from the file, because the recording device has no height sensor, the elevation data is interpolated completely from the model.

So the file's own elevation is treated as a claim to be verified rather than as ground truth. That is the right way round for consumer devices, whose barometric altimeters drift and whose GPS altitude is noisy, and it means an activity recorded by a device without an altitude sensor still renders correctly in 3D.

The elevation model consists of HGT files retrieved from the NASA SRTM dataset, which is the Shuttle Radar Topography Mission data, a global digital elevation model produced by NASA and distributed through the USGS.

Then the activity name is guessed. The method is to take the highest point in the track data, on the assumption that this is the most prominent point of the whole activity, for example a summit. That point is cross-checked against a peak database on the server, and the data comes from OpenStreetMap, containing all OSM features annotated as Peak, with more than 520k entries.

If there is no peak in the vicinity, a reverse geocoding request is sent to Maptiler.

Once all the data is gathered, it is stored in a PostGIS extended PostgreSQL database, and the activity is ready to be put on the spotlight.

That is the whole pipeline, and it is a good illustration of what a track viewer has to do beyond drawing a polyline. The elevation check is a correctness feature, the peak lookup is a naming feature, and the reverse geocoding is the fallback when neither the data nor the peak database can tell you where you were.

The 3D view is two files and a Babylon.js scene

The rendering side is described in terms of exactly what the server sends, and that is a useful way to think about the architecture.

When you view an activity in the 3D viewer, the server provides two key files. The first is an extended GeoJSON file describing the track latitude and longitude data, time and elevation data. The second is a glTF file which contains the 3D model of the topography.

Babylon.js displays the glTF file and loads the texture, which is the map tiles, from Maptiler. A custom script then draws the track on top of the texture of the 3D model, and that script also handles the D3.js graph data conversion from the GeoJSON file, the mouse interaction and so on.

So the 3D model is not generated on the fly from the track. It is a mesh of the terrain, the track is a line drawn over it, and the map tiles are the texture applied to the terrain surface. That is a scene graph problem, which is why Babylon.js is the choice rather than a charting library.

The 2D map is then described as very straightforward. Just show the GeoJSON data in a MapLibre map, again using Maptiler as the source for the map data.

And the heatmap is the third view. When you view the heatmap, which is called TrekMapper, the server provides a list of the centre coordinates for every track associated with your account, which is rendered by MapLibre GL JS to a heatmap, and the documentation points at MapLibre's own heatmap example for details.

That last point is worth pausing on. The heatmap is not computed from the full track geometry. It is computed from one point per track, the centre coordinate. The consequence is that a heatmap of this kind shows where you have been, not how much of each place you have covered, and it is far cheaper on the wire because it is a few thousand points rather than a few million.

The progressive loading behaviour follows from the same decision. In high zoom levels, the script requests a simplified GeoJSON for each track within the view, and those are displayed in their own layer. Simplified means the track resolution is downsampled quite significantly and no further information, such as altitude data, is provided. This makes the number of displayed coordinates on the device more manageable, with the downside of noticeably simplified tracks when completely zoomed in.

After clicking on the map, Turf.js is used to determine the closest track.

The stack is deliberately boring except at the edges

The technology choices are listed in enough detail to be worth reading, because most of them are unremarkable and that is the point.

The back end is constructed with Java and Spring Boot, backed with PostgreSQL and PostGIS, and the front end is based on Bootstrap. Good old plain JavaScript is used for interaction with the server.

That last sentence is doing the work. There is no single-page application framework here, no build step for the client beyond what the JavaScript needs, and the interaction layer is plain JavaScript talking to a Spring Boot API. For an application whose hard parts are geospatial and 3D rather than interface state, that is a reasonable trade, and it means the front end does not need to be a separate build pipeline with its own dependency tree.

The three specialised libraries are chosen for specific jobs. Babylon.js performs the actual 3D magic. D3.js handles the graph, with the documentation noting it is very versatile but has a steep learning curve. And MapLibre GL JS renders the 2D map, described as very straightforward to use in this particular case.

The README is explicit about being opinionated in the other direction, recommending the reader look at Babylon.js if they have never heard of it. That is the one library a reader is expected to learn properly, and it makes sense that it is the 3D one rather than the charting one.

The GPS and 3D file handling is not in this repository at all. All of the GPS file handling and 3D file conversion is done by TopoLibrary, which is partially based on JPX for reading GPS tracks and the Garmin FIT SDK for reading FIT files.

So the repository is the application and the service layer, and the parsing of the device files and the terrain mesh generation live in a separate library. That split is a sensible one, since the FIT SDK is a C library that has to be bound and the GPX reading is pure Java, and neither has anything to do with the web application.

The repository layout matches that division. There is src/ for the application, a DataPreparation/ directory for the bulk import of the OpenStreetMap data, build.gradle and settings.gradle with the Gradle wrapper, and docs/ containing the development environment instructions.

Data sources, licensing and the parts you have to supply yourself

The data sources section is short and it is the part that determines what you can run yourself.

The elevation model uses HGT files from the NASA SRTM dataset, linked through the USGS product page. The peaks and saddles annotation comes from OpenStreetMap, downloaded from Geofabrik, and filtered, converted and imported into PostgreSQL with Imposm3, which is the OpenStreetMap to PostgreSQL importer that handles the geometry types OSM uses.

So the peak database with more than 520k entries is not a service you call. It is a bulk import you run, from a regional extract, into your own database. The DataPreparation directory at the repository root is where that work happens, and it is a significant piece of setup that the feature list does not convey.

The map tiles come from Maptiler, which is a paid commercial tile service. That is the one dependency you cannot self-host without extra work, and it is worth being clear about, because it means CubeTrek is not a fully self-hosted application in the way a static site generator or a file server is. The 3D texture and the 2D basemap both come from the same provider.

The library and framework choices are BSD-licensed and MIT-licensed open source projects, and CubeTrek itself is GPLv2.0.

The contribution model is stated briefly. Pull requests are welcome, and the project asks you to consider becoming a Supporter by getting a subscription, which helps pay the bills.

The setting up section simply points at a document, docs/dev-environment.md, for the development environment setup. There is no command list in the documentation for setting up the backend, which is a gap worth knowing about before you plan to run it yourself, and it is the reason the DataPreparation and PostGIS pieces are the hard part of a local setup rather than the build.

The homepage is cubetrek.com, and the description is a home for all your GPS tracks, to visualise, share and manage.

Editorial conclusion

Adopt CubeTrek if you keep GPS tracks from Garmin, Polar or Coros devices and want to see the shape of a route rather than a line on a flat map, since the 3D model and the elevation cross-check are the reason it exists. Skip it if you only want a map and statistics, since a general activity tracker already does that, and if you cannot run a Java service with PostGIS and a map tile provider. Verify first which device formats you import, that you are prepared to run the PostGIS database yourself, and where your map tiles come from, since the tile provider is a paid service the application depends on.

Frequently asked questions

What does CubeTrek do with an uploaded GPS track?

The server reads the tracks, downsamples them to a reasonable resolution, and calculates descriptive values such as the geographical bounding box, distance and time. The elevation data is then cross-checked against the elevation model to verify the device height sensors were calibrated, a simple correction is applied if needed, and if elevation is absent from the file it is interpolated completely from the model.

How does CubeTrek name an activity?

It takes the highest point in the track data, assuming that is the most prominent point of the activity such as a summit, and cross-checks it against a peak database on the server. That database comes from OpenStreetMap features annotated as Peak and contains more than 520k entries. If there is no peak nearby, a reverse geocoding request is sent to Maptiler.

What technology does CubeTrek use for the 3D view and the maps?

The back end is Java with Spring Boot on PostgreSQL and PostGIS, and the front end is Bootstrap with plain JavaScript for server interaction. The 3D model is a glTF file served by the backend and displayed with Babylon.js with map tiles as texture from Maptiler, the graphs use D3.js, and the 2D map and the TrekMapper heatmap are rendered with MapLibre GL JS. GPS file handling and 3D file conversion are done by a separate TopoLibrary.

Official sources

  1. License: GPL-2.0
  2. Project website
  3. README
  4. Releases
  5. r-follador/CubeTrek on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/r-follador-cubetrek.svg)](https://hysenlabs.com/projects/r-follador-cubetrek)

Was this useful?