The TorqueWrench is a virtual click-type torque wrench for a Meta Quest 3 VR training simulation.
The component models the physical interactions required to configure, attach, engage, and operate a torque wrench. It communicates meaningful interaction events to the surrounding training, feedback, and assessment systems without directly implementing training progression.
The specification describes the intended interaction behavior independently of any particular Unity or Meta XR API implementation, and uses generalized language from the Meta XR Interaction SDK and Unity APIs for reference.
The goal is to reproduce the important physical affordances of a real torque wrench while maintaining intuitive and responsive VR interaction.
The interaction should communicate tool state primarily through:
The user should learn the physical operation of the tool rather than a sequence of controller inputs.
The TorqueWrench is responsible for what happened during the interaction. The training system is responsible for determining what that event means in the context of the exercise.
The virtual wrench consists of:
All physical characteristics should be exposed as configurable parameters.
| Parameter | Description |
|---|---|
minimumTorque |
Minimum selectable torque |
maximumTorque |
Maximum selectable torque |
currentTorqueSetting |
Current target torque |
torquePerNotch |
Torque represented by one adjustment notch |
notchesPerRevolution |
Number of adjustment increments per revolution |
axialTravelPerRevolution |
Collar travel over one full adjustment revolution |
adjustmentAxis |
Local axis used for torque adjustment |
direction |
Current ratchet direction |
ratchetIncrement |
Angular movement between ratchet feedback events |
breakoverAngle |
Handle movement during break-over |
breakHapticProfile |
Haptic profile for break-over |
ratchetHapticProfile |
Haptic profile for ratchet events |
attachmentChain |
Currently installed attachment chain |
mountDistance |
Maximum distance for attachment mounting |
mountAngle |
Maximum angular error for attachment mounting |
engagementDistance |
Maximum distance for lug engagement |
engagementAngle |
Maximum angular error for lug engagement |
Reference measurements from the physical wrench may be used as initial values.
For example:
notchesPerRevolution = 20
axialTravelPerRevolution ≈ 1 mm
These values should remain configurable.
The wrench exposes semantic events to the surrounding application.
OnWrenchGrab()
OnWrenchRelease()
OnSecondaryGrip()
OnSecondaryRelease()
OnTorqueAdjustmentBegin()
OnTorqueSettingChanged()
OnTorqueAdjustmentEnd()
OnDirectionChanged()
OnAttachmentGrab()
OnAttachmentAdded()
OnAttachmentRemoved()
OnLugCandidate()
OnLugAligned()
OnLugEngaged()
OnLugDisengaged()
OnRatchet()
OnTorqueBreak()
OnTorqueAchieved()
OnOvertighten()
OnLugComplete()
The exact event mechanism is an implementation decision.
| Term | Meaning |
|---|---|
| Pinch | Trigger-only precision interaction |
| Grab | Grip/palm interaction used for larger physical objects |
| Primary Grip | Main handle interaction point |
| Secondary Grip | Head interaction point used to stabilize the wrench |
| Target Torque | Torque value selected on the wrench |
| Simulated Torque | Torque currently generated by the fastener model |
| Ratchet | Reverse or incremental mechanism movement without advancing the fastener |
| Break | Discrete wrench mechanism event when target torque is reached |
| Torqued | State following a completed break event |
| Overtightened | Continued tightening after the break event |
| Attachment Chain | Sequence of extensions and/or socket connected to the wrench |
Located on the wrench handle.
Used to:
The primary grip uses Grab.
Located near the wrench head.
Used to:
The secondary grip uses Grab.
The secondary hand does not independently apply torque.
| Interaction | Input | Preconditions | Output |
|---|---|---|---|
| Grab wrench | Grab | Wrench available | Wrench follows hand |
| Stabilize wrench | Grab | Wrench held | Secondary physical constraint |
| Adjust torque | Two-hand Grab + relative rotation | Not engaged | Torque setting changes |
| Change direction | Pinch | Not engaged | Direction changes |
| Grab socket | Pinch | Socket available | Socket follows hand |
| Attach socket | Pinch + alignment | Wrench not engaged | Socket mounts |
| Remove socket | Pinch + pull | Wrench not engaged | Socket detaches |
| Engage lug | Position/orientation | Correct socket | Socket engages lug |
| Tighten | Wrench rotation | Lug engaged | Fastener advances |
| Reverse | Opposite rotation | Lug engaged | Ratchet feedback; no tightening |
| Reach torque | Continued tightening | Simulated torque ≥ target | Break event |
| Overtighten | Continued tightening | After break | Overtighten event |
| Release wrench | Release Grab | Non-conflicting state | Wrench released |
The wrench is a physically manipulable object rather than a UI representation.
When grabbed, the wrench should:
The preferred behavior is a physics-based interaction rather than directly overwriting the wrench transform each frame. The implementation should prioritize:
Torque adjustment is permitted only when:
wrench is not engaged with a lug
The user adjusts the wrench using two hands:
The wrench head provides the reference frame.
The system therefore measures relative handle-to-head rotation, rather than world-space rotation.
The adjustment interaction ends when either contact point is released.
The system measures relative rotation between the handle and head.
Only rotation around the configured adjustmentAxis contributes to torque adjustment.
Conceptually:
relativeRotation =
signed rotation of Handle relative to Head
around adjustmentAxis
The system accumulates this rotation and converts it into adjustment increments.
notch =
Round(
accumulatedRotation /
(360° / notchesPerRevolution)
)
The torque setting is:
currentTorqueSetting =
baseTorque +
notch * torquePerNotch
The result is constrained:
minimumTorque <= currentTorqueSetting <= maximumTorque
The implementation may retain continuous angular information internally to prevent loss of precision while presenting discrete physical adjustment increments to the user.
The adjustment collar physically translates as the torque setting changes.
The movement is parameterized by the wrench's measured adjustment travel.
axialOffset =
accumulatedRotation / 360°
* axialTravelPerRevolution
The collar position becomes:
collarPosition =
initialPosition +
adjustmentAxis * axialOffset
For the reference wrench:
20 notches ≈ 1 full revolution
1 full revolution ≈ 1 mm axial travel
Therefore:
axialTravelPerNotch =
axialTravelPerRevolution /
notchesPerRevolution
The actual relationship should be measured from the physical wrench and exposed as configuration.
The visible torque scale should remain synchronized with the physical collar position.
The user should be able to determine the selected torque from the virtual wrench itself without relying on a floating HUD.
The direction selector is a small precision control operated using Pinch.
The selector has two physical states:
CLOCKWISE
COUNTER_CLOCKWISE
These names describe the direction of wrench rotation that drives the ratchet, not whether the fastener is being tightened or loosened.
Changing direction produces:
The selector cannot be changed while the wrench is engaged with a lug.
The wrench itself does not need to know that clockwise means "tighten."
The lug/fastener configuration determines which rotational direction tightens that particular fastener.
For example:
wrench.direction = CLOCKWISE
lug.tighteningDirection = CLOCKWISE
means clockwise wrench rotation advances the fastener toward greater torque.
Conversely:
wrench.direction = COUNTER_CLOCKWISE
lug.tighteningDirection = CLOCKWISE
means the selected wrench direction does not tighten the fastener and instead produces ratcheting.
This preserves the physical meaning of the wrench selector while keeping fastener behavior configurable.
Sockets and extensions share a common attachment interface.
An attachment may contain:
InputMount
OutputMount
The wrench contains:
ToolMount
A resulting attachment chain may therefore be:
The wrench does not need to know whether the terminal socket is attached directly or through one or more extensions.
Each attachment explicitly defines its mounting transforms.
ToolMountThe attachment interface on the wrench.
InputMountThe transform through which an attachment connects to its parent.
OutputMountThe transform through which the next attachment connects.
Lug.MountPointThe drive interface on the lug.
The terminal drive transform can therefore be resolved recursively through the attachment chain.
The attachment system should traverse the installed children/chain when resolving the terminal mount rather than storing a separate hard-coded socket position on the wrench.
This allows arbitrary extension chains.
Sockets and extensions are small precision objects and use Pinch.
The user can:
Attachments can be added or removed whenever the wrench is not engaged.
When the wrench has no attachment installed, a phantom yellow socket is displayed at the ToolMount.
The phantom communicates:
The phantom socket is:
It is an affordance rather than a physical object.
The phantom should disappear or update when an attachment is mounted.
An attachment becomes a mounting candidate when:
distance < mountDistance
AND
orientationError < mountAngle
AND
attachment is compatible
When mounted:
attachmentChainAttachments can be removed whenever the wrench is not engaged.
The user:
The terminal attachment interacts with the lug's MountPoint.
An engagement candidate exists when:
distance < engagementDistance
AND
orientationError < engagementAngle
AND
socketType == requiredSocketType
Provide subtle:
Provide:
The system:
The alignment tolerance should accommodate normal Quest controller tracking while preserving the sense that the user intentionally seated the socket.
Once the terminal socket is engaged, the wrench becomes rotationally coupled to the lug.
The primary hand controls wrench rotation.
The secondary hand may stabilize the wrench but does not independently apply torque.
The core interaction is:
Conceptually:
Controller movement
↓
Wrench rotation
↓
Fastener displacement
↓
Fastener resistance
↓
Simulated torque
↓
Torque threshold
The simulation does not attempt to infer physical hand force from controller input.
Instead, the fastener resistance model determines the resistance encountered during rotation.
Two values are maintained independently:
targetTorque
currentSimulatedTorque
targetTorqueThe torque value selected on the wrench.
currentSimulatedTorqueThe torque currently generated by the simulated fastener interaction.
These values must not be conflated.
The fastener resistance model determines how rotational movement produces increasing torque.
The wrench compares the resulting simulated torque against its configured threshold.
While:
currentSimulatedTorque < targetTorque
the wrench is in the TORQUING state.
The wrench should:
Each ratchet event produces:
Normal ratchet feedback should be substantially weaker than the break event.
When:
currentSimulatedTorque >= targetTorque
the torque threshold has been achieved.
This generates:
OnTorqueAchieved()
and initiates the wrench's break-over mechanism.
The threshold crossing should be treated as a discrete event for the current tightening operation.
The break is the defining feedback event of the click-type torque wrench.
It should communicate target torque through physical feedback rather than requiring visual UI.
The break consists of three coordinated channels.
The handle rotates/breaks over by:
breakoverAngle
relative to the wrench head.
A distinct mechanical click is played.
The controller receives a short, stronger haptic impulse.
The break should be clearly distinguishable from ordinary ratchet events.
The break should occur once for the current torque application.
After the break, continued tightening is considered an error.
The system records the amount of tightening rotation after the break:
overRotation =
total tightening rotation after break
and generates:
OnOvertighten()
The wrench should not produce another normal successful torque event as a result of continued tightening.
How overtightening is communicated to the user is determined by the training layer.
The physical wrench may continue to resist or permit movement according to the chosen fastener model, but the additional rotation must remain distinguishable from successful torque application.
Feedback is divided into three modalities:
The wrench interaction system generates semantic feedback events. The feedback system determines the final presentation.
Haptic feedback should communicate mechanical events without overwhelming the user.
| Event | Relative Intensity | Character |
|---|---|---|
| Wrench Grab | Low | Short |
| Secondary Grip | Low | Short |
| Torque Adjustment Detent | Low | Repeated |
| Direction Change | Low–Medium | Short |
| Attachment Mount | Medium | Short |
| Lug Alignment | Low | Short |
| Lug Engagement | Medium | Short |
| Positive Ratchet | Low | Repeated |
| Negative Ratchet | Low | Repeated |
| Torque Break | High | Distinct single impulse |
| Overtighten | Training-dependent | Training-dependent |
Positive and negative ratchet events should use distinguishable timing or profiles if needed, while remaining subtle enough that they do not compete with the break event.
Audio should reinforce the physical mechanism.
| Event | Audio |
|---|---|
| Torque adjustment | Small detent/click |
| Direction change | Selector click |
| Attachment mount | Mechanical seat/click |
| Lug engagement | Socket seating sound |
| Positive ratchet | Ratchet click |
| Negative ratchet | Ratchet click with appropriate directional variation |
| Torque break | Distinct torque-wrench click |
| Overtighten | Training-dependent |
The torque-break sound should be substantially more salient than normal ratchet sounds.
The wrench should provide visual confirmation through the physical object whenever possible.
| Event | Visual |
|---|---|
| Torque adjustment | Collar and scale movement |
| Direction | Selector position |
| Empty tool mount | Phantom yellow socket |
| Attachment candidate | Mount highlight |
| Attachment mounted | Snapped attachment |
| Lug candidate | Lug/socket highlight |
| Lug aligned | Alignment indication |
| Lug engaged | Seated socket |
| Torque break | Physical handle break-over |
| Overtighten | Training-dependent |
Floating UI should not replace physical feedback for basic wrench operation.
Where practical, virtual controls should behave like their physical counterparts.
The user should manipulate the wrench, socket, lug, and other virtual objects directly rather than progressing through animations or passive demonstrations.
Two primary controller interactions are used:
Interactions that require stabilizing one portion of the wrench while manipulating another should use two physical contact points.
Physical characteristics should be configurable rather than hard-coded to the reference wrench.
The wrench should expose semantic events rather than directly controlling training UI, progression, or scoring.
The following should be validated against the physical reference wrench during implementation.
The final implementation should be tuned specifically for Meta Quest 3.
Considerations include:
The exact Meta XR and Unity APIs should be selected during implementation based on the currently supported SDK and interaction framework.
The interaction specification should remain stable if the underlying implementation changes.
The TorqueWrench should remain independent from the training experience.
The wrench should not directly control:
Instead:
The wrench reports what happened; the surrounding experience decides what that event means.
This allows the same physical interaction component to support instructional, guided, free-practice, and assessment modes without changing the underlying wrench behavior.