Microtube Docs
Developers / SDK architecture & API / Overview

SDK Architecture & API

How the HEXR Unity SDK is put together, how the glove connects, how interactions become haptics, and how to drive the glove from your own code.

SDK version

This page describes com.microtube.hexr version 0.9.3.

Package structure

The package is a stack. Your scene talks to the top; the glove sits at the bottom. The two backend layers only compile when their XR SDK is installed, and the core never depends on them.

AssemblyNamespaceHoldsCompiles when
HaptGlove.RuntimeHaptGloveHaptGloveHandler, Bluetooth transports, Haptics command buildersAlways
HexR.RuntimeHexRManager, hand tracking, Pressure Controllers, touch points, scene components, floating menuAlways
HexR.Runtime.MetaOVRHexR.MetaOVRMeta grab and poke detection, interactable events, passthroughMeta Interaction SDK installed
HexR.Runtime.OpenXRHexR.OpenXRXR Interaction Toolkit integration (OpenXR headsets, including PICO)XR Interaction Toolkit installed
HexR.EditorHexRHexR menu, Auto Setup, validator, HexR Tools windowEditor only

Backends register themselves with the core when they load. The collider visualizer, HexRUsable and the floating menu stay in the global namespace so older scenes keep working.

The HEXR scene

HexR → Create HexR Rig adds the first two. Your XR SDK provides the third.

ObjectComponentsRole
HexR MainHexRManagerOwns both gloves, runs connections, re-attaches the hands after a scene change. Reach it as HexRManager.Instance
Left / Right Hand PhysicsHaptGloveHandler, HexRTrackedHand, FingerUseTrackingOne per hand: the Bluetooth link, which tracked hand it follows, how bent each finger is
HexR Floating MenuHexRFloatingMenuIn-headset panel: connect gloves, show touch points, watch each finger’s haptics, switch scenes and demos. Pressed with a fingertip
Left / Right Pressure ControllerPressureTrackerMainThe haptics controller for that hand
Every scene needs one active pair of Pressure Controllers

The touch points find them by name when the scene starts. A hand without one produces no haptics. HexR → Add Pressure Controller adds them.

The tracked hand

HexRTrackedHand.handRoot points at your SDK’s hand. HEXR finds the joints by name:

XR SDKHand rootJoints
Meta Interaction SDKOpenXRLeftHand / OpenXRRightHandXRHand_IndexTip, XRHand_Palm, …
XR Interaction Toolkit + XR HandsL_Wrist / R_Wrist under Left / Right Hand Interaction VisualL_IndexTip, L_Palm, …

Each touch point is a small trigger collider, a kinematic Rigidbody (Unity needs one for trigger events) and a HapticFingerTrigger that says which hand and finger it is. HEXR has no hand of its own: since 0.9 the touch points sit on the tracked hand on every backend. An older project with a “ghost” hand can remove it with HexR → Migration → Remove Ghost Hand.

Connecting the glove

Your app opens the Bluetooth connection itself. No pairing in system settings, no companion app. Each glove has its own HaptGloveHandler.

Where your app runsBluetooth
Android headsets — Meta Quest, PICOSupported; the rig’s default
Windows — Unity Editor and 64-bit buildsSupported. In a build, set Build Platform on each HaptGloveHandler to Window. The Haptics Tester does this in the Editor

Events

C# events on HaptGloveHandler; subscribe with +=. They are not UnityEvents, so they do not show in the Inspector.

EventWhen
onBluetoothConnected(HandType)The glove connected
onBluetoothConnectionFailed(HandType)An attempt failed
onBluetoothDisconnected(HandType)A connected glove dropped out
onPumpAction(HandType, bool)The air supply started or stopped
onBatteryStateChange(BatteryState)Full, Medium or Low
onDeviceFound(id, name)A scan found a device
HexRManager.ConnectAttemptEndedStatic. A connect press finished, either way

How haptics fire

TriggerUse it forExample
XR interaction eventsFeeling an object while it is grabbed or hoveredHexRInteractableHaptics
Physics contactFeeling a surface, a liquid, a heartbeatSpecialHaptics
Your codeGame events, sequences, testsPressureTrackerMain

On Android, commands sent close together are grouped into one Bluetooth write about every 100 ms. Response time from command to sensation is under 20 ms.

The hand-near check

A Pressure Controller sends most haptics only while IsHandNear() is true. Any one of these makes it true:

