From d9fac6d88e494db331f50501aafe50baa35cac33 Mon Sep 17 00:00:00 2001 From: Bilawal Sidhu <106619546+bilawalsidhu@users.noreply.github.com> Date: Mon, 14 Sep 2026 21:15:29 -0500 Subject: [PATCH] feat(ui): tilt and north-up compass controls (#571) Supersedes #442 by @yashveeeeeeer, ported onto the current component layout with fixes from review. Verified before merge: format, package boundaries, unit suite, build, and the browser tracking suite; a browser harness for the change where one applies; adversarial review applied. Co-authored-by: Yashveer Singh --- CHANGELOG.md | 9 + docs/CURRENT-STATE.md | 21 +- scripts/format-scope.json | 2 + scripts/package-boundaries.json | 3 + src/cockpitMarkup.test.mjs | 19 +- src/ui/applicationShell.js | 18 + src/ui/cameraOrientationControls.js | 269 ++++++++++++ src/ui/cameraOrientationControls.test.mjs | 491 ++++++++++++++++++++++ src/ui/shellElements.js | 2 + src/ui/styles/cockpit.css | 9 +- src/ui/styles/recording.css | 8 +- src/ui/styles/responsive.css | 23 + src/ui/styles/status.css | 27 ++ src/ui/templates/scene-chrome.html | 7 + 14 files changed, 895 insertions(+), 13 deletions(-) create mode 100644 src/ui/cameraOrientationControls.js create mode 100644 src/ui/cameraOrientationControls.test.mjs diff --git a/CHANGELOG.md b/CHANGELOG.md index 168d709cd..d78afc657 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -163,6 +163,15 @@ of current runtime behavior, see [`docs/CURRENT-STATE.md`](docs/CURRENT-STATE.md ### Added +- Two map-orientation controls sit beside Share in the top-center globe + actions. Tilt Map swings between a straight-down map and a 35-degree oblique + around the point under the centre of the view, keeping that point and the + distance to it. North Up rotates around the same point until north is at the + top, keeping the pitch, and its needle shows the current bearing. Both decline + without moving the camera when nothing is under the centre of the view, and + both follow Reset Globe out of Clean UI, recording, Scene playback and Cockpit + (#442 — thanks @yashveeeeeeer). + - Add Open Calgary traffic cameras as a keyless CCTV source pack (thanks @rileygramlich): the public City of Calgary catalog, frames pinned to the city's own host and upgraded to HTTPS, with the Open Government Licence – diff --git a/docs/CURRENT-STATE.md b/docs/CURRENT-STATE.md index 4305e0356..9fc27133a 100644 --- a/docs/CURRENT-STATE.md +++ b/docs/CURRENT-STATE.md @@ -1450,7 +1450,15 @@ This is the current runtime/source-of-truth snapshot for the project. > user intent. > Display orders 3D immediately above Celestial and Clean UI immediately > below it. The top-center action group places Clear Layers to the left of -> Share and Reset Globe to the right. Clear Layers turns off the currently +> Share, then Tilt Map and North Up, and Reset Globe to the right. Tilt Map +> swings the camera between a straight-down map and a 35-degree oblique around +> the point under the centre of the view, keeping that point and the distance +> to it; North Up rotates around the same point until north is at the top, +> keeping the pitch. Its needle shows the current bearing. Both decline +> without moving the camera when nothing is under the centre of the view (a +> camera facing the sky), and both are explicit camera actions, so either one +> releases a followed aircraft the way the other camera controls do. They +> follow Reset Globe out of Clean UI, recording, Scene playback and Cockpit. Clear Layers turns off the currently > selected manager-owned data layers, including an active Context choice, > while retaining visual, HUD, map, and panel settings. A disabled layer may > still release camera work that it owns through its normal teardown. @@ -1496,8 +1504,9 @@ This is the current runtime/source-of-truth snapshot for the project. > the Cockpit HUD at 145), scrolling internally when the layer list is longer than > the corridor. Cesium's credit line is never passable and still bounds the > corridor. Layer toggles stay live from there, and collapsing returns the -> plain launcher. The map-only Clear, Share, and Reset Globe actions are hidden -> for the duration of Cockpit, both as a group and as individual controls. +> plain launcher. The map-only Clear, Share, Tilt Map, North Up, and Reset +> Globe actions are hidden for the duration of Cockpit, both as a group and as +> individual controls. > It uses the `radar` symbol; both tabs are reachable with Tab and Left/Right arrows switch between them. Its action row > places the single Cockpit entry before Search Nearby Sites. Cockpit removes > the duplicate floating map entry and topline exit; the bottom-center @@ -1607,9 +1616,9 @@ This is the current runtime/source-of-truth snapshot for the project. > tray inside the screen. > Adaptive remeasurement preserves the user's > scroll position across Tactical, Minimal, and HUD Off layouts. -> During an active Scene run, Clear Selected Layers and Reset Globe remain -> hidden until playback stops or completes because the Scene transport owns -> layer and camera sequencing for that interval. +> During an active Scene run, Clear Selected Layers, Tilt Map, North Up and +> Reset Globe remain hidden until playback stops or completes because the +> Scene transport owns layer and camera sequencing for that interval. > The Cockpit Contact summary exposes Previous and Next contact navigation > plus its collapse control; it does not offer a Focus action because the > first-person Cockpit camera remains owned by the tracked aircraft. diff --git a/scripts/format-scope.json b/scripts/format-scope.json index 8832b5ff7..054639107 100644 --- a/scripts/format-scope.json +++ b/scripts/format-scope.json @@ -150,6 +150,8 @@ "scripts/qa-visual-input.mjs", "src/ui/displayControls.js", "src/ui/displayControls.test.mjs", + "src/ui/cameraOrientationControls.js", + "src/ui/cameraOrientationControls.test.mjs", "src/ui/effects.js", "src/ui/visualEffects.js", "src/ui/visualPresets.js", diff --git a/scripts/package-boundaries.json b/scripts/package-boundaries.json index 23f7383d4..6ca0583d9 100644 --- a/scripts/package-boundaries.json +++ b/scripts/package-boundaries.json @@ -458,6 +458,7 @@ "src/data/installationFeedback.js", "src/data/layerState.js", "src/data/militaryAwarenessEngine.js", + "src/data/scenePick.js", "src/keySetupCore.mjs", "src/loadingFeedback.js", "src/locationStatus.js", @@ -473,6 +474,7 @@ "src/styles/surveillance.js", "src/styles/thermal.js", "src/ui/applicationShell.js", + "src/ui/cameraOrientationControls.js", "src/ui/applicationShortcuts.js", "src/ui/cctv.js", "src/ui/cctvBindings.js", @@ -1490,6 +1492,7 @@ "src/styles/surveillance.js", "src/styles/thermal.js", "src/ui/applicationShell.js", + "src/ui/cameraOrientationControls.js", "src/ui/applicationShortcuts.js", "src/ui/cctv.js", "src/ui/cctvBindings.js", diff --git a/src/cockpitMarkup.test.mjs b/src/cockpitMarkup.test.mjs index 8acf28d16..371c0bc2c 100644 --- a/src/cockpitMarkup.test.mjs +++ b/src/cockpitMarkup.test.mjs @@ -45,7 +45,7 @@ test('Cockpit has one reset action beside its bottom exit path', () => { ); const topCenterActions = html.match(/