From 92ac36bc67fbba32ece141623cb6224df0444540 Mon Sep 17 00:00:00 2001 From: Nils Pukropp Date: Mon, 2 Nov 2026 12:57:01 +0100 Subject: [PATCH] Remove the wheel-up rewind Holding the drop and the w key no longer spin it back and restart the tune; the help and the first-start hint no longer mention it. --- web/index.html | 2 -- web/src/main.ts | 37 ++----------------------------------- web/src/player.ts | 27 --------------------------- web/src/visual.ts | 6 ------ 4 files changed, 2 insertions(+), 70 deletions(-) diff --git a/web/index.html b/web/index.html index 1c3a456..6d57295 100644 --- a/web/index.html +++ b/web/index.html @@ -241,7 +241,6 @@
double-tap
like
swipe up / down
next / previous
drag waveform
seek
-
hold the drop
wheel up: rewind the tune
click · space
play / pause
@@ -256,7 +255,6 @@
z
zen: just the drop
c
filters and settings
h
history
-
w · hold drop
wheel up: rewind the tune
0–9 · , .
jump to 0–90 % · seek 5 s
m · + −
mute · volume
?
this help
diff --git a/web/src/main.ts b/web/src/main.ts index 6365369..46ba9a0 100644 --- a/web/src/main.ts +++ b/web/src/main.ts @@ -16,7 +16,6 @@ const PREFETCH_AHEAD = 4; // fetch more when this close to the end const SKIP_SECONDS = 8; // leaving earlier than this counts as a skip const COMPLETE_RATIO = 0.85; const DOUBLE_TAP_MS = 300; -const LONG_PRESS_MS = 550; // holding the drop this long rewinds the tune const PRELOAD_AFTER_MS = 2500; // start buffering the next track once this one has played a bit const KEEP_BUILT = 3; // cards further than this from the current one drop their elements const HISTORY_AFTER = 1; // s heard before a track goes into the history @@ -322,14 +321,6 @@ async function share(card: Card): Promise { } } -/// The rewind: spin the drop back, slow the tune down, and run it again. -function wheelUp(): void { - if (!current()) return; - visual.wheelUp(); - player.wheelUp(); - toast("wheel up!"); -} - // Player events ----------------------------------------------------------- player.on("timeupdate", () => { @@ -430,38 +421,15 @@ if ("mediaSession" in navigator) { } } -// Tap to play/pause, double-tap to like, hold to rewind --------------------- +// Tap to play/pause, double-tap to like ------------------------------------- let lastTap: { at: number; card: Card | null; toggled: boolean } = { at: 0, card: null, toggled: false }; -let press: { timer: number; x: number; y: number } | null = null; -let pressFired = false; -feedEl.addEventListener("pointerdown", (e) => { - if (!started || !(e.target as Element).closest(".card.current .art")) return; - pressFired = false; - press = { - x: e.clientX, - y: e.clientY, - timer: window.setTimeout(() => { - press = null; - pressFired = true; - wheelUp(); - }, LONG_PRESS_MS), - }; -}); -const cancelPress = (e: PointerEvent) => { - if (press && (e.type !== "pointermove" || Math.hypot(e.clientX - press.x, e.clientY - press.y) > 10)) { - clearTimeout(press.timer); - press = null; - } -}; -for (const ev of ["pointermove", "pointerup", "pointercancel"]) feedEl.addEventListener(ev, (e) => cancelPress(e as PointerEvent)); // A long press opens the context menu on some phones. feedEl.addEventListener("contextmenu", (e) => { if ((e.target as Element).closest(".art")) e.preventDefault(); }); feedEl.addEventListener("click", (e) => { if (pager.suppressClick) return; - if (pressFired) { pressFired = false; return; } const target = e.target as Element; if (target.closest("button, a, input, .wave-wrap")) return; const el = target.closest(".card"); @@ -554,7 +522,7 @@ function start(): void { showUpNext(); if (!localStorage.getItem(HINT_KEY)) { localStorage.setItem(HINT_KEY, "1"); - toast(isTouch ? "tap to pause · double-tap to like · hold the drop to rewind" + toast(isTouch ? "tap to pause · double-tap to like · swipe up for next" : "click to pause · double-click to like · ? for shortcuts", 5000); } } @@ -990,7 +958,6 @@ document.addEventListener("keydown", (e) => { else if (k === "r" && card) actions.radio(card); else if (k === "x" && card) dislike(card); else if (k === "s" && card) share(card); - else if (k === "w") wheelUp(); else if (k === "h") sheets.history.open(); else if (k === "c") sheets.filters.open(); else if (k === "v") { setVisuals(visual.visuals === "liquid" ? "simple" : "liquid"); toast(`${visual.visuals} visuals`); } diff --git a/web/src/player.ts b/web/src/player.ts index 374d95d..3245e3f 100644 --- a/web/src/player.ts +++ b/web/src/player.ts @@ -20,7 +20,6 @@ const CROSSFADE_KEY = "pl8inf.crossfade"; const BASS_KEY = "pl8inf.bass"; const BASS_DB = 6; // gain of the bass boost's low shelf … const BASS_HZ = 120; // … below this -const TAPE_STOP = 0.45; // s the rewind's tape stop takes type Hls = HlsType; type HlsClass = typeof HlsType; @@ -301,32 +300,6 @@ export class Player { this.audio.pause(); } - /// The soundsystem rewind: the record is pulled back, the music slows down and - /// drops in pitch, and the tune starts again from the top. - async wheelUp(): Promise { - const a = this.audio; - if (a.paused) { - this.seek(0); - this.resume(); - return; - } - const pitch = a.preservesPitch; - a.preservesPitch = false; - const t0 = performance.now(); - await new Promise((done) => { - const step = () => { - const k = Math.min(1, (performance.now() - t0) / 1000 / TAPE_STOP); - a.playbackRate = Math.max(0.1, 1 - 0.9 * k * k); - if (k < 1) requestAnimationFrame(step); - else done(); - }; - requestAnimationFrame(step); - }); - a.playbackRate = 1; - a.preservesPitch = pitch; - this.seek(0); - } - seek(seconds: number): void { const a = this.audio; a.currentTime = Math.max(0, Math.min(a.duration || 0, seconds)); diff --git a/web/src/visual.ts b/web/src/visual.ts index 594a668..d05585d 100644 --- a/web/src/visual.ts +++ b/web/src/visual.ts @@ -143,12 +143,6 @@ export class Visualizer { return this.blob?.lost ? null : this.blob; } - /// Spin the drop backwards, hard: the rewind. - wheelUp(): void { - this.blob?.spin.fling([0, -26, 0]); - this.start(); - } - /// A play/pause from a tap was taken back by the second tap of a double-tap. cancelFlash(): void { this.blob?.settleIcon();