feat(web): add step-back to replay viewer
Build and Deploy / build-and-push (push) Successful in 3m47s
Build and Deploy / build-and-push (push) Successful in 3m47s
The "⏮ Restart" button now steps back one move at a time instead of resetting to the beginning. Re-creates the ReplayPlayer and fast-forwards to (step_idx - 1) without rendering intermediate frames; the CSS transform transition then animates each card back to its previous position. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -30,7 +30,7 @@
|
|||||||
<section id="board"></section>
|
<section id="board"></section>
|
||||||
|
|
||||||
<section id="controls">
|
<section id="controls">
|
||||||
<button id="btn-prev" disabled>⏮ Restart</button>
|
<button id="btn-prev" disabled>◀ Back</button>
|
||||||
<button id="btn-play">▶ Play</button>
|
<button id="btn-play">▶ Play</button>
|
||||||
<button id="btn-step">⏭ Step</button>
|
<button id="btn-step">⏭ Step</button>
|
||||||
<span id="progress" class="muted">step 0 / 0</span>
|
<span id="progress" class="muted">step 0 / 0</span>
|
||||||
|
|||||||
@@ -301,16 +301,30 @@ btnPlay.addEventListener("click", () => {
|
|||||||
}, STEP_INTERVAL_MS);
|
}, STEP_INTERVAL_MS);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/// Step the player back one move. Re-creates the ReplayPlayer and fast-
|
||||||
|
/// forwards to (step_idx - 1) without rendering intermediate frames, then
|
||||||
|
/// renders once so the CSS transition animates each card to its previous
|
||||||
|
/// position.
|
||||||
|
function stepBack() {
|
||||||
|
if (!player || player.step_idx() === 0) return;
|
||||||
|
if (playInterval) {
|
||||||
|
clearInterval(playInterval);
|
||||||
|
playInterval = null;
|
||||||
|
btnPlay.textContent = "▶ Play";
|
||||||
|
}
|
||||||
|
const target = player.step_idx() - 1;
|
||||||
|
player = new ReplayPlayer(replayJson);
|
||||||
|
for (let i = 0; i < target; i++) {
|
||||||
|
player.step();
|
||||||
|
}
|
||||||
|
render(player.state());
|
||||||
|
btnPrev.disabled = player.step_idx() === 0;
|
||||||
|
btnStep.disabled = false;
|
||||||
|
btnPlay.disabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
btnPrev.addEventListener("click", () => {
|
btnPrev.addEventListener("click", () => {
|
||||||
if (!replayJson) return;
|
if (player) stepBack();
|
||||||
// Drop every existing card so the next render fades them all in
|
|
||||||
// at the freshly-dealt positions. Without this, cards from the
|
|
||||||
// current state would slide to wherever the new deal puts them
|
|
||||||
// — confusing since the deal is supposed to look like a fresh
|
|
||||||
// start, not a continuation.
|
|
||||||
cardEls.forEach((el) => el.remove());
|
|
||||||
cardEls.clear();
|
|
||||||
resetPlayer();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
bootstrap();
|
bootstrap();
|
||||||
|
|||||||
Reference in New Issue
Block a user