import type Decimal from 'break_eternity.js'; import { useEffect, useRef } from 'react'; import type { PointerEvent } from 'react'; interface Props { time: Decimal; onTick: () => void; onReset: () => void; onInitialize: () => void; } const HOLD_TICK_INTERVAL_MS = 1000; const MIN_TICK_INTERVAL_MS = 50; export default function Topbar({ time, onTick, onReset, onInitialize }: Props) { const timeoutRef = useRef | null>(null); // Mutable, not React state: doTick reschedules itself via setTimeout, so it must always read // and write the CURRENT speed directly — a value captured in a render's closure (e.g. via // useState) would stay frozen for the lifetime of that closure, since nothing ever forces // doTick to be re-created from a fresh render while a hold is in progress. const speedRef = useRef(HOLD_TICK_INTERVAL_MS); function stopHolding() { if (timeoutRef.current !== null) { clearTimeout(timeoutRef.current); timeoutRef.current = null; } speedRef.current = HOLD_TICK_INTERVAL_MS; } function doTick() { onTick(); speedRef.current = Math.max(MIN_TICK_INTERVAL_MS, Math.pow(speedRef.current, 0.97)); timeoutRef.current = setTimeout(doTick, speedRef.current); } function startHolding(e: PointerEvent) { if (e.button !== 0) return; e.currentTarget.setPointerCapture(e.pointerId); stopHolding(); doTick(); } useEffect(() => { window.addEventListener('blur', stopHolding); return () => { window.removeEventListener('blur', stopHolding); stopHolding(); }; }, []); return (

Граф ресурсов детерминированная тиковая симуляция

Время {time.toStringWithDecimalPlaces(4)}
); }