> ## Documentation Index
> Fetch the complete documentation index at: https://docs.metabind.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# animations

> Animation constructors for spring physics, timing curves, and chainable modifiers.

Animation constructors create `AnimationComponent` values that define the timing and feel of state transitions. Pass them to [withAnimation](/bindjs/functions/withAnimation) or the `.animation()` modifier.

## Spring

A spring animation with response and damping parameters. This is the most common animation type.

```typescript theme={null}
Spring(options?: {
    response?: number;
    dampingFraction?: number;
    blendDuration?: number;
}): AnimationComponent;
```

<ParamField path="response" type="number" optional default="0.55">
  Duration of the spring's settle time in seconds. Lower values produce faster animations.
</ParamField>

<ParamField path="dampingFraction" type="number" optional default="0.825">
  Damping ratio. 0 = no damping (infinite oscillation), 1 = critical damping (no bounce).
</ParamField>

<ParamField path="blendDuration" type="number" optional>
  Duration in seconds for blending between animations.
</ParamField>

```typescript theme={null}
const body = () => {
    const [scale, setScale] = useState(1.0)

    return VStack([
        Circle()
            .fill(Color("blue"))
            .frame({ width: 100, height: 100 })
            .scaleEffect(scale),
        Button("Bounce", () => {
            withAnimation(Spring({ dampingFraction: 0.5 }), () => {
                setScale(scale === 1.0 ? 1.5 : 1.0)
            })
        })
    ])
}
```

## InterpolatingSpring

A spring animation defined by physical stiffness, damping, and mass for precise control.

```typescript theme={null}
InterpolatingSpring(options: {
    stiffness: number;
    damping: number;
    mass: number;
}): AnimationComponent;
```

<ParamField path="stiffness" type="number" required>
  Spring stiffness coefficient. Higher values produce faster, stiffer springs.
</ParamField>

<ParamField path="damping" type="number" required>
  Damping coefficient. Higher values produce less bounce.
</ParamField>

<ParamField path="mass" type="number" required>
  Mass of the spring. Higher values produce slower animations with more momentum.
</ParamField>

```typescript theme={null}
const body = () => {
    const [offset, setOffset] = useState(0)

    return VStack([
        Circle()
            .fill(Color("red"))
            .frame({ width: 50, height: 50 })
            .offset({ x: offset, y: 0 }),
        Button("Animate", () => {
            withAnimation(InterpolatingSpring({
                stiffness: 50,
                damping: 10,
                mass: 2
            }), () => {
                setOffset(offset === 0 ? 200 : 0)
            })
        })
    ])
}
```

## EaseIn

An ease-in timing curve that starts slow and accelerates toward the end.

```typescript theme={null}
EaseIn(options?: { duration?: number }): AnimationComponent;
```

<ParamField path="duration" type="number" optional>
  Animation duration in seconds.
</ParamField>

```typescript theme={null}
const body = () => {
    const [show, setShow] = useState(false)

    return VStack([
        Text("Hello")
            .opacity(show ? 1 : 0),
        Button("Fade In", () => {
            withAnimation(EaseIn({ duration: 1.0 }), () => {
                setShow(true)
            })
        })
    ])
}
```

## EaseInOut

An ease-in-out timing curve that starts and ends slow with acceleration in the middle.

```typescript theme={null}
EaseInOut(options?: { duration?: number }): AnimationComponent;
```

<ParamField path="duration" type="number" optional>
  Animation duration in seconds.
</ParamField>

```typescript theme={null}
const body = () => {
    const [rotation, setRotation] = useState(0)

    return VStack([
        Rectangle()
            .fill(Color("purple"))
            .frame({ width: 100, height: 100 })
            .rotationEffect(rotation),
        Button("Rotate", () => {
            withAnimation(EaseInOut({ duration: 0.8 }), () => {
                setRotation(rotation + 180)
            })
        })
    ])
}
```

## EaseOut

An ease-out timing curve that starts fast and decelerates toward the end.

```typescript theme={null}
EaseOut(options?: { duration?: number }): AnimationComponent;
```

<ParamField path="duration" type="number" optional>
  Animation duration in seconds.
</ParamField>

```typescript theme={null}
const body = () => {
    const [offset, setOffset] = useState(0)

    return VStack([
        Rectangle()
            .fill(Color("green"))
            .frame({ width: 100, height: 100 })
            .offset({ x: offset, y: 0 }),
        Button("Slide Out", () => {
            withAnimation(EaseOut({ duration: 0.5 }), () => {
                setOffset(300)
            })
        })
    ])
}
```

## Linear

A linear timing curve with constant speed throughout.

```typescript theme={null}
Linear(options?: { duration?: number }): AnimationComponent;
```

<ParamField path="duration" type="number" optional>
  Animation duration in seconds.
