D4. Attaching Objects in VR

Learning Outcomes
- Explain the concept of sockets for object snapping in XR. Before class, explore how sockets work by relating them to real-world analogies like plugs or mechanical joints.
- Configure a grab-ready object in Unity for socket interaction. For preparation, set up a 3D object with a
RigidbodyandXR Grab Interactablecomponent, then test its basic grabbing behavior.- Use vector comparisons to validate alignment in snapping interactions. Ahead of the session, review and experiment with
Vector3.Angle()andVector3.Distance()in a script to see how they can enforce positional and rotational constraints.- Apply best practices for socket-based object attachment. Come ready with one real-world engineering example where precise part alignment is critical, and connect it to XR development considerations.
Sockets
In VR, a socket is a designated area or docking station where an interactable object snaps into a predetermined position and orientation. This ensures objects—like gears in a gearbox or sensors on a panel—align correctly when placed, enhancing user experience through predictable, visually coherent interactions. By using the XR Socket Interactor to define clear attachment points and aligning attach transforms, objects consistently snap into place. Additionally, employing interaction layers restricts attachments to the correct objects, further enhancing performance and usability.

Use Cases
Sockets are a flexible interaction pattern that can be applied across multiple VR domains:
- Engineering & Manufacturing: Assembly training (e.g., attaching machine parts, wiring circuits). Maintenance procedures (e.g., snapping tools back into holders, replacing components).
- Medical Training: Attaching prosthetics or surgical tools to rigs. Snapping medical instruments into sterilization trays or stands.
- Education & Simulation: Teaching physics concepts by building circuits or modular systems. Assembling molecules or models piece by piece.
- Gaming & Entertainment: Weapon or tool customization (e.g., attaching scopes, silencers, or handles). Puzzle mechanics (e.g., fitting shapes into sockets, key-lock systems).
- Architecture & Design: Furniture arrangement with snap-to points. Modular building systems with predefined docking stations.
- Everyday Utilities: Organizing objects on a workstation (e.g., snapping items into holders). Virtual prototyping where parts must consistently align.

Principles
Before diving into technical setup, it is important to understand the principles of socket-based interactions:
- Predictability: Users should always know how and where an object will attach. Clear visual and spatial cues reduce confusion.
- Precision vs. Flexibility: Decide whether sockets should allow loose placement (ease of use) or enforce strict tolerances (engineering realism).
- Feedback & Affordances: Provide visual, audio, or haptic feedback when an object is close to or correctly aligned with a socket.
- One-to-One Relationships: Each socket should be designed for a specific object type (via
Interaction Layers) to avoid unintended snapping. - Performance Considerations: Use minimal colliders and avoid overlapping triggers to maintain smooth interactions.
- Reversibility: Decide whether objects can be removed after being socketed, and under what conditions (e.g., only with a specific tool or action).
XR Socket Interactor
A socket behaves like a snap-to mechanism, ensuring that objects align correctly—enhancing functional realism and user experience. The XR Socket Interactor component is essential for attachment mechanics in Unity’s XR Interaction Toolkit. Unlike direct interactors (e.g., controllers that grab objects explicitly), a socket passively detects eligible interactables inside its trigger collider and aligns them to a specified attach point. For example, in the logistics station of XFactory, the barcode scanner’s charging base contains a socket that holds the scanner securely. Using an XR Socket Interactor, the base ensures the scanner only snaps into place in the correct orientation, simulating the real-world feeling of docking it into its holder. This provides users with tactile feedback and reinforces proper handling, just like in real operations.

