Skip to content

Releases: hook-365/adsb-3d

v0.6.1: placed maps stay placed

Choose a tag to compare

@hook-365 hook-365 released this 06 Aug 04:18

Two fixes from the demo-recording session on issue #6:

  • AR free-fly is locked to scope-style movement when hit-test placement is available, so a scope parked on real furniture stays there. Headsets without hit-test keep free-fly for manual positioning.
  • Headset performance in busy airspace: trails render at half density (capped to the most recent 300 points) while presenting, cutting the dominant geometry load. An [xr] perf console line every 5 seconds reports frame time and draw calls for further tuning.

Full details in CHANGELOG.md.

v0.6.0: the sky lands on your desk

Choose a tag to compare

@hook-365 hook-365 released this 06 Aug 03:30

The VR/AR release. Every feature here was shaped by real Quest 3 hardware testing from @tyzbit, who also recorded the attached demo video: orbiting live traffic, free-flying through it, and dropping the scope onto actual furniture with AR place mode.

Highlights

  • AR place mode: look at a surface, pull the trigger, the airspace parks there. WebXR hit-test snaps it to tables, desks, and beds.
  • Free-fly, tuned by feel: first-person yaw, deliberate height control, zoom that anchors on what you're looking at. "Years of video games finally paying off."
  • Wrist menu with full settings parity: three pages generated from a declarative spec, guarded by a test so no future setting can silently miss the in-headset UI.
  • Fat lines: altitude lines and trails at real pixel widths scaled to your render resolution. No more 1px shimmer at 5040x2640 per eye.
  • Honest quality readout: the settings panel now reports the actual per-eye resolution your headset granted.
  • Stereo mode for WayVR / crossed-eye viewers: billboard and exit button rendered in both eyes.
  • Mobile bottom sheet: the aircraft detail card no longer eats the map on phones. Fixed-height sheet, internal scroll, photo docked beside the airframe data at its natural aspect.

Full details in CHANGELOG.md. The attached mp4 is the full-length demo; a shorter cut is embedded in the README.

v0.5.3: the ground is where you are

Choose a tag to compare

@hook-365 hook-365 released this 03 Aug 22:27

Changed

  • Flat mode grounds at the home field, not sea level. Without 3D terrain enabled, aircraft altitudes render relative to your station's field elevation (clamped at the map plane) — so a jet rolling out at a 4,200 ft-elevation airport sits on the map instead of floating field-elevation-high above it. With 3D terrain on, geometry stays true MSL, as before.
  • Documentation now states explicitly that ALTITUDE and every FEEDN_ALT are feet MSL.

Pairs with v0.5.0's 3D terrain and v0.5.2's shadow-draped icons: high-elevation stations now read correctly with terrain on or off.

Full details in CHANGELOG.md.

v0.5.2: terrain polish — icons that fall like shadows

Choose a tag to compare

@hook-365 hook-365 released this 03 Aug 22:09

A polish pass on 3D terrain, driven by real-world testing over the Wasatch on a Salt Lake City feed.

Fixed

  • Ground icons now drape over terrain like shadows. The flat ground-projection icons were being sliced by slopes (or, in an intermediate attempt, hovering above them). Each icon is now a segmented mesh whose vertices conform to the terrain under its heading-rotated footprint — it falls across ridgelines the way an actual shadow would, and hides honestly behind mountains. Which is, after all, what a ground projection is.
  • The emergency-squawk ring rides the terrain instead of pulsing at sea level (previously up to thousands of feet underground on high-elevation feeds).
  • No more sea-level flash on load. Aircraft ground anchors rendered at sea level until elevation tiles finished decoding, then popped up one by one as data ticks arrived. An arriving elevation tile now re-anchors every aircraft on the next frame.

Full details in CHANGELOG.md.

v0.5.1: integration tests, retention fix, polite polling

Choose a tag to compare

@hook-365 hook-365 released this 03 Aug 21:36

A patch release, headlined by the project's first merged outside code contribution — thanks @ValkyrieUK!

Added

  • Full-stack integration test suite + CI (#9): a deterministic Docker Compose stack (readsb + ACARS fixtures, TimescaleDB, both backends, the production nginx image in live-only and multi-feed modes) now verifies every push end to end, including a backend restart to catch non-idempotent schema startup.

Fixed

  • Fresh installs silently ended up with no retention policy (#9): the retention call failed on clean database init and the service restarted healthy without it, so data grew without bound. Existing databases were unaffected. Upgrading to this release repairs affected databases automatically — a startup migration detects the missing policy and adds it with your configured RETENTION_DAYS. If you can't upgrade yet, the manual fix is:
    SELECT add_retention_policy('aircraft_positions', INTERVAL '90 days');
  • The suite's timescaledb healthcheck raced the postgres init phase on fast machines; it now probes TCP.

Changed

  • track-service polls remote feeders every 5 s instead of every 1 s (heuristic on the feeder address; FEEDER_POLL_SECONDS overrides in either direction). Local feeders keep the 1 s cadence. Polling a stranger's home connection every second around the clock was impolite.

Full details in CHANGELOG.md.

v0.5.0: the community-issues release

Choose a tag to compare

@hook-365 hook-365 released this 03 Aug 20:41

Everything in this release traces to a GitHub issue (#6, #7, #8, #10).

Added

  • Localization — English, plus machine-drafted German and Spanish pending native review (#10). Language follows the browser locale by default; a drift-guard test keeps all locales in lockstep.
  • Altitude scale slider (#8) — continuous vertical bias from low-altitude detail (pattern traffic spreads apart) through linear to high-altitude detail (flight levels spread apart). Applies consistently to aircraft, trails, playback, heatmap, terrain, and VR.
  • 3D terrain (#7, opt-in) — the basemap rises to real ground elevation (AWS Open Data, no API key). Range rings and markers drape over the hills, ground icons anchor to terrain, the camera stays above the surface, and the detail card shows height above ground. ENABLE_TERRAIN=false disables deploy-wide. Try it with the OpenTopoMap basemap.
  • VR comfort options (#6) — movement model (scope vs free-fly) and turn style (snap vs smooth), in settings and on the wrist menu. B/Y cycles through aircraft nearest-first.

Fixed

  • The AR rendering freeze (#6) — a theme recolor of the removed passthrough sky threw inside the XR frame loop; subscriber fan-outs now isolate failures.
  • A/X recenter no longer teleports the world away; the wrist-menu Labels toggle now governs the VR billboard, which keeps a minimum readable size; AR keeps the basemap as a floating diorama; VR starts at table height.

Full details in CHANGELOG.md.

v0.4.0: performance and UX push

Choose a tag to compare

@hook-365 hook-365 released this 28 May 22:27

A frontend + backend performance and UX push. The headline goal was
to make the Europe / Hetzner feed (~1500 contacts) feel as snappy
as the local feed in both initial load and steady state, and to
let survey aircraft and loitering tankers keep their full in-scope
trails instead of being cut off at 10 minutes.

Added

  • Click to extend trail. Selecting any aircraft now lifts its
    per-hex trail cap and triggers a 24 h history backfill, so a
    single survey orbiting an airfield gets its full pattern even on
    a busy feed. The per-hex cap survives the aircraft dropping out
    and reappearing within the session.
  • URL deep-link isolation. Loading a shared #hex link now
    also applies that hex as the search query, so the recipient
    lands on just that aircraft and its trail. Clearing the search
    box brings the rest of the fleet back.
  • Per-feed trail policy. The local feed defaults to unlimited
    trail length with a 4 h history backfill window, so survey
    aircraft and loitering tankers keep their full in-scope history.
    Higher-density feeds keep the conservative 600-point cap and
    30 min backfill.
  • Stationary sample dedup. Aircraft that haven't moved past the
    jitter threshold only sample once per minute instead of once per
    second, so a parked aircraft over 12 hours accumulates ~720
    trail points instead of ~43k.
  • Altitude inheritance. The Aircraft record carries an
    altFtKnown flag and the store keeps a per-hex last-known
    altitude cache; transient frames that lack alt_baro and
    alt_geom substitute the prior good altitude instead of
    snapping the cone to ground. Historical backfill does the same
    forward-inheritance walk during parsePoints.

Changed

  • Aircraft list is now virtualized. Only rows inside the
    scroll viewport (plus a small overscan) get real DOM. Initial
    load on Europe is dramatically faster and scroll feels native
    at any fleet size. Filter / sort / search changes re-target
    scroll to keep the selected row in view; snapshot-only updates
    leave scrollTop alone.
  • Search filters the map. Typing in the panel search box
    now hides non-matching aircraft from the scene as well as the
    list, matching the behavior of the MIL / GROUND / AIR / EMERG
    filter buttons. Selected aircraft are exempt.
  • Lazy-loaded feature modules. The voice panel, historical
    playback, heatmap layer, and ACARS browser modal are dynamic
    imports now. They no longer ship in the cold-load bundle for
    deployments (or sessions) that don't use them.
  • Browser tab title reads ADS-B 3D · {feed location} and
    updates on feed switch.
  • Backend track-service. /tracks/{hex} and
    /tracks/bulk/timelapse auto-downsample when resolution=full
    is requested over a window wider than 4 hours; targets ~7200
    points across the window, so a 24 h selection-extension call
    returns ~700 kB instead of ~8.6 MB. asyncpg pool max_size
    raised from 20 to 40 so multi-tab and bursty backfill traffic
    no longer pushes the acquire timeout.

Fixed

  • Invisible-aircraft clicks. Three.js's raycaster doesn't
    honor Group.visible = false, so invisible pick proxies inside
    filtered-out aircraft were still registering hits. Clicking on
    empty sky in MIL-filter mode no longer surfaces civilian
    aircraft hiding underneath.
  • Trails dipping to ground. Transient upstream frames with
    no altitude data used to snap the cone and trail to zero
    altitude. The new altitude inheritance keeps the cone at its
    last known altitude through the gap, both live and on backfill.

Performance

The reconciler is the biggest contributor; together these changes
take the steady-state per-frame cost on Europe from "noticeably
laggy" to "indistinguishable from local".

  • Reconciler syncFrame gates per-aircraft work on per-hex rev
    counters from the store. Most frames find every aircraft at the
    same rev as last frame and skip the full refresh block.
  • altitudeColorCached / altitudeColorStyleCached return shared
    Color instances and interned CSS strings bucketed by 250 ft
    altitude steps. refreshTrail, refreshColor, refreshLabel
    switched over, saving ~450 k Color allocations per second on
    a busy feed.
  • Yaw quaternion math is cached against lastTrackDeg and shared
    between the cone and the ground icon.
  • updateLabelLOD skips its per-entry pass when the camera hasn't
    moved past a small epsilon since the last call.
  • Settings subscriber only walks the entry map when one of the
    three visibility-relevant keys actually flipped.
  • Label frustum culling. Labels whose anchor is outside the
    camera view are flipped to visible = false so
    CSS2DRenderer skips them; a panned-in view on Europe does
    ~150 DOM transform writes per render instead of ~1500.
  • Growable + incremental trail buffers. Trail buffer
    allocations grow by doubling as needed. A fast path appends
    only the new tail segments to existing buffer slots when the
    trail's first sample is unchanged. A selected aircraft with a
    multi-hour trail goes from rewriting the entire buffer every
    refresh to writing one new segment.

Tests

127 → 145 unit tests across reconciler / store / filter / altitude
color / parsePoints altitude inheritance.

v0.3.0: WebXR support (Phases 1-5)

Choose a tag to compare

@hook-365 hook-365 released this 28 May 03:31

v0.3.0 brings the full WebXR pipeline online. Any connected headset can now open an immersive session directly from the page.

Enter VR in Settings opens an immersive-vr session with head tracking, controllers as laser pointers, and a world-space billboard above the selected aircraft. Trigger pulls raycast aircraft picks through the same selection path as a mouse click, so the detail panel and follow-cam stay in sync.

In-VR wrist menu on the left controller, tilted toward the eye. The right laser hovers rows and the trigger activates them: cycle Theme, cycle Basemap, toggle Range rings, Labels, or Alt lines. No need to lift the headset to change anything.

Locomotion via the thumbsticks and buttons. Left stick scales the world from tabletop to room-scale (persisted across sessions). Right stick snap-turns 30° per push. Right A/X button recenters the scope in front of you.

Enter AR on devices that support immersive-ar (Quest 3, Vision Pro, etc.). Sky and basemap drop away and aircraft float in your living room via passthrough.

See CHANGELOG.md for the full entry.

v0.2.0 — Color themes + FAA chart basemaps

Choose a tag to compare

@hook-365 hook-365 released this 28 May 01:00

v0.2.0 — color themes + FAA chart basemaps

Five built-in palettes (Midnight Glass, Daylight, Sectional Chart,
Phosphor CRT, High Contrast) with prefers-color-scheme auto mode and
live in-place switching across CSS and Three.js materials.

Five FAA aeronautical chart basemaps (US only): Sectional, Sectional

  • Roads, Helicopter, IFR Low, IFR High — served via VFRMap with
    auto-discovery of the 56-day chart cycle at container start.

See CHANGELOG.md for the full entry.

ADS-B 3D v0.1.0

Choose a tag to compare

@hook-365 hook-365 released this 22 May 03:40

First public release of ADS-B 3D — a real-time 3D visualization of ADS-B aircraft traffic. A ground-up TypeScript / Three.js rewrite of the original vanilla-JS app.

Highlights

  • Live 3D view — per-second updates with a tar1090 altitude color palette; click-through aircraft detail cards with photos, filed routes, and autopilot data.
  • Historical playback — scrub the last 1h / 24h / 7d at 1×–60× speed, with a 3D airway-density heatmap.
  • ACARS — optional datalink message decoding with OOOI flight-phase tracking.
  • Multi-feed — switch between multiple receivers in-place, no page reload.
  • VHF voice scanner — optional call-based airband audio panel.

Ships as a single nginx Docker image plus optional track-service and acars-service.

Getting started

See the README for the quick start, and CHANGELOG.md for full detail.

Multi-arch images (linux/amd64, arm64, arm/v7) build from this tag and publish to GHCR:

  • ghcr.io/hook-365/adsb-3d:0.1.0
  • ghcr.io/hook-365/adsb-track-service:0.1.0
  • ghcr.io/hook-365/adsb-acars-service:0.1.0