SSGOI LogoSSGOI
← Back to Blog
Double Spring: Natural Ease-In-Out

Double Spring: Natural Ease-In-Out

Daeseung Moon
springanimationeasing

The Limitation of Single Spring

Think about a typical spring animation. An object attached to a spring moves toward its target.

Force = -stiffness × (currentPosition - target)

The problem is at the start. At t=0, the distance between current position and target is at its maximum, so the force is maximum. The object accelerates sharply from the very beginning.

Start ●━━━━━━━━━━━━━━━━━━━━━━━━━━━━● Target
      ↑
      Maximum distance = Maximum force = Sudden start!

This is why spring animations only give an "ease-out" feel. They start fast and end slowly.

The Double Spring Solution

Double spring connects two springs:

Target ←―[Leader Spring]―← Leader ←―[Follower Spring]―← Me(Output)
  • Leader: Directly tracks the target
  • Follower(Me): Tracks the leader (this is the actual output)

Behavior Over Time

t=0 (Start)

Target      Leader    Me
  ●━━━━━━━━━━●━━━━━━●
              ↑
        Leader starts first
        Distance between me and leader = small
        → Force on me = small
        → Slow start! (ease-in)

t=middle

Target    Leader              Me
  ●━━━━━━●━━━━━━━━━━━━━━━━●
          ←――――――――――――→
          Distance increases
          → Force increases
          → Acceleration!

t=end

Target/Leader              Me
  ●━━━━━━━━━━━━━━━━━━━━●
   ↑
   Leader arrives first and slows down
   Distance between me and leader = decreases again
   → I also decelerate (ease-out)

Understanding Through Analogy

Single Spring = Directly connected to target with a rubber band

  • The rubber band is maximally stretched at the start, causing a sudden pull

Double Spring = There's a guide ahead, and I follow the guide

  • Even if the guide starts first, the distance between me and the guide is small initially
  • As the guide gets ahead, I'm gradually pulled
  • When the guide slows down near the destination, I naturally decelerate too

In Code

// Every frame:

// Step 1: Leader chases the target
leader = stepSpring(leader, target, constants)

// Step 2: I(follower) chase the leader (not the target!)
follower = stepSpring(follower, leader.position, constants)

// follower.position is the actual output

The key is that from the follower's perspective, the target is a "moving target (leader)". Since the leader starts slowly, I start slowly too. When the leader speeds up in the middle, I speed up. When the leader slows down at the end, I slow down too.

Using in SSGOI

// Basic double spring (same stiffness)
{
  stiffness: 180,
  damping: 22,
  doubleSpring: true
}

// Strong ease-in (follower stiffness is half)
{
  stiffness: 180,
  damping: 22,
  doubleSpring: 0.5
}

// Even stronger ease-in
{
  stiffness: 180,
  damping: 22,
  doubleSpring: 0.3
}

The smaller the doubleSpring value, the lower the follower's stiffness, making it follow the leader more slowly. This creates a stronger ease-in effect.

When Should You Use It?

SituationRecommendation
Quick response is importantSingle spring
Smooth start/end is importantDouble spring
Premium UI transitionsDouble spring
Game character movementSingle spring

Use double spring where a "designed" feel matters, like page transitions or modal animations.

Mathematical Background

The response of a single spring is exponential decay:

x(t) = 1 - (1 + γt)e^(-γt)

Double spring is equivalent to applying this response twice (convolution). The result is an exponential decay multiplied by a higher-order polynomial, creating the S-curve characteristic.

Physically, it's like connecting two mass-spring systems in series. The first spring absorbs external forces, and the second spring only receives the dampened force.