Review this Unity Documentation to learn more about
XR Socket Interactor.
Inspector Properties
When you add an XR Socket Interactor component to a GameObject, you’ll see the following key fields in the Inspector:
Interaction Manager: Reference to theXR Interaction Managerthat coordinates all interactors and interactables. Default:None (XR Interaction Manager)— if left blank, it will attempt to auto-find one in the scene.Interaction Layer Mask: Determines which interactables are allowed to interact with this socket. Default:Everything— meaning it will accept all interactables unless filtered.Handedness: Restricts socket usage to a specific controller hand if required. Default:None(no restriction).Attach Transform: A child transform that defines the exact snap position and rotation. This must be set manually for precise alignment.Starting Selected Interactable: Option to auto-attach a specific object when the scene starts.Keep Selected Target Valid: If enabled, the socket maintains its selection even when the interactable temporarily leaves the socket’s trigger.Show Interactable Hover Mesh: Toggle to render a hover mesh when an object is near the socket.Hover Mesh Material: Assign a material for valid hover visualization.Can’t Hover Mesh Material: Assign a material for invalid hover states.Hover Scale: Adjust scale of the mesh preview during hover.
Hover Socket Snapping: If enabled, the interactable will visually snap into the socket’s attach transform during hover—before being selected.Socket Scale Mode: Defines how scaling is applied to objects when attached. Options include None, Match, or other scaling modes.Socket Active: Toggles the socket’s availability. Useful for dynamically enabling or disabling sockets during gameplay.Recycle Delay Time: Sets a cooldown before the socket can accept the same interactable again. Prevents rapid attach/detach cycling.
Events & Extensibility
XR Socket Interactor provides several event hooks for developers to attach custom logic:
-
Interactor Filters: Allow filtering or conditions for which interactables can hover or be selected. -
Interactor Events:Hover Entered (HoverEnterEventArgs): Triggered when an interactable enters the socket’s detection zone.Hover Exited (HoverExitEventArgs): Triggered when it leaves.Select Entered (SelectEnterEventArgs): Triggered when an interactable is successfully socketed.Select Exited (SelectExitEventArgs): Triggered when the interactable is removed from the socket.
All of these event lists are empty by default but can be expanded in the
Inspectorto assign UnityEvents, scripts, or feedback mechanisms.
Example
In engineering contexts, sockets can represent part mounts, assembly points, holders, or loading positions. In this example, we simulate assembling a tire onto a brake caliper and disk, and securing it using five lug nuts, grabbed from a stack box.
- Prepare Your Interactable Objects:
- In the
Hierarchy > Assembly, locate your 3D model of theTireon theMetal Table. This object will be socketed (i.e., assembled) onto theTire Stand. - Locate the
Tire Lug NutGameObjects inside theStack_Box_02_Prefab_02on theMetal Table. These will be picked up and assembled onto theTire. - Interactable objects are those that users can grab, move, and place using XR controllers.
- In the
- Configure Physics:
- Add
Rigidbodycomponents to theTireandTire Lug NutGameObjects. This allows realistic physics and prevents clipping through socket points. - Enable
Use Gravity. - Set
Collision DetectiontoContinuous Dynamic.

- Add
- Make the Objects Grabbable:
- Add
XR Grab Interactablecomponents to theTireandTire Lug NutGameObjects. - Enable
Smooth PositionandSmooth Rotationfor natural grabbing behavior. - Since the tire is relatively large and heavy, set its
Movement TypetoVelocity Trackingto simulate realistic physics while maintaining responsive control. - Lug nuts are small and lightweight. Therefore,
Movement Type = Kinematicgives more precise control, especially when aligning with small sockets. - Confirm that the models have
Collidercomponents.

- Add
- Create the Tire Socket:
- On the
Tire Stand, create an empty GameObject and name itTire Socket. - Add a
Sphere CollidertoTire Socket. - Adjust the collider radius (e.g.,
0.2) to detect the approaching Tire. - Enable
Is Trigger. - With
Tire Socketselected, add theXR Socket Interactorcomponent.

- On the
- Set Up the Attach Transform:
- Create a child GameObject under
Tire Socket, name itAttach Tire. - Position and rotate it so the
Tirealigns correctly. - Assign
Attach Tireto theAttach Transformfield ofXR Socket Interactor.

