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>