Grip Pose
A GripPose holds a rig’s hands the way you name: pistol, handle, cup. A pose says only how far each finger bends, how far they fan out and what the thumb reaches for, and nothing in it names a bone, so one pose fits any rig. Which way those bends go is worked out from each rig’s own hand, the first time it is held.
It shapes the hand. Putting the hand on an object is up to whatever attaches it, usually an entity under the hand joint and two-bone IK for the arm.
Hold a hand
Section titled “Hold a hand”Put a GripPose on the rig’s root and name a pose for either hand:
import { GripPose } from 'esengine';
world.insert(hero, GripPose, { rightPose: 'pistol', leftPose: 'support' });
// Squeeze: the index finger goes from resting to pressing, and nothing else moves.world.update(hero, GripPose, (grip) => { grip.rightTrigger = 1; });| Field | What it does |
|---|---|
rightPose, leftPose |
The pose each hand takes. Empty fades that hand out and leaves it to whatever else moves it. |
rightWeight, leftWeight |
How much of the pose applies, over what a clip is doing with the fingers. |
rightTrigger, leftTrigger |
How far the index finger has gone from resting to pressing, in a pose that has both. |
blendSeconds |
About how long a change of pose takes. It starts from still and comes to rest, with no jump. |
rightHand, leftHand |
The hand joint, by path from this entity. Empty looks for it by name. |
It runs after the animator, so a walk cycle goes on moving the arm while the pose holds the fingers, and works with no animator at all. It runs while the game plays, not while a scene is laid out.
The poses
Section titled “The poses”| Name | For |
|---|---|
open |
A flat hand, as the rig rests. |
relaxed |
A hand hanging at rest. |
fist |
Closed, the thumb over the fingers. |
pistol |
A pistol’s grip, the index finger along the frame. trigger presses it. |
support |
A hand under a rifle’s foregrip. |
handle |
A hammer, a sword, a tool’s handle. |
pinch |
Thumb and index finger together. |
cup |
Round a mug or a ball, fingers apart. |
To add your own, or replace one by name:
import { registerGripPose } from 'esengine';
registerGripPose('claw', { thumb: { opposition: 1, gap: 0.2 }, index: { curl: 0.9, base: 0.2 }, middle: { curl: 0.9, base: 0.2 }, ring: { curl: 0.9, base: 0.2 }, pinky: { curl: 0.9, base: 0.2 },});| Number | What it says |
|---|---|
curl |
How far the finger bends, 0 as the rig rests to 1 closed. |
base |
How far its first joint bends, where that differs: a finger laid along a frame, or hooked. Defaults to curl. |
spread |
How far the fingers fan out, -1 to 1. |
bend |
Each joint’s bend in degrees, knuckle first, from where the rig rests: [30, 45, 20]. Over curl and base. What the editor writes. |
fan |
How far this one finger leans out from the middle of the hand, in degrees: the index and middle toward the thumb, the ring and little finger away. Over spread. |
trigger |
On the pose: the index finger as rightTrigger takes it to 1. |
opposition |
The thumb: how far it goes from where it rests to what it reaches for, 0 to 1. |
to |
The thumb: fingers (the middle of the middle finger, as a fist or a handle) or index (the index tip, as a pinch). |
gap |
The thumb: how far short of it it stops, in lengths of the index finger: the grip or the mug in between. |
The thumb is not bent by numbers of its own: it reaches. Its tip goes to a point on the other fingers as they stand that frame, on the palm’s side of them, and its two joints bend together to get there, so it lies over the fingers in a fist and comes round a grip. Out of reach (flat fingers are), it points at the place.
gripPoseByJoint(pose) writes any pose out joint by joint, holding the hand exactly as before: the starting point for changing one joint. bend and fan are measured on the hand’s own axes, not a bone’s, so a pose said joint by joint still fits any rig and either hand.
On your rig
Section titled “On your rig”The hand is found by name: a joint called something like RightHand or hand_r, with fingers named thumb, index, middle, ring, and pinky or little under it. Bones in the palm (index_metacarpal_r) are passed through. Where a rig’s names say nothing of the kind, name the joint in rightHand. If its fingers are not named either, it cannot be held.
A rig with fewer fingers does without the rest, and says which in the log. gripPoseStatus(app, entity) answers what was found on each hand.
Holding an object
Section titled “Holding an object”Three parts, each answering one question:
| Part | Answers |
|---|---|
GripProfile, on the object |
Where on it each palm sits: an anchor entity for the leading hand and one for the supporting hand, and the fingers’ pose for each. |
| The arm | How the shoulder, elbow and wrist get the palm there: two-bone IK, the elbow keeping the side the clip bends it to, the wrist turned to the anchor. |
| The fingers | How each finger is held: a pose captured from a hand, blended over the clip as slerp(clip, grip, weight), or a grip pose by name. |
An anchor is any entity under the object, placed with the ordinary move and rotate gizmos. Its origin is the palm’s centre (halfway from the hand joint to the middle knuckle), its +Z the way the fingers point, and its +Y the way the palm faces.
import { GripHolder, GripPlacement, GripProfile } from 'esengine';
world.insert(rifle, GripProfile, { mainAnchor: gripAnchor, supportAnchor: foregripAnchor, mainPose: 'pistol', supportPose: 'support' });world.insert(hero, GripHolder, { held: rifle, placement: GripPlacement.Object });GripHolder field |
What it does |
|---|---|
held |
The object held: an entity with a GripProfile. None lets go. |
mainHand |
Right or Left: the hand that leads. |
placement |
Hand: the object rides the leading hand wherever the clip puts it. Object: the game places the object (aiming) and the leading arm is brought to it. |
weight, supportWeight |
How much of the hold applies over the clip, and of the supporting hand’s under that. |
blendSeconds |
How long taking hold, letting go and changing what is held take. Every joint eases from where it was, from still and to rest, so no hand jumps. |
rightHand, leftHand |
The hand joints by path, where their names do not find them. |
GripProfile field |
What it does |
|---|---|
mainAnchor, supportAnchor |
The anchor entities. No supporting anchor holds the object in one hand. |
mainPose, supportPose |
Each hand’s fingers: a grip pose by name, or a captured finger pose. |
mainFingers, supportFingers |
Each hand’s fingers joint by joint, as JSON of a grip pose (the editor writes it). Over the pose by name where set. |
hand |
The hand the anchors were placed for. Held with the other hand leading, both are mirrored. |
mirror |
The object’s own plane that mirrors them: the one square to its X (the default), Y or Z. |
wrap |
Whether the fingers close onto the object’s GripSurface shapes, each stopping where it meets one. On by default; with no surface it does nothing. |
It runs after the animator, in one order every frame, so nothing can drive itself round a loop: the clip’s pose; then the object, on the leading hand or where the game put it; then the supporting anchor, read off the object as it now stands; then that arm; then the fingers of both. The object never reads the supporting hand. Each frame solves from the clip’s pose, never from its own last answer, and nothing reads a clock but the game’s: the same inputs and steps give the same bones, bit for bit.
Finger poses
Section titled “Finger poses”captureFingerPose(world, handJoint) takes the turn of every named joint under a hand as it stands, as plain JSON; registerFingerPose(name, pose) keeps it for a GripProfile to name. Pose the hand with a GripPose, a clip or by hand, capture it, and save the JSON with the game. A captured pose names its rig’s bones, so it belongs to that rig; a grip pose by name fits any.
Closing onto the object
Section titled “Closing onto the object”A pose says how far the fingers close; what they close onto is the object’s. Put a GripSurface on the object, or on anything under it, for each part a hand goes round: a cylinder or capsule for a handle or a barrel, a sphere, a box for a block grip. It is sized in its entity’s own units, as a collider is:
GripSurface field |
What it does |
|---|---|
shape |
Cylinder, Capsule, Sphere or Box. |
direction |
The axis a cylinder or capsule runs along: X, Y or Z of the entity. |
center |
Its middle, in the entity’s own units. |
radius, height |
A cylinder’s, capsule’s or sphere’s radius, and a cylinder’s or capsule’s whole length. |
size |
A box’s size. |
With wrap on, each finger closes from open toward the pose’s angles, all its joints together; the bone that first meets a surface stops there with every joint before it, and the joints after it go on closing. The thumb comes in along the way it reaches and stops where a bone of it meets one. A finger stops a little short of the shape, by about its own thickness (8% of the index finger’s length), and never goes further than the pose: a finger the pose leaves open stays open. A bone that starts inside a surface (a handle pressed into the palm) may go on, but no deeper. It is a distance from a point to a shape, a few hundred a hand: no physics and no mesh, and the same every time.
So a fist with wrap on closes every finger onto the handle, whatever its thickness, and a pistol keeps its index finger out along the frame.
The other hand
Section titled “The other hand”Anchors are placed once, for the hand hand names. A holder leading with the other hand gets both anchors mirrored in the object’s mirror plane: their places reflected and their turns made the other hand’s palm. Fingers by name, and fingers joint by joint, are a hand’s shape rather than its bones, so they mirror too. A captured pose does not: it names one hand’s bones.
In the editor
Section titled “In the editor”Select an object with a GripProfile. Its section in Details edits the grip, and a character holding it shows the grip in the viewport as you change it, without Play:
- Preview. Pick the character. One without a
GripHoldergets one, holding this object and placed by it, so it reaches for the object where it stands in the scene. The leading-hand switch sets the holder’smainHand, which is how to see the mirrored grip. A palm that cannot reach its anchor says how far short it stops. - Anchors. Pick an entity, or Create one under the object. Select moves to it, for the move and rotate gizmos. The viewport draws each palm where it goes, mirrored when the other hand leads: a frame for the palm, an arrow the way the fingers point, a dashed line the way the palm faces, a stub on the thumb’s side; amber for the leading hand, blue for the supporting one.
- Clip. Pick a timeline and drag the time, or play it: the character is posed by it in the viewport and the grip goes over it, as in Play. Only the viewport is posed; taking the clip off, turning the preview off or leaving the section gives the pose back.
- Fingers. Start from a grip pose, then change any joint’s bend or any finger’s lean in degrees. The first change writes the pose out joint by joint into
mainFingersorsupportFingers; Reset goes back to the pose itself. In the viewport, each finger joint of the previewing character has a handle (amber on the leading hand, blue on the supporting one): drag it to bend that joint, one undo step a drag. - Close onto surfaces. The
wrapswitch, which fingers touch a surface now, and the object’s surfaces. Create adds a cylinder across the leading palm under its anchor, sized by the character’s palm, to fit to the handle with the gizmos and its fields. The viewport draws the surfaces in green with the palms.
The preview is the viewport’s Preview FX, the same switch spring bones use. It moves only the viewport’s bones and the held object, never the scene, and turning it off gives them back as the scene has them.
On another body
Section titled “On another body”Anchors are where a palm goes, not where a hand joint goes, and the arm is solved each frame from the body it is on, so a body with longer or shorter arms still puts its palm on the anchor. Past its reach, the arm points straight at the anchor and the wrist still turns to it: the palm stops short, the same way every time.
Limits of holding
Section titled “Limits of holding”- Fingers close onto simple shapes, not the mesh. An object’s surfaces are what it says they are; a grip of an odd shape is a few of them.
- The thumb has no handle in the viewport. It is reached for, not bent, so it is set by its numbers; a captured pose is not edited in the section.
- The editor plays a timeline, not an Animator’s state machine, under the grip; the machine itself runs in Play.
- Only the supporting arm is bent with
Handplacement, and only the leading one is first withObject; a shoulder or the spine does not lean to help an arm reach. - One object a holder.
Limits
Section titled “Limits”- A
GripPoseon its own does not touch anything. A pose is a shape, not a fit: fingers can sink into a wide grip or stop short of a narrow one. Holding the object with aGripHolderand puttingGripSurfaces on it closes them onto it. - A hand’s numbers are worked out once, from how the rig stands when it is first held. A rig whose hand is mid-animation by then has its axes taken from that. In practice they are close.
- Rigs with a negative scale on an arm are not handled. A mirrored bone turns the wrong way.
- Checked on a real rig of one kind. The poses were tuned on a Mixamo-named character, and the same hand built with bones facing other ways and under other names gives the same fingertips, but no second real rig has been looked at.
- Not measured on a device. It is a few quaternions for each of up to 30 joints a frame, and nothing once settled on a rig no clip moves.