- Create a child GameObject under
- Measure the Attach Transform:
- To accurately set up the
Attach Transformfor the Tire socket, temporarily mount the full Tire model onto the stand in the correct position and orientation. - Create a child GameObject under the socket and manually copy the Tire’s transform values (position and rotation) into it. This ensures a perfect snap alignment when the
Tireis placed in VR.
- To accurately set up the
- Create Lug Nut Sockets:
- On the
Brake DiskGameObject (a child of theTireunderTire Stand), create an empty GameObject and name itLug Socket. - Position it at the tip of the first screw post where a lug nut will be attached.
- Add a
Sphere CollidertoLug Socket. - Enable
Is Trigger. - Adjust the radius (e.g.,
0.03–0.05) to create a small, accurate detection zone. - Add the
XR Socket Interactorcomponent toLug Socket. - Optionally, configure the
Interaction Layer Maskto only accept objects tagged asLugNut. - Create a child GameObject under
Lug Socketand name itAttach Lug. - Adjust its position and rotation so the lug nut aligns properly with the screw post.
- Assign
Attach Lugto theAttach Transformfield of the socket.

Make sure all
Lug Nutobjects have theirInteraction Layer Maskset toLugNutso that the sockets can detect and accept them correctly without interfering with theTiresocket. Interaction layers restrict sockets to accept only specific types of parts. This prevents misplacement and guides users toward correct assembly behaviors. - On the
- Duplicate for Remaining Lug Nut Positions:
- In the
Hierarchy, duplicateLug Socketfour times. - Reposition each socket at the tip of its corresponding screw post.
- This method ensures consistent and accurate socket configuration across all lug nut positions while saving setup time.

