Skip to content

Tags: UsersFirst/tandemonium-controller-lab

Tags

core-v0.4.1

Toggle core-v0.4.1's commit message
chore(core): release 0.4.1

Adds SensorFusion.gravityRollRadians() — drift-free roll from the gravity
vector for lean-to-steer input (#109). Backward-compatible with 0.4.0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Qnt4svMm6b8zkWfSk75vW

core-v0.4.0

Toggle core-v0.4.0's commit message
chore(core): release 0.4.0

Multiple Steam Controllers + WebHID-first pooling (#108). New public API:
MAX_CONTROLLERS, playerSlotIds(), isPresentableEntry(),
ControllerManager.presentablePoolEntries(), and connectHidForSlot's { prompt }
option. Backward-compatible with 0.3.x callers.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Qnt4svMm6b8zkWfSk75vW

pr-107

Toggle pr-107's commit message
chore(#106): update lockfile for node-hid + auto-unpack-natives plugin

core-v0.3.2

Toggle core-v0.3.2's commit message
core: add ControllerManager.claimHidDeviceForSlot + release 0.3.2

The HID-only counterpart of claimPadForSlot: claim a specific HID device into a
specific seat, for controllers invisible to the Gamepad API (Steam Controller
Puck, DualSense-BT). The versus lobby calls it for HID-only join candidates; it
was crashing / silently failing so a Steam Controller couldn't ACTIVE/ASSIGN.
Resolves the pool entry (streaming sibling for a fan-out Puck), claims + attaches
it. Tested.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YNqB4zV3F6aBAg6LUxuvBY

core-v0.3.1

Toggle core-v0.3.1's commit message
core: add ControllerManager.claimPadForSlot + release 0.3.1

Adds a public "claim a SPECIFIC pad into a SPECIFIC slot" API for versus/co-op
seat assignment (the game's versus lobby calls mgr.claimPadForSlot(slotId, gp)
when a controller presses to join a chosen seat). Distinct from
claimFirstAvailable (which picks a pad); here the caller supplies both. Rejects
occupied/unknown slots, missing pads, and a pad already seated. Tested.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YNqB4zV3F6aBAg6LUxuvBY

core-v0.3.0

Toggle core-v0.3.0's commit message
chore(core): release 0.3.0 — WebHID-first controller support

Bumps @usersfirst/controller-core after the seat-select lobby + overlay picker +
single-owner pool merge (#102): DS4/DualSense/Steam/Switch Pro parsing (buttons,
sticks, triggers, Capture/paddles), per-unit identity, phantom/stall recovery.
Tag core-v0.3.0 pins the vendored copy for downstream (Tandemonium game).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YNqB4zV3F6aBAg6LUxuvBY

pr-84

Toggle pr-84's commit message

Verified

This commit was signed with the committer’s verified signature.
claude Claude
PlayStation BT IMU: guard against accel-as-gyro offset shift (macOS s…

…ide-to-side) (#83)

First pass at the macOS BT DualSense "side to side" fusion bug. The IMU-offset
probe already runs on Bluetooth (the docstring claiming USB-only was stale);
the gap was the selection in init(), which trusted the documented offset
whenever its at-rest ACCEL looked ~1g — without checking gyro. A byte-shifted
offset (e.g. macOS/IOKit including the leading report-ID byte in the BT 0x31
DataView) reads an accel axis AS a gyro axis, so its at-rest "gyro" sits near
gravity (~8192). Fusion integrates that as rotation → the model swings side to
side, exactly the in-game symptom.

- Extract the selection into a testable `_chooseImuOffset(probe)` and add an
  accel-as-gyro guard: reject the default when its at-rest |gyro| is pinned
  near gravity, and recover the cleanest candidate (~1g accel AND near-zero
  gyro). The high-gyro gate means a small real bias / a handled pad never trips
  it, so the existing off-by-2 still-pad protection is preserved.
- Add raw-bytes + length diagnostic logging on the probe so a macOS BT 0x31
  capture (the key unknown) is one console line away.
- Fix the stale "USB only" probe docstring.
- Tests: default-kept, macOS accel-as-gyro recovery, off-by-2 still-pad
  protection, and motion fallback (89 pass).

Hardware-verification pending: needs a real macOS + DualSense BT capture to
confirm the exact byte mechanism (length/report-ID-byte) and that the fix
lands the correct orientation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017NiS2a4jZ877XgftkH1Dd1

pr-82

Toggle pr-82's commit message
feat(core): Phase 1 scaffold — InputFrame contract + WebHID-first arb…

…iter (#80)

Introduce the source-agnostic input architecture from the plan doc, WebHID
as the foundational spine and Steam Input reserved as an optional adapter:

- input-frame.js: the normalized InputFrame contract + pure helpers
  (makeEmptyFrame, frameFromGamepad, quatToPlain, identityMatchKey,
  chooseSource). Zero deps; motion.quaternion is a plain IPC-safe object.
- sources/base-source.js: ControllerSource abstract base (mirrors
  ControllerDriver).
- sources/webhid-source.js: WebHIDSource wrapping the existing
  ControllerManager (the default/primary source).
- sources/gamepad-source.js: GamepadAPISource (driver-less fallback, no gyro).
- input-arbiter.js: InputArbiter — composes sources, dedups the same
  physical controller across them, and reads exactly ONE per controller
  (WebHID-first; forced for Deck built-in; per-controller opt-in preference).
- Barrel + package.json subpath exports for the above.
- test/input-frame.test.js: 15 dependency-free tests (contract helpers +
  arbiter dedup/force/preference/resilience). Core suite: 100 pass.

SteamInputSource intentionally NOT added here — it lands in the optional
@usersfirst/controller-steam package (Phase 2). core stays Steam-free.

Refs #80.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WcfARPqppdCKv8f3iWkhFu

pr-76

Toggle pr-76's commit message
Grip sense: bar reacts to grip, glow rework, distinct definitions

Grip-sense glow (on-top marker) and bars (handle strip meshes) are now two
clearly separate, independently-toggled indicators:

- Bars react to grip: sit at an inert rest grey and ease to the grip color
  (with a fixed emissive lift) while that side is gripped — so the bar itself
  reads activation (#74). Per-side materials are cloned so left/right light
  independently. Driven by setGripBarsVisible, independent of the glow.
- Glow rework: the cylinder reads as a real glow again — a band texture that
  wraps the full circumference (consistent from any angle) and fills most of
  the length with soft fades at the ends, using normal blending so it stays
  visible over the light handles (additive vanished over near-white). The
  Glow Length slider now scales the lit length as expected.
- gripMarkerYaw knob (per profile, degrees) angles each glow's bumper/trigger
  end toward the controller centerline; set to 18 for the Steam Controller.
- Decoupled the bar's lit emissive from the Grip Glow Brightness slider
  (fixed GRIP_BAR_LIT_EMISSIVE) so brightness is glow-only, matching its
  label. Refreshed all stale "bars are static/cosmetic" docs + tooltips.

Also: fix settings dropdowns rendering light text on a white popup on Windows
(color-scheme: dark + explicit option colors).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

webhid-overlay-latest

Toggle webhid-overlay-latest's commit message
ci: stamp commit + build time into the overlay, and roll "latest" rel…

…ease on main

Adds a build stamp (short commit SHA linking to the commit + UTC build time)
to the overlay app and the landing page, injected at build time — mirrors the
`lobby-version` stamp in petegordon/tandemonium.

- scripts/stamp-build-version.js rewrites the `#build-version` placeholder in
  one or more HTML files from $BUILD_STAMP; no-ops locally (stays "dev build").
- build-desktop.yml stamps apps/overlay/src/index.html before packaging, so the
  Windows .exe and macOS .app show which build they are.
- deploy-pages.yml stamps the web overlay AND web/index.html landing page, so
  you can confirm build freshness before downloading.

Also fixes the stale website download: the release job now runs on every push
to main, publishing/refreshing a single rolling `webhid-overlay-latest` release
(make_latest) whose assets the landing page's /releases/latest/download/... link
follows. Previously releases were cut only on tags/manual dispatch, so main
pushes built throwaway run artifacts and the .exe download never updated.
Semver `webhid-overlay-v*` tags still produce their own named releases.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>