</ParamField>

```typescript theme={null}
const body = () => {
    const [position, setPosition] = useState(0)

    return VStack([
        Circle()
            .fill(Color("orange"))
            .frame({ width: 40, height: 40 })
            .offset({ x: position, y: 0 }),
        Button("Move", () => {
            withAnimation(Linear({ duration: 2.0 }), () => {
                setPosition(position === 0 ? 300 : 0)
            })
        })
    ])
}
```

## Bouncy

A spring animation with extra bounce for playful, attention-grabbing effects.

```typescript theme={null}
Bouncy(options?: {
    duration?: number;
    extraBounce?: number;
}): AnimationComponent;
```

<ParamField path="duration" type="number" optional>
  Approximate animation duration in seconds.
</ParamField>

<ParamField path="extraBounce" type="number" optional>
  Extra bounce amount. 0 = no extra bounce, 1 = very bouncy.
</ParamField>

```typescript theme={null}
const body = () => {
    const [scale, setScale] = useState(1.0)

    return VStack([
        Text("Tap me!").font("title").scaleEffect(scale),
        Button("Bounce", () => {
            withAnimation(Bouncy({ extraBounce: 0.4 }), () => {
                setScale(scale === 1.0 ? 1.3 : 1.0)
            })
        })
    ])
}
```

## Snappy

A spring animation with higher damping for a quick, responsive feel.

```typescript theme={null}
Snappy(options?: {
    response?: number;
    dampingFraction?: number;
    blendDuration?: number;
}): AnimationComponent;
```

<ParamField path="response" type="number" optional>
  Duration of the spring's settle time in seconds.
</ParamField>

<ParamField path="dampingFraction" type="number" optional>
  Damping ratio. 0 = no damping, 1 = critical damping.
</ParamField>

<ParamField path="blendDuration" type="number" optional>
  Duration in seconds for blending between animations.
</ParamField>

```typescript theme={null}
const body = () => {
    const [isExpanded, setIsExpanded] = useState(false)

    return VStack([
        Rectangle()
            .fill(Color("cyan"))
            .frame({ width: 200, height: isExpanded ? 200 : 100 }),
        Button(isExpanded ? "Collapse" : "Expand", () => {
            withAnimation(Snappy(), () => {
                setIsExpanded(!isExpanded)
            })
        })
    ])
}
```

## Chainable Modifiers

All animation constructors return an `AnimationComponent` that supports these chainable methods:

### delay

Delays the start of the animation.

```typescript theme={null}
.delay(seconds: number): AnimationComponent
```

```typescript theme={null}
const animation = Spring().delay(0.5)
```

### speed

Multiplies the animation speed.

```typescript theme={null}
.speed(multiplier: number): AnimationComponent
```

```typescript theme={null}
const slow = EaseInOut({ duration: 1.0 }).speed(0.5)
const fast = Linear({ duration: 2.0 }).speed(2.0)
```

### repeatCount

Repeats the animation a fixed number of times.

```typescript theme={null}
.repeatCount(count: number): AnimationComponent
```

```typescript theme={null}
const bouncing = Bouncy().repeatCount(3)
```

### repeatForever

Repeats the animation indefinitely.

```typescript theme={null}
.repeatForever(autoreverses: boolean | { autoreverses: boolean }): AnimationComponent
```

<ParamField path="autoreverses" type="boolean | { autoreverses: boolean }">
  If `true`, the animation reverses direction each cycle. If `false`, it restarts from the beginning.
</ParamField>

```typescript theme={null}
// Continuous rotation
const spinning = Linear({ duration: 2.0 }).repeatForever(false)

// Pulsing effect (forward and back)
const pulsing = EaseInOut({ duration: 1.0 }).repeatForever(true)
```

### Combining modifiers

```typescript theme={null}
const body = () => {
    const [offset, setOffset] = useState(0)

    return VStack([
        Circle()
            .fill(Color("pink"))
            .frame({ width: 60, height: 60 })
            .offset({ x: offset, y: 0 }),
        Button("Complex Animation", () => {
            const animation = Bouncy({ extraBounce: 0.3 })
                .delay(0.3)
                .speed(0.5)
                .repeatCount(3)

            withAnimation(animation, () => {
                setOffset(100)
            })
        })
    ])
}
```

## Notes

* Default parameter values are platform-specific and optimized for each environment.
* Spring animations (`Spring`, `InterpolatingSpring`, `Bouncy`, `Snappy`) may overshoot their target based on damping settings.
* Timing curve animations (`EaseIn`, `EaseInOut`, `EaseOut`, `Linear`) run for a fixed duration and do not overshoot.
* Use `repeatForever` sparingly to avoid performance issues.

## See Also

* [withAnimation](/bindjs/functions/withAnimation) -- wrap state changes with animation