- In the
- Add Hover Audio Feedback (Interactor Event):
- In your project, create a
HoverSoundPlayer.csscript:
using UnityEngine; using UnityEngine.XR.Interaction.Toolkit; public class HoverSoundPlayer : MonoBehaviour { public AudioSource hoverAudio; // assign in Inspector // Called by XR Socket Interactor → Interactor Events → Hover Entered public void PlayHoverSound(HoverEnterEventArgs args) { if (hoverAudio != null) hoverAudio.Play(); } }- Create an
Empty GameObjectin your scene, name itHoverSoundManager. Add theHoverSoundPlayercomponent to it. - Add (or reference) an
AudioSourcewith your hover sound and drag it into theHover Audiofield of the script. - Select a
XR Socket Interactor(for example,Tire Socketor eachLug Socket). - In the
Inspector, expandInteractor Events → Hover → Hover Entered. - Click
+, drag theHoverSoundManagerGameObject into the object field. - From the function dropdown, choose:
HoverSoundPlayer → PlayHoverSound(HoverEnterEventArgs).

You can reuse the same
HoverSoundManageracross all sockets to keep setup simple. - In your project, create a
- Deploy and Test:
- Deploy the app to your device.
- You can experience a complete tire assembly sequence.
- When the part hovers over the socket, you’ll hear the sound play.
Snapping with Constraints
While the XR Socket Interactor provides basic snapping behavior, engineering applications often demand precise spatial alignment. For example, parts in the tire and lug nut assembly or the V8 engine may need to be within specific rotational or positional tolerances to be accepted—just as in real-world mechanical assemblies. To enable this behavior, the VR app should enforce custom alignment rules for snapping, reject improperly placed parts using haptics and audio, and validate placement based on vector math and distance checks.

Angle Tolerances
Vector math allows you to check angle tolerances. You can use dot products to calculate the angle between the up vector of the part and the correct alignment vector (e.g., global up for vertical orientation). This allows you to enforce a tolerance range, such as ±10°. In XFactory’s assembly station, for example, you may want to validate that a lug nut is aligned correctly before snapping to the brake disk. Get the lug nut’s transform.up, compare it to Vector3.up, use Vector3.Angle() to measure the deviation, and accept the snap only if within a defined range (e.g., ±10°):
using UnityEngine;
using UnityEngine.XR.Interaction.Toolkit;
public class PartAngleValidator : MonoBehaviour
{
public float maxAngleDeviation = 10f; // degrees
public AudioSource errorAudio;
private XRSocketInteractor socket;
void Start()
{
socket = GetComponent<XRSocketInteractor>();
socket.selectEntered.AddListener(CheckPartAngle);
}
void CheckPartAngle(SelectEnterEventArgs args)
{
Transform part = args.interactableObject.transform;
float angle = Vector3.Angle(part.up, Vector3.up);
// Compare part's up with world up
if (angle > maxAngleDeviation)
{
RejectPart(args.interactableObject, "Part angle too steep.");
}
}
void RejectPart(IXRSelectInteractable part, string reason)
{
socket.interactionManager.CancelInteractableSelection(part);
if (errorAudio != null)
errorAudio.Play();
Debug.Log("Snap rejected: " + reason);
}
}
Attach the PartAngleValidator.cs script to the socket GameObject where angle precision matters (e.g., a tire mount, engine part, or panel slot). Configure maxAngleDeviation in the inspector and assign an AudioSource for feedback (optional).

Distance
You can prevent snapping if a part is not close enough to its intended attach point, ensuring users move the part with adequate precision. For example, use Vector3.Distance() to measure how far an interactable is from the socket’s Attach Transform, and reject the snap if it exceeds a threshold:
using UnityEngine;
using UnityEngine.XR.Interaction.Toolkit;
public class PartDistanceValidator : MonoBehaviour
{
public Transform attachTransform; // Drag in the Attach point of the socket
public float maxSnapDistance = 0.15f; // meters
public AudioSource errorAudio;
private XRSocketInteractor socket;
void Start()
{
socket = GetComponent<XRSocketInteractor>();
socket.selectEntered.AddListener(CheckPartDistance);
}
void CheckPartDistance(SelectEnterEventArgs args)
{
Transform part = args.interactableObject.transform;
float distance = Vector3.Distance(part.position, attachTransform.position);
if (distance > maxSnapDistance)
{
RejectPart(args.interactableObject, "Part too far from socket.");
}
}
void RejectPart(IXRSelectInteractable part, string reason)
{
socket.interactionManager.CancelInteractableSelection(part);
if (errorAudio != null)
errorAudio.Play();
Debug.Log("Snap rejected: " + reason);
}
}
Attach the PartDistanceValidator.cs script to any socket where positional accuracy is important. In the Inspector, drag the corresponding Attach child GameObject into the script’s Attach Transform field.

Feedback
When misalignment is detected during socket interaction, it is important to give the user clear and immediate feedback. This can include audio cues (e.g., error sounds), haptic feedback via the VR controllers, visual cues or messages, or rejection of the snap, allowing retry or resetting the part’s position. For example, if a tire, bolt, or gear is misaligned or too far from the socket, you can reject the interaction, play a sound, and vibrate the controller to alert the user:
using UnityEngine;
using UnityEngine.XR.Interaction.Toolkit;
using UnityEngine.XR.Interaction.Toolkit.Interactors;
using UnityEngine.XR.Interaction.Toolkit.Interactables;
public class PartSnapValidator : MonoBehaviour
{
public Transform attachTransform;
public float maxAngle = 10f;
public float maxDistance = 0.15f;
public AudioSource errorAudio;
private XRSocketInteractor socket;
void Start()
{
socket = GetComponent<XRSocketInteractor>();
socket.selectEntered.AddListener(ValidatePart);
}
void ValidatePart(SelectEnterEventArgs args)
{
Transform part = args.interactableObject.transform;
float angle = Vector3.Angle(part.up, Vector3.up);
float distance = Vector3.Distance(part.position, attachTransform.position);
if (angle > maxAngle || distance > maxDistance)
{
RejectPart(args);
}
}
void RejectPart(SelectEnterEventArgs args)
{
IXRSelectInteractable part = args.interactableObject;
socket.interactionManager.CancelInteractableSelection(part);
// Audio feedback
if (errorAudio != null)
errorAudio.Play();
// Haptic feedback
XRBaseInputInteractor controller = args.interactorObject as XRBaseInputInteractor;
if (controller != null)
{
controller.SendHapticImpulse(0.7f, 0.2f); // intensity, duration
}
Debug.Log("Part rejected: not aligned or positioned correctly.");
}
}
Attach the PartSnapValidator.cs script to any socket that requires combined angle and distance validation. Make sure to assign the correct Attach Transform (child GameObject) in the Inspector. Optionally, assign an AudioSource to play error feedback when misalignment is detected.

Best Practices
The following best practices will help ensure reliable, realistic, and maintainable socket-based interactions in your XR projects—particularly when assembling complex objects.
-
Attach Transforms: Ensure that the local axes of the
Attach Transformmatch the intended orientation of the attached object. This guarantees seamless and realistic snapping during placement. In XFactory, when inserting a piston into a V8 engine block, a misaligned attach transform can cause the piston to appear rotated or offset. -
Trigger Colliders: Always use the smallest collider radius that still detects the intended object. Prefer
Sphere CollidersorBox Collidersthat tightly match socket volume. Set the collider asIs Triggerto detect entry without physical collisions. In XFactory, inserting a piston onto the engine block should not trigger the nearby crankshaft socket—use fine-tuned colliders to avoid overlap. -
Interaction Layers: Define dedicated
Interaction Layers for object categories (e.g.,Pistons,Tires,Tools). Assign both interactable objects and sockets to the correct layers via theInteraction Layer Mask. This limits what objects can interact with each socket and reduces unintended behavior. In XFactory, only allow parts with theEnginePartslayer to snap into engine sockets, preventing users from accidentally inserting another object into a piston slot. -
Alignment Validation: For realistic mechanical constraints, validate position and orientation before accepting a snap. Use
Vector3.Angle()for angular checks andVector3.Distance()for proximity. Reject poorly aligned parts and provide user feedback (e.g., audio, haptics). In XFactory, a piston must be within ±10° of vertical and under 0.15 meters from the socket before it’s accepted. -
Improper Object Snapping: If a part snaps incorrectly, check that the
Attach Transformis positioned and rotated accurately. Ensure theAttach Transformis assigned in theXR Socket Interactorcomponent. Use debugging tools (e.g.,Debug.DrawRay()) to visualize socket orientation in theSceneview. You can even write a script to visually validate attach transforms during development using gizmos. -
Unintended Interactions: Ensure that only intended object types can enter and attach to a socket. Double-check
Interaction Layer Maskon both socket and object. Use Tag filtering or custom scripts for more granular control. In XFactory, a socket expecting a cylinder head should not accept a tire, even if they share colliders orRigidbodysettings. -
Physics Behavior: Assign
Rigidbodycomponents to all grabbable objects. EnableContinuous Dynamiccollision detection to prevent fast-moving objects from tunneling through sockets or floors. If the object jitters or behaves unpredictably when grabbed, check for incorrectmassordragsettings,Collidercomponents that intersect at spawn time, or missing or incorrect layer-based collisions in Unity’s Physics settings. In XFactory, a scanner dropped near a rack may fall through the floor if itsRigidbodyusesDiscretecollision detection. -
Custom Logic:
XR Socket Interactorsare powerful but limited to proximity-based attachment. For realistic workflows (e.g., enforcing assembly order, alignment tolerances), pair sockets with scripts that validate geometry, check user sequence, and give meaningful feedback. In XFactory, only allow cylinder head snapping after all V8 pistons are correctly installed—using a simple script that loops through each piston socket and validates itsselectTarget.
Key Takeaways
Sockets in VR function as precise snap points that ensure objects align correctly, enhancing both realism and usability in XR assembly tasks. By configuring interactable objects with the appropriate physics settings, XR Grab Interactable components, and XR Socket Interactors, developers can create intuitive and reliable attachment systems. Careful setup of attach transforms, interaction layers, and collider sizes helps prevent misplacements and unintended interactions. For engineering-grade accuracy, adding alignment and distance validation through vector math ensures that only correctly positioned parts snap into place, with immediate audio, visual, or haptic feedback guiding the user. When combined with best practices in organization, physics configuration, and custom logic, these techniques enable robust, realistic, and maintainable socket-based interactions for complex VR assembly experiences.