Skip to content

Commit

Permalink
Merge pull request #1905 from framer/fix/optimised-ready
Browse files Browse the repository at this point in the history
Defer real optimised animation until Chrome is ready to paint
  • Loading branch information
mergetron[bot] authored Jan 23, 2023
2 parents 11a1a91 + edce87c commit d010343
Show file tree
Hide file tree
Showing 21 changed files with 239 additions and 229 deletions.
58 changes: 26 additions & 32 deletions dev/optimized-appear/interrupt-delay-after.html
Original file line number Diff line number Diff line change
Expand Up @@ -78,50 +78,44 @@
// Emulate server rendering of element
root.innerHTML = ReactDOMServer.renderToString(Component)

// Start Motion One animation
const animation = startOptimizedAppearAnimation(
startOptimizedAppearAnimation(
document.getElementById("box"),
"opacity",
[0, 1],
{
duration: duration * 1000,
ease: "linear",
delay: 250,
}
)

const ready = animation.ready
? (callback) => animation.ready.then(callback)
: (callback) => requestAnimationFrame(callback)
ready(() => {
/**
* Set currentTime to 500ms - because of the delay this will cut
* into the animation at 0.25
*/
if (animation) {
},
(animation) => {
/**
* Set currentTime to 500ms - because of the delay this will cut
* into the animation at 0.25
*/
animation.currentTime = (duration * 1000) / 2
animation.pause()
}

// Hydrate root mid-way through animation
ReactDOM.hydrateRoot(root, Component)
// Hydrate root mid-way through animation
ReactDOM.hydrateRoot(root, Component)

/**
* Check the animation isn't in its initial state
*/
setTimeout(() => {
const { opacity: initialOpacity } = window.getComputedStyle(
document.getElementById("box")
)
/**
* Check the animation isn't in its initial state
*/
setTimeout(() => {
const { opacity: initialOpacity } =
window.getComputedStyle(
document.getElementById("box")
)

if (initialOpacity === "0") {
showError(
document.getElementById("box"),
`opacity should have animated`
)
}
}, 100)
})
if (initialOpacity === "0") {
showError(
document.getElementById("box"),
`opacity should have animated`
)
}
}, 100)
}
)
</script>
</body>
</html>
33 changes: 14 additions & 19 deletions dev/optimized-appear/interrupt-delay-before.html
Original file line number Diff line number Diff line change
Expand Up @@ -71,34 +71,29 @@
// Emulate server rendering of element
root.innerHTML = ReactDOMServer.renderToString(Component)

// Start Motion One animation
const animation = startOptimizedAppearAnimation(
startOptimizedAppearAnimation(
document.getElementById("box"),
"opacity",
[0, 1],
{
duration: duration * 1000,
ease: "linear",
delay: 250,
}
)
},
(animation) => {
/**
* Set currentTime to 200ms - this will put the animation
* still before the delay period
*/
if (animation) {
animation.currentTime = 200
animation.pause()
}

const ready = animation.ready
? (callback) => animation.ready.then(callback)
: (callback) => requestAnimationFrame(callback)
ready(() => {
/**
* Set currentTime to 500ms - because of the delay this will cut
* into the animation at 0.25
*/
if (animation) {
animation.currentTime = 200
animation.pause()
// Hydrate root mid-way through animation
ReactDOM.hydrateRoot(root, Component)
}

// Hydrate root mid-way through animation
ReactDOM.hydrateRoot(root, Component)
})
)
</script>
</body>
</html>
59 changes: 20 additions & 39 deletions dev/optimized-appear/interrupt-spring.html
Original file line number Diff line number Diff line change
Expand Up @@ -45,26 +45,20 @@
// This is the tree to be rendered "server" and client-side.
const Component = React.createElement(motion.div, {
id: "box",
initial: { y: 0, scale: 1, opacity: 0 },
animate: { y: 100, scale: 2, opacity: 1 },
initial: { y: 0, scale: 1 },
animate: { y: 100, scale: 2 },
transition: { type: "spring", stiffness, damping, mass },
/**
* On animation start, check the values we expect to see here
*/
onAnimationStart: () => {
matchOpacity(document.getElementById("box"), 0.463589)
matchViewportBox(document.getElementById("box"), {
bottom: 270.2061767578125,
left: 76.59794616699219,
right: 223.4020538330078,
top: 123.40205383300781,
bottom: 269.70709228515625,
left: 76.76429748535156,
right: 223.23570251464844,
top: 123.23570251464844,
})
},
onUpdate: () => {
console.log(
getComputedStyle(document.getElementById("box")).opacity
)
},
style: { willChange: "opacity" },
[optimizedAppearDataAttribute]: "a",
})
Expand All @@ -88,6 +82,9 @@
while (!state.done) {
state = springAnimation.next(t)
keyframes.push(state.value)

if (t === 100) console.log(state.value)
if (t === 110) console.log(state.value)
t += springTimeResolution
}

Expand Down Expand Up @@ -122,35 +119,19 @@
document.getElementById("box"),
"transform",
transformKeyframes,
transformOptions
)

