Same discrete model as the 3D simulator — six stable "face-up" poses of a cube, and a direct grasp-and-rotate edge between two poses only when the wrist rotation it needs is within the gripper's limit — but with the pose-to-pose angle computed correctly instead of inheriting a bug from the 3D source.
Bug found and fixed here (verified numerically, never touched the 3D file): the 3D sim derives each pose's orientation as Quaternion.setFromUnitVectors(faceNormal, up), then reads the required wrist angle straight off angleTo() between those two quaternions. That constructor picks one arbitrary "twist" about the vertical axis for each pose — but spinning an object about the vertical axis never changes which face is up, so that twist is physically free, and the 3D code never minimizes over it. A standalone Node scratch script reproducing three.js's exact setFromUnitVectors byte-for-byte confirmed the effect: the resulting angle table is 90° / 180° / 90° / 90° / 120° / 120° etc. instead of the correct cube geometry, and one genuinely adjacent pair — "green (−y) up" → "blue (+z) up", faces that share an edge — came back as a full 180° flip in the 3D table when the true minimal wrist rotation between them is 90°.
// correct rule for a cube's 6 face-up poses:
angle(i, i) = 0° (same pose)
angle(i, opposite) = 180° (true opposite faces: R↔O, Y↔G, B↔P)
angle(i, j) = 90° (every other pair — they share an edge)
Everything downstream — the adjacency graph, the breadth-first search, the animated approach / grasp / lift / rotate / lower / release sequence and the accumulated rotation readout — runs on this corrected table.
- Target face buttons — choose which face should end up facing up.
- Wrist rotation limit — the maximum single-grasp reorientation the wrist joint can perform; drop it below 90° and every direct edge vanishes (nothing is reachable in one grasp); between 90° and just under 180° only adjacent-face hops are direct and opposite faces need a 2-hop regrasp.
- Randomize Start — snaps the object to a random one of the 6 poses before planning.
- Plan & Execute — runs BFS on the current pose graph (top view), then animates the gripper (bottom view) executing every hop.
- Pose graph — drag to pan, scroll/pinch to zoom; gray lines are direct one-grasp hops at the current limit, the orange path is the planned route.
Real-world relevance: exactly this kind of regrasp graph shows up whenever an object's reachable reorientations are limited by wrist joint range, gripper clearance, or workspace obstacles — a staple sub-problem in pick-and-place task and motion planning.