feat(hud): Cyber HUD theme with GPU contact sonar (#706)

Add the opt-in Cyber HUD layout with coordinated map and cockpit panel
styling, GPU-only contact sonar (rings, range, power, opacity, sector) with
native-rendering fallback, and set_cyber_sonar voice controls. Sonar visual
style inspired by kk376's tactical naval sonar (#214).

Co-authored-by: Sameh Khamis <[email protected]>
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
authored and GitHub committed 2026-09-23 20:31:56 -07:00
1 parent f913066cf2
commit 513dc87a0e
74 files changed
+7320 -90

No files matched your search

+18 -1
View File
@@ -1,3 +1,5 @@
import { HUD_LAYOUTS } from '../hudLayoutPolicy.js';
// Canonical action arguments. Descriptive wording is supplied separately.
const schemas = [
{
@@ -313,11 +315,26 @@ const schemas = [
},
layout: {
type: 'string',
enum: ['tactical', 'operator', 'minimal'],
enum: [...HUD_LAYOUTS],
},
},
},
},
{
name: 'set_cyber_sonar',
parameters: {
type: 'object',
additionalProperties: false,
properties: {
enabled: { type: 'boolean' },
rings: { type: 'integer', minimum: 3, maximum: 12 },
rangePct: { type: 'integer', minimum: 60, maximum: 120 },
intensityPct: { type: 'integer', minimum: 0, maximum: 100 },
opacityPct: { type: 'integer', minimum: 35, maximum: 100 },
sectorDeg: { type: 'integer', minimum: 8, maximum: 60 },
},
},
},
{
name: 'set_detection',
parameters: {
+15 -5
View File
@@ -15,14 +15,21 @@ const stable = (value) =>
)
: value;
test('the complete Realtime tool payload pins the additive analyst, satellite and Local ADS-B release', () => {
test('the complete Realtime tool payload pins the additive analyst, satellite, Local ADS-B and Cyber release', () => {
const digest = createHash('sha256')
.update(JSON.stringify(stable(GEV_REALTIME_TOOLS)))
.update(
JSON.stringify(
stable(
GEV_REALTIME_TOOLS.filter((tool) => tool.name !== 'set_cyber_sonar'),
),
),
)
.digest('hex');
assert.equal(
digest,
// Re-derived for the additive `local-adsb` set_layer_visibility value.
'4de5c78425d8233794cfd37fdb797605ae93611ba71b7208f4d912b587a0e859',
// Re-derived for the additive `local-adsb` set_layer_visibility value and
// the Cyber HUD layout; the separate sonar tool is excluded above.
'590d537d93e132ac64ac5e211ad5bb9d7d1b1f22e2dd963dda5465fab4510a3b',
);
});
@@ -80,7 +87,7 @@ test('metadata cannot add tools, fields, types or enum values', () => {
test('all legacy action arguments are byte-identical after removing the deliberate additions', () => {
const legacy = structuredClone(GEV_ACTION_SCHEMAS).filter(
(tool) => tool.name !== 'next_satellite_pass',
(tool) => !['next_satellite_pass', 'set_cyber_sonar'].includes(tool.name),
);
const layers = legacy.find((tool) => tool.name === 'analyst_query').parameters
.properties.layers.items;
@@ -106,6 +113,9 @@ test('all legacy action arguments are byte-identical after removing the delibera
}
}
// Independently derived by executing trusted c9f9896 actionSchemas in the restricted container.
const hud = legacy.find((tool) => tool.name === 'set_hud').parameters
.properties.layout;
hud.enum = hud.enum.filter((layout) => layout !== 'cyber');
assert.equal(
createHash('sha256').update(JSON.stringify(legacy)).digest('hex'),
'820fff21658f6907e1010b2b79c5431a77f4e34afd2277d62d8de46c368b6f8c',
+11
View File
@@ -1058,6 +1058,17 @@ export function createGevActionRunner({
return { ...out, hud: styleManager.getControlState().hud };
}
if (name === 'set_cyber_sonar') {
if (typeof styleManager?.setCyberSonar !== 'function') {
return {
ok: false,
action: 'set_cyber_sonar',
error: 'Cyber sonar controls are unavailable.',
};
}
return { action: 'set_cyber_sonar', ...styleManager.setCyberSonar(args) };
}
if (name === 'set_detection') {
const result = styleManager.setDetection({
enabled: typeof args.enabled === 'boolean' ? args.enabled : undefined,