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

**URL:** <https://community.cesium.com/t/cesium-sgp4-viewer-a-whole-satellite-catalog-16-000-objects-propagated-with-sgp4-on-a-cesiumjs-globe/47447>\
**Category:** General\
**Tags:** showcase\
**Created:** [September 30, 2026, 10:51am UTC](https://community.cesium.com/t/cesium-sgp4-viewer-a-whole-satellite-catalog-16-000-objects-propagated-with-sgp4-on-a-cesiumjs-globe/47447 "2026-09-30T10:51:08Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![dsanchez31](https://sea2.discourse-cdn.com/cesium/user_avatar/community.cesium.com/dsanchez31/32/35010_2.png) [@dsanchez31](https://community.cesium.com/u/dsanchez31)\
**Post date:** [September 30, 2026, 10:51am UTC](https://community.cesium.com/t/cesium-sgp4-viewer-a-whole-satellite-catalog-16-000-objects-propagated-with-sgp4-on-a-cesiumjs-globe/47447/1 "2026-09-30T10:51:08Z")

</div>

Hi everyone,

Following the [discussion about the Sandcastle gallery](https://community.cesium.com/t/would-a-third-party-plugin-example-sgp4-satellite-catalog-be-welcome-in-the-sandcastle-gallery/47425) (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.

 ![Capture d'écran 2026-09-30 091758](https://global.discourse-cdn.com/cesium/original/3X/2/8/28af7a3c25cbb5e339d8a99692bde51b1d49eec5.jpeg)

 ![Capture d'écran 2026-09-30 091825](https://global.discourse-cdn.com/cesium/original/3X/d/c/dcbd4b0bdfd3107f6f55ba3c16aec760b951b421.jpeg)

## 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

- **Live demo:** [cesium-sgp4-viewer examples](https://dsanchez31.github.io/cesium-sgp4-viewer/) (vanilla TypeScript and React versions)
- **Sandcastle:** [open the demo](https://sandcastle.cesium.com/#c=lVZ/bxM5EP0qowppHV3w0gOdTqXhaNMAuUt/qCmcEEHEsSdZU6+9Z3vThpLvfvI6m2xCi8ofTbXjN2/ejD1jpylwdLLMn7pZ8eLpXOINWpAahkwLzpxXSEc6TcMfXDDnEXwmHUylQpDaG/AZwt9szobcysJDwTQqMFPIvC/cQZq6DVGMRLnJK064yhCUnFhmF4mDfv9NDyalVAIsMuGgW8Fhak1eRSnYDBMHM2UmTME4Lo/b4AxIXxGWDl0FnaNdgNTOM82xkQswFbgXoAwTKOhIjzQ32nkY9I8vjy4/fvnQuxz2z8+gA4liHp1PXu5C3l8OoAPjOkEuNP3qBCo5t1SjT3WRp6+FY5pn+O35fvpjgV8/uduJt0yFdP4eKJVyivSrG69lXA16UcJIAyQPqphl6c815EzqFG9ZXih0qWCepWGT/G2Vch0tFGq1tR0gzvIWdF6FyBpv4MKaXDokxKIzao5tsPgVuQ8YuAsogEjjagpheJmj9pRbZB57CsMXSSIgab2MXvGTOsuhA87ybbPRQRZ0YBV3dxWtNTborYRETSQI7oUFMu6aUgnQJqYHT+6c5ctxqw6+1pghE5QVBWpBInmELFuNCq16plNVJB5K+qGykSSWvWu0Z1KjTdqxKkzLnHlp9AF4W2I72LzMUUmNDdOEORywBdoLya/RHsCUKReXZmi4Eds2qafm2Nw2TQ4V8hCor4XkzJuGQ5XE6pBxZfh1/B16LKBTJ9KtTXT4cXjVO/3SHZx3//ly+n5w1b8Y9HuXuxx5qbwslKwq8sez3WWXhdIfVfkjdKpcNxjHUSMVOClnw8zcvLEsR3eBdojcaLGBjzRhbqH5aoNjTW+YbB5X0mjXuGtxu+6gYNbhlcIu80yZWRuGzKNS0sditwE1myjsa7ReMtVlOVoGS+jAjdTC3NBYm+GseBH3uVJU83u8Dec8yiHx3xQ9z8iqcVstGjBkW5SrNbgq0o5GEjyaDiooXZ25bfkk1rK9xdkGxSao3AEkmZmjTeIRhntTJc3daK2SS1MYIrM8g8kCNMsRjIWz88ujE+if0I0wF0EPN7rURVn3eQRTvyjCWUjiZ9JcKhTjmBklqmyTs53AW1gmRG+O2g+k86hD+8VY7eYxqXX+V4YrolP7zpkqkXorc9Ki3gzMDdouc0jqmVAVnDr0b6TyaEm0Qs3T6UCS1DaAv0CXSm2+D4C4SoOj2lgm+oI6z6x3/0qfkYqjBd+/h2WW47YAKjVXpUC3wrUjbWMSNSbWDP2q0seLviCJN0ZNmE1a6zFW5VvvauOWZ0JcmdlM4XHpvdEkObcT6V3SXg0MIDxDfo2iWctYFVMhoQMrRFPZboRKzinqknyKFHdVxxxAcqQUWJzJHENQo+PsOlht3rr+lxFCQoFbsGzvsAx654/x/lQBP99DcPpYgtMHCN4+luDtAwTvHkvwrknw+VfrPagmAhgNcST8GJLEmHF0hPaLwHskh72LsMfQMKXuIzkzv8ChjcbkMbnXx/n5yXoQbN02ubFFdmWen5Bn9M/WI4h+/znR7xuiQLXqEE2SmFDwXc/lZivJ6dbCXT08wrgyCmm4BTYDZfzkbg2uZsYSyJYpTpllqw1Nc+yvZRvG8NuGDGBcoJVGbGExzhFH49qp1KVHR715I29RkP3WEnKpx+2ap56Uy3X3L1ukRTkLdx+pnmRVvnVClWVlD+i99t6h8wuF1fPytcwLYz2UVhFKU495Ub3H00nJr9FT7lxwOkxrl0Mh5yBFZ7S38+ga7QFXzLnOaG9aKjWU33C09+owFXK+5RaeDlLPzudoFVsESLb/ahCNlNLDNNu/x2s1YBuM/wM)
- **GitHub:** [GitHub - dsanchez31/cesium-sgp4-viewer: Show a whole satellite catalog on a CesiumJS globe, from a list of TLEs: every object at its SGP4 position, its orbit, its name, following the scene's clock. · GitHub](https://github.com/dsanchez31/cesium-sgp4-viewer)
- **npm:** `npm install @dsanchez31/cesium-sgp4-viewer cesium`

TLE data from [CelesTrak](https://celestrak.org), maintained by Dr. T.S. Kelso.

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

David Sanchez

---

<div class="post-metadata">

**Author:** ![donmccurdy](https://sea2.discourse-cdn.com/cesium/user_avatar/community.cesium.com/donmccurdy/32/4683_2.png) [@donmccurdy](https://community.cesium.com/u/donmccurdy)\
**Post date:** [October 2, 2026, 9:03pm UTC](https://community.cesium.com/t/cesium-sgp4-viewer-a-whole-satellite-catalog-16-000-objects-propagated-with-sgp4-on-a-cesiumjs-globe/47447/3 "2026-10-02T21:03:14Z")

</div>

Great demo here @dsanchez31

> [@dsanchez31](#):
>
> 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.

The newer [BufferPointCollection](https://cesium.com/learn/cesiumjs/ref-doc/BufferPointCollection.html) and [BufferPolylineCollection](https://cesium.com/learn/cesiumjs/ref-doc/BufferPolylineCollection.html) 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](https://github.com/CesiumGS/cesium/pull/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. 🙂

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.

---

<div class="post-metadata">

**Author:** ![dsanchez31](https://sea2.discourse-cdn.com/cesium/user_avatar/community.cesium.com/dsanchez31/32/35010_2.png) [@dsanchez31](https://community.cesium.com/u/dsanchez31)\
**Post date:** [October 4, 2026, 4:46pm UTC](https://community.cesium.com/t/cesium-sgp4-viewer-a-whole-satellite-catalog-16-000-objects-propagated-with-sgp4-on-a-cesiumjs-globe/47447/4 "2026-10-04T16:46:08Z")

</div>

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

I’ll definitely look into [cesium#13511](https://github.com/CesiumGS/cesium/pull/13511) and the newer [BufferPointCollection](https://cesium.com/learn/cesiumjs/ref-doc/BufferPointCollection.html) and [BufferPolylineCollection](https://cesium.com/learn/cesiumjs/ref-doc/BufferPolylineCollection.html) 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!
