Skip to content

Commit 2d34939

Browse files
committed
framerate independent
1 parent e1a609c commit 2d34939

1 file changed

Lines changed: 33 additions & 19 deletions

File tree

index.html

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -55,29 +55,15 @@
5555
const GRAVITY = 0.15;
5656
let gravityOn = true;
5757
let unraveling = false;
58+
let unravelIdx = -1;
5859
window.addEventListener('keydown', (e) => {
5960
if (e.key === 'f' || e.key === 'F') {
6061
gravityOn = !gravityOn;
6162
if (gravityOn && !unraveling) {
6263
unraveling = true;
6364
hint.style.opacity = '0';
64-
// Unlock letters from the tail end, one every few frames
65-
let nextUnlock = letters.length - 1;
66-
// Find first still-locked from the tail
67-
while (nextUnlock >= 0 && !letters[nextUnlock].locked) nextUnlock--;
68-
function unravelStep() {
69-
if (!gravityOn || nextUnlock < 0) { unraveling = false; return; }
70-
for (let j = 0; j < 1 && nextUnlock >= 0; j++) {
71-
if (letters[nextUnlock].locked) {
72-
letters[nextUnlock].locked = false;
73-
letters[nextUnlock].px = letters[nextUnlock].x;
74-
letters[nextUnlock].py = letters[nextUnlock].y - 0.5;
75-
}
76-
nextUnlock--;
77-
}
78-
requestAnimationFrame(unravelStep);
79-
}
80-
unravelStep();
65+
unravelIdx = letters.length - 1;
66+
while (unravelIdx >= 0 && !letters[unravelIdx].locked) unravelIdx--;
8167
}
8268
}
8369
});
@@ -309,6 +295,19 @@
309295

310296
// Physics
311297
function simulate() {
298+
// Unravel step (one letter per fixed tick)
299+
if (unraveling) {
300+
if (!gravityOn || unravelIdx < 0) { unraveling = false; }
301+
else if (letters[unravelIdx].locked) {
302+
letters[unravelIdx].locked = false;
303+
letters[unravelIdx].px = letters[unravelIdx].x;
304+
letters[unravelIdx].py = letters[unravelIdx].y - 0.5;
305+
unravelIdx--;
306+
} else {
307+
unravelIdx--;
308+
}
309+
}
310+
312311
// Unlock propagation
313312
for (let i = letters.length - 2; i >= 0; i--) {
314313
if (letters[i].locked && !letters[i + 1].locked) {
@@ -402,8 +401,23 @@
402401
}
403402
}
404403

405-
function render() {
406-
simulate();
404+
// Fixed-timestep loop: simulate at 60Hz regardless of display refresh rate
405+
const FIXED_DT = 1 / 60;
406+
const MAX_STEPS = 4; // cap to avoid spiral of death
407+
let accumulator = 0;
408+
let lastTime = -1;
409+
410+
function render(now) {
411+
if (lastTime < 0) { lastTime = now; requestAnimationFrame(render); return; }
412+
const dt = Math.min((now - lastTime) / 1000, MAX_STEPS * FIXED_DT);
413+
lastTime = now;
414+
accumulator += dt;
415+
416+
while (accumulator >= FIXED_DT) {
417+
simulate();
418+
accumulator -= FIXED_DT;
419+
}
420+
407421
for (let i = 0; i < letters.length; i++) {
408422
if (!letters[i].locked) els[i].classList.add('draggable');
409423
els[i].style.transform = `translate(${letters[i].x}px, ${letters[i].y}px)`;

0 commit comments

Comments
 (0)