2 Commits
Author SHA1 Message Date
tiennm99 edcb95c4a6 fix(controls): compare motionScreen against pixelsAxis (not drag) so signMul matches the dragPx reference frame
Drag-down on +z front-face cubies still inverted direction after the
face-anchor fix. Root cause was a dual-reference-frame mismatch in
chooseRotationAxis:

  curAngle = (drag · pixelsAxis) * signMul   ← measured along pixelsAxis
  signMul  = sign(motionScreen · drag)        ← measured against drag

When pixelsAxis and the drag vector are anti-aligned (e.g. dragAxis='y'
where pixelsAxis points screen-UP since world +y projects to screen -y,
but the user drags screen-DOWN), the two reference frames disagree and
sign(curAngle) ends up opposite sign(motionScreen · drag) — so positive
rotation moves the cubie opposite the user's drag.

Fix: compare motionScreen against pixelsAxis (= screenDirs[dragAxisIdx])
so both halves of the curAngle formula share the same reference frame.

Adds 24 correctness tests asserting sign(curAngle) == sign(motionScreen ·
drag) for every face × cardinal drag — fails on the previous code, passes
after the fix. Also removes the temporary RUBIK_DEBUG diagnostic logs.
2026-05-09 12:42:51 +07:00
tiennm99 c615138853 fix(controls): face-anchor cross product to stop edge/corner rotation reversing direction
Drag-to-rotate sent edge and corner cubies the opposite direction at tilted
camera angles. Root cause: motionWorld = R̂ × hitWorldPos picks up an in-plane
component of P (β·F̂) for non-center cubies; under projection this can
dominate motionScreen and flip signMul.

Anchor the cross product to the face-normal axis only — drops the leakage
so signMul is identical for every cubie on a face.

Adds tests/gesture-math.test.js with face-invariance assertions across
centers, edges, and corners on all 6 faces × 4 cardinal drags.
2026-05-09 11:28:29 +07:00