mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-22 07:15:47 +00:00
Feat/performance probe fps overlay (#472)
* feat(perf-probe): add FPS overlay toggle and tidy probe modal Add optional rAF-based FPS readout controlled by a persisted probe flag. Remove the separate keyboard shortcut. Collapse all phase sections by default. * perf(fps-overlay): subscribe only to showFpsOverlay flag Add usePerfProbeFlag so the overlay does not re-render when other probe toggles change. Track the animation frame id with a loop-local variable.
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
import { usePerfProbeFlag } from '../utils/perfFlags';
|
||||
|
||||
const SAMPLE_MS = 500;
|
||||
|
||||
/** FPS from rAF callbacks over sliding ~500ms windows; only runs when Performance Probe enables the overlay. */
|
||||
export default function FpsOverlay() {
|
||||
const showFpsOverlay = usePerfProbeFlag('showFpsOverlay');
|
||||
const [fps, setFps] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
if (!showFpsOverlay) {
|
||||
setFps(0);
|
||||
return;
|
||||
}
|
||||
|
||||
let frames = 0;
|
||||
let lastReport = performance.now();
|
||||
let rafId = 0;
|
||||
|
||||
const loop = () => {
|
||||
frames++;
|
||||
const now = performance.now();
|
||||
if (now - lastReport >= SAMPLE_MS) {
|
||||
const elapsedSec = (now - lastReport) / 1000;
|
||||
setFps(Math.round(frames / elapsedSec));
|
||||
frames = 0;
|
||||
lastReport = now;
|
||||
}
|
||||
rafId = requestAnimationFrame(loop);
|
||||
};
|
||||
|
||||
rafId = requestAnimationFrame(loop);
|
||||
return () => cancelAnimationFrame(rafId);
|
||||
}, [showFpsOverlay]);
|
||||
|
||||
if (!showFpsOverlay) return null;
|
||||
|
||||
return createPortal(
|
||||
<div className="fps-overlay" aria-hidden="true">
|
||||
{fps}
|
||||
{' '}
|
||||
<span className="fps-overlay__unit">FPS</span>
|
||||
</div>,
|
||||
document.body,
|
||||
);
|
||||
}
|
||||
@@ -1112,6 +1112,14 @@ export default function Sidebar({
|
||||
<p className="sidebar-perf-modal__hint">
|
||||
Temporary runtime switches to estimate UI effect cost.
|
||||
</p>
|
||||
<label className="sidebar-perf-modal__item">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={perfFlags.showFpsOverlay}
|
||||
onChange={e => setPerfProbeFlag('showFpsOverlay', e.target.checked)}
|
||||
/>
|
||||
<span>Show FPS overlay (requestAnimationFrame rate)</span>
|
||||
</label>
|
||||
<div className="sidebar-perf-modal__cpu">
|
||||
<div className="sidebar-perf-modal__cpu-title">Live CPU (approx)</div>
|
||||
{perfCpu == null ? (
|
||||
@@ -1242,7 +1250,7 @@ export default function Sidebar({
|
||||
/>
|
||||
<span>Disable central route content mount</span>
|
||||
</label>
|
||||
<details className="sidebar-perf-modal__phase sidebar-perf-modal__phase--nested" open>
|
||||
<details className="sidebar-perf-modal__phase sidebar-perf-modal__phase--nested">
|
||||
<summary className="sidebar-perf-modal__phase-title">Shared mainstage layers (multiple pages)</summary>
|
||||
<label className="sidebar-perf-modal__item">
|
||||
<input
|
||||
@@ -1254,7 +1262,7 @@ export default function Sidebar({
|
||||
</label>
|
||||
</details>
|
||||
|
||||
<details className="sidebar-perf-modal__phase sidebar-perf-modal__phase--nested" open>
|
||||
<details className="sidebar-perf-modal__phase sidebar-perf-modal__phase--nested">
|
||||
<summary className="sidebar-perf-modal__phase-title">Home (`/`)</summary>
|
||||
<label className="sidebar-perf-modal__item">
|
||||
<input
|
||||
@@ -1346,7 +1354,7 @@ export default function Sidebar({
|
||||
</label>
|
||||
</details>
|
||||
|
||||
<details className="sidebar-perf-modal__phase sidebar-perf-modal__phase--nested" open>
|
||||
<details className="sidebar-perf-modal__phase sidebar-perf-modal__phase--nested">
|
||||
<summary className="sidebar-perf-modal__phase-title">Tracks (`/tracks`)</summary>
|
||||
<label className="sidebar-perf-modal__item">
|
||||
<input
|
||||
@@ -1390,7 +1398,7 @@ export default function Sidebar({
|
||||
</label>
|
||||
</details>
|
||||
|
||||
<details className="sidebar-perf-modal__phase sidebar-perf-modal__phase--nested" open>
|
||||
<details className="sidebar-perf-modal__phase sidebar-perf-modal__phase--nested">
|
||||
<summary className="sidebar-perf-modal__phase-title">Albums (`/albums`)</summary>
|
||||
<label className="sidebar-perf-modal__item">
|
||||
<input
|
||||
@@ -1402,7 +1410,7 @@ export default function Sidebar({
|
||||
</label>
|
||||
</details>
|
||||
</details>
|
||||
<details className="sidebar-perf-modal__phase" open>
|
||||
<details className="sidebar-perf-modal__phase">
|
||||
<summary className="sidebar-perf-modal__phase-title">Phase 3 — Active diagnostics (quick access)</summary>
|
||||
<label className="sidebar-perf-modal__item">
|
||||
<input
|
||||
|
||||
Reference in New Issue
Block a user