The viewer server provides a browser-based 3D visualization of satellite constellations using CesiumJS. It runs a local HTTP server that serves a Cesium globe and generates CZML data on demand for 21 analysis layer types.
humeris serve
humeris serve --port 9000Pre-loads three Walker shells (500/450/400 km, 1584 sats each) and live
ISS data from CelesTrak. Opens http://localhost:<port> in your browser.
# Generate constellation_viewer.html
python scripts/view_constellation.py
# Generate and open in browser
python scripts/view_constellation.py --openProduces a ~10 MB self-contained HTML file with baked-in CZML. No server required — open the file directly in any browser.
Server mode starts with these Walker shells:
| Shell | Altitude | Inclination | Planes x Sats | Phase Factor | RAAN Offset |
|---|---|---|---|---|---|
| Walker-500 | 500 km | 30° | 22 x 72 | 17 | 0.0° |
| Walker-450 | 450 km | 30° | 22 x 72 | 17 | 5.45° |
| Walker-400 | 400 km | 30° | 22 x 72 | 17 | 10.9° |
Plus live ISS data from CelesTrak (animated track).
The viewer dispatches 21 analysis types via _generate_czml(). Each uses
sensible defaults that can be overridden via the params dict in the API.
| Type | What it shows | Default behaviour |
|---|---|---|
walker / celestrak |
Satellite constellation orbits | Animated if ≤100 sats, snapshot if >100 |
eclipse |
Satellites colored by shadow state | Snapshot: green/orange/red points. Animated: interval-based color |
coverage |
Ground heatmap of visible satellite count | Snapshot or animated. 10° grid, 10° min elevation |
ground_track |
Sub-satellite polyline trace | First satellite, 2h duration, 60s step |
ground_station |
Station marker + visibility circle + access windows | 10° min elevation, 6-sat subset for access |
| Type | What it shows | Default behaviour |
|---|---|---|
sensor |
Ground-level FOV ellipses following sub-satellite point | 30° circular half-angle |
isl |
Satellite points + ISL polylines colored by SNR | Ka-band, 5000 km range, 100-sat cap |
network_eclipse |
ISL links colored by endpoint eclipse state | Ka-band, 5000 km range, 100-sat cap |
coverage_connectivity |
Ground rectangles colored by coverage × Fiedler value | Ka-band, 10° grid, 100-sat cap |
| Type | What it shows | Default behaviour |
|---|---|---|
fragility |
Satellites colored by spectral fragility index | Ka-band, 1 orbital period control horizon, 100-sat cap |
hazard |
Satellites fade green→red over projected orbital lifetime | Cd=2.2, A=0.01 m², m=4 kg. Duration = ½ lifetime capped 1 yr |
precession |
J2 RAAN drift over extended timeline | 7-day duration, 15-min step, 24-sat subset |
conjunction |
Two-satellite close approach replay with proximity line | states[0] vs states[n/2], ±30 min, 10s step |
kessler_heatmap |
Altitude × inclination debris density heatmap | 200-2000 km, 0-180°, 50 km × 10° bins |
conjunction_hazard |
Conjunction screening with NASA-STD-8719.14 hazard levels | 2h window, 100 km threshold, ROUTINE/WARNING/CRITICAL coloring |
dop_grid |
Ground heatmap colored by dilution of precision | 10° grid |
radiation |
Satellites colored by radiation environment | 2h duration, 60s step |
beta_angle |
Satellites colored by solar beta angle | Snapshot |
deorbit |
Satellites colored by deorbit compliance status | Cd=2.2, A=0.01 m², m=4 kg |
station_keeping |
Satellites colored by station-keeping ΔV budget | Cd=2.2, A=0.01 m², m=4 kg |
cascade_sir |
SIR epidemic cascade debris evolution | 2h duration, 60s step |
relative_motion |
Relative motion trajectory between two satellites | states[0] vs states[1], 2h duration |
maintenance |
Satellites colored by maintenance schedule status | Cd=2.2, A=0.01 m², m=4 kg |
Used by isl, fragility, network_eclipse, and coverage_connectivity:
_DEFAULT_LINK_CONFIG = LinkConfig(
frequency_hz=26e9, # 26 GHz Ka-band
transmit_power_w=10.0, # 10 W
tx_antenna_gain_dbi=35.0, # 35 dBi
rx_antenna_gain_dbi=35.0, # 35 dBi
system_noise_temp_k=500.0, # 500 K
bandwidth_hz=100e6, # 100 MHz
additional_losses_db=2.0, # 2 dB
required_snr_db=10.0, # 10 dB
)Used by sensor:
_DEFAULT_SENSOR = SensorConfig(
sensor_type=SensorType.CIRCULAR,
half_angle_deg=30.0,
)Used by hazard:
_DEFAULT_DRAG = DragConfig(
cd=2.2, # Drag coefficient
area_m2=0.01, # Cross-sectional area (m²)
mass_kg=4.0, # Satellite mass (kg)
)O(n²) analyses cap satellite count to prevent lockup:
| Constant | Value | Used by |
|---|---|---|
_MAX_TOPOLOGY_SATS |
100 | isl, fragility, network_eclipse, coverage_connectivity |
_MAX_PRECESSION_SATS |
24 | precession |
_SNAPSHOT_THRESHOLD |
100 | auto mode selection (animated vs snapshot) |
Pass custom configurations through the params dict when adding layers
via the API:
{
"type": "isl",
"source_layer": "layer-1",
"params": {
"max_range_km": 8000.0
}
}Internal params (prefixed with _) can override default configs:
| Param key | Type | Applies to |
|---|---|---|
_link_config |
LinkConfig |
isl, fragility, network_eclipse, coverage_connectivity |
_sensor |
SensorConfig |
sensor |
_drag_config |
DragConfig |
hazard |
_station |
GroundStation |
ground_station |
max_range_km |
float |
isl, network_eclipse |
control_duration_s |
float |
fragility |
lat_step_deg |
float |
coverage |
lon_step_deg |
float |
coverage |
min_elevation_deg |
float |
coverage |
duration |
timedelta |
all (default 2h) |
step |
timedelta |
all (default 60s) |
from datetime import datetime, timezone
from humeris.domain.constellation import ShellConfig, generate_walker_shell
from humeris.domain.propagation import derive_orbital_state
from humeris.adapters.viewer_server import LayerManager, create_viewer_server
epoch = datetime.now(tz=timezone.utc)
# Create layer manager
mgr = LayerManager(epoch=epoch)
# Add a constellation
shell = ShellConfig(altitude_km=550, inclination_deg=53,
num_planes=6, sats_per_plane=10,
phase_factor=1, raan_offset_deg=0, shell_name="Demo")
sats = generate_walker_shell(shell)
states = [derive_orbital_state(s, epoch, include_j2=True) for s in sats]
layer_id = mgr.add_layer(
name="Constellation:Demo", category="Constellation",
layer_type="walker", states=states, params={},
)
# Add analysis layer referencing the constellation's states
eclipse_id = mgr.add_layer(
name="Analysis:Eclipse", category="Analysis",
layer_type="eclipse", states=states, params={},
)
# Add a ground station
gs_id = mgr.add_ground_station(
name="Delft", lat_deg=52.0, lon_deg=4.4, source_states=states[:6],
)
# Start server
server = create_viewer_server(mgr, port=8765)
server.serve_forever()