Cesium-sgp4-viewer: a whole satellite catalog (~16,000 objects) propagated with SGP4 on a CesiumJS globe

Hi everyone,

Following the discussion about the Sandcastle gallery (thanks @darcyvdd for the suggestion), here is the project as a showcase.

cesium-sgp4-viewer is an open-source (Apache-2.0) library that shows a whole satellite catalog on a CesiumJS globe from a list of TLEs: every object at its SGP4 position, its orbit and its name, following the scene’s clock.

The use case

Plotting satellites from TLEs is a common need. The straightforward way in Cesium, one Entity with a SampledPositionProperty and a path per satellite, works well for a few hundred objects, but a public catalog like CelesTrak’s active list has tens of thousands. I wanted the full catalog to stay smooth, with any clock behaviour: live, paused, accelerated, reversed or scrubbed.

How it uses Cesium

  • Points: a single PointPrimitiveCollection for the whole catalog, updated in place: one draw call.
  • Orbits: one custom primitive with its own vertex and fragment shaders. Rings are uploaded to the GPU as they come out of the workers and rotated under the Earth with one matrix per frame. In 2D, the same buffers are drawn as ground tracks computed in the vertex shader.
  • Clock: everything follows viewer.clock, so the standard timeline and animation widgets just work.
  • Inertial camera (optional): the camera stays fixed in ICRF, using Cesium’s Earth orientation data, so the Earth turns under the orbits.
  • Picking and labels: click selection with the orbit highlighted, names on hover or for every visible satellite.

Outside Cesium, SGP4 (via satellite.js) runs in a small pool of web workers. The main thread only interpolates (degree-5 Lagrange, error bounded at 50 m in the tests), and filtering by regime (LEO/MEO/GEO/HEO), name or NORAD ID never triggers a new propagation.

What I learned

Moving from entities to primitives was the key to scaling. The honest trade-off: the orbit primitive relies on renderer classes that are exported but not documented (DrawCommand, VertexArray, ShaderProgram, …). If a future release changes them, the library turns orbits off with a console warning, and points, labels and picking keep working since they only use the public API. Feedback on a better approach is very welcome.

Try it

TLE data from CelesTrak, maintained by Dr. T.S. Kelso.

Questions, ideas and bug reports are welcome, here or on GitHub!

David Sanchez

Great demo here @dsanchez31

The newer BufferPointCollection and BufferPolylineCollection APIs might be a good fit for what you’re doing here. They’re meant to handle larger collections of many objects, and with cesium#13511 in the v1.146 release, should support animation on large collections as well. If that doesn’t work for you, we’d welcome feedback too. :slight_smile:

The one drawback I see for your application is that these APIs don’t support the 2D view mode currently, but I think we’d be open to contributions improving that. I might recommend opening an issue to discuss the approach first, if you’re interested in attempting it.

Thanks @donmccurdy, I really appreciate the feedback and the pointer!

I’ll definitely look into cesium#13511 and the newer BufferPointCollection and BufferPolylineCollection APIs.

I’ll set up a branch to benchmark new APIs against the current setup and open an issue on the Cesium repository to discuss the 2D support roadmap.

Thanks again for taking the time to check out the project!