const opacityKeyframes = generateSpringKeyframes(0, 1)
const opacityAnimation = startOptimizedAppearAnimation(
document.getElementById("box"),
"opacity",
opacityKeyframes,
{
duration: opacityKeyframes.length * springTimeResolution,
ease: "linear",
transformOptions,
(animation) => {
if (animation) {
animation.currentTime = 100
animation.pause()
}

// Hydrate root mid-way through animation
setTimeout(() => {
ReactDOM.hydrateRoot(root, Component)
}, 40)
}
)

const ready = animation.ready
? (callback) => animation.ready.then(callback)
: (callback) => requestAnimationFrame(callback)
ready(() => {
// TODO: Dont manipulate animation until ready
if (animation) {
animation.currentTime = 100
animation.pause()
opacityAnimation.currentTime = 100
opacityAnimation.pause()
}

// Hydrate root mid-way through animation
ReactDOM.hydrateRoot(root, Component)
})
</script>
</body>
</html>
27 changes: 11 additions & 16 deletions dev/optimized-appear/interrupt-tween-opacity.html
Original file line number Diff line number Diff line change
Expand Up @@ -68,30 +68,25 @@
// Emulate server rendering of element
root.innerHTML = ReactDOMServer.renderToString(Component)

// Start Motion One animation
const animation = startOptimizedAppearAnimation(
startOptimizedAppearAnimation(
document.getElementById("box"),
"opacity",
[0, 1],
{
duration: duration * 1000,
ease: "linear",
}
)
},
(animation) => {
// Manually set start time to half way through the animation
if (animation) {
animation.currentTime = (duration * 1000) / 2
animation.pause()
}

const ready = animation.ready
? (callback) => animation.ready.then(callback)
: (callback) => requestAnimationFrame(callback)
ready(() => {
// Manually set start time to half way through the animation
if (animation) {
animation.currentTime = (duration * 1000) / 2
animation.pause()
// Hydrate root mid-way through animation
ReactDOM.hydrateRoot(root, Component)
}

// Hydrate root mid-way through animation
ReactDOM.hydrateRoot(root, Component)
})
)
</script>
</body>
</html>
24 changes: 10 additions & 14 deletions dev/optimized-appear/interrupt-tween-transforms.html
Original file line number Diff line number Diff line change
Expand Up @@ -81,22 +81,18 @@
{
duration: duration * 1000,
ease: "linear",
}
)
},
(animation) => {
// Manually set start time to half way through the animation
if (animation) {
animation.currentTime = (duration * 1000) / 2
animation.pause()
}

const ready = animation.ready
? (callback) => animation.ready.then(callback)
: (callback) => requestAnimationFrame(callback)
ready(() => {
// Manually set start time to half way through the animation
if (animation) {
animation.currentTime = (duration * 1000) / 2
animation.pause()
// Hydrate root mid-way through animation
ReactDOM.hydrateRoot(root, Component)
}

// Hydrate root mid-way through animation
ReactDOM.hydrateRoot(root, Component)
})
)
</script>
</body>
</html>
25 changes: 11 additions & 14 deletions dev/optimized-appear/interrupt-tween-x.html
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
})
},
[optimizedAppearDataAttribute]: "a",
children: "Content",
})

// Emulate server rendering of element
Expand All @@ -81,22 +82,18 @@
{
duration: duration * 1000,
ease: "linear",
}
)
},
(animation) => {
// Manually set start time to half way through the animation
if (animation) {
animation.currentTime = (duration * 1000) / 2
animation.pause()
}

const ready = animation.ready
? (callback) => animation.ready.then(callback)
: (callback) => requestAnimationFrame(callback)
ready(() => {
// Manually set start time to half way through the animation
if (animation) {
animation.currentTime = (duration * 1000) / 2
animation.pause()
// Hydrate root mid-way through animation
ReactDOM.hydrateRoot(root, Component)
}

// Hydrate root mid-way through animation
ReactDOM.hydrateRoot(root, Component)
})
)
</script>
</body>
</html>
35 changes: 15 additions & 20 deletions dev/optimized-appear/persist.html
Original file line number Diff line number Diff line change
Expand Up @@ -71,34 +71,29 @@
// Emulate server rendering of element
root.innerHTML = ReactDOMServer.renderToString(Component)

// Start Motion One animation
const animation = startOptimizedAppearAnimation(
startOptimizedAppearAnimation(
document.getElementById("box"),
"opacity",
[0, 1],
{
duration: duration * 1000,
ease: "linear",
}
)
},
(animation) => {
// Manually set start time to half way through the animation
if (animation) {
animation.currentTime = duration * 1000
}

/**
* This is necessary in Chrome
*/
requestAnimationFrame(() => {
// Manually set start time to half way through the animation
if (animation) {
animation.currentTime = duration * 1000
/**
* Give it time to commit the finished animation
*/
setTimeout(() => {
// Hydrate root mid-way through animation
ReactDOM.hydrateRoot(root, Component)
}, 50)
}

/**
* Give it time to commit the finished animation
*/
setTimeout(() => {
// Hydrate root mid-way through animation
ReactDOM.hydrateRoot(root, Component)
}, 50)
})
)
</script>
</body>
</html>
Loading

0 comments on commit d010343

Please sign in to comment.