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.
This commit is contained in:
nvrl committed 2026-11-02 12:57:01 +01:00
1 parent aa0e28d326
commit 92ac36bc67
4 files changed
+2 -70

No files matched your search

-2
View File
@@ -241,7 +241,6 @@
<dt>double-tap</dt><dd>like</dd> <dt>double-tap</dt><dd>like</dd>
<dt>swipe up / down</dt><dd>next / previous</dd> <dt>swipe up / down</dt><dd>next / previous</dd>
<dt>drag waveform</dt><dd>seek</dd> <dt>drag waveform</dt><dd>seek</dd>
<dt>hold the drop</dt><dd>wheel up: rewind the tune</dd>
</dl> </dl>
<dl class="pointer-only"> <dl class="pointer-only">
<dt>click · space</dt><dd>play / pause</dd> <dt>click · space</dt><dd>play / pause</dd>
@@ -256,7 +255,6 @@
<dt>z</dt><dd>zen: just the drop</dd> <dt>z</dt><dd>zen: just the drop</dd>
<dt>c</dt><dd>filters and settings</dd> <dt>c</dt><dd>filters and settings</dd>
<dt>h</dt><dd>history</dd> <dt>h</dt><dd>history</dd>
<dt>w · hold drop</dt><dd>wheel up: rewind the tune</dd>
<dt>0–9 · , .</dt><dd>jump to 0–90 % · seek 5 s</dd> <dt>0–9 · , .</dt><dd>jump to 0–90 % · seek 5 s</dd>
<dt>m · + −</dt><dd>mute · volume</dd> <dt>m · + −</dt><dd>mute · volume</dd>
<dt>?</dt><dd>this help</dd> <dt>?</dt><dd>this help</dd>
+2 -35
View File
@@ -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 SKIP_SECONDS = 8; // leaving earlier than this counts as a skip
const COMPLETE_RATIO = 0.85; const COMPLETE_RATIO = 0.85;
const DOUBLE_TAP_MS = 300; 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 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 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 const HISTORY_AFTER = 1; // s heard before a track goes into the history
@@ -322,14 +321,6 @@ async function share(card: Card): Promise<void> {
} }
} }
/// 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 events -----------------------------------------------------------
player.on("timeupdate", () => { 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 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. // 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("contextmenu", (e) => { if ((e.target as Element).closest(".art")) e.preventDefault(); });
feedEl.addEventListener("click", (e) => { feedEl.addEventListener("click", (e) => {
if (pager.suppressClick) return; if (pager.suppressClick) return;
if (pressFired) { pressFired = false; return; }
const target = e.target as Element; const target = e.target as Element;
if (target.closest("button, a, input, .wave-wrap")) return; if (target.closest("button, a, input, .wave-wrap")) return;
const el = target.closest(".card"); const el = target.closest(".card");
@@ -554,7 +522,7 @@ function start(): void {
showUpNext(); showUpNext();
if (!localStorage.getItem(HINT_KEY)) { if (!localStorage.getItem(HINT_KEY)) {
localStorage.setItem(HINT_KEY, "1"); 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); : "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 === "r" && card) actions.radio(card);
else if (k === "x" && card) dislike(card); else if (k === "x" && card) dislike(card);
else if (k === "s" && card) share(card); else if (k === "s" && card) share(card);
else if (k === "w") wheelUp();
else if (k === "h") sheets.history.open(); else if (k === "h") sheets.history.open();
else if (k === "c") sheets.filters.open(); else if (k === "c") sheets.filters.open();
else if (k === "v") { setVisuals(visual.visuals === "liquid" ? "simple" : "liquid"); toast(`${visual.visuals} visuals`); } else if (k === "v") { setVisuals(visual.visuals === "liquid" ? "simple" : "liquid"); toast(`${visual.visuals} visuals`); }
-27
View File
@@ -20,7 +20,6 @@ const CROSSFADE_KEY = "pl8inf.crossfade";
const BASS_KEY = "pl8inf.bass"; const BASS_KEY = "pl8inf.bass";
const BASS_DB = 6; // gain of the bass boost's low shelf … const BASS_DB = 6; // gain of the bass boost's low shelf …
const BASS_HZ = 120; // … below this const BASS_HZ = 120; // … below this
const TAPE_STOP = 0.45; // s the rewind's tape stop takes
type Hls = HlsType; type Hls = HlsType;
type HlsClass = typeof HlsType; type HlsClass = typeof HlsType;
@@ -301,32 +300,6 @@ export class Player {
this.audio.pause(); 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<void> {
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<void>((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 { seek(seconds: number): void {
const a = this.audio; const a = this.audio;
a.currentTime = Math.max(0, Math.min(a.duration || 0, seconds)); a.currentTime = Math.max(0, Math.min(a.duration || 0, seconds));
-6
View File
@@ -143,12 +143,6 @@ export class Visualizer {
return this.blob?.lost ? null : this.blob; 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. /// A play/pause from a tap was taken back by the second tap of a double-tap.
cancelFlash(): void { cancelFlash(): void {
this.blob?.settleIcon(); this.blob?.settleIcon();