feat(audio-player): scrub interaction rework — free-flow drag, pixel magnetism, touch pull-away precision (plan §9)
Mouse: drag is free-flow 1:1 (rail only on Shift+drag, now with window from/to edge labels); clicks land with pixel magnetism (MAGNET_RADIUS_PX=10) — the old 5-second threshold was sub-pixel on long books and never fired, which was the 'chapter scrub isn't accurate' bug. Hover inside the radius locks the tooltip to the line with a highlight. Shift+click jumps to the nearest line from anywhere. Touch: drag is an incremental cursor (applyDrag) whose scale tightens continuously as the finger pulls off the bar (dragScale, exponential 10^(-|dy|/80px)) — the rail is the feedback: window shrinks with the zoom (touchRailSpan) and lifts toward the finger (railLiftPx). Dialog retitled 'Shortcuts & interactions' with a Mouse & touch section driven by POINTER_GUIDE (audio-keys.ts). Old seconds-threshold snapToChapter deleted. 133 unit tests; 19 Playwright checks on the KJV (1189ch) and Gardens (34ch) books.
This commit is contained in:
1 parent
1f30602c23
commit
96fd2aad42
6 files changed
+386
-69
No files matched your search
@@ -213,6 +213,26 @@ export function visibleKeymap(): KeyActionSpec[] {
|
||||
return KEYMAP.filter((spec) => !spec.hidden);
|
||||
}
|
||||
|
||||
// Pointer/wheel/touch interactions (plan §9) are not key events — the
|
||||
// dispatcher never sees them — but they belong in the same dialog so
|
||||
// every scrub gesture is discoverable in one place. templ x-fors this
|
||||
// table through the component's `pointerGuide` property (same binding
|
||||
// pattern as speeds/skipChoices).
|
||||
export interface PointerGuideRow {
|
||||
// Badge label, e.g. "Shift + drag".
|
||||
label: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export const POINTER_GUIDE: readonly PointerGuideRow[] = [
|
||||
{ label: "Click", description: "Seek — lands on a chapter line within a pixel's reach" },
|
||||
{ label: "Drag", description: "Free scrub across the whole bar" },
|
||||
{ label: "Shift + click", description: "Jump to the nearest chapter line" },
|
||||
{ label: "Shift + drag", description: "Precision rail (±5 min) around the nearest line" },
|
||||
{ label: "Wheel", description: "Nudge ±5s (Shift: ±60s)" },
|
||||
{ label: "Touch + pull away", description: "Scrub, then drag off the bar for fine control" },
|
||||
];
|
||||
|
||||
// resolveShortcut maps a keydown's (key, altKey) to an action, or null
|
||||
// when nothing claims it. Single characters match case-insensitively;
|
||||
// Alt-qualified bindings take precedence order for free: a plain key
|
||||
|
||||
Reference in new issue
Block a user