perf(cuesheet): add temporary first-render metrics scaffold

Adds a dev-only, self-contained instrumentation module under
common/devtools/cuesheet-metrics to measure the first-render (mount) cost
of virtualised cuesheet rows, so scroll-performance changes can be backed
by before/after numbers.

- Console-only API on window.__cuesheetPerf (deterministic scroll benchmark
  + manual start/stop), gated by isDev && ?perf=1, runtime-inert in prod.
- Whole-row mount probe plus per-subsystem attribution: colour calc,
  getVisibleCells, AutoTextarea autosize, Tooltip portal mount,
  useReactiveTextInput hotkey-handler init; FPS/long-frame timing.
- All edits to existing files tagged // PERF-METRICS for a one-pass teardown.

Temporary: to be deleted once the optimizations are proven.
This commit is contained in:
Claude
2026-06-15 20:17:01 +00:00
parent c238147b75
commit eab63e838d
12 changed files with 437 additions and 21 deletions
@@ -14,6 +14,7 @@ import {
import EmptyPage from '../../../common/components/state/EmptyPage';
import EmptyTableBody from '../../../common/components/state/EmptyTableBody';
import { useEntryActionsContext } from '../../../common/context/EntryActionsContext';
import { useCuesheetPerf } from '../../../common/devtools/cuesheet-metrics/useCuesheetPerf'; // PERF-METRICS
import type { RundownSource } from '../../../common/hooks-query/useScopedRundown';
import type { ExtendedEntry } from '../../../common/utils/rundownMetadata';
import { usePersistedRundownOptions } from '../../../features/rundown/rundown.options';
@@ -72,6 +73,7 @@ export default function CuesheetTable({
const setScrollHandler = useEventSelection((state) => state.setScrollHandler);
const virtuosoRef = useRef<TableVirtuosoHandle | null>(null);
useCuesheetPerf(virtuosoRef); // PERF-METRICS
const { listeners } = useTableNav();
const meta = useMemo(
@@ -5,6 +5,7 @@ import { CSSProperties, memo, useMemo } from 'react';
import { IoEllipsisHorizontal } from 'react-icons/io5';
import IconButton from '../../../../common/components/buttons/IconButton';
import { timeSync, useMountProbe } from '../../../../common/devtools/cuesheet-metrics/usePerfMark'; // PERF-METRICS
import type { ExtendedEntry } from '../../../../common/utils/rundownMetadata';
import { cx, getAccessibleColour } from '../../../../common/utils/styleUtils';
import { AppMode } from '../../../../ontimeConfig';
@@ -56,25 +57,29 @@ function EventRow({
const openMenu = useCuesheetTableMenu((store) => store.openMenu);
useMountProbe('EventRow', true); // PERF-METRICS
const { rowBgColour, backgroundColor, mutedText } = useMemo(() => {
const accessible = getAccessibleColour(colour);
const tmpColour = cssOrHexToColour(accessible.color) as RGBColour;
return timeSync('row.colourCalc', () => { // PERF-METRICS
const accessible = getAccessibleColour(colour);
const tmpColour = cssOrHexToColour(accessible.color) as RGBColour;
let rowBgColour: string | undefined;
if (isLoaded) {
rowBgColour = '#087A27'; // $active-green
} else if (colour) {
const accessibleBg = cssOrHexToColour(accessible.backgroundColor);
if (accessibleBg !== null) {
rowBgColour = colourToHex({ ...accessibleBg, alpha: accessibleBg.alpha * 0.25 });
let rowBgColour: string | undefined;
if (isLoaded) {
rowBgColour = '#087A27'; // $active-green
} else if (colour) {
const accessibleBg = cssOrHexToColour(accessible.backgroundColor);
if (accessibleBg !== null) {
rowBgColour = colourToHex({ ...accessibleBg, alpha: accessibleBg.alpha * 0.25 });
}
}
}
return {
rowBgColour,
backgroundColor: accessible.backgroundColor,
mutedText: colourToHex({ ...tmpColour, alpha: tmpColour.alpha * 0.8 }),
};
return {
rowBgColour,
backgroundColor: accessible.backgroundColor,
mutedText: colourToHex({ ...tmpColour, alpha: tmpColour.alpha * 0.8 }),
};
}); // PERF-METRICS
}, [colour, isLoaded]);
return (
@@ -117,9 +122,7 @@ function EventRow({
{eventIndex}
</td>
)}
{table
.getRow(rowId)
.getVisibleCells()
{timeSync('row.getVisibleCells', () => table.getRow(rowId).getVisibleCells()) // PERF-METRICS
.map((cell) => {
return (
<td