fix: use requestAnimationFrame + real timestamps for clock simulation
Replace setInterval with requestAnimationFrame loop that tracks elapsed time via performance.now(). Clock ticks now fire based on real time rather than assuming perfect interval spacing, so user interactions (toggling inputs, dragging gates) no longer cause the clock to stutter or pause. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,9 +1,18 @@
|
||||
// Clock simulation engine
|
||||
// Clock simulation engine — uses real timestamps for consistent timing
|
||||
import { state } from './state.js';
|
||||
import { evaluateAll } from './gates.js';
|
||||
import { forceRecordSample } from './waveform.js';
|
||||
|
||||
export function simTick() {
|
||||
let lastTickTime = 0;
|
||||
let animFrameId = null;
|
||||
|
||||
function simLoop(now) {
|
||||
if (!state.simRunning) return;
|
||||
|
||||
// Fire ticks that are due based on real elapsed time
|
||||
while (now - lastTickTime >= state.simSpeed) {
|
||||
lastTickTime += state.simSpeed;
|
||||
|
||||
// Toggle all CLOCK gates
|
||||
state.gates.forEach(g => {
|
||||
if (g.type === 'CLOCK') {
|
||||
@@ -11,10 +20,12 @@ export function simTick() {
|
||||
}
|
||||
});
|
||||
evaluateAll();
|
||||
// Force record even if evaluateAll didn't detect change
|
||||
if (state.recording && state.waveformVisible) {
|
||||
forceRecordSample();
|
||||
}
|
||||
}
|
||||
|
||||
animFrameId = requestAnimationFrame(simLoop);
|
||||
}
|
||||
|
||||
export function startSim() {
|
||||
@@ -29,18 +40,18 @@ export function startSim() {
|
||||
state.waveformVisible = true;
|
||||
document.getElementById('waveform-panel').classList.add('visible');
|
||||
document.getElementById('sim-btn').classList.add('active');
|
||||
// Trigger resize via event so renderer picks it up
|
||||
window.dispatchEvent(new Event('resize'));
|
||||
}
|
||||
|
||||
state.simInterval = setInterval(simTick, state.simSpeed);
|
||||
lastTickTime = performance.now();
|
||||
animFrameId = requestAnimationFrame(simLoop);
|
||||
updateSimUI();
|
||||
}
|
||||
|
||||
export function stopSim() {
|
||||
state.simRunning = false;
|
||||
if (state.simInterval) clearInterval(state.simInterval);
|
||||
state.simInterval = null;
|
||||
if (animFrameId) cancelAnimationFrame(animFrameId);
|
||||
animFrameId = null;
|
||||
updateSimUI();
|
||||
}
|
||||
|
||||
@@ -57,10 +68,8 @@ export function updateSimUI() {
|
||||
}
|
||||
|
||||
export function adjustSpeed(delta) {
|
||||
const wasRunning = state.simRunning;
|
||||
state.simSpeed = Math.max(50, Math.min(2000, state.simSpeed + delta));
|
||||
if (state.simRunning) {
|
||||
clearInterval(state.simInterval);
|
||||
state.simInterval = setInterval(simTick, state.simSpeed);
|
||||
}
|
||||
// No need to restart — the loop reads simSpeed dynamically
|
||||
updateSimUI();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user