Self-hosted service
iTowns/itowns avatar
iTowns/itowns

iTowns puts a geospatial layer between your data and Three.js

A Three.js-based framework written in Javascript/WebGL for visualizing 3D geospatial data

1,274 stars316 forksJavaScriptNOASSERTION

At a glance

What is it?
iTowns is a JavaScript and WebGL framework built on Three.js for visualising 2D and 3D geospatial data, handling WMS, WMTS, TMS, MVT, 3D Tiles, GeoJSON and GPX as base maps, terrain, vector features and 3D models. It is dual licensed under Cecill-B and MIT, maintained by IGN and CIRIL Group, and is part way through a move to a monorepo with separate packages.
Who is it for?
iTowns suits a team that has to publish map and 3D data to browsers and wants the tiling, projection, elevation and vector plumbing handled for them, with a styling API on top and a widgets library for navigation. It does not suit a project that only needs a simple 2D map, since the framework is built around 3D scenes and Three.js, and the monorepo restructuring means the package layout is still moving.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

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

Editorial analysis

What sits between the data and the renderer

iTowns is described as a Three.js-based framework written in JavaScript and WebGL for visualizing 2D and 3D geospatial data. The position of the word framework matters here, because Three.js is a renderer and iTowns is everything you need to put geospatial data in front of it.

Three.js draws triangles in a scene. Everything that makes those triangles mean something is the work: the projection system, the tile pyramid, the elevation model under a terrain layer, the vector tile decoder, the 3D model loader, the camera constraints that keep the user above the ground. iTowns provides that layer and exposes a dedicated API for styling the result, so the visual language of a layer is configured rather than hand built.

The formats it supports are the coverage map. WMS, WMTS and TMS for raster and tile services, MVT for vector tiles, 3D Tiles for large 3D model sets, GEOJSON and GPX for vector and track data, and the list is described as various protocols and formats that can be displayed as base maps, terrain elevation, vector features and 3D models. That last list is the important one, because it maps formats onto the roles they play in a scene rather than presenting them as a grab bag.

The audience is a mapping or geospatial team that has to ship this to browsers, in France and beyond. The project is an original work from the French IGN and the MATIS research laboratory, and the maintainers are IGN and CIRIL Group, so the use cases behind the code are civil mapping, terrain and 3D city data rather than a general purpose graphics demo.

Coordinates and projections are the core abstraction

The example in the README that shows how to use the library starts with a coordinate, and that is the right place to start, because in a geospatial application the projection is not a detail.

js
import { Coordinates } from 'itowns';

const coordinates = new Coordinates('EPSG:4326', 88., 50.3, 120.3);

// change projection system to pseudo mercator
coordinates.as('EPSG:3857');

A Coordinates object carries a projection identifier and the values in that projection, and the as method converts it to another. The two identifiers in the example are the geographic system and the pseudo Mercator system used by most web basemaps, and the mismatch between them is the classic source of the bug where a layer lands in the wrong place or at the wrong scale.

This is where the library earns its keep against writing directly on Three.js. The renderer has no notion of a projection, so a project working on raw Three.js either hardcodes one system and loses the other, or carries its own conversion layer, which is exactly the kind of code that is easy to get subtly wrong and hard to test.

The widget example shows the other half of the setup, a GlobeView created on a container element and a navigation widget attached to it:

js
import { Navigation } from 'itowns/widgets';

const viewerDiv = document.getElementById('viewerDiv');

const view = new itowns.GlobeView(viewerDiv);

const navigation = new Navigation(view, {
    position: 'bottom-right',
    translate: { y: -40 },
});

The view owns the camera, the layers and the rendering loop, and the widget attaches to that view rather than to the DOM, which is why widgets are a separate import path.

Four ways to consume it, one of them in progress

The installation story has more routes than most libraries of this size, and the reason is the monorepo migration the README describes.

The preferred way is npm, with the main package installed like any other:

bash
npm install --save itowns

Widgets come from a subpath, itowns/widgets, so a project that does not need them does not pull them in.

Then there are the bundles. Two are provided, ESM and UMD, for including directly in an HTML file. The UMD bundle exposes itowns on the window object:

html
<script src="node_modules/itowns/dist/itowns.umd.js"></script>
<script type="text/javascript">
    const  coord = new itowns.Coordinates('EPSG:4326', 3.5, 44);
</script>

And the note attached to it is worth reading, because the UMD bundle also packages the peer dependencies, including threejs and proj4, with the packages.json files holding the full list. So the UMD route gives you a self contained script, and a larger one.

The ESM bundle is used with an importmap, and the README's example pins three at a specific version, 0.182.0, from a CDN, which is a sensible thing for the documentation to show since the version of the renderer has to match what the library was built against.

Alongside that, the project is moving to a monorepo organisation with a segmentation into sub-modules so that you can import only the parts you need, and the first one is @itowns/geographic, which contains the ES5-compatible sources kept up to date with the latest release. That last detail is the interesting one: an ES5 build is what a project with older browser support or a legacy bundler needs, and rather than deprecating it, the project keeps it in step with every release.

Running the examples locally on port 8080

The development setup is the same in both supported routes, and the examples are how you evaluate the library, since the README links an interactive demo and a list of examples on the project site.

With npm, you need Node.js, with the LTS version recommended, and the sequence is a clone, an install and a start:

bash
git clone https://github.com/itowns/itowns.git
cd itowns
npm ci
npm start

With Docker, the same clone and then a build and a run:

bash
git clone https://github.com/itowns/itowns.git
cd itowns
docker build -t itowns .
docker run -p 8080:8080 itowns

