Gzip compression
Impact: ~92% payload reduction (11.6 MB → 915 KB)GZipMiddleware is applied globally on the FastAPI backend with a 1 KB minimum threshold:
ETag caching
Impact: Eliminates JSON parsing on unchanged responses Both/api/live-data/fast and /api/live-data/slow return an ETag header. The frontend stores it and sends If-None-Match on subsequent requests:
Viewport culling
Impact: Reduces rendered features proportional to zoom level The map computes the current viewport bounds on every pan/zoom and applies a 20% buffer:Imperative map updates
Impact: Bypasses React reconciliation for high-frequency layers For layers that update every 15 seconds with thousands of features (flights, satellites, fires), callingsetData() directly on the MapLibre source skips React’s virtual DOM diffing entirely:
Clustered rendering
Impact: Reduces visible feature count at low zoom levels Ships, CCTV cameras, earthquakes, fire hotspots, and data centers use MapLibre’s built-in clustering. At low zoom levels, nearby features are merged into a single cluster marker with a count label. They separate as you zoom in.Debounced viewport updates
Impact: Prevents GeoJSON rebuild thrash during pan/zoom GeoJSON is not rebuilt on every map move event. Instead, viewport bounds updates are debounced:- Standard layers — 300ms debounce after the map stops moving.
- Dense layers (satellites, fires) — 2s debounce, as rebuilding 2,000+ satellite positions or 5,000+ fire hotspots is more expensive.
Position interpolation
Impact: Smooth animation between 15-second data refreshes Aircraft, ships, and satellites don’t teleport between poll cycles. AuseInterpolation hook animates positions on a 10-second tick:
dtSeconds since the last data timestamp. The result is smooth, continuous movement regardless of poll latency.
React.memo
Impact: Prevents unnecessary re-renders of heavy panel components Heavy sidebar components are wrapped withReact.memo so they only re-render when their specific props change:
dataVersion increment from the polling hook would trigger a full re-render of all panels — including the MaplibreViewer, which would restart its GeoJSON build pipeline.
Coordinate precision
Impact: Reduces JSON payload size by ~30% for coordinate-heavy responses All lat/lng values are rounded to 5 decimal places (~1 meter precision) before being stored in the data cache:48.123456789012345) are truncated to 48.12346. For geospatial visualization at any zoom level below ~0.1m resolution, 5 decimals is indistinguishable from the original precision.
Bbox filtering query params
Impact: Reduces server response size for zoomed-in views Both/api/live-data/fast and /api/live-data/slow accept optional s, w, n, e bounding box parameters. When provided, the server filters each data collection to features within the padded bounds before serializing:
_bbox_filter function handles antimeridian-crossing bounding boxes (e.g., viewing the Pacific near the date line) by detecting when west > east after padding.
Optimization summary
| Optimization | Layer | Mechanism |
|---|---|---|
| Gzip compression | Network | GZipMiddleware(minimum_size=1000) |
| ETag caching | Network | MD5 hash of serialized payload |
| Viewport culling | Client + server | 20% padded bounds check |
| Imperative updates | Rendering | source.setData() bypassing React |
| Clustered rendering | Rendering | MapLibre cluster=true |
| Debounced viewport | Client | 300ms / 2s setTimeout |
| Position interpolation | Rendering | 10s tick extrapolation |
React.memo | React | Prevents re-renders on unchanged props |
| Coordinate precision | Network | round(lat, 5) before storage |
| Bbox filtering | Network | Server-side spatial filter |