24 files, -319 LoC. Behaviour preserved, 369/369 tests green. - hermes-ink caches: shared lruEvict helper for the four parallel LRU caches (stringWidth, wrapText, sliceAnsi, lineWidth); touch-on-read stays inlined per cache; tightened output.ts skip-slice fast path. - wheelAccel: trimmed provenance header, collapsed env parsing, ternary dispatch in computeWheelStep. - perfPane: folded ensureLogDir into once-flag, spread-with-overrides for fastPath/phases instead of full rebuilds. - env: extracted truthy() (used 4×). - virtualHeights: collapsed user/diff/slash height bumps; trail+todos estimate. - useInputHandlers: scrollIdleTimer cleanup on unmount, ?? undefined shorthand. - useMainApp: dropped dead liveTailVisible IIFE and liveProgress indirection. - appLayout, markdown, messageLine, entry: vertical rhythm, dropped narration comments, inlined one-shot vars. - fix: empty catch blocks → /* best-effort */ for no-empty lint.
29 lines
756 B
TypeScript
29 lines
756 B
TypeScript
// FPS counter overlay (HERMES_TUI_FPS=1). Zero-cost when disabled.
|
|
|
|
import { Text } from '@hermes/ink'
|
|
import { useStore } from '@nanostores/react'
|
|
|
|
import { SHOW_FPS } from '../config/env.js'
|
|
import { $fpsState } from '../lib/fpsStore.js'
|
|
|
|
const fpsColor = (fps: number) => (fps >= 50 ? 'green' : fps >= 30 ? 'yellow' : 'red')
|
|
|
|
export function FpsOverlay() {
|
|
if (!SHOW_FPS) {
|
|
return null
|
|
}
|
|
|
|
return <FpsOverlayInner />
|
|
}
|
|
|
|
function FpsOverlayInner() {
|
|
const { fps, lastDurationMs, totalFrames } = useStore($fpsState)
|
|
|
|
// Zero-pad widths so digit churn doesn't jitter the corner.
|
|
return (
|
|
<Text color={fpsColor(fps)}>
|
|
{fps.toFixed(1).padStart(5)}fps · {lastDurationMs.toFixed(1).padStart(5)}ms · #{totalFrames}
|
|
</Text>
|
|
)
|
|
}
|