Both methods serve on port 8080, which keeps the two routes interchangeable, and the Dockerfile is built on node:lts-alpine3.21, copies the package manifests, installs with npm ci using --ignore-scripts and --prefer-offline, copies the source, exposes 8080 and runs npm start as its command.

There is also a one line variant for trying a remote branch without cloning, which is useful when you want to see a change that has not been released:

bash
docker run -p 8080:8080 $(docker build -q https://github.com/itowns/itowns.git#<branch>)

with the branch name replaced by the one you want, for example master or dev.

For the npm packages there is an equivalent channel for unreleased work, and it is the same idea expressed in the package manager. itowns@next gives you the version built after each merged pull request, and itowns@latest goes back to the latest stable release.

The examples directory is the real feature list

The examples folder in the repository is long, and reading its file names is the fastest way to understand what the library can actually do, since the README's format list describes inputs rather than outcomes.

There are loaders for the formats the project cares about: 3dtiles_loader.html, copc_3d_loader.html and copc_simple_loader.html for point cloud data, entwine_3d_loader.html and entwine_simple_loader.html for the Entwine format, laz_dragndrop.html for point cloud files, and misc_collada.html for models.

Then there are the rendering and interaction pieces. effects_postprocessing.html, effects_split.html and effects_stereo.html cover the post processing and split screen and stereo paths, and customColorLayerEffect.html shows the customisation of a layer's appearance, which is the styling API in action. The camera examples, misc_camera_animation.html, misc_camera_traveling.html and misc_clamp_ground.html, deal with how the user moves through the scene, and layers/ holds the layer configuration examples, with geoid_geoidLayer.html for the geoid and a demo/ subdirectory for the interactive demo linked from the site.

The Stereo and Split examples are worth a second look, because a web 3D viewer that handles a stereo display and a split screen comparison is a differentiator, and it sits in the same list as the format loaders.

The test setup mirrors the example breadth. The package scripts separate unit tests, which run across the workspaces, from functional tests, which are mocha driven against the built output with a 200 second timeout, and the full test command runs the transpile, the coverage run, the build and then the functional tests in sequence, so a change is checked at the unit level, built, and then exercised in a browser-like environment.

Governance, funding and the dual licence

The licence is the first thing to check, and it is unusual in a good way. iTowns is dual licensed under Cecill-B V1.0 and MIT, and incorporated libraries are published under their original licences. The repository's own metadata records the licence as a custom one that GitHub cannot categorise, which is a side effect of that arrangement rather than a restriction.

The dual licensing is the practical detail that matters. Cecill-B is the French open source licence, and offering MIT as well means a project bound by a corporate or copyleft policy can take the permissive option without a conversation with anyone.

The provenance explains the rest. The project is an original work from French IGN and the MATIS research laboratory, funded through research programmes involving the French National Research Agency, Cap Digital, UPMC, Mines ParisTec, CNRS and LCPC, and maintained over the years by several organisations including IGN, Oslandia, AtolCD and CIRIL Group. It is currently maintained by IGN and CIRIL Group, and the governance is described as open and explicited in a separate itowns-governance repository, which is a level of formality that a research project rarely has and a commercial one always wants.

The publiccode.yml file at the repository root is another marker of the same lineage, since it is the metadata format used to publish publicly funded code.

On maintenance, the published releases are 2.46.0 in October 2025, 2.45.1 in March 2025 and 2.45.0 in February 2025, and the repository is not archived with the last push on 2026-10-15. The browser support policy is stated too, and it is a firm one: the project officially targets the last two major versions of Firefox, Chromium based browsers and Safari at the date of each release, and older browsers supporting WebGL 2.0 may work but are not supported.

Editorial conclusion

iTowns suits a team that has to publish map and 3D data to browsers and wants the tiling, projection, elevation and vector plumbing handled for them, with a styling API on top and a widgets library for navigation. It does not suit a project that only needs a simple 2D map, since the framework is built around 3D scenes and Three.js, and the monorepo restructuring means the package layout is still moving. Verify first which package you should depend on, because the split between the main package, the widgets, the debug tools and the ES5 compatible @itowns/geographic package is in progress, and check the browser support policy, since the project officially supports only the last two major versions of Firefox, Chromium based browsers and Safari at each release.

Frequently asked questions

What is iTowns?

It is a Three.js-based framework written in JavaScript and WebGL for visualizing 2D and 3D geospatial data, supporting formats and protocols including WMS, WMTS, TMS, MVT, 3D Tiles, GEOJSON and GPX as base maps, terrain elevation, vector features and 3D models.

How do I install iTowns in a project?

With npm install --save itowns, importing the pieces you need from itowns and itowns/widgets. Bundles are also published, an ESM bundle for use with an importmap and a UMD bundle that exposes itowns on the window object.

How do I run the iTowns examples locally?

Either with npm, using git clone, cd itowns, npm ci and npm start, or with Docker, using docker build -t itowns . and docker run -p 8080:8080 itowns. Both methods serve the site on port 8080.

Can I try unreleased versions of iTowns from npm?

Yes. Installing itowns@next gives you the version published after each merged pull request, and installing itowns@latest switches back to the latest stable release. A Docker equivalent exists, building straight from a branch URL.

What licence is iTowns released under?

It is dual licensed under Cecill-B V1.0 and MIT, with incorporated libraries published under their original licences. The project is an original work from French IGN and the MATIS research laboratory and is currently maintained by IGN and CIRIL Group.

Official sources

  1. Issues
  2. iTowns/itowns on GitHub
  3. Project website
  4. README
  5. Releases
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/itowns-itowns.svg)](https://hysenlabs.com/projects/itowns-itowns)

Was this useful?