Skip to content

From React Native Animated ​

Most Animated code has a direct counterpart in Jolt. The main difference is that Jolt has no Animated.Value: you animate a view's properties, and Jolt computes the curve once and plays it natively, the way useNativeDriver: true would for every animation.

Timing ​

ts
// React Native
Animated.timing(opacity, { toValue: 1, duration: 500, useNativeDriver: true }).start()

// Jolt
animate(card, { opacity: 1 }, { duration: 500, ease: 'easeInOut' })

Animated.timing defaults to 500 ms and Easing.inOut(Easing.ease), which is very close to Jolt's easeInOut. Jolt tweens default to 300 ms and easeOut, so pass both when a port should look the same. Easing.bezier(x1, y1, x2, y2) becomes cubicBezier(x1, y1, x2, y2) or the array [x1, y1, x2, y2], and any easing function still works. Easing.quad, Easing.cubic, Easing.poly(4), Easing.poly(5), Easing.sin and Easing.exp are the quad, cubic, quart, quint, sine and expo curves: on their own they ease in ('cubicIn'), Easing.out(Easing.cubic) is 'cubicOut' and Easing.inOut(Easing.cubic) is 'cubicInOut'.

Springs ​

stiffness, damping and mass carry over unchanged. For friction and tension, origamiSpring() applies the same Origami conversion Animated.spring uses, with the same defaults of 7 and 40:

ts
// React Native
Animated.spring(x, {
  toValue: 100,
  friction: 3,
  tension: 40,
  useNativeDriver: true,
}).start()

// Jolt
animate(card, { x: 100 }, origamiSpring({ friction: 3, tension: 40 }))

bounciness and speed have no converter; describe those springs with Jolt's bounce and duration instead.

Three Animated.spring configurations converted with origamiSpring(), tossed and interrupted on the iOS simulator. Real-time playback.

Composition ​

React NativeJolt
Animated.sequence([...])sequence([...])
Animated.parallel([...])one animate() with several properties, or steps with at: '<'
Animated.stagger(60, [...])animate(views, ..., { stagger: 60 })
Animated.delay(200)delay: 200, or a step at: '+200'
Animated.loop(anim)repeat: Infinity
Animated.loop(anim, { iterations })repeat: iterations - 1
loop(sequence([delay(d), anim]))repeat: Infinity, repeatDelay: d
.start(({ finished }) => ...)await animate(...) resolves with finished
value.stopAnimation()stop(view, ['x'])
value.setValue(v)set(value, v), or set(view, { x: v })

Animated.Value and interpolate ​

Animated.Value is a motion value, and interpolate is to(). Binding the mapped values replaces passing them in style:

ts
// React Native
const progress = useRef(new Animated.Value(0)).current
const style = {
  opacity: progress.interpolate({ inputRange: [0, 1], outputRange: [0, 0.45] }),
  transform: [
    { translateY: progress.interpolate({ inputRange: [0, 1], outputRange: [200, 0] }) },
  ],
}
Animated.spring(progress, { toValue: 1, useNativeDriver: true }).start()

// Jolt
const progress = motionValue(0)
bind(backdrop, { opacity: progress.to([0, 1], [0, 0.45]) })
bind(sheet, { y: progress.to([0, 1], [200, 0]) })
animate(progress, 1, origamiSpring())

to() clamps by default, while interpolate extends; pass { clamp: false } for extrapolate: 'extend'. A value that only drives one view along a timeline can also be plain keyframes: the input range becomes times, the output range the keyframes, and easeTrack: true runs the driving animation's easing over the whole track. See track easing. A value driven by a scroll offset is scrollLinked(), and one driven by a pan gesture is drag() with value.

Adding and multiplying values ​

Animated.add and Animated.multiply combine two animations on one property. In Jolt, play the second one on a layer: translations and rotations add, scale and opacity multiply.

ts
animate(logo, { scale: [1, 1.04, 1] }, { duration: 1200, repeat: Infinity }) // the base
animate(logo, { scale: [1, 1.15, 1] }, { duration: 300, layer: 'kick' }) // multiplied on top

Platform APIs ​

React NativeJolt
useNativeDriver: truealways: every animation plays natively
LayoutAnimationanimateLayout()
Keyboard events and keyboardWillShow timingonKeyboard() and followKeyboard()
AccessibilityInfo.isReduceMotionEnabled()reducedMotion() and onReducedMotion()
Animated.event on onScrollscrollValue() with bind(), or scrollLinked()
PanResponder writing into an Animated.Valuedrag() with value, release included
a value that outlives a remounted viewmotion states with attach()

Released under the MIT License.