Files
gods-eye-view/src/ui/frameRateMonitor.js
T
Bilawal SidhuandBilawal Sidhu a3a19883b4 feat: add Scope controls and conditional HUD text backplates (#1410)
* feat: add scope controls and conditional HUD backplates

* docs: assign scope changelog to PR 1410

* fix: stabilize title backplate and brighten secondary labels

---------

Co-authored-by: Bilawal Sidhu <[email protected]>
2026-10-26 00:24:27 -05:00

86 lines
2.4 KiB
JavaScript

import { t } from '../i18n/index.js';
/** Count rendered globe frames while the optional readout is visible. */
export function createFrameRateMonitor({ viewer, documentRef = document }) {
const host = documentRef.getElementById('title-bar');
const frameEvent = viewer?.scene?.postRender;
if (!host || !frameEvent) return { destroy() {} };
const readout = documentRef.createElement('div');
readout.className = 'frame-rate-readout scene-text-holdout';
readout.hidden = true;
// i18n-ignore: FPS is a unit code, the same in every language
readout.textContent = 'FPS —';
readout.title = t('Rendered globe frames per second · toggle with `');
host.appendChild(readout);
let removeFrameListener = null;
let timer = null;
let frames = 0;
let startedAt = 0;
let destroyed = false;
function hide() {
readout.hidden = true;
removeFrameListener?.();
removeFrameListener = null;
clearInterval(timer);
timer = null;
}
function show() {
frames = 0;
startedAt = performance.now();
// i18n-ignore: FPS is a unit code, the same in every language
readout.textContent = 'FPS —';
readout.hidden = false;
removeFrameListener = frameEvent.addEventListener(() => {
frames++;
});
timer = setInterval(() => {
const now = performance.now();
const elapsed = now - startedAt;
readout.textContent =
// i18n-ignore: FPS is a unit code, the same in every language
documentRef.hidden || elapsed <= 0
? 'FPS —'
: `FPS ${Math.round((frames * 1000) / elapsed)}`;
frames = 0;
startedAt = now;
}, 1000);
}
function onKeyDown(event) {
if (event.key !== '`' && event.code !== 'Backquote') return;
if (
event.defaultPrevented ||
event.repeat ||
event.isComposing ||
event.ctrlKey ||
event.altKey ||
event.metaKey ||
event.shiftKey
)
return;
if (
event.target?.isContentEditable ||
event.target?.closest?.(
'input, textarea, select, [contenteditable]:not([contenteditable="false"])',
)
)
return;
event.preventDefault();
if (readout.hidden) show();
else hide();
}
documentRef.addEventListener('keydown', onKeyDown);
return {
destroy() {
if (destroyed) return;
destroyed = true;
hide();
documentRef.removeEventListener('keydown', onKeyDown);
readout.remove();
},
};
}