buildJellyTransform static method

Matrix4 buildJellyTransform({
  1. required Offset velocity,
  2. double maxDistortion = 0.7,
  3. double velocityScale = 1000.0,
})

Creates a jelly transform matrix based on velocity.

Applies organic squash and stretch effects that create a satisfying "jelly" animation:

  • Squashes in the direction of movement
  • Stretches perpendicular to movement
  • Intensity scales with velocity magnitude

This creates the iOS-style elastic effect seen when dragging indicators.

Parameters:

  • velocity: Direction and speed of movement as an Offset
  • maxDistortion: Maximum distortion factor 0-1 (default: 0.7)
  • velocityScale: Scale factor for velocity; higher = less distortion (default: 1000.0)

Returns: A Matrix4 transform that can be applied to a widget.

Example:

Transform(
  alignment: Alignment.center,
  transform: DraggableIndicatorPhysics.buildJellyTransform(
    velocity: Offset(velocityX, 0),
    maxDistortion: 0.8,
    velocityScale: 10,
  ),
  child: indicator,
)

Implementation

static Matrix4 buildJellyTransform({
  required Offset velocity,
  double maxDistortion = 0.7,
  double velocityScale = 1000.0,
}) {
  final speed = velocity.distance;
  if (speed == 0) return Matrix4.identity();

  // Normalize velocity direction
  final direction = velocity / speed;

  // Calculate distortion intensity based on speed
  final distortionFactor =
      (speed / velocityScale).clamp(0.0, 1.0) * maxDistortion;

  // Squash in direction of movement
  final squashX = 1.0 - (direction.dx.abs() * distortionFactor * 0.5);
  final squashY = 1.0 - (direction.dy.abs() * distortionFactor * 0.5);

  // Stretch perpendicular to movement
  final stretchX = 1.0 + (direction.dy.abs() * distortionFactor * 0.3);
  final stretchY = 1.0 + (direction.dx.abs() * distortionFactor * 0.3);

  // Combine effects
  final scaleX = squashX * stretchX;
  final scaleY = squashY * stretchY;

  return Matrix4.identity()..scale(scaleX, scaleY);
}