SignalSet by
Grabbing, or hovering to grabYour SDK’s grab interactor — wired for you by Auto Setup and on every scene load
Poking, or about toYour SDK’s poke interactor — wired the same way
A fingertip inside a ProximityCheck volumeA ProximityCheck you add to an object that is not an SDK interactable
CheckedNot checked
Single…Haptic, TriggerAll…, TriggerCustom…, TriggerPinchPressureHapticFingerTrigger.TriggerFixPressure, every SpecialHaptics effect, CustomSingleHaptics / CustomSingleVibrations with byPassHandCheck: true, RemoveAllHaptics and the Remove…Haptics calls

If your call does nothing, check IsHandNear() first, or pass byPassHandCheck: true while testing.

Channels and parameters

Six channels: Haptics.Finger.Thumb, Index, Middle, Ring, Pinky, Palm. Each plays one mode at a time. Values outside a range are clamped.

ModeFeels likeParameters
PressureA steady pressintensity 0.1–1 (about 15–50 kPa); speed 0.1–1, how fast it ramps
VibrationPressure pulsing on and offfrequency 0.1–40 Hz; intensity 0.1–1. Below 5 Hz it sets pulse pressure, from 5 Hz pulse length
Slow pulseA shaped, slow rhythmfrequency 0.1–2 Hz; intensity; peakRatio 0.2–0.8; speed; endIntensity (below 0.1 releases)
Counted pulsesA set number of pulsesfrequency; intensity; pulseCount 1–1000

Scene components

Most projects never call the API. These components fire haptics on their own.

ComponentUse it forKey fields
HexRInteractableHaptics — start hereFeel your SDK’s own interactable (XRI or Meta) while grabbed or hovered. The backend is picked automaticallyfireOn Select / Hover / SelectAndHover; finger toggles; strength; followGrip + minStrength; backend
SpecialHapticsA trigger collider that plays a preset effect when touchedTypeOfHaptics (table below), HapticPressure, VibrationsFrequencyValue, InTimer / OutTimer
ProximityCheckTell the Pressure Controller a hand is near an object that is not an SDK interactableAuto Set Up button wires both Pressure Controllers
HexRPhysicalButtonA button pressed by a real fingertip, no SDK needed. The floating menu is built from itonPressed; accepted fingers (index by default)
HexRUsableTriggers, handles, grips: fires when chosen fingers curlUseThreshold; WhenUseTriggerEvents / WhenStopUsingTriggerEvents
HapticFingerTriggerThe touch point itself. Read it in your own OnTriggerEnter to learn which hand and finger touchedhandType, fingertype; TriggerFixPressure, TriggerVibrationPressure, RemoveHaptics
HexRGrabbableHEXR's own grab, picked up by the glove hands with no interaction SDK. For an object that should also grab without gloves, use HexRInteractableHapticsPinchGrab / PalmGrab; needs a trigger Collider and a Rigidbody
SpecialHaptics effectFeels like
CustomHapticsConstant pressure while touched
CustomVibrationsVibration at a set frequency and strength
FountainEffectRunning water
RainDropEffectRaindrops on the palm
HeartBeatEffectA beating heart, regular or irregular
HandSqueezeEffectFires OnSqueezeEventTrigger when the hand closes on the zone. Needs FingerUseTracking on the rig’s hands

C# API

Call these when you want haptics driven by your own logic.

PressureTrackerMain — on each Pressure Controller

MethodDoes
CustomSingleHaptics(finger, state, targetPressure, speed, byPassHandCheck)Pressure on one channel. state true applies, false releases; targetPressure and speed 0.1–1
CustomSingleVibrations(finger, state, targetPressure, frequency, byPassHandCheck)Vibration on one channel; frequency 0.1–40 Hz
SingleThumbHaptic(float) … SinglePalmHaptic(float)Pressure 0.1–1 on one channel. One float, so they wire to a UnityEvent
RemoveThumbHaptics() … RemovePalmHaptics()Release one channel
TriggerAllHapticsIncrease(float) / TriggerAllVibrations(frequency)Every channel at once
TriggerCustomHapticsIncrease(bool[6], pressure, speed) / TriggerCustomlVibrations(bool[6], intensity, frequency)A chosen set of channels, in Thumb…Palm order
TriggerPinchPressure(float) / RemovePinchPressure()Thumb-and-index pinch
RemoveAllHaptics() / RemoveAllVibrations()Release everything
IsHandNear()Whether the hand-near check passes

HexRManager — HexRManager.Instance

MemberDoes
ConnectLeftBT() / ConnectRightBT()Connect that glove. Safe to wire to a button
leftHand / rightHandEach glove’s HaptGloveHandler
XRFrameworkOpenXR or MetaOVR
RebindHandsToCurrentScene()Re-attach the touch points to this scene’s hands. Runs by itself on every scene load
Collider settingsSize and placement of the touch points Auto Setup adds, per skeleton
ConnectAttemptEndedStatic event: a connect press finished

