fix(audio): Shift+grab opens the precision rail anchored at the playhead

The first grab implementation degraded Shift+grab to a quarter-speed
relative crawl — losing the ±5-minute rail the user expects when they
grab the handle with Shift held. The rail is back: Shift+grab anchors
railWindow at the CURRENT position (not the nearest chapter line, and
never teleports the playhead on pointerdown); plain grab stays relative
1:1. GRAB_FINE_SCALE is deleted as dead code, and the dialog guide
documents the restored gesture.
This commit is contained in:
John O'Keefe committed 2026-10-27 19:04:59 -04:00
1 parent b462c7fb44
commit e5d4744977
4 files changed
+38 -37

No files matched your search

+4 -7
View File
@@ -10,7 +10,6 @@ import {
dragScale,
DRAG_REF_PX,
DRAG_SCALE_MIN,
GRAB_FINE_SCALE,
GRAB_SLOP_PX,
isHandleGrab,
nearestChapterLine,
@@ -236,15 +235,13 @@ describe("isHandleGrab / applyGrab (§9 handle grab: no teleport)", () => {
);
});
it("crawls at fine scale without teleporting when Shift toggles mid-drag", () => {
it("moves 1:1 with pointer travel and clamps to the book", () => {
const pxPerSecond = 800 / duration26h;
expect(applyGrab(5000, 100, pxPerSecond, duration26h, GRAB_FINE_SCALE)).toBeCloseTo(
5000 + 100 * ((1 / pxPerSecond) * GRAB_FINE_SCALE),
expect(applyGrab(5000, 100, pxPerSecond, duration26h)).toBeCloseTo(
5000 + (100 / 800) * duration26h,
5,
);
// Scale changes only affect SUBSEQUENT travel — a zero-delta move
// with a new scale must leave the position alone.
expect(applyGrab(5000, 0, pxPerSecond, duration26h, GRAB_FINE_SCALE)).toBe(5000);
expect(applyGrab(50, 100, 0, duration26h)).toBe(50);
});
it("clamps to the book and survives a dead bar", () => {