Skip to content

Instantly share code, notes, and snippets.

@steveruizok
Created March 2, 2020 12:10
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save steveruizok/20e3365dc5669715497fcf99dab83e97 to your computer and use it in GitHub Desktop.
Save steveruizok/20e3365dc5669715497fcf99dab83e97 to your computer and use it in GitHub Desktop.
Framer Motion Animation Sequences
import * as React from "react"
import { Override, Data, AnimationControls, useAnimation } from "framer"
import { useAnimationSequence } from "./useAnimationSequence"
import { animationSequence } from "./animationSequence"
// Learn more: https://framer.com/docs/overrides/
let heart1: AnimationControls
let heart2: AnimationControls
let heart3: AnimationControls
const { start, stop, loop } = animationSequence(
() => [
heart1.start({ x: -32, y: -40 }),
heart2.start({ x: 32, y: -32 }),
heart3.start({ x: 32, y: -32 }),
],
() => [
heart1.start({ x: -16, y: -180 }),
heart2.start({ x: 60, y: -160 }),
heart3.start({ x: 60, y: -160 }),
],
() => [
heart1.start({ x: -32, y: -300 }),
heart2.start({ x: 16, y: -280 }),
heart3.start({ x: 16, y: -280 }),
],
() => [
heart1.start({ x: 0, y: 0, transition: { duration: 3 } }),
heart2.start({ x: 0, y: 0 }),
heart3.start({ x: 0, y: 0 }),
]
)
export function Heart1(props): Override {
heart1 = useAnimation()
React.useEffect(() => {
loop()
}, [])
return { animate: heart1 }
}
export function Heart2(props): Override {
heart2 = useAnimation()
return {
animate: heart2,
transition: { type: "spring", stiffness: 100, damping: 20 },
}
}
export function Heart3(props): Override {
heart3 = useAnimation()
return {
animate: heart3,
transition: { type: "spring", stiffåness: 200, damping: 100 },
}
}
import AnimationControls from "framer"
type AnimationStep = () => Promise<any> | Promise<any>[]
export function animationSequence(...animationSteps: AnimationStep[]) {
let playing = false
let looping = false
let sequence = null as IterableIterator<AnimationStep>
function* generator(...steps: AnimationStep[]) {
for (let step of steps) {
yield step
}
}
async function start() {
if (sequence) {
stop()
}
play()
sequence = generator(...animationSteps)
for (;;) {
const next = sequence.next()
// Stopped
if (!playing) {
return false
}
// Complete
if (next.done) {
if (!looping) {
stop()
}
return true
}
const step = next.value()
await (Array.isArray(step) ? Promise.all(step) : step)
}
}
function play() {
playing = true
}
function stop() {
playing = false
}
async function loop() {
looping = true
const loopFn = async () => {
await start()
if (playing) {
loop()
} else {
looping = false
}
}
stop()
loopFn()
}
return { start, stop, loop, isPlaying: playing }
}
import * as React from "react"
import AnimationControls from "framer"
type AnimationStep = () => Promise<any> | Promise<any>[]
export function useAnimationSequence(...animationSteps: AnimationStep[]) {
const playing = React.useRef(false)
const looping = React.useRef(false)
const sequence = React.useRef<IterableIterator<AnimationStep>>(null)
const [isPlaying, setIsPlaying] = React.useState(false)
function* generator(...steps: AnimationStep[]) {
for (let step of steps) {
yield step
}
}
const start = React.useCallback(async () => {
if (sequence.current) {
stop()
}
play()
sequence.current = generator(...animationSteps)
for (;;) {
const next = sequence.current.next()
// Stopped
if (!playing.current) {
return false
}
// Complete
if (next.done) {
if (!looping.current) {
stop()
}
return true
}
const step = next.value()
await (Array.isArray(step) ? Promise.all(step) : step)
}
}, [])
const play = React.useCallback(async () => {
playing.current = true
setIsPlaying(true)
}, [])
const stop = React.useCallback(() => {
playing.current = false
setIsPlaying(false)
}, [])
const loop = React.useCallback(() => {
looping.current = true
const loopFn = async () => {
await start()
if (playing.current) {
loop()
} else {
looping.current = false
}
}
stop()
loopFn()
}, [])
return { start, stop, loop, isPlaying }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment