Animation constructors create AnimationComponent values that define the timing and feel of state transitions. Pass them to withAnimation or the .animation() modifier.
Spring
A spring animation with response and damping parameters. This is the most common animation type.
Spring(options?: {
response?: number;
dampingFraction?: number;
blendDuration?: number;
}): AnimationComponent;
Duration of the spring’s settle time in seconds. Lower values produce faster animations.
Damping ratio. 0 = no damping (infinite oscillation), 1 = critical damping (no bounce).
Duration in seconds for blending between animations.
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.
InterpolatingSpring(options: {
stiffness: number;
damping: number;
mass: number;
}): AnimationComponent;
Spring stiffness coefficient. Higher values produce faster, stiffer springs.
Damping coefficient. Higher values produce less bounce.
Mass of the spring. Higher values produce slower animations with more momentum.
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.
EaseIn(options?: { duration?: number }): AnimationComponent;
Animation duration in seconds.
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.
EaseInOut(options?: { duration?: number }): AnimationComponent;
Animation duration in seconds.
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.
EaseOut(options?: { duration?: number }): AnimationComponent;
Animation duration in seconds.
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.
Linear(options?: { duration?: number }): AnimationComponent;
Animation duration in seconds.
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.
Bouncy(options?: {
duration?: number;
extraBounce?: number;
}): AnimationComponent;
Approximate animation duration in seconds.
Extra bounce amount. 0 = no extra bounce, 1 = very bouncy.
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.
Snappy(options?: {
response?: number;
dampingFraction?: number;
blendDuration?: number;
}): AnimationComponent;
Duration of the spring’s settle time in seconds.
Damping ratio. 0 = no damping, 1 = critical damping.
Duration in seconds for blending between animations.
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.
.delay(seconds: number): AnimationComponent
const animation = Spring().delay(0.5)
speed
Multiplies the animation speed.
.speed(multiplier: number): AnimationComponent
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.
.repeatCount(count: number): AnimationComponent
const bouncing = Bouncy().repeatCount(3)
repeatForever
Repeats the animation indefinitely.
.repeatForever(autoreverses: boolean | { autoreverses: boolean }): AnimationComponent
autoreverses
boolean | { autoreverses: boolean }
If true, the animation reverses direction each cycle. If false, it restarts from the beginning.
// 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
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