Grabbing Interaction Types
IWSDK's grabbing system provides three distinct interaction patterns, each implemented with different handle configurations and pointer management strategies. Understanding their architectural differences helps choose the right pattern for specific use cases.
One-Hand Grabbing
Single-controller direct manipulation optimized for immediate, responsive interactions.
Architecture Characteristics
- Handle Configuration:
multitouch: false
,projectRays: false
- Pointer Events:
pointerEventsType: { deny: 'ray' }
— prevents ray interference - Transform Support: Translation and rotation only (no scaling)
Implementation Details
The system creates a standard HandleStore
with constraints derived directly from component properties:
// Simplified handle creation from GrabSystem
const handle = new HandleStore(object, () => ({
rotate: entity.getValue(OneHandGrabbable, 'rotate') ? {
x: [rotateMin[0], rotateMax[0]],
y: [rotateMin[1], rotateMax[1]],
z: [rotateMin[2], rotateMax[2]]
} : false,
translate: entity.getValue(OneHandGrabbable, 'translate') ? {
x: [translateMin[0], translateMax[0]],
y: [translateMin[1], translateMax[1]],
z: [translateMin[2], translateMax[2]]
} : false,
multitouch: false // Single pointer only
}));
Design Trade-offs
- Immediacy vs Complexity — Instant response but limited to basic transformations
- Simplicity vs Capability — Easy to predict behavior but no scaling operations
- Performance vs Features — Minimal overhead but fewer manipulation options
Best Use Cases
- Interactive tools and instruments (valves, levers, handles)
- Simple object repositioning
- Quick grab-and-move interactions
- Objects that should maintain their scale
Two-Hand Grabbing
Dual-controller manipulation enabling advanced operations including scaling through multi-pointer coordination.
Architecture Characteristics
- Handle Configuration:
multitouch: true
, enables dual-pointer calculations - Pointer Events:
pointerEventsType: { deny: 'ray' }
— same ray denial as one-hand - Transform Support: Translation, rotation, and scaling
Multi-Pointer Mathematics
Two-hand grabbing uses the relationship between controllers to derive transformations:
- Translation: Controlled by primary hand position
- Rotation: Derived from the orientation relationship between hands
- Scaling: Based on the distance between controllers — closer hands reduce scale, farther hands increase scale
Implementation Details
The handle configuration enables multitouch and adds scaling constraints:
const handle = new HandleStore(object, () => ({
rotate: /* rotation constraints */,
translate: /* translation constraints */,
scale: entity.getValue(TwoHandsGrabbable, 'scale') ? {
x: [scaleMin[0], scaleMax[0]],
y: [scaleMin[1], scaleMax[1]],
z: [scaleMin[2], scaleMax[2]]
} : false,
multitouch: true // Enables dual-pointer processing
}));
Design Trade-offs
- Capability vs Complexity — Supports scaling but requires coordination between hands
- Precision vs Effort — Enables precise manipulation but demands two-hand engagement
- Features vs Performance — Rich interaction set but higher computational cost
Best Use Cases
- Resizable objects (artwork, models, UI panels)
- Precise positioning tasks requiring stability
- Objects where scale adjustment is important
- Complex manipulation requiring both hands' dexterity
Distance Grabbing
Ray-based remote manipulation with specialized movement algorithms for telekinetic-style interactions.
Architecture Characteristics
- Handle Configuration: Custom
DistanceGrabHandle
class with movement mode algorithms - Pointer Events:
pointerEventsType: { deny: 'grab' }
— opposite configuration from direct grabbing - Transform Support: Translation, rotation, and scaling with mode-specific behaviors
Movement Mode Algorithms
Distance grabbing implements four distinct movement algorithms:
MoveTowardsTarget Algorithm
// From DistanceGrabHandle.update()
const pointerOrigin = p1.pointerWorldOrigin;
const distance = pointerOrigin.distanceTo(position);
if (distance > this.moveSpeed) {
const step = pointerOrigin.sub(position)
.normalize()
.multiplyScalar(this.moveSpeed);
position.add(step);
} else {
// Snap to target when close enough
position.copy(pointerOrigin);
quaternion.copy(p1.pointerWorldQuaternion);
}
MoveAtSource Algorithm
// Delta-based movement tracking
const current = p1.pointerWorldOrigin;
if (this.previousPointerOrigin != undefined) {
const delta = current.sub(this.previousPointerOrigin);
position.add(delta);
}
this.previousPointerOrigin.copy(current);
MoveFromTarget & RotateAtSource
- MoveFromTarget: Direct 1:1 mapping with ray endpoint (delegates to standard handle)
- RotateAtSource: Rotation-only mode with automatic translation/scale disabling
Pointer Event Strategy
Distance grabbing uses a reverse pointer event configuration to prevent conflicts:
// Distance grabbable objects deny grab pointers, accept rays
obj.pointerEventsType = { deny: 'grab' };
// Versus direct grabbing which denies rays
obj.pointerEventsType = { deny: 'ray' };
Return-to-Origin Mechanics
The returnToOrigin
feature overrides the standard handle application:
// From DistanceGrabHandle.apply()
if (this.returnToOrigin && this.outputState?.last) {
target.position.copy(this.initialTargetPosition);
target.quaternion.copy(this.initialTargetQuaternion);
target.scale.copy(this.initialTargetScale);
return; // Skip standard handle application
}
Design Trade-offs
- Reach vs Directness — Can interact with any visible object but lacks direct tactile feedback
- Flexibility vs Predictability — Multiple movement modes provide options but require mode selection
- Magic vs Realism — Enables impossible interactions but may feel less grounded
Best Use Cases
- Out-of-reach objects in large environments
- Magical or supernatural interaction themes
- Accessibility — reaching objects without physical movement
- Telekinetic gameplay mechanics
Selection Guidelines
Interaction Context
- Immediate objects: Use direct grabbing (one/two-hand)
- Remote objects: Use distance grabbing
- Resizable content: Requires two-hand grabbing
- Tool-like objects: Usually one-hand grabbing
User Experience Patterns
Most applications combine multiple grabbing types:
- Gallery Setup: Paintings (one-hand rotation-only), Sculptures (two-hand with scaling), Floating artifacts (distance with return-to-origin)
- Workshop Environment: Tools (one-hand), Workpieces (two-hand), Stored materials (distance)
- Gaming Context: Weapons (one-hand), Interactive objects (two-hand), Magic items (distance)
The system's automatic handle management makes it seamless to use different grabbing types on different objects within the same scene.