From a40ff04fd1e35339a27bd4e391f16b22ca882795 Mon Sep 17 00:00:00 2001 From: Me Here Date: Tue, 26 May 2026 08:03:15 -0500 Subject: [PATCH] As-built: recessed thumb-roller for tempo (no protruding knob); USB-C bus power MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Tempo control: replace the protruding knob with a recessed side-mount thumb-roller — a detented encoder (EC11/PEC12) with a ribbed wheel exposed only at the edge through a slot, like a mouse scroll wheel, so there's nothing to snap off. Scroll/drag tempo interaction is unchanged; the ribs scroll for roll feedback (--rib) instead of a knob pointer. - Power: no battery — the device is USB-C bus-powered from the same port that carries config. Dropped the LiPo + TP4056 charger + 5 V boost from the BOM (total ≈ $49) and marked USB-C as 5 V in + config. Co-Authored-By: Claude Opus 4.7 (1M context) --- player-asbuilt.html | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/player-asbuilt.html b/player-asbuilt.html index 22484fb..674118c 100644 --- a/player-asbuilt.html +++ b/player-asbuilt.html @@ -12,9 +12,10 @@ the upgrade from the cramped 128×64 mono OLED — full colour, smooth type, hi-DPI. It also draws the beat indicator itself — a row of beat dots with the current beat's subdivisions below — so there's no separate LED bar; - • controls arranged for use: an EC11 encoder below the screen (turning it - never hides the readout) with arcade pushbuttons spread below — PREV far - left, NEXT far right, a big central PLAY — so you don't hit the wrong one; + • controls arranged for use: a recessed thumb-roller for tempo — a detented + encoder with a side-mount wheel, so nothing sticks out to snap off — below + the screen, with arcade pushbuttons spread below: PREV far left, NEXT far + right, a big central PLAY, so you don't hit the wrong one; • rear I/O: external trigger in (footswitch), a 1/4" instrument pass-through with the click mixed in the ANALOG domain (DAC → summing op-amp → balanced line driver), a shared 1/4" balanced-TRS main out, plus an analog monitor @@ -101,12 +102,14 @@ wheel never hides the readout · PREV far-left / NEXT far-right · big central PLAY */ .controls{ display:flex; flex-direction:column; align-items:center; gap:13px; margin:14px 0 2px } .enc-wrap{ display:flex; flex-direction:column; align-items:center; gap:5px } - .enc{ width:52px; height:52px; border-radius:50%; cursor:ns-resize; position:relative; touch-action:none; - background:repeating-conic-gradient(from 0deg, #424b57 0 7deg, #2c333d 7deg 14deg); - border:2px solid #565f6c; box-shadow:0 3px 8px rgba(0,0,0,.5), inset 0 1px 1px rgba(255,255,255,.12) } - .enc::before{ content:""; position:absolute; inset:9px; border-radius:50%; background:radial-gradient(circle at 38% 32%,#3b434f,#181c22 75%) } - .enc::after{ content:""; position:absolute; left:50%; top:7px; width:3px; height:12px; background:var(--cyan); border-radius:2px; - transform-origin:50% 19px; transform:translateX(-50%) rotate(var(--a,0deg)); box-shadow:0 0 5px var(--cyan) } + /* recessed thumb-roller (side-mount encoder wheel) — only the edge is exposed */ + .roller{ width:28px; height:50px; border-radius:7px; cursor:ns-resize; position:relative; touch-action:none; overflow:hidden; + background:#0a0d12; border:1px solid #04060a; box-shadow:inset 0 0 0 1px rgba(255,255,255,.03), 0 2px 4px rgba(0,0,0,.5) } + .roller::before{ content:""; position:absolute; inset:2px 4px; border-radius:4px; /* ribbed wheel surface, scrolls via --rib */ + background:repeating-linear-gradient(0deg, rgba(255,255,255,.11) 0 1px, rgba(0,0,0,.5) 1px 4px); + background-position:0 var(--rib,0px) } + .roller::after{ content:""; position:absolute; inset:0; border-radius:7px; pointer-events:none; /* cylinder sheen: bright centre, curving dark at top/bottom */ + background:linear-gradient(180deg, rgba(0,0,0,.72) 0%, rgba(255,255,255,.12) 48%, rgba(255,255,255,.12) 52%, rgba(0,0,0,.72) 100%) } .enc-wrap small{ font-size:8px; color:var(--silk); letter-spacing:.12em; opacity:.85 } .keys{ display:flex; align-items:flex-end; justify-content:space-between; width:100%; padding:0 2px } .key-mid{ display:flex; align-items:flex-end; gap:20px } @@ -192,7 +195,7 @@
2.0″ 320×240 IPS TFT (ST7789) — beat & subdivisions on‑screen
-
TEMPO
+
TEMPO
Prev
@@ -233,7 +236,7 @@

Bill of materials

-

Rough parts list for the device above — an RP2040 build with analog click injection. +

Rough parts list for the device above — a USB‑C‑powered RP2040 build with analog click injection. Ballpark one-off prices (USD); cheaper at volume.

@@ -244,7 +247,7 @@ - + @@ -252,13 +255,12 @@ - - + - +
PartQty~$
Controls
Arcade pushbutton, 24 mm — Prev · Next · Tap34
Arcade pushbutton, 30 mm — Play12
EC11 rotary encoder + knurled knob — tempo12
Detented encoder (EC11 / PEC12) + side‑mount thumb‑roller — recessed; nothing to snap off12
Audio — analog click injection
PCM5102A I²S DAC — line‑level click13
Dual op‑amp, NE5532 / OPA2134 — hi‑Z instrument buffer + summing mixer11
PAM8302A mono Class‑D + 8 Ω 2 W speaker — monitor14
Connectors & power
1/4″ jack — Inst In (TS) · Out (TRS) · Trig In (TS)33
LiPo 1200 mAh + TP4056 charger + 5 V boost16
Power slide switch + PWR LED11
USB‑C bus power (5 V) + PWR LED — same port carries config; no battery11
Build
Custom PCB (or perfboard)15
Passives, headers, wire — R/C for the analog stage + decoupling3
3D‑printed enclosure + screws / standoffs15
Total (one‑off)≈ $55
Total (one‑off)≈ $49

Audio is summed in the analog domain: the DAC's click is mixed with a high‑impedance @@ -346,8 +348,8 @@ function loadSetlistObj(sl){ setlist=sl; idx=0; const wasRunning=state.running; let taps=[]; function tapTempo(){ const now=performance.now(); taps=taps.filter(t=>now-t<2000); taps.push(now); if(taps.length>=2){ let s=0; for(let i=1;i