mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 10:24:02 +00:00
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]>
125 lines
4.5 KiB
JavaScript
125 lines
4.5 KiB
JavaScript
/**
|
|
* Resolve where Cockpit's Display/Radio strip hangs in the right margin.
|
|
*
|
|
* The strip is anchored under the REC readout it shares that margin with, and
|
|
* is pulled back up whenever the briefing card below would otherwise be
|
|
* overrun — never above `minTop`, so it can't climb into the topline. The
|
|
* returned `maxHeight` is measured from that resolved top, so a corridor the
|
|
* strip cannot honour by moving is honoured by shrinking instead.
|
|
*
|
|
* @param {object} input
|
|
* @param {number} input.recBottom Bottom edge of the REC readout, in px.
|
|
* @param {number} input.signalTop Top edge of the briefing card, in px.
|
|
* @param {number} input.stripHeight Rendered height of the strip, in px.
|
|
* @param {number} input.viewportHeight Viewport height, in px.
|
|
* @param {number} [input.collapsedHeight] Height of one collapsed launcher.
|
|
* @param {number} [input.recGap] Clearance under the REC readout.
|
|
* @param {number} [input.signalGap] Clearance above the briefing card.
|
|
* @param {number} [input.minTopFloor] Absolute ceiling for the strip, in px.
|
|
* @param {number} [input.minTopRatio] Viewport-relative ceiling, 0..1.
|
|
* @param {boolean} [input.signalCollapsed] Whether the briefing card is collapsed.
|
|
* @param {boolean} [input.utilityExpanded] Whether Display or Radio is expanded.
|
|
* @param {number} [input.bottomInset] Reserved viewport space below an expanded panel.
|
|
* @param {number} [input.signalHeight] Collapsed briefing header reserved below the utility.
|
|
* @param {boolean} [input.reserveViewportLane] Theme relocates the briefing below the expanded utility.
|
|
* @returns {{ top: number, maxHeight: number }}
|
|
*/
|
|
export function resolveCockpitUtilityAnchor({
|
|
recBottom,
|
|
signalTop,
|
|
stripHeight,
|
|
viewportHeight,
|
|
collapsedHeight = 0,
|
|
recGap = 12,
|
|
signalGap = 8,
|
|
minTopFloor = 96,
|
|
minTopRatio = 0.12,
|
|
signalCollapsed = false,
|
|
utilityExpanded = false,
|
|
bottomInset = 80,
|
|
signalHeight = 0,
|
|
reserveViewportLane = false,
|
|
}) {
|
|
const viewport = Math.max(0, Number(viewportHeight) || 0);
|
|
const minTop = Math.max(minTopFloor, viewport * minTopRatio);
|
|
const anchoredTop = Math.max(minTop, (Number(recBottom) || 0) + recGap);
|
|
const strip = Math.max(0, Number(stripHeight) || 0);
|
|
const signal = Number(signalTop);
|
|
const expandedLaneBottom = Math.max(
|
|
0,
|
|
viewport -
|
|
Math.max(0, Number(bottomInset) || 0) -
|
|
Math.max(0, Number(signalHeight) || 0),
|
|
);
|
|
const lowerBound =
|
|
reserveViewportLane && signalCollapsed && utilityExpanded
|
|
? expandedLaneBottom
|
|
: Number.isFinite(signal)
|
|
? signal
|
|
: viewport;
|
|
const clearedTop = lowerBound - signalGap - strip;
|
|
const top = Math.max(minTop, Math.min(anchoredTop, clearedTop));
|
|
const floor = Math.max(0, Number(collapsedHeight) || 0) || 50;
|
|
|
|
return { top, maxHeight: Math.max(floor, lowerBound - top - signalGap) };
|
|
}
|
|
|
|
/**
|
|
* Resolve whether a collapsed Cockpit utility launcher can share the desktop
|
|
* corridor with the currently expanded utility panel.
|
|
*
|
|
* @param {object} input
|
|
* @param {number} input.availableHeight
|
|
* @param {number} input.expandedHeight
|
|
* @param {number} input.collapsedHeight
|
|
* @param {number} [input.gap]
|
|
* @param {number} [input.minimumExpandedHeight]
|
|
* @returns {{ primaryOnly: boolean, expandedMaxHeight: number }}
|
|
*/
|
|
export function resolveCockpitUtilityLayout({
|
|
availableHeight,
|
|
expandedHeight,
|
|
collapsedHeight,
|
|
gap = 7,
|
|
minimumExpandedHeight = 120,
|
|
}) {
|
|
const available = Math.max(
|
|
minimumExpandedHeight,
|
|
Number(availableHeight) || 0,
|
|
);
|
|
const expanded = Math.max(0, Number(expandedHeight) || 0);
|
|
const collapsed = Math.max(0, Number(collapsedHeight) || 0);
|
|
const spacing = Math.max(0, Number(gap) || 0);
|
|
const primaryOnly = expanded + spacing + collapsed > available;
|
|
|
|
return {
|
|
primaryOnly,
|
|
expandedMaxHeight: Math.max(
|
|
minimumExpandedHeight,
|
|
available - (primaryOnly ? 0 : spacing + collapsed),
|
|
),
|
|
};
|
|
}
|
|
|
|
/** Shared Cyber panel slot, with footer controls above the lower frame (83vh). */
|
|
export function resolveCyberCockpitPanelLane({
|
|
viewportHeight,
|
|
top,
|
|
launcherHeight = 60,
|
|
signalHeight = 44,
|
|
contactHeight = 64,
|
|
}) {
|
|
const gap = 8;
|
|
const footerHeight = Math.max(
|
|
contactHeight + gap,
|
|
launcherHeight + signalHeight + gap * 2,
|
|
);
|
|
const bottom = viewportHeight * 0.82;
|
|
const panelHeight = Math.max(120, bottom - top - footerHeight);
|
|
return {
|
|
panelHeight,
|
|
utilityHeight: panelHeight + gap + launcherHeight,
|
|
signalTop: top + panelHeight + launcherHeight + gap * 2,
|
|
};
|
|
}
|