---
title: AFS_Core_Pawn
product: Advanced Framework Pro
version: 1.0
engine: Unreal Engine 5.8
updated: 2026-10-05
canonical: https://docs.human-codeable.com/plugins/afs-core-pawn.html
---

System

# AFS_Core_Pawn

The VR, desktop and mobile pawns, motion controllers, hand animation, touch input, and the C++ hand-tracking and gesture system with its Hand Pose Studio editor.

#### What it gives you

- Three pawn families in Pawn and Character variants
- Motion controller actors with per-hand abilities
- Hand tracking, gesture recognition and synthetic input keys
- Hand Pose Studio for authoring grip poses

#### Requires

None

Engine: OpenXR OpenXRHandTracking

#### Required by

None

21 assets72 API members

## Description

This plugin provides the player. Three pawn families — VR, desktop and mobile — each in a plain `Pawn` and a `Character` variant, so you can choose between simple movement and full character movement without changing anything else.

The VR pawn spawns its motion controllers as actors rather than components, attached to a `CameraHandle` that sits between the actor root and the camera. That separation is what makes room-scale work: the capsule can be recentred under the player's head and its height adjusted to the real player without dragging the tracked camera with it.

Hand tracking is handled in C++. Gestures are described declaratively as data assets — finger curl ranges, bone distances, bone angles, a hold time and a priority — and when one is recognised the plugin **injects a synthetic input key**. That means gestures bind in Enhanced Input exactly like a controller button, and no ability needs to know gestures exist.

## Setup

1. Enable `AFS_Core_Pawn`. OpenXR and OpenXR Hand Tracking are enabled with it.
2. Subclass the pawn you need — start from `BP_Pawn_VR_Char_Showroom` rather than the raw `BP_Pawn_VR_Char`, since the showroom variant already has the common abilities attached.
3. On the VR pawn, set **Left Controller** and **Right Controller** to the motion controller classes you want. `AFE_Showroom` ships controller-mesh and hand-mesh variants of each.
4. Assign your pawn classes in the level's `PDA_Level`.

[![Assigning motion controller classes on the VR pawn](../images/AFS_Core_Pawn_setup-1600.webp?v=a997270b)](../images/AFS_Core_Pawn_setup-1600.webp?v=a997270b)

Assigning motion controller classes on the VR pawn

Tip

With no headset connected the VR pawn still spawns its controllers, pinned to fixed offsets in front of the camera. This keeps VR code paths exercised when you test in a flat editor window.

## Usage

### Choosing which pawn spawns

You do not choose in the level — you choose in the `PDA_Level` data asset. Leave **Pawn Select** on Dynamic and the framework detects headset, then mobile platform, then falls back to desktop.

### Adding an ability to a hand

Add a `BPC_ControllerAbility` subclass to the motion controller Blueprint, not to the pawn. It receives its pawn, controller and side through `InitiateControllerAbility`.

### Recentring the capsule after movement

Call `Interface_RecenterCapsule` on the pawn. Locomotion already does this; call it yourself if you move the player by other means.

### Defining a gesture

Create a `UAFSHandGestureDefinition` data asset. Add finger curl rules, bone distance rules and bone angle rules — all must pass simultaneously. Set **Min Hold Time** to avoid flicker and **Priority** to resolve overlaps. Assign the left and right input keys, then bind those keys in your input mapping context.

[![A gesture definition with curl and distance rules](../images/AFS_Core_Pawn_gesture_dataasset-1600.webp?v=f4cef594)](../images/AFS_Core_Pawn_gesture_dataasset-1600.webp?v=f4cef594)

A gesture definition with curl and distance rules

### Authoring a hand pose

Use Hand Pose Studio — see [Author a hand pose](../workflows/author-hand-pose.html).

## Key properties

| Property | On | When to change |
|---|---|---|
| `Left Controller` / `Right Controller` | `BP_Pawn_VR` | To swap between controller meshes and hand meshes, or to your own |
| `HMD` | `BP_Pawn_VR` | Rarely; set automatically from the runtime |
| `Trace Distance` | `BPC_Input_Touch` | To change how far mobile touch input reaches |
| `Min Hold Time` | Gesture definition | Raise if a gesture flickers on and off |
| `Priority` | Gesture definition | Raise when two gestures can both match the same hand shape |

## Extending

Derive from a pawn, implement `BPI_PawnInfo`, and return the right `E_Pawn_Type`. Assign it in `PDA_Level` and the rest of the framework adapts.

To add a new gesture, create a data asset — no code. To add a new synthetic key, extend `FAFSGestureInputKeys` in C++ and register it during module startup.

## Performance notes

Performance

The VR pawn's `AutoAdjustCapsuleHeight` polls on a 0.5 s loop rather than ticking. Gesture evaluation runs per hand per frame while hand tracking is active — if you define many gestures, use Priority and Min Hold Time to keep the matching set small.

## Example map

`Map_Examples_Interaction_Hands` demonstrates hand tracking, custom poses and gesture-driven interaction.

## Troubleshooting

**The player spawns at floor height.** The pawn is the plain `Pawn` variant where the `Character` variant was expected, or teleport location correction is not being applied.

**Hands do not appear.** The motion controller classes are not assigned on the pawn, or OpenXR Hand Tracking is not enabled.

**A gesture never fires.** Its rules cannot all be satisfied simultaneously — widen a curl range first, since those are the most commonly over-tightened.

## API reference

Every blueprint asset in this plugin. Expand an asset to see its members.

### AnimBP

**ABP_Hand**2 members

extends `AnimInstance` · implements `BPI_AnimBP_Hand`

Animation blueprint driving the framework's hand mesh. It implements the hand animation contract, easing every value handed to it (pointing, thumb up, trigger and grip axes, hand tracking and a custom pose) into a blend weight over time rather than snapping, and mirrors the right-handed pose set for the left hand after asking the owning motion controller which side it is. Assign it as the animation class on a hand mesh, or subclass it to add poses of your own.

| Kind | Name | Signature | Description |
|---|---|---|---|
| event | `BlueprintInitializeAnimation` | `()` | Executed when the Animation is initialized |
| event | `BlueprintUpdateAnimation` | `(DeltaTimeX: float)` | Executed when the Animation is updated |

**CR_Hand_HandTracking**2 members

extends `ControlRig`

Control rig posing the hand mesh from tracked hand data. It takes the bone transforms the motion controller reports, maps them onto the named left and right bone chains, and mirrors the right-hand set when it drives the left. Driven by the hand animation blueprint; there is nothing to set unless your hand skeleton names its bones differently.

| Kind | Name | Signature | Description |
|---|---|---|---|
| var | `Transforms` | `Transform[]` | Tracked joint transforms the rig poses the hand from, one per XR hand joint, in the hand mesh's own space. Filled in by the animation blueprint through Hand Hand Tracking Transforms rather than set here, and empty whenever hand tracking is not reporting. |
| var | `Mirror` | `bool` | Whether the incoming joint transforms are mirrored before the rig applies them. Set for the left hand, because the hand mesh and its animations are right-handed and both hands share this one rig. |

### Blueprints/Desktops

**BP_Pawn_Desktop**3 members

extends `Character` · implements `BPI_Trace`, `BPI_PawnInfo`, `BPI_AbilityRestriction`

Base keyboard-and-mouse pawn: a character with a camera, the pawn interaction state component and the character teleport ability. Handles look, move, jump, crouch and sprint from the desktop mapping context, switches between Game Only, Game and UI and UI Only control modes, and answers the trace contract by tracing from the camera or the mouse and caching the hit for a fiftieth of a second. Subclass it to add abilities; the Char variant adds a visible body.

| Kind | Name | Signature | Description |
|---|---|---|---|
| fn | `ResetTraceTimer` | `()` | Internal handler that marks the cached trace stale so the next Get Latest Trace runs a fresh line trace. Fired by a timer set to the trace refresh interval rather than called directly. |
| event | `Client_Possessed` | `(NewController: Controller)` | Called on the owning client once the pawn has a controller. Waits until the pawn really is locally controlled, adds the desktop input mappings, applies the current screen control mode, puts the crosshair on screen and hands the pawn to every pawn ability. |
| event | `Client_Unpossessed` | `(OldController: Controller)` | Called on the owning client when the pawn loses its controller. Removes the desktop input mappings, unpossesses every pawn ability and takes the crosshair off screen. |

**BP_Pawn_Desktop_Char**0 members

extends `BP_Pawn_Desktop`

Desktop pawn with a visible body: head, torso and headset meshes marked owner-no-see, so other players in a networked session see a figure where the local player sees only the view from the camera. It adds no behaviour beyond the desktop pawn it inherits from, so subclass it, as the showroom pawns do, to give the pawn the abilities it needs.

No editor-visible members; this asset configures defaults only.

### Blueprints/Mobile

**BP_Pawn_Mobile**2 members

extends `Character` · implements `BPI_AbilityRestriction`, `BPI_Trace`, `BPI_PawnInfo`

Base touch pawn: a character with a camera, the touch input component, the pawn interaction state component and the character teleport ability. One finger swiping turns and pitches the view, a double tap on ground within thirty degrees of level teleports the pawn there, and focus and traces follow the first finger through the trace contract. Subclass it to add abilities; the Char variant adds a visible body.

| Kind | Name | Signature | Description |
|---|---|---|---|
| event | `Client_Possessed` | `(NewController: Controller)` | Called on the owning client once the pawn has a controller. Waits until the pawn really is locally controlled, adds the mobile input mappings and hands the pawn to every pawn ability. |
| event | `Client_Unpossessed` | `(OldController: Controller)` | Called on the owning client when the pawn loses its controller. Removes the mobile input mappings and unpossesses every pawn ability. |

**BP_Pawn_Mobile_Char**0 members

extends `BP_Pawn_Mobile`

Touch pawn with a visible body: head, torso and headset meshes marked owner-no-see, so other players in a networked session see a figure where the local player sees only the view from the camera. It adds no behaviour beyond the mobile pawn it inherits from, so subclass it, as the showroom pawns do, to give the pawn the abilities it needs.

No editor-visible members; this asset configures defaults only.

### Blueprints/VR

**BP_Pawn_VR**9 members

extends `Character` · implements `BPI_Pawn_VR`, `BPI_PawnInfo`, `BPI_AbilityRestriction`, `BPI_Trace`

Base VR pawn: a character carrying the camera on a replicated camera handle, alongside the character teleport ability. It spawns one motion controller per hand from the Left Controller and Right Controller class settings, recentres the capsule under the head, matches capsule height to the camera, and applies ability restrictions to its own pawn abilities and to every controller ability on either hand. Choose the controller classes, then subclass it to add abilities.

| Kind | Name | Signature | Description |
|---|---|---|---|
| fn | `ResetTrace`Trace | `()` | Clears the pawn's valid-trace flag, so anything reading the trace treats it as nothing being under the pointer until the next trace fills it in again. |
| fn | `getFocussedComponent`Debug | `(out SceneComponent: SceneComponent)` | Debug stub with no implementation behind it. Always returns nothing, whatever the move focus setting. |
| fn | `CorrectPawnPosition`Pawn | `(InVector: Vector, InRotation: Rotator, UseRotation: bool, out Location: Vector, out Rotation: Rotator)` | Returns the actor location and rotation needed to put the headset, rather than the capsule, at the position you ask for. Only the horizontal offset between capsule and camera is removed, so height is left alone; with Use Rotation on, the supplied rotation is corrected by the player's current head yaw as well. |
| fn | `SetupMotionController`Controls | `(MotionControllerClass: class<BP_MotionController>, Side: E_Side)` | Replaces the hand on one side: destroys the controller already registered there, then spawns the given class attached to the camera handle with the pawn, headset type and side already filled in. Passing no class leaves that side empty. |
| event | `SwitchControllers` | `(LeftController: class<BP_MotionController>, RightController: class<BP_MotionController>)` | Swaps both hands at once, destroying whatever is there and spawning the two given classes for left and right. Use it to move between hand meshes and controller meshes at runtime. |
| event | `Server_PrepareVRPawn` | `(HMD: E_HMD)` | Records which headset the player is on, replicating it to the hands, and then spawns the left and right controllers configured on the pawn. Called from Client Possessed once the pawn is locally controlled. |
| event | `AutoAdjustCapsuleHeight` | `(Set: bool)` | Starts a twice-a-second loop that resizes the capsule to match the player's head height, clamped between 40 and 300 centimetres, and shifts the actor and camera handle by the same amount so the view does not jump. Only corrects drifts of 15 centimetres or more; pass false to end the loop. |
| event | `Client_Possessed` | `(NewController: Controller)` | Called on the owning client once the pawn has a controller. Waits until the pawn really is locally controlled, prepares the VR pawn and spawns the hands, forces Game Only input with the cursor hidden, sets the spectator screen to a single cropped eye and hands the pawn to every pawn ability. |
| event | `Client_Unpossessed` | `(OldController: Controller)` | Called on the owning client when the pawn loses its controller, and unpossesses every pawn ability. The spawned hands are left alone; destroy them yourself if the pawn is to be reused. |

**BP_Pawn_VR_Char**0 members

extends `BP_Pawn_VR`

VR pawn with a visible body: head and torso meshes marked owner-no-see, so other players see an avatar while the wearer sees only the world, with the camera raised to standing height. It adds no behaviour beyond the VR pawn it inherits from, so subclass it, as the showroom pawns do, to give the pawn the abilities it needs.

No editor-visible members; this asset configures defaults only.

### Blueprints/VR/MotionControllers

**BP_MotionController**5 members

extends `Actor` · implements `BPI_MotionController`

Base motion controller actor, one per hand: the actor that hand abilities are added to and initiated by. The VR pawn spawns it from its per-side controller class and attaches it to the camera handle, handing over the pawn, the headset type and the hand side, all three of which replicate. It answers the motion controller contract for side and attached actors, and grants one ability exclusive focus by holding a blocker on every other ability on the hand. Subclass it rather than placing it.

| Kind | Name | Signature | Description |
|---|---|---|---|
| var | `Pawn`Internal | `Pawn` | Owning VR pawn, handed over on spawn. Used to tell whether this hand belongs to the locally controlled player, so replicated hands do not run local-only logic. |
| var | `HMD`Internal | `E_HMD` | Headset family this hand was spawned for, taken from the pawn. Hand controllers use it to pick the mesh offset that suits the physical controller, since each one sits differently in the palm. |
| var | `Side`Internal | `E_Side` | Which hand this is, Left or Right, fixed at spawn by the pawn. Abilities read it through Get Motion Controller Side to choose their input mappings, grip sockets and mirrored hand poses. |
| event | `SetMeshVisibility` | `(Set: bool)` | Broadcasts Mesh Visibility Changed with the requested state. Nothing is hidden here; the derived controller listens for the broadcast and hides its own mesh, so an ability can ask for the hand to disappear without knowing what it looks like. |
| event | `SetupMotionController` | `()` | Empty hook left for a derived controller to do its own setup after being spawned and given its pawn, side and headset type. Neither shipped controller uses it. |

### Blueprints/VR/MotionControllers/Controller

**BP_MotionController_Controller**4 members

extends `BP_MotionController`

Motion controller that shows a controller model rather than a hand: a static mesh, a small collision sphere at the tip and the engine's XR device visualisation component. Change Controller Mesh picks the mesh and material for the headset in use out of the built-in Quest, Rift, Vive, Index and Windows Mixed Reality sets, or hides them and leaves OpenXR to draw its own model. Use the Left and Right variants, which fill in the per-hand mesh and offset.

| Kind | Name | Signature | Description |
|---|---|---|---|
| fn | `SetControllerMesh` | `(ControllerMaterial: MaterialInterface, LeftControllerMesh: StaticMesh, RightControllerMesh: StaticMesh)` | Applies one of the built-in controller looks: makes a dynamic instance of the material, stores it, and gives the mesh component the left or the right mesh according to this controller's side. Change Controller Mesh calls it with the pair that belongs to the headset in use, so go through that unless you are adding a headset of your own. |
| event | `SetupMotionController` | `()` | Override of the set-up hook the pawn calls once the controller knows which hand it is. It adds nothing of its own and passes straight to the parent, so it sits here as somewhere to hang your own set-up. |
| event | `ChangeControllerMesh` | `(OpenXR: bool, CustomHMD: E_HMD)` | Chooses the controller model. With OpenXR set it clears the mesh and hides the component, leaving the engine's XR device visualisation to draw whatever the runtime reports. Otherwise it switches on the headset enum and applies the built-in Quest, Rift or Vive meshes. Several cases of that enum are deliberately empty, which is why some headsets show no model at all. |
| event | `MC_SetControllerVisibility`Motion Controller | `(Set: bool)` | Shows or hides the controller's visual representation, for example to hide a hand mesh while an object is held. |

**BP_MotionController_Controller_Left**0 members

extends `BP_MotionController_Controller`

Left-hand instance of the controller-model motion controller, carrying the Quest 2 left mesh and the offset that seats it on the tracked pose. Set it as the VR pawn's Left Controller when the pawn should show controllers rather than hands; subclass it if you want to start from a different default model.

No editor-visible members; this asset configures defaults only.

**BP_MotionController_Controller_Right**0 members

extends `BP_MotionController_Controller`

Right-hand instance of the controller-model motion controller: the Quest 2 right mesh, the offset that seats it on the tracked pose, and the motion source switched to the right hand. Set it as the VR pawn's Right Controller when the pawn should show controllers rather than hands; subclass it if you want to start from a different default model.

No editor-visible members; this asset configures defaults only.

### Blueprints/VR/MotionControllers/Hand

**BP_MotionController_Hands**10 members

extends `BP_MotionController` · implements `BPI_MotionController_Hands`

Motion controller that shows an animated hand instead of a controller model. It carries the hand mesh and its animation blueprint under a per-headset offset, folds grip, trigger, index-touch and thumb-touch input for its own side into replicated hand state and pushes that to the animation, and feeds OpenXR hand-tracking bones through when the headset reports them. Answers the hands contract: snapping to a socket, hand collision and whether the hand is open. Use the Left and Right variants.

| Kind | Name | Signature | Description |
|---|---|---|---|
| fn | `UpdateHandTrackingMesh`Hand Tracking | `()` | Pushes a tracked hand pose into the animation blueprint. Reads the hand tracking state for this controller's side, converts every joint into the hand mesh's own space with the hand tracking correction applied, and hands the array over through Hand Hand Tracking Transforms, which is where the control rig reads it. Called while hand tracking is live, and it has nothing to apply when tracking is not valid. |
| fn | `DrawHandtrackingDebug`Hand Tracking | `()` | Draws a short set of red, green and blue axes at every tracked hand joint, each line lasting about a frame. Purely a debugging aid: hook it to a key or the tick while you are working out why a tracked hand looks wrong, and leave it out otherwise. |
| event | `SetupMotionController` | `()` | Override of the set-up hook the pawn calls once the controller knows which hand it is. It adds nothing of its own and passes straight to the parent, so it sits here as somewhere to hang your own set-up. |
| event | `Server_SnapToSocket` | `(SnapSocket: ST_Socket)` | Server event storing the socket this hand has snapped to, so other clients see the hand holding the object the same way the holder does. |
| event | `Server_SetPose` | `(GrabPose: AnimSequenceBase)` | Server event storing the custom hand pose with notify, so a grab's pose plays on every client rather than only in the holder's own view. |
| event | `Server_GribAxis` | `(GribAxis: float)` | Server event publishing this hand's grip axis with notify, so remote clients see the fingers close by the same amount. The name carries a typo for grip and is left as it is so existing graphs keep compiling. |
| event | `ServerSetThumbDown` | `(ThumbDown: bool)` | Server event publishing whether the thumb is resting on the controller, with notify, which is what gives remote clients the thumbs-up pose. |
| event | `Server_SetIndexDown` | `(IndexDown: bool)` | Server event publishing whether the index finger is resting on the trigger, with notify, which is what makes a remote hand point. |
| event | `CheckHandTracking` | `()` | Decides whether this hand is being tracked rather than held. Reads the hand tracking state for its side and, only when the answer has changed, stores it, moves the hand offset to either the hand tracking or the default offset, and tells the animation blueprint to blend between the driven finger poses and the control rig. It is called repeatedly, so that gate is what keeps it cheap. |
| event | `Server_TriggerAxis` | `(TriggerAxis: float)` | Server event publishing this hand's trigger axis with notify, so the index finger curls by the same amount on every client. |

**BP_MotionController_Hands_Left**1 members

extends `BP_MotionController_Hands`

Left-hand instance of the hand-mesh motion controller: the mannequin XR left mesh, the offset that seats it on the tracked pose, and a grab transform read from that mesh's left grab-search socket. Set it as the VR pawn's Left Controller for hand-style VR, or subclass it to use a hand mesh of your own.

| Kind | Name | Signature | Description |
|---|---|---|---|
| fn | `MCHands_getGrabWorldTransform`Motion Controller Hands | `(out Transform: Transform)` | Returns the world transform of the hand's grab point, the position objects are picked up relative to. |

**BP_MotionController_Hands_Right**1 members

extends `BP_MotionController_Hands`

Right-hand instance of the hand-mesh motion controller: the mannequin XR right mesh, its offset, the motion source switched to the right hand, and a grab transform read from that mesh's right grab-search socket. Set it as the VR pawn's Right Controller for hand-style VR, or subclass it to use a hand mesh of your own.

| Kind | Name | Signature | Description |
|---|---|---|---|
| fn | `MCHands_getGrabWorldTransform`Motion Controller Hands | `(out Transform: Transform)` | Returns the world transform of the hand's grab point, the position objects are picked up relative to. |

### Components

**BPC_Input_Touch**22 members

extends `ActorComponent`

Actor component turning raw touch into gestures. Feed it Touch Pressed, Moved and Released and it keeps each finger's location, starting location, delta, smoothed swipe delta and duration, then broadcasts a delegate for single and double taps with one or two fingers, for swipes and for drags, and presses named keys so the same gestures can be bound as Enhanced Input actions. It also keeps a line trace under the first finger unless Use Trace is off. Add it to a pawn that takes touch input.

