-
Shell v2.1: BT picker, RS scroll, MP3 ambient, focus polish
release / Build Windows .zip (push) Canceled after 0sreleased this
2026-05-31 22:58:32 +03:00 | 36 commits to main since this releaseSix-item user pass on v0.10.0 polish:
-
B closes Backups modal. Targeted fix in ShellApp's button hook:
the Backups overlay is the one shell surface that uses base
(only listens for keyboard Esc). All other overlays wire
their own B. -
Right-stick scroll. internal/controller now emits a new
"controller:scroll" {dx, dy} event from ThumbR (50 Hz,
normalised to [-1..+1], dy flipped to scroll-down-positive).
Frontend exposes useControllerScroll. ShellSettingsPage and
GameDrawer wire it (px factor 18 = ~900 px/s at full deflection).Also: universal *:focus-visible ring (2 px accent outline) so
the d-pad walk visibly shows where the cursor went — v0.10.0
relied on per-component focus styles which were inconsistent. -
GameDrawer adopts the roving-focus + RS-scroll model from
ShellSettingsPage. d-pad / LS walk focusables (↑↓ AND ←→ since
the drawer is single-column), A clicks the focused element,
text/number/select inputs skipped, B closes. -
Sound: drop pack picker, hardcode "subtle" voice. sound.ts
simplified to a boolean gs:soundOn (with v0.9 gs:soundPack
migration). SoundPack / getSoundPack / setSoundPack /
subscribeSoundPack kept as backward-compat shims so callers
compile. Settings now shows one checkbox. -
Ambient: replace procedural drone with user-supplied MP3 loop.
Bundled as frontend/src/assets/ambient.mp3 (Vite picks it up).
At runtime: fetch + decodeAudioData → trim first/last 15 s by
sample count → bake a seamlessly-looping buffer where the last
6 s crossfade tail-into-head via sin/cos equal-power ramps
(sin²+cos²=1, no level dip at the splice). source.loop=true on
that buffer gives a click-free continuous pad. 4 s fade-in,
1.5 s fade-out, master cap 0.10.Tweaked the frontend-ui.md rule to reflect that an embedded
audio asset is now used for ambient; the procedural rule still
stands for nav tones. -
Bluetooth picker.
internal/bluetooth — Win32 BluetoothAPIs.dll wrappers:
BluetoothFindFirstDevice / FindNextDevice / FindDeviceClose
BluetoothSetServiceState
BLUETOOTH_DEVICE_INFO is 560 bytes on x64 per MSDN — Go natural
alignment with the documented dwSize+pad layout matches.
runtime.LockOSThread while holding the find-handle."Connect" = enable all known audio profile GUIDs (A2DP sink,
AVRCP, HFP/HSP gateways). Headphones expose different
combinations; an unsupported profile returns
ERROR_SERVICE_DOES_NOT_EXIST which we treat as a clean skip. As
long as at least one service flipped, return nil; otherwise
first-non-skip-error wins.sync.Mutex serialises the slow blocking calls
(BluetoothSetServiceState can block ~30 s while the radio
negotiates with the headset).Pairing is OUT of scope — OpenWindowsBluetoothSettings punts to
fsquirt.exe for "add a new device".App.ListBluetoothDevices / Connect / Disconnect /
OpenWindowsBluetoothSettings exposed. Frontend
BluetoothPicker.tsx — full-screen list, audio devices sorted
first, A toggles, X/R refreshes, B closes. Wired into
DevicesMenu (BT tile no longer disabled) and Settings (📶
button now active in shell mode).
ADR: .claude/decisions/0026-bluetooth-picker-rs-scroll-mp3-ambient.md
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
Downloads
-