HaptGloveHandler — one per glove, namespace HaptGlove

MemberDoes
whichHandLeft or Right
BTConnection()Connect, or disconnect if connected. Prefer the manager’s Connect…BT(), which adds permissions and the one-at-a-time rule
bleConnectedConnected right now?
UseCustomDeviceName, OptionalCustomDeviceNameLook for a glove by a name you choose
RememberDevice(id), ForgetDevice(), ConnectToDevice(id)Which glove it goes straight to
hapticsBuilds commands: HEXRPressure, HEXRVibration, HEXRPulse. GetChannelState(finger) returns what the last command set on a channel, as a ChannelState (HapticMode, intensity, frequency)
BTSend(byte[])Send a command straight to the glove. Skips the hand-near check
GetBatteryLevel(), GetAirPressure()Latest battery level and pressure readings

HexRTrackedHand and FingerUseTracking — on each hand

MemberDoes
HexRTrackedHand.handType, handRootWhich hand, and the tracked hand it follows
ResolveRawFingerJoint(finger), ResolveRawPalmJoint()The tip or palm joint, on either skeleton
FingerUseTracking.ThumbUse … LittleUse0 = fully curled, 1 = fully extended. Self-calibrating: settles once the hand has opened and closed
FingerUseTracking.isHandOpen()All fingers extended?

Scene changes and editor tools

Your SDK’s hands die with their scene; the rig lives on. So after every scene load the manager re-attaches:

Then the log says [HexR] Rebound Left hand … 6 haptic trigger(s): five fingertips and the palm.

Auto Setup does the same in the Editor so it is saved with the scene. It only adds what is missing and never moves a collider you tuned. Run it from Create HexR Rig, HexR → Troubleshoot → Re-run Auto Setup, or the manager’s Auto Set Up HexR button. Validate Scene Setup then reports anything still unwired.

MenuDoes
HexR → HexR ToolsThe tools window: Haptics Tester (connect a glove in Play mode, fire any channel, watch live pressure), HexR Setup (the validator as a checklist), Project Setup (detects your backend, installs its packages)
HexR → Create Demo SceneRig, Pressure Controllers, a grabbable object and a haptic zone
HexR → Create HexR RigThe rig and Pressure Controllers for your backend, then Auto Setup
HexR → Add Pressure ControllerThe pair of Pressure Controllers
HexR → Add HexR MenuThe floating menu in your own scene
HexR → TroubleshootRe-run Auto Setup, Validate Scene Setup
HexR → MigrationOne-off upgrades, such as Remove Ghost Hand
Floating menu → Show CollidersDraws every touch point on the tracked hands
Floating menu → HAPTICSThe value last sent to each finger and the palm of each glove, as your code passed it: lit while on, dimmed after. Turn it off with showHapticsReadout

Type index

Every public type in com.microtube.hexr, for looking a name up. Where a section above covers it, the link goes there.

Components

TypeWhat it is
HexRManagerThe rig: both gloves, connections, re-attaching the hands. Members
HaptGloveHandlerOne glove’s Bluetooth link and command sender. Members
PressureTrackerMainA Pressure Controller: every haptic for one hand goes through it. Methods
HexRTrackedHand, FingerUseTrackingWhich tracked hand a glove follows, and how bent each finger is. Members
HapticFingerTriggerThe touch point on each fingertip and the palm. Scene components
HexRInteractableHapticsHaptics on your SDK’s own interactable. Scene components
HexRGrabbableHEXR’s own grab, by the glove hands with no interaction SDK. Scene components
SpecialHaptics, ProximityCheck, HexRPhysicalButton, HexRUsablePreset effects, the hand-near volume, fingertip buttons, curl-to-use. Scene components
HexRFloatingMenuThe in-headset panel. The HEXR scene
HaptGloveCollidersVisualizerDraws the touch points; what the menu’s Show Colliders uses. SetVisible(bool), IsShowing
HaptGloveUIOn HexR Main: keeps the manager’s glove status text up to date
SceneLoaderScene transitions for the app. Sits on the same persistent object as HexRManager
HexRGripByHandOpenXR: gives a stock XRGrabInteractable a grip per hand, and a pinch or fist hold, without replacing it. GripMode picks the hold
OpenXRHandNearSource, MetaOVRHandNearSourceFeed the hand-near check from the grab and poke interactors. Auto Setup adds them
OpenXRBackendSetup, MetaOVRBackendSetupWire those sources onto the Pressure Controllers, in the Editor and at run time. Nothing to add yourself
MetaOVRPassthrough, IHexRPassthroughPassthrough on Meta, and the interface the menu uses to refresh any backend’s passthrough after a scene load

Enums and values

TypeValues and where it is used
HapticsCommand builders, on HaptGloveHandler.haptics. Channels and parameters
Haptics.FingerThumb, Index, Middle, Ring, Pinky, Palm
Haptics.HapticMode, Haptics.ChannelStateWhat the last command set on a channel: Off, Pressure, Vibration or Pulse, with intensity and frequency. From GetChannelState(finger)
HandTypeLeft / Right, on HaptGloveHandler and on HapticFingerTrigger
FingerTypeWhich finger a HapticFingerTrigger is, in fingertype
BatteryStateFull, Medium, Low. Events
TargetPlatformA glove handler’s Build Platform: Android or Windows. Connecting the glove
FireOnHexRInteractableHaptics.fireOn: Select, Hover, SelectAndHover
HexRBackendChoiceWhich interaction SDK drives a component: Auto or a named backend
HexRHandSideWhich hand an interaction came from, as a backend reports it
HeartBeatSpecialHaptics heartbeat: Regular or Irregular
Options, OptionHexRGrabbable.Options PinchGrab / PalmGrab; HexRGrabbable.Option gravity On / Off; HexRManager.Options is XRFramework
FingertipCentersPer-finger touch point offsets in the manager’s collider settings

Backend plumbing, editor and internals

TypeWhat it is
IHexRInteractionBackend, IHexRInteractionBinding, IHexRInteractionSink, HexRInteractionBackends, HexRHandSideResolverHow an XR SDK plugs into HEXR. Only needed to add a backend of your own
HexRCompatStand-ins for Unity APIs renamed between 2022.3 and Unity 6. See Unity version support
HexRMenu, HexRAutoSetup, HexRSetupValidator, SetupCheck, HexRToolsWindowEditor: the HexR menu, Auto Setup, Validate Scene Setup and the HexR Tools window. Editor tools
HexRSettingEditorGUI, HexRInteractableHapticsEditor, HapticEffectControllerEditor, ProximityCheckEditor, FingerUseTrackingEditorSettingEditor: the Inspectors for HexRManager, HexRInteractableHaptics, SpecialHaptics, ProximityCheck and FingerUseTracking
BLE, BLEScan, BLEData, Characteristic, Service, DeviceUpdate, ErrorMessage, ScanStatus, Encode, Decode, FunIndex, AndroidUiThreadInternal: the Bluetooth layer under HaptGloveHandler. Not for direct use; go through the handler or a Pressure Controller

Python

Outside Unity, HaptGlovePython builds the same commands; you write them with bleak. Setup and examples are in the Python guide.

MethodDoes
hexr_pressure_multiple(fingers, states, intensities, speeds)Pressure on several channels in one write; intensities and speeds 0.1–1
hexr_vibrations(finger, state, frequency, intensity, peakRatio, speed, endIntensity)The slow pulse, 0.1–2 Hz. hexr_vibrations_multiple takes lists
AddressDiscovery.py, CharacteristicDiscovery.py, ExampleHaptics.pyFind your glove, list what it exposes, run a ready example
Fingers are enum members

Use Haptics.Finger.Index, not "Index". A string raises AttributeError.

Example

Press the index finger while a fingertip is inside this zone. HapticFingerTrigger says which hand touched, so the command goes to the right Pressure Controller.

csharp
using UnityEngine;
using HaptGlove;
using HexR;

public class IndexPress : MonoBehaviour
{
    public PressureTrackerMain leftHand;    // Left Pressure Controller
    public PressureTrackerMain rightHand;   // Right Pressure Controller

    void OnTriggerEnter(Collider other)
    {
        PressureTrackerMain hand = HandOf(other);
        // finger, apply, intensity 0.1-1, ramp speed 0.1-1, bypass the hand-near check
        if (hand != null) hand.CustomSingleHaptics(Haptics.Finger.Index, true, 0.8f, 1f, true);
    }

    void OnTriggerExit(Collider other)
    {
        PressureTrackerMain hand = HandOf(other);
        if (hand != null) hand.CustomSingleHaptics(Haptics.Finger.Index, false, 0f, 1f, true);
    }

    PressureTrackerMain HandOf(Collider other)
    {
        HapticFingerTrigger finger = other.GetComponent();
        if (finger == null) return null;
        return finger.handType == HapticFingerTrigger.HandType.Left ? leftHand : rightHand;
    }
}

Where to go next

Integrating into an existing app? Start with HexRInteractableHaptics before the lower-level PressureTrackerMain or HaptGloveHandler.