A-Frame Grabable Object
With hand-tracking, it's hard to detect whether the user intend to grab an object or not because of lack of buttons. Magnet-helper is a tool that allows developers to create more natural and realistic hand interactions in WebXR experiences. We'll create a simple A-Frame scene where you can attract and hold 3D objects using your hands. This is part of the Handy-work package: https://github.com/vincentianxing/handy-work
Method 1
Set Up Your Project
Create a new HTML file and include the A-Frame and Handy-Work libraries by adding the following script tags in the head of your HTML file:
<!DOCTYPE html>
<html>
<head>
<script src="<https://aframe.io/releases/1.2.0/aframe.min.js>"></script>
<script src="<https://raw.githubusercontent.com/AdaRoseCannon/handy-work/main/handy-work.js>"></script>
</head>
Create the A-Frame Scene
Next, add a basic A-Frame scene in the body of your HTML:
<body>
<a-scene>
<!-- Your 3D objects will go here -->
</a-scene>
</body>
</html>
You can add any 3D objects you want to interact with. For this tutorial, we'll add a simple sphere:
<a-sphere id="magnet-target" position="0 1.5 -3" radius="1" color="#EF2D5E"></a-sphere>
Add Handy-Work and Magnet-Helper Component
We'll create an A-Frame component that uses the Handy-Work library to track the user's hands and magnet-helper for object interaction. Add this script inside your head tag:
<script>
AFRAME.registerComponent('magnet-hands', {
init: function () {
const sceneEl = this.el;
const targetEl = sceneEl.querySelector('#magnet-target');
const magnet = new handyWork.MagnetHelper(targetEl.object3D, {strength: 0.05, distance: 2});
handyWork.start();
handyWork.addEventListener('frame', (e) => {
const hands = e.detail;
hands.forEach(hand => {
if (hand.pinchStrength > 0.7) {
// attract the target object when the user pinches their fingers
const {position} = hand.pointerPose;
magnet.attractTo(position);
}
});
});
}
});
</script>
This initializes the hand tracking and magnet-helper when the scene is loaded. Every time a new frame is received, the listener function will be called with an event object containing the tracked hand data.
Add the Magnet-Hands Component to the Scene
Lastly, add your new magnet-hands component to the A-Frame scene:
<a-scene magnet-hands>
<a-sphere id="magnet-target" position="0 1.5 -3" radius="1" color="#EF2D5E"></a-sphere>
</a-scene>
You should now be able to attract the sphere in your A-Frame scene using hand tracking and the magnet-helper from Handy-Work.
Method 2
If you want to grab most 3D models in general regardless of customization.
Add these in your index.html and use the starter code from Handy-work
<!-- These get drawn towards grabable objects, moving the whole hand and the attached elements-->
<a-entity id="left-magnet" data-left="grip" data-magnet="magnet-left" grab-magnet-target="startEvents:squeezestart,pose_fist;stopEvents:pose_flat_fuseShort,squeezeend;noMagnetEl:#left-no-magnet;"></a-entity>
<a-entity id="right-magnet" data-right="grip" data-magnet="magnet-right" grab-magnet-target="startEvents:squeezestart,pose_fist;stopEvents:pose_flat_fuseShort,squeezeend;noMagnetEl:#right-no-magnet;"></a-entity>
<!-- markers to let us know the real location of the hands, you probably want to make them visible="false" or just make them empty <a-entities> -->
<a-entity id="left-no-magnet" data-left="grip" data-no-magnet>
<a-entity html="html:#my-interface;cursor:#cursor" position="-0.142 -0.0166 -0.02928" rotation="-80 90 0" scale="0.7 0.7 0.7"></a-entity>
</a-entity>
<a-entity id="right-no-magnet" data-right="grip" data-no-magnet></a-entity>