Godot addon architecture & API
How the HexR Godot addon is built, its GDScript API, and how it maps onto the Unity package.
What is in the addon
| Folder | What |
|---|---|
core/ | The glove protocol (frame encoder, telemetry decoder), HaptGloveHandler, Haptics, SceneLoader and the HexR autoload |
transport/ | Bluetooth LE: Android (the HexRBle Java plugin), Windows (the HexRBleWinRT extension) and simulated gloves for tests and other platforms |
hands/, haptics/, components/, interaction/ | Tracked hands and their HapticFingerTriggers, PressureTrackerMain, the scene nodes, the XR Tools binding |
ui/, remote/, editor/ | The floating menu, HexR Remote, the HexR menu, the HexR Tools dock, the inspectors and the Android export step |
All GDScript, so it runs on the standard (non-.NET) Godot. Native code only where Godot cannot reach Bluetooth or screen capture: a Java Android plugin and a C++/WinRT extension, both built by CI and shipped in the release zip.
Wire compatibility
The addon sends the same bytes as the Unity package: its encoder does Unity’s arithmetic in 32-bit floats, and its tests compare 555 command frames with the Unity package’s output. It speaks the same HexR Remote protocol, so the HexR Companion works with Godot and Unity apps alike.
Connecting the glove
- A connect scans for
HaptGloveAR Left/Right, or goes straight to the glove it remembers (per platform, inuser://hexr.cfg). - It subscribes to the glove’s readings once per connection, negotiates the largest packet the headset allows, and cuts each write to fit on frame boundaries.
- Failed attempts retry after 1, 2, 4 and 8 seconds, for up to a minute; a 20-second watchdog restarts a silent attempt; a dropped glove reconnects by itself.
- On Android, commands go out at most every 100 ms, batched. Releases skip the queue. When the app pauses, the Java plugin releases the glove itself, because scripts stop running.
GDScript API
The calls most games use. Every class, signal, property and method is in the addon’s API reference ↗, and in Godot’s built-in help: press F1 and search for HexR.
HexR (autoload)
connect_hand(hand), disconnect_hand(hand), toggle_hand(hand), begin_connect(hand), connect_left_bt(), connect_right_bt(), is_hand_connected(hand), is_hand_connecting(hand), glove(hand), controller(hand), tracked_hand(hand), finger_use(hand); the gloves as left_hand and right_hand. Signals glove_connected, glove_disconnected, glove_connect_failed, connect_attempt_ended, battery_state_changed, pump_changed, status_changed, device_found.
HaptGloveHandler
bt_send(bytes), bt_connection(), bt_disconnection(), release_all_channels(), release_channels(fingers), get_battery_level(), get_air_pressure_kpa(), get_finger_position(), set_battery_level_update_interval(seconds), remember_device(id), forget_device(), connect_to_device(id); properties which_hand, haptics, ble_connected, status_text, optional_custom_device_name, release_when_paused. Signals bluetooth_connected, bluetooth_disconnected, bluetooth_connection_failed, battery_state_changed, pump_changed.
PressureTrackerMain
single_index_haptic(intensity) … single_palm_haptic, remove_index_haptics() …, custom_single_haptics, custom_single_vibrations, trigger_all_haptics_increase, trigger_custom_haptics_increase, trigger_pinch_pressure, trigger_all_vibrations, trigger_custom_vibrations, trigger_pulse_it, remove_all_haptics, remove_all_vibrations, is_hand_near(), static strength_to_intensity(strength); readings thumb_pressure … palm_pressure and tank_pressure.
SceneLoader
Static, as in Unity: load_scene(name_or_index), load_next_scene(), load_previous_scene(), reload_current_scene(), get_current_scene_name(), get_current_scene_index(), over the scenes listed in hexr/scenes.
Coming from Unity
The classes keep the Unity package’s names: HaptGloveHandler, Haptics, PressureTrackerMain, HapticFingerTrigger, HexRTrackedHand, FingerUseTracking, SpecialHaptics, ProximityCheck, HexRGrabbable, HexRPhysicalButton, HexRUsable, HexRInteractableHaptics, HexRFloatingMenu, HexRRemote, HaptGloveCollidersVisualizer, SceneLoader. Their members are Unity’s in Godot’s snake_case, so TriggerPinchPressure is trigger_pinch_pressure and typeOfHaptics is type_of_haptics. The editor matches too: a HexR menu with Unity’s items, and the HexR Tools dock with its three tabs (Haptics Tester, HexR Setup, Project Setup). Where Godot differs, and why:
| Unity package | Godot addon | Why |
|---|---|---|
HexRManager.Instance | the HexR autoload (or HexRManager.instance) | Godot’s singletons are autoloads |
Connect / Disconnect / IsConnected(hand) | connect_hand / disconnect_hand / is_hand_connected(hand) | Every Godot object already has connect, disconnect and is_connected |
TriggerAllHapticsIncrease(0.5f) | trigger_all_haptics_increase(0.5) | Godot’s snake_case; enum values are UPPER_CASE |
HEXRPressure overloads | hexr_pressure, hexr_pressure_multi, hexr_vibration_ramped, … | GDScript has no overloads |
UnityEvents OnGrab, onPressed | signals grabbed, pressed | Godot’s signals |
Gravity on HexRGrabbable | gravity_on_release | Area3D already has gravity |
HapticFingerTrigger.FingerType | Haptics.Finger everywhere | One channel order, the glove’s |
| Build Settings scene list | Project Settings → HexR → Scenes (hexr/scenes) | Godot has no Build Settings list |
| Auto Setup, hand roots | none needed | The finger triggers follow the OpenXR hand tracker directly |
| XRI / Meta Interaction SDK backends | Godot XR Tools | Godot’s XR toolkit |
| Package Manager git URL | the release zip, unzipped into addons/ | Godot installs addons as folders |
A project that already has a class with one of these names (a SceneLoader autoload, say) gets Godot’s “hides a global script class” error: rename yours.
HexR Remote
Add a HexRRemote node and the HexR Companion’s Headsets tab finds the app on the same Wi-Fi: both gloves’ state and pressures, connect and release, scene switching, your commands, and the headset’s view and sound on Android (the wearer accepts a capture prompt). It outlives scene changes.
# A button in the HexR Companion's Headsets tab, while this node is in the scene.
func _ready() -> void:
HexRRemote.register_command("reset", "Reset demo", reset_demo)
func _exit_tree() -> void:
HexRRemote.unregister_command("reset")HexR Remote is not authenticated: anyone on the same Wi-Fi with a HexR Remote client can control the gloves. Bring a dedicated router to events.
How it is tested
Every push runs the GDScript tests on Godot 4.6 and 4.7.2, with both Jolt and Godot Physics: the byte-exact frames, the decoder, the connection campaign against a simulated glove, the scene nodes through real physics overlaps, and HexR Remote over real sockets, checked again with the Unity package’s own Remote probe. The Android plugin and the Windows extension build in CI with their own tests.