nRF52840 Steam Controller 2 puck reimplementation — WebUSB. Chrome/Edge only.
If nothing appears in the device picker, the copycat may be busy (quit any app holding it) or needs a replug.
Switching reboots the copycat and re-enumerates USB (~2 s). WebUSB works in every mode, including Steam/Lizard with Steam running (Chrome claims the vendor interface; Steam keeps the HID slots). Switch HORIPAD + WebUSB is PC-only.
Hold all four back paddles (L4+R4+L5+R5) plus a face button to switch mode without the WebUI. A is always Steam. B / X / Y are configurable below (defaults: B=Lizard, X=Xbox, Y=Switch HORIPAD).
IMU (raw): —
Raw SC2 accel (before scaling). This controller is a ±2 g sensor (~16384 = 1 g); the Switch report divides it by 4 to present the genuine ±8 g (4096 = 1 g) scale so the console's gravity-correction engages and the gyro stops drifting.
Polls/s ≈ 250 expected; it's capped by Loop period (≈4000 µs needed). "Slowest stage" is the loop section eating the most time per iteration.
adafruit-nrfutil dfu serial … then replug.
.uf2 file onto it to flash, then it reboots automatically.
Right-pad cursor in Steam-mode lizard (Steam closed) and in Xbox mode. Sensitivity is a divisor — lower = faster pointer. Glide = how long the cursor coasts after a flick.
Scales rumble amplitude across all modes (100% = native, 200% = double, 0% = off).
120 Hz (default) is low-latency and drift-free. 66 Hz is a genuine-cadence compatibility fallback. Full rate (~250 Hz) is lowest-latency but non-genuine — use only if your console tolerates it.
Gyro sensitivity multiplier for Switch Pro mode (1.0× = unchanged).
Back-paddle → button, applied in Xbox & Switch modes. QAM remap applies to all modes (0 = default per-mode behavior).
The firmware logs everything from boot into a big RAM ring: Steam's writes (ifN), the frames we transmit to the controller (TX→ctlr), and RF LINK UP/DOWN edges. For the reconnect buzz: trigger it (it appears moments after the puck boots / the controller reconnects), then connect here and click Dump from boot — the trigger is still in the ring. (Only present in a logging build, -DOPK_LOG=1.)
Dump streams the whole ring (oldest→newest) and then keeps live-updating until you press Stop. cmd is the command/report byte, then the raw bytes.