| Kind | Name | Signature | Description |
|---|---|---|---|
| var | `Max Tap Time`Settings | `float` | maximum time in seconds that allows a touch to be registered as tap |
| var | `Max Double Tab Time`Settings | `float` | maximum time in seconds that can be between to taps if they are to be registered as double tap |
| var | `Swipe Sensitivity Threshold`Settings | `float` | the minimum amount of pixels the finger has to move for a swipe to be recognized. |
| var | `Swipe Interpolation Speed`Settings | `float` | Smoothing speed applied to the swipe delta before it is broadcast through On Swipe Update Interpolated, which is what the mobile pawn steers its camera with. Higher values track the finger more closely and jitter more. |
| var | `Hold Time`Settings | `float` | time in seconds until hold is registered |
| var | `Use Trace`Trace | `bool` | Whether a world trace is run under the first finger on press and on tap. Switch it off to save the trace, but Get Latest Trace then never refreshes and anything that reads it, such as double-tap teleport, stops responding. |
| var | `Trace Hit Distance`Trace | `float` | How far into the world the touch trace reaches from the camera, in centimetres. Surfaces beyond it are never reported as a hit. |
| fn | `ClearIndex` | `(Index: ETouchIndex)` | Forgets a finger entirely, removing its location, initial location, delta, duration and classification. Called on release, and also on the partner finger of a two-finger tap so it cannot fire a second time. |
| fn | `isAnyOtherFingerTabbing` | `(IgnoreIndex: ETouchIndex, out Found: bool, out FoundIndex: ETouchIndex)` | Returns the first finger other than the one you pass in that is still classified as a tap. Used on release to tell a two-finger tap from a one-finger tap; Found is false when no other finger is down. |
| fn | `getTouchFunction`Getter | `(Index: ETouchIndex, out Function: E_Touch_Function)` | Returns what a finger is currently being treated as, tap, swipe or drag. Every touch starts as a tap and is reclassified as it moves; an untracked index reports None. |
| fn | `getTouchDuration`Getter | `(Index: ETouchIndex, out Duration: float)` | Returns how long a finger has been held down, in seconds, counted from the moment it was pressed. Comes back as zero for a finger that is not being tracked. |
| fn | `getTouchDelta`Getter | `(Index: ETouchIndex, out Delta: Vector2D)` | Returns how far a finger has moved since the last update, in screen pixels. Left at zero for a finger that is not being tracked. |
| fn | `getTouchInitialLocation`Getter | `(Index: ETouchIndex, out Location: Vector2D)` | Returns the screen position at which a finger first went down, which is the anchor a swipe or drag is measured from. Comes back as zero once that finger has been released. |
| fn | `getTouchLocations`Getter | `(Index: ETouchIndex, out Found: bool, out Location: Vector2D)` | Returns the latest screen position of a finger, with Found telling you whether that finger is being tracked at all. Location is meaningless when Found is false. |
| fn | `getAngleAndDegree`Util | `(InitialVector: Vector2D, EndVector: Vector2D, IntervalSize: int, out Angle: float, out Index: int)` | Returns the direction from one screen point to another as an angle in degrees, wrapped to 0-360. The interval index is meant to bucket that angle into equal segments, but the division is inverted, so it comes back as zero for any interval size below a full turn. |
| fn | `TouchReleased`Touch | `(Index: ETouchIndex, TouchLocation: Vector)` | Ends tracking of a finger: raises Event Touch Released with the duration it was held, which is where taps, swipes and drags are dispatched, and then clears every map entry for that index. |
| fn | `TouchMoved`Touch | `(Index: ETouchIndex, TouchLocation: Vector)` | Updates the stored screen position for a finger and raises Event Touch Moved. The delta and the tap or swipe classification are worked out on tick, not here. |
| fn | `TouchPressed`Touch | `(Index: ETouchIndex, TouchLocation: Vector)` | Starts tracking a finger: records its location as both the current and the initial position, zeroes its duration and delta, classifies it as a tap for now, and raises Event Touch Pressed. Call it from the pawn's touch input binding. |
| event | `EventTouchPressed` | `(TouchIndex: ETouchIndex, ScreenLocation: Vector2D)` | Raised by Touch Pressed once the finger has been recorded, and refreshes the world trace under it. Bind to it to react to a finger going down before it has been classified. |
| event | `EventTouchReleased` | `(TouchIndex: ETouchIndex, ScreenLocation: Vector2D, Duration: float)` | Raised by Touch Released and does the actual gesture dispatch. A tap becomes a one- or two-finger single or double tap, broadcasts the matching delegate and pulses a synthetic input key for a twentieth of a second; a swipe broadcasts On Swipe End; a drag broadcasts On Drag Release. |
| event | `EventTouchMoved` | `(TouchIndex: ETouchIndex, ScreenLocation: Vector2D)` | Raised by Touch Moved after the finger's stored position has been updated. Empty by default; bind to it to react to finger movement without polling. |
| event | `UpdateTrace` | `(Index: ETouchIndex, ScreenPosition: Vector2D)` | Line traces from the given screen position into the world on the visibility channel and stores the result as the latest trace, which the mobile pawn hands out through Get Latest Trace. Only the first finger traces, and only while Use Trace is on. |

### Interfaces

**BPI_AnimBP_Hand**7 members

extends `Interface`

Contract between a hand motion controller and the animation blueprint on its mesh: index pointing, thumb up, trigger and grip axes, hand tracking on or off, a custom pose and the hand-tracking bone transforms. The controller calls it on whatever animation instance the mesh happens to have, so an animation blueprint of your own needs only to implement this to stand in for the shipped one.

| Kind | Name | Signature | Description |
|---|---|---|---|
| fn | `Hand_HandTrackingTransforms`Hand Anim BP | `(Transforms: Transform[])` | Implemented by the hand's animation blueprint to receive the tracked joint transforms for this hand, relative to the hand mesh. Called by the hand motion controller once per frame while tracking is valid. |
| fn | `Hand_SetHandPose`Hand Anim BP | `(HandPose: AnimSequenceBase)` | Implemented by the hand's animation blueprint to play a custom pose over the whole hand. Called by the hand motion controller, typically when something gripped supplies its own pose; an empty sequence means return to the driven poses. |
| fn | `Hand_SetHandTracking`Hand Anim BP | `(Set: bool)` | Implemented by the hand's animation blueprint to blend between the driven finger poses and the pose built from tracked joints. Called by the hand motion controller when hand tracking starts or stops being available. |
| fn | `Hand_SetHandValue_GripAxis`Hand Anim BP | `(Axis: float)` | Implemented by the hand's animation blueprint to close the hand by the analogue grip amount, 0 for open and 1 for a full grasp. Called by the hand motion controller as the grip moves. |
| fn | `Hand_SetHandValue_TriggerAxis`Hand Anim BP | `(Axis: float)` | Implemented by the hand's animation blueprint to curl the index finger by the analogue trigger amount, 0 to 1. Called by the hand motion controller as the trigger moves. |
| fn | `Hand_SetHandValue_Thumb`Hand Anim BP | `(IsThumbUp: bool)` | Implemented by the hand's animation blueprint to raise or lower the thumb. Called by the hand motion controller when the thumbs-up state changes or replicates in. |
| fn | `Hand_SetHandValue_Index`HandAnimBP | `(IsPointing: bool)` | Implemented by the hand's animation blueprint to point or unpoint the index finger. Called by the hand motion controller when the pointing state changes or replicates in. |

**BPI_Pawn_VR**1 members

extends `Interface`

Contract letting a motion controller announce itself to the VR pawn it belongs to, along with the hand side it stands for. The pawn records it in its per-side controller map and, when no headset is running, parks it in front of the camera so the setup still works on a flat screen. Implement it on a VR pawn of your own that has to accept the framework's controllers.

| Kind | Name | Signature | Description |
|---|---|---|---|
| fn | `Interface_RegisterControllerToVRPawn`VR Pawn | `(MotionController: BP_MotionController, Side: E_Side)` | Implemented by the VR pawn to take ownership of a freshly spawned motion controller for one hand. The controller calls it on itself so the pawn can look it up later by side, for example when applying an ability restriction to both hands. |

### Libraries

**ML_MotionController**0 members

extends `BP_MotionController`

Macro library for motion controllers: a side guard that only continues on the hand this controller stands for, and a button handler folding the left and right start and completed input events into one boolean with that guard applied. Parented to the motion controller base, so the macros appear only inside controllers inheriting from it; the hand controller uses them for its per-hand input.

No editor-visible members; this asset configures defaults only.

### Settings

**BP_Value_Settings_Float_Pawn_Speed**1 members

extends `BP_Value_Settings_Float`

Ready-made slider for how fast the pawn moves, scaling the movement ability's speed. Point a slider row at it to put locomotion speed on a settings screen.

| Kind | Name | Signature | Description |
|---|---|---|---|
| event | `Value_setFloat`Value_Float | `(SourceInfo: ST_SourceInfo, Value: float)` | Implemented by a float value to take a new value from the pawn described by the source info. Sliders call it as their handle moves; the drag state reads the value as 0 to 1 across its own range. |

### Widgets/Crosshair

**Widget_Crosshair**2 members

extends `UserWidget`

Screen-centre crosshair for the desktop pawn, which creates it on possession and adds it to the viewport. Its colour comes from the pawn's interaction state component, so it follows whatever is under the pointer, and it hides itself whenever the mouse cursor is showing or the control mode is anything other than Game Only. The desktop pawn names this class directly, so change the look by editing it rather than by pointing the pawn elsewhere.

| Kind | Name | Signature | Description |
|---|---|---|---|
| fn | `Get_Crosshair_ColorAndOpacity_0` | `() → LinearColor` | Returns the tint for the crosshair image, taken from the interaction state the pawn is currently in, which is how the crosshair changes as you look at something you can act on. Falls back to opaque white when the pawn has no interaction state component. |
| fn | `ShouldCrosshairBeVisible` | `() → bool` | Returns true only while there is a local player controller, the mouse cursor is hidden and the pawn reports Game Only screen control. Any free-mouse or menu mode therefore hides the crosshair. |
