We'd love your input: Coordinate reference systems and local coordinates in CesiumJS

Hi everyone,

The CesiumJS team is exploring how we might better support different coordinate reference systems (CRSs), vertical datums, and local coordinate systems, and we’d like to better understand your needs and current workflows.

There are several existing feature requests that touch different parts of this problem:

Rather than looking at these only as individual features, we’re interested in understanding the broader workflows behind them.

Some examples of capabilities we have in mind include:

  • Reprojecting data for 2D rendering

  • Working with different vertical reference datums, such as Mean Sea Level or a regional height datum rather than height relative to the WGS84 ellipsoid

  • Displaying coordinates and measurements in a particular CRS, even when the underlying scene uses CesiumJS’s global coordinate system

  • Working directly with local/project coordinates, such as for surveying, CAD, BIM, or other engineering data where the data’s own coordinate system may be meaningful to users

  • Combining datasets from different coordinate systems

These are examples, not a proposed scope or API, each of which could ultimately require very different solutions.

We also want to be transparent that we’re in the exploration stage and have not committed to implementing these capabilities in CesiumJS. Before deciding, we want to better understand the problems you are actually trying to solve so we can balance feature requests with the overall maintainability and scope of CesiumJS

If you work with CRSs, vertical datums, or local coordinate systems in a CesiumJS application, we’d especially like to hear:

What is your use case? What coordinate systems or datums are you working with, and what do you need to accomplish?

Where do you encounter friction in you workflow? Is the challenge getting data into CesiumJS, rendering it correctly, working with coordinates at runtime, presenting coordinates or measurements to users, or something else?

How are you solving it today? Are you preprocessing data, using PROJ or another geospatial library, converting through a backend service, maintaining your own transforms, or using another visualization tool?

How important is better support in CesiumJS? Is this mostly a convenience, a significant source of complexity, or something currently blocking a workflow?

We’re also interested in cases that don’t fit neatly into the examples above. Part of the goal here is to understand whether there are common workflows we could support more cohesively, rather than addressing each coordinate-system problem independently.

Thanks!

We’ve run into this frequently on engineering and infrastructure projects.

Our biggest challenges aren’t reprojecting global datasets, but integrating survey, CAD, BIM, point cloud, geotechnical and terrain data that often arrive in different horizontal and vertical reference systems. We’ve ended up building our own CRS transformation framework, including geoid-based height corrections to support project-specific vertical datums.

The main friction points are:

  • Vertical datums are by far the biggest challenge. Horizontal transformations are relatively straightforward with tools like PROJ, but converting between ellipsoidal heights and project/local height datums adds a lot of complexity.

  • Local engineering coordinate systems are common in CAD, BIM and survey data, and users often want coordinates, measurements and asset locations reported in those systems rather than WGS84.

  • Combining datasets from multiple suppliers frequently requires custom transformation and validation workflows before data can be visualised confidently.

Today we solve this with a combination of client-side processing, using PROJ and geoid tif files, and pre-processing data using FME and Python.

For us, better support in CesiumJS would be highly valuable. The biggest wins would be:

  • Native support for vertical datums and geoid models.
  • First-class handling of local/project coordinate systems.
  • Easier coordinate display and measurement in user-defined CRSs.
  • A consistent framework for managing multiple coordinate systems within a scene.

Adding a use case, since it lines up closely with a couple of items on your list.

Use case: we’re building a web-diffused LOD300 3D digital twin of a dense urban area, sourced from BIM/CAD, natively in a projected CRS (CC44 / Lambert Conformal Conic, EPSG:3944) with a national vertical datum(NGF-IGN69 EPSG:5720) . For glTF export we reduce coordinates by a fixed false-origin offset to keep vertex magnitudes small (float32 precision into blender), then re-apply the true offset at the tileset transform level.

1. On-the-fly display conversion, independent of the render CRS
The “displaying coordinates and measurements in a particular CRS” item is exactly what we need — and we’d stress it doesn’t require touching how CesiumJS itself computes and renders (WGS84/ECEF stays the render CRS). What’s missing is a two-way conversion layer at the UI/interaction level: pick a point on the globe → report it in an arbitrary target CRS (our local projected system), and conversely, enter/query a position in that CRS → place/highlight it on the globe. For engineering and planning audiences working under a local projected-CRS mandate, lat/long or ECEF isn’t the coordinate system they think in, and right now we maintain our own PROJ pipeline and specific API for the vertical datum (Reframe from swistopo in Switzerland) just for this display layer.

2. Projected data draped on the globe without visible warping, at cm precision
This is the harder one, and we see two genuinely different strategies depending on data type, not one:

  • Large continuous data (terrain/ortho): distortion from a projected CRS isn’t constant across a large footprint, so this needs true per-vertex reprojection into geographic/ECEF. No way around it.
  • Discrete, individually-small objects (buildings): for a conformal projection like Lambert/CC44, distortion at the scale of a single building footprint is effectively a pure similarity transform (uniform scale + rotation + translation), not a warp. A single local transform matrix per object/tile is enough — vertex reprojection is unnecessary and wasteful at that scale. We rely on this distinction constantly, and it would help a lot if CesiumJS’s tooling made it an explicit, supported pattern rather than something every team derives on its own.

3. Precision on export/import, tied to point 2
Concretely: our source geometry lives in projected coordinates, locally reduced by an XY shift to protect float32 vertex precision during glTF export. What we don’t have yet is a clean, standard path to carry that shift plus the true CRS transform through to CesiumJS placement without precision loss — keep the mesh geometry small-magnitude/float32-safe, and apply the full-precision georeferencing (double precision) only at the transform-matrix level, conceptually close to a per-tile transform in 3D Tiles, but currently something we hand-roll rather than something the ecosystem standardizes around.

4. What the ideal export tooling would look like
What we’d actually want, end to end: at export time, from Blender/BIM/CAD, attach the CRS directly to each GLB as machine-readable metadata — a horizontal EPSG code and a vertical datum EPSG code, plus the true local origin (easting/northing/height) that GLB was reduced from — written into a glTF extension a tiling tool can read. From there, either the tiler computes the ECEF placement transform itself (projection + geoid/vertical datum handling) and writes it per tile into tileset.json, or we compute it ourselves and just need a standard, documented place to declare it so a generic tiler can consume it directly rather than requiring a bespoke pipeline. Right now that whole chain — CRS in Blender → transform math → tileset.json — is a project-specific script. Standardizing just the declaration (“this GLB is georeferenced in EPSG:X horizontal / EPSG:Y vertical, true origin at E/N/H”) would let tooling do the rest, instead of every team reimplementing PROJ + geoid handling from scratch.

Happy to go into more detail on our pipeline if useful.