mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 19:04:02 +00:00
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:
74 files changed
+7320
-90
No files matched your search
@@ -1943,6 +1943,98 @@ try {
|
||||
}),
|
||||
);
|
||||
|
||||
// Cyber relocates its collapsed briefing header into the expanded utility
|
||||
// lane. Exercise actual height changes without reload and measure both cards.
|
||||
await page.evaluate(() => {
|
||||
const manager = window.__godsEyeView.styleManager;
|
||||
manager._setHudVariant('cyber');
|
||||
manager.hud.setMode('on');
|
||||
manager._setCockpitDisclosure('display', false);
|
||||
manager._setCockpitDisclosure('radio', true);
|
||||
});
|
||||
const cyberRadioOrder = await page.evaluate(() => {
|
||||
const manager = window.__godsEyeView.styleManager;
|
||||
manager.cockpitView.syncSignalLayout();
|
||||
const display = document
|
||||
.getElementById('cockpit-display-toggle-btn')
|
||||
.closest('.cockpit-utility-control');
|
||||
const radio = document
|
||||
.getElementById('cockpit-radio-toggle-btn')
|
||||
.closest('.cockpit-utility-control');
|
||||
const displayRect = display.getBoundingClientRect();
|
||||
const radioRect = radio.getBoundingClientRect();
|
||||
return {
|
||||
display: displayRect.toJSON(),
|
||||
radio: radioRect.toJSON(),
|
||||
displayExpanded: display.classList.contains('is-expanded'),
|
||||
radioExpanded: radio.classList.contains('is-expanded'),
|
||||
gap: radioRect.top - displayRect.bottom,
|
||||
};
|
||||
});
|
||||
check(
|
||||
'Cyber expanding Radio preserves the authored Display-then-Radio order',
|
||||
!cyberRadioOrder.displayExpanded
|
||||
&& cyberRadioOrder.radioExpanded
|
||||
&& cyberRadioOrder.display.height > 0
|
||||
&& cyberRadioOrder.radio.height > 0
|
||||
&& cyberRadioOrder.gap >= 7,
|
||||
JSON.stringify(cyberRadioOrder),
|
||||
);
|
||||
await page.screenshot({ path: path.join(shotsDir, 'cyber-radio-order.png') });
|
||||
await page.evaluate(() => {
|
||||
const manager = window.__godsEyeView.styleManager;
|
||||
manager._setCockpitDisclosure('radio', false);
|
||||
manager._setCockpitDisclosure('display', true);
|
||||
});
|
||||
const cyberStyleStates = await page.evaluate(() => {
|
||||
const manager = window.__godsEyeView.styleManager;
|
||||
const states = [];
|
||||
for (const style of ['normal', 'surveillance', 'thermal', 'retro']) {
|
||||
document.querySelector(`.style-btn[data-style="${style}"]`).click();
|
||||
states.push({
|
||||
requestedStyle: style,
|
||||
activeStyle: manager.activeStyle,
|
||||
hud: manager.hud.getVariant(),
|
||||
theme: document.documentElement.dataset.uiTheme,
|
||||
selector: document.getElementById('hud-layout-select').value,
|
||||
savedHud: manager.getVisualState().hud.variant,
|
||||
});
|
||||
}
|
||||
return states;
|
||||
});
|
||||
check('Cockpit visual-style controls retain Cyber HUD, selector, shell and saved layout',
|
||||
cyberStyleStates.every(state => state.activeStyle === state.requestedStyle
|
||||
&& state.hud === 'cyber' && state.theme === 'cyber'
|
||||
&& state.selector === 'cyber' && state.savedHud === 'cyber'),
|
||||
JSON.stringify(cyberStyleStates));
|
||||
for (const height of [987, 720, 640, 900]) {
|
||||
await page.setViewport({ width: 1440, height, deviceScaleFactor: 1 });
|
||||
await new Promise((resolve) => setTimeout(resolve, 400));
|
||||
const geometry = await page.evaluate(() => {
|
||||
const signal = document.getElementById('cockpit-signal-stream');
|
||||
const utility = document.getElementById('cockpit-utility-controls');
|
||||
const expanded = utility.querySelector('.cockpit-utility-control.is-expanded');
|
||||
const s = signal.getBoundingClientRect();
|
||||
const u = expanded.getBoundingClientRect();
|
||||
const toggle = document.getElementById('cockpit-signal-toggle');
|
||||
const t = toggle.getBoundingClientRect();
|
||||
const hit = document.elementFromPoint(t.x + t.width / 2, t.y + t.height / 2);
|
||||
return { height: innerHeight, theme: document.documentElement.dataset.uiTheme,
|
||||
collapsed: signal.dataset.collapsed, signal: s.toJSON(), utility: u.toJSON(),
|
||||
reachable: Boolean(hit && toggle.contains(hit)),
|
||||
contained: u.bottom <= s.top - 7 && s.bottom < innerHeight,
|
||||
};
|
||||
});
|
||||
check(`Cyber collapsed Live Signals remains visible and reachable after resize to ${height}px`,
|
||||
geometry.theme === 'cyber' && geometry.collapsed === 'true'
|
||||
&& geometry.signal.width > 0 && geometry.signal.height > 0
|
||||
&& geometry.reachable && geometry.contained, JSON.stringify(geometry));
|
||||
if (height === 640 || height === 900) {
|
||||
await page.screenshot({ path: path.join(shotsDir, `cyber-resize-${height}.png`) });
|
||||
}
|
||||
}
|
||||
await page.evaluate(() => window.__godsEyeView.styleManager._setHudVariant('operator'));
|
||||
|
||||
const signalTransition = await page.evaluate(() => {
|
||||
const manager = window.__godsEyeView.styleManager;
|
||||
const cockpit = manager.cockpitView;
|
||||
|
||||
Reference in new issue
Block a user