Add a custom movement¶
Named movements are defined in a TOML config, not in code - so adding one is an edit, not a rebuild. This is the right path when the gesture is something you can name ahead of time. (For arbitrary runtime poses, see Stream a custom pose instead.)
Where the config lives¶
On first run VHI generates user://movements.toml. Godot's user:// resolves
to a per-project app-data directory:
| OS | Resolved path |
|---|---|
| macOS | ~/Library/Application Support/Godot/app_userdata/Virtual Hand Interface/movements.toml |
| Windows | %APPDATA%\Godot\app_userdata\Virtual Hand Interface\movements.toml |
| Linux | ~/.local/share/godot/app_userdata/Virtual Hand Interface/movements.toml |
The default path is the ConfigFilePath export,
baked into the build at edit-time - so a compiled binary can't change its
default. To use a TOML kept under version control, open the control panel
(right side, > button) and click Load Config File to pick any TOML from
disk; VHI then watches that file for hot-reload instead. The same panel has
Edit Config File, which opens the current file in your OS's default text
editor.
Edit and hot-reload¶
VHI watches the file with a FileSystemWatcher - save the TOML and the hand
updates live, no restart.
Each movement is a [movements.<Name>] table with one line per joint -
joint_name = [x, y, z], the joint's max-flexion pose in Euler degrees.
There is no rest pose in the file; rest is always neutral ([0, 0, 0]). On the
X axis, positive = flexion, negative = extension. The generated file is the
best reference - open it and copy an existing entry like Fist, rename it, and
adjust the joint values.
Files written before VHI 2 are signed the other way
They said negative = flexion, and VHI negated every row again on the
way to the bone, so the two cancelled. That is fixed, which means the old signs
now mean what they say — backwards. A file without a convention key is
detected as Unity-signed and migrated in place on first load, with a
.unity-signed.bak copy left beside it. Check the result if you had hand-tuned
poses.
# movements.toml - one movement entry (joint_name = [x, y, z], degrees)
convention = "rig-native" # positive X is flexion; omit and the file is migrated
[movements.MyGesture]
wrist = [0, 0, 0]
thumb_proximal = [20, 0, 0]
thumb_middle = [30, 0, 0]
thumb_distal = [30, 0, 0]
index_proximal = [40, 0, 0]
# … index_middle, index_distal, then middle_*, ring_*, pinky_* (16 joints total)
Make it selectable¶
Once the movement is in the config:
- it appears in
GetRecordingSessionState().available_movements, so a client can discover it without hard-coding anything; - a standard discrete DOF declaring
"mygesture"as one of its states resolves to it and holds its end pose, andStartRecordingTrajectorycycles it when you want a swept trajectory for recording; - the keyboard Left / Right cycle through it;
- it shows up in MyoGestic's movement palette.
Keep names in sync
a discrete DOF matches by name. If MyoGestic sends class labels straight
through to a discrete DOF, the classifier's class names and the movement
names in this TOML need to agree - unknown names are rejected with
applied = false.