mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 02:14:01 +00:00
Flights and Military Flights tint aircraft red while the latest poll carries squawk 7500/7600/7700 or an adsb.lol ADS-B emergency status (general/unlawful/nordo/downed). Minimum-fuel and lifeguard priorities are reported but not tinted. The Cockpit HUD aircraft-meta line names the broadcast code in red. The status is not sticky: a cleared code stops highlighting on the next refresh. The analyst/voice query engine gains squawk, emergency and emergencyKind fields. No new source or request: OpenSky state vectors already carry the squawk and adsb.lol/readsb carries both fields. Built by the Hex project (Crew Leo Agile dev team). Co-Authored-By: Claude <[email protected]>
281 lines
13 KiB
JavaScript
281 lines
13 KiB
JavaScript
export {
|
||
GROUND_FLOOR_WARM_MAX_ALT_M,
|
||
POSITION_HISTORY_LIMIT,
|
||
LANDED_MISSING_POLL_LIMIT,
|
||
MISSING_POLL_LIMIT,
|
||
ERROR_BACKOFF_INTERVAL,
|
||
} from './recordPolicy.js';
|
||
import * as Cesium from 'cesium';
|
||
import { EMERGENCY_TINT_CSS } from '../../data/aircraftEmergency.js';
|
||
|
||
/**
|
||
* @module militaryFlights
|
||
* @description Real-time military flight tracking layer powered by the adsb.lol API.
|
||
*
|
||
* Renders aircraft as amber chevron billboards in a single BillboardCollection
|
||
* for GPU-efficient batch drawing. Supports click-to-track: selecting an aircraft
|
||
* spawns an Entity the camera follows, whose position is driven by a
|
||
* dead-reckoning CallbackProperty. The whole fleet renders at
|
||
* now - RENDER_DELAY_SEC so positions interpolate BETWEEN two known fixes
|
||
* instead of extrapolating ahead and snapping back when the next poll lands.
|
||
*
|
||
* Billboard orientation uses alignedAxis set to the WGS84 surface normal at each
|
||
* position so that the rotation angle (heading/track) operates in the local tangent
|
||
* plane where 0 deg = north; near nadir the icons switch to screen-aligned
|
||
* rotation (camera.heading - track) with hysteresis.
|
||
*/
|
||
|
||
/** @constant {number} Milliseconds to wait before retrying after a transient error */
|
||
|
||
/** @constant {number} Max position samples retained per aircraft for dead reckoning */
|
||
|
||
/** @constant {number} Base billboard display scale */
|
||
|
||
export const BILLBOARD_SCALE = 0.7;
|
||
|
||
/** @constant {Cesium.Color} Default amber tint for untracked military billboards */
|
||
|
||
export const MIL_ICON_COLOR = Cesium.Color.fromCssColorString('#FFB800');
|
||
|
||
/** @constant {Cesium.Color} Lighter amber tint applied to the actively tracked aircraft */
|
||
|
||
export const TRACKED_ICON_COLOR = Cesium.Color.fromCssColorString('#FFD166');
|
||
|
||
/** @constant {Cesium.Color} Red tint for aircraft broadcasting an emergency (mirror of flights) */
|
||
|
||
export const EMERGENCY_ICON_COLOR =
|
||
Cesium.Color.fromCssColorString(EMERGENCY_TINT_CSS);
|
||
|
||
// --- Ground traffic (owner reversal 2026-07-03; mirror of flights.js) ---------------
|
||
// adsb.lol/readsb flags ground traffic with alt_baro === "ground" (no separate
|
||
// boolean). Such aircraft are RENDERED instead of floating at the 3 km altitude
|
||
// fallback: same silhouette + rotation pipeline, clickable/trackable/detectable,
|
||
// sticky metadata updating normally. The on-ground flip restyles the existing
|
||
// billboard IN PLACE (landing/takeoff transition, never a removal); ground planes
|
||
// draw no trails. In 3D mode they take model slots like airborne planes (owner
|
||
// decision 2026-07-03 — no air/ground distinction), placed by the one-shot
|
||
// ground snap (see _modelDisplayPosition).
|
||
//
|
||
// TINT: full-strength amber, same as airborne (owner verdict 2026-07-03 field
|
||
// test: the day-1 slate-gray 50%-alpha muted tint was unreadable — "in NYC I can
|
||
// barely see them"). "On the ground" reads from the ×0.8 scale + missing trail;
|
||
// "feed-dropped, coasting" stays the 45%-alpha stale fade.
|
||
/** Ground billboards render slightly smaller so airport clutter stays visually minor. */
|
||
|
||
export const GROUND_SCALE = 0.8;
|
||
|
||
// --- 3D model rendering (mirrors flights.js) -----------------------------------------
|
||
// When enabled, military aircraft render as 3D glTF jet models once the camera is below
|
||
// MODEL_ALT_CEIL_M (zoomed in); higher up they stay flat billboards. Eligibility is
|
||
// FRUSTUM-based (on-screen), and the slots go to either the nearest planes ('proximity')
|
||
// or every in-view plane ('all'), each backed by a hard cap so a draw-call explosion
|
||
// can't tank the frame (no instancing yet). Distinct asset + amber tint set this layer
|
||
// apart from the commercial flights layer.
|
||
|
||
export const JET_MODEL_URL = '/models/jet.glb';
|
||
|
||
export const MODEL_ALT_CEIL_M = 800000;
|
||
// m: below this camera altitude, draw 3D models (raised so it's easy to trigger)
|
||
|
||
export const MODEL_MIN_PX = 24;
|
||
// floor so distant models stay visible without ballooning into a min-pixel blob (mirror of flights.js, whose models now share this layer's ~30 m world size)
|
||
|
||
export const TRACKED_MODEL_MIN_PX = 40;
|
||
// keep the glTF silhouette comparable to the selected 2D glyph at handoff
|
||
|
||
export const TRACKED_MODEL_MAX_PX = 200;
|
||
// owner-selected close-range tracked-target feel
|
||
|
||
export const MODEL_NATIVE_RADIUS_M = 29.83;
|
||
|
||
// jet.glb is transform-applied at real-world scale — native bounding radius
|
||
// 29.83 m at scale 1. ×1 → ~22–43 m aircraft across CLASS_SCALE_3D, matching
|
||
// flights.js world sizes. At the old copied ×24, models rendered
|
||
// 600–1000 m across (invisible at the ~6 km follow range where minimumPixelSize
|
||
// dominates, but zoom under ~1 km put the camera INSIDE the plane). Locked by
|
||
// modelScale.test.mjs.
|
||
|
||
export const MODEL_SCALE = 1;
|
||
|
||
// Per-mode caps + radii — mirror of flights.js. Modes differ by RADIUS (not just cap) so Proximity
|
||
// and All aren't identical when few planes are in range; on-screen planes win the cap (see flights.js).
|
||
|
||
export const MODEL_MAX = 150;
|
||
// 'proximity' cap
|
||
|
||
export const MODEL_MAX_ALL = 350;
|
||
// 'all' cap
|
||
|
||
export const MODEL_PROX_ADD_M = 150000;
|
||
// proximity: model NEW planes within 150 km
|
||
|
||
export const MODEL_PROX_KEEP_M = 185000;
|
||
// proximity: KEEP modeled planes out to 185 km
|
||
|
||
// Cockpit keeps the standard Display radii but lowers the GLB budget. Contacts
|
||
// inside the selected band remain AIR silhouettes when they cannot own a model;
|
||
// contacts outside the band use compact dots.
|
||
|
||
export const COCKPIT_MODEL_MAX = 60;
|
||
// max concurrent GLBs in cockpit (never raises the map cap)
|
||
|
||
export const MODEL_ALL_ADD_M = 400000;
|
||
// all: model NEW planes within 400 km (~to the horizon)
|
||
|
||
export const MODEL_ALL_KEEP_M = 450000;
|
||
// all: KEEP modeled planes out to 450 km
|
||
|
||
export const MODEL_HEADING_OFFSET_DEG = 180;
|
||
// every aircraft GLB is exported nose -X in the shared transform-applied convention
|
||
// Preserve the layer's amber identity while reducing approved texture/livery
|
||
// contribution to a weak diffuse hint, matching civilian launch presentation.
|
||
|
||
export const MODEL_COLOR_BLEND_AMOUNT = 0.94;
|
||
|
||
// airplane.glb (the shared 747) constants for this layer's heavy classes. The
|
||
// asset has its former 24× runtime calibration baked into transform-applied
|
||
// meter-scale geometry; these values mirror flights.js and are regression-pinned.
|
||
|
||
export const PLANE_MODEL_URL = '/models/airplane.glb';
|
||
|
||
export const PLANE_MODEL_SCALE = 1;
|
||
|
||
export const PLANE_NATIVE_RADIUS_M = 34.41;
|
||
|
||
export const PLANE_BELLY_OFFSET_NATIVE = 6.719;
|
||
|
||
// Grounded-model belly offset: jet.glb's centred origin sits 5.631 native units (= meters — this
|
||
// asset is real-world scale) ABOVE its lowest vertex (glTF Y-up scene AABB with node
|
||
// transforms applied — same reader as modelScale.test.mjs, measured 2026-07-03).
|
||
// × MODEL_SCALE(1) × class multiplier ≈ 4.4–8.6 m of lift, so a ground-snapped model
|
||
// rests its lowest geometry (gear/belly) ON the sampled tile skin instead of sinking to
|
||
// the fuselage-centerline origin. Locked against the GLB by modelScale.test.mjs.
|
||
|
||
export const MODEL_BELLY_OFFSET_NATIVE = 5.631;
|
||
|
||
/** Amber fade target for the tracked billboard once the model takes over (mirrors flights.js CYAN_TRANSPARENT). */
|
||
|
||
export const AMBER_TRANSPARENT = MIL_ICON_COLOR.withAlpha(0);
|
||
|
||
export const COCKPIT_CONTACT_SIZE_PX = 6;
|
||
|
||
export const TRACKED_BILLBOARD_SCALE_BY_DISTANCE = new Cesium.NearFarScalar(
|
||
1000,
|
||
3.0,
|
||
8000000,
|
||
0.5,
|
||
);
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Track-history trail state (PRD WS-F F2/F4): a fading polyline behind the
|
||
// tracked aircraft. The accumulation array is intentionally SEPARATE from
|
||
// _positionHistory (capped at POSITION_HISTORY_LIMIT=5 for dead reckoning)
|
||
// so the visible trail can grow to TRAIL_MAX_POINTS fixes.
|
||
// ---------------------------------------------------------------------------
|
||
|
||
/** @constant {string} Military trail hue (PRD F4, pinned). */
|
||
|
||
export const TRAIL_COLOR = '#FFB800';
|
||
|
||
/** @constant {number} Combined cap on trail vertices (backfill + live accumulation). */
|
||
|
||
export const TRAIL_MAX_POINTS = 400;
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Render-behind smoothing (mirrors flights.js): the fleet renders at
|
||
// now - RENDER_DELAY_SEC so positions interpolate BETWEEN two known fixes
|
||
// instead of extrapolating ahead and snapping back when the next poll lands.
|
||
// Removing the delay reintroduces the back/forward oscillation and is a
|
||
// regression.
|
||
// ---------------------------------------------------------------------------
|
||
|
||
/** @constant {number} Display latency in seconds (= one poll interval). */
|
||
|
||
export const RENDER_DELAY_SEC = 15;
|
||
|
||
/** @constant {number} Polls an aircraft may miss before removal (transient adsb.lol dropouts). */
|
||
|
||
// --- Landed-plane fast cull (mirror of flights.js; owner field report
|
||
// 2026-07-02: "phantom" planes lingered ~2 min at airports after touchdown).
|
||
// The feed's ground flag lags the actual landing, so a landed plane's last
|
||
// airborne fixes show it low + slow on the runway; when it then drops out of
|
||
// the poll it has landed, not hit a transient gap — evict after ONE missed
|
||
// poll. Thresholds: below ~500 ft baro (≈150 m MSL — near-sea-level fields
|
||
// only; a high-elevation airport ghost falls back to the normal grace) AND
|
||
// below ~45 kts ground speed (≈23 m/s — rollout/taxi; nothing in normal
|
||
// FLIGHT is this slow, so cruise planes always keep the full grace).
|
||
/** @constant {number} Max baro altitude (ft, MSL) for the landed fast cull (~150 m). */
|
||
|
||
export const LANDED_ALT_MAX_FT = 500;
|
||
|
||
/** @constant {number} Max ground speed (m/s) for the landed fast cull (~45 kts). */
|
||
|
||
export const LANDED_SPEED_MAX_MPS = 23;
|
||
|
||
/** @constant {number} Missed-poll allowance for likely-landed planes (1 = removed on the first missed poll). */
|
||
|
||
// Field-test fix (RS46, 2026-07-06): only contacts rendering below this
|
||
// ellipsoidal height get the below-ground floor clamp + a coarse floor-cell
|
||
// warm. Terrain outside the extreme Himalaya tops out well under this, so
|
||
// cruise traffic (which can never be below ground) costs zero terrain
|
||
// lookups; low pattern/heli work — the class that actually clips hillsides —
|
||
// gets the floor.
|
||
/** @constant {number} Max render altitude (m, ellipsoidal) eligible for the ground-floor clamp. */
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Nadir-stable icon orientation (mirrors flights.js): surface-normal alignment
|
||
// degenerates when the camera looks straight down (the normal is parallel to
|
||
// the view direction and the shader's screen-projected angle is 0/0). Near
|
||
// nadir we switch to screen-aligned billboards with
|
||
// rotation = camera.heading - track (screen-up points at azimuth
|
||
// camera.heading; a CW track t appears t-h from screen-up; billboard rotation
|
||
// is CCW-positive => r = h - t). Discrete switch with hysteresis; rotations
|
||
// are continuous at the boundary with this formula.
|
||
// ---------------------------------------------------------------------------
|
||
|
||
/** @constant {number} Fleet dead-reckoning tick interval (ms) — ~12Hz, not per-frame. */
|
||
|
||
export const FLEET_DR_INTERVAL_MS = 80;
|
||
|
||
/** @constant {number} Max ms between rotation passes while the camera is idle. */
|
||
|
||
export const ROTATION_REFRESH_MS = 1000;
|
||
|
||
/** Max course slew (deg/s) — well above real turns (≤4°/s), hides fix-boundary
|
||
* steps. Scaled down toward COURSE_MIN_DPS at low speed (courseSlewCapDps). */
|
||
|
||
export const COURSE_MAX_DPS = 60;
|
||
|
||
/** Never spend a long render stall's full elapsed time in one visible course step. */
|
||
|
||
export const COURSE_SLEW_DT_MAX_SEC = 0.25;
|
||
|
||
// -- Tracked-display reconciliation (see flights.js for the rationale): absorb a raw
|
||
// position step (warm-up→interpolation handoff, feed glitch, backfill splice) into a
|
||
// correction offset that decays to zero over DR_CORRECTION_MS, so the tracked icon,
|
||
// camera, and trail head never visibly jump — with zero steady-state lag. --
|
||
|
||
export const DR_CORRECTION_MS = 900;
|
||
|
||
/** Bounded on-demand loading for the tracked model (mirror of flights.js). The
|
||
* tracked regime is DEFAULT-ON and its driver runs every `scene.preUpdate`, so
|
||
* a missing or corrupt GLB — or a dead network — would otherwise spin
|
||
* load→reject at frame rate for as long as the contact stays selected.
|
||
* Failures are counted PER SELECTION: a short backoff absorbs a transient
|
||
* blip, then the layer stops asking until the operator selects something else.
|
||
* The billboard is the visual throughout (the handoff only fades it once a
|
||
* model actually renders), so a latched failure degrades to exactly the
|
||
* pre-3D presentation. */
|
||
|
||
export const TRACKED_MODEL_MAX_LOAD_FAILS = 3;
|
||
|
||
export const TRACKED_MODEL_RETRY_BACKOFF_MS = 1500;
|
||
|
||
/** Boost flip = BATCHED release through the fleet tick (mirror of flights.js —
|
||
* destroying the whole fleet synchronously in the style handler stalls the
|
||
* render thread). Models tagged with their load-time boost state; stale queue
|
||
* entries skip; in-flight loads invalidated immediately; tracked reloads
|
||
* synchronously (single primitive). */
|
||
|
||
export const IR_RELOAD_BATCH = 40;
|