How to use
Tutorial
Follow this tutorial to learn everything you need to know.
Overview
Creating a website like this, where captivating animations seamlessly unfold as users scroll, is a challenging endeavor. Even with the powerful GSAP library, navigating the intricacies of the required logic can be a daunting task.
That's why Animate Screen was created, a solution designed to streamline the process. It's engineered to simplify the intricate task of defining the diverse phases of the animation and specifying the animations in each phase.
Dependencies
This package is built upon the GSAP library, but you don't need an in-depth knowledge of GSAP. A modest familiarity with the properties used in defining a tween is all that's necessary.
Installation
To install this package you have to run the following command.
npm install animate-screen
Screen animation
To begin using this package, you have to include the AnimateScreen
component. This component contains all the components that have to be animated and defines all the animation phases.
import { AnimateScreen } from 'animate-screen'
function App() {
return (
<AnimateScreen phases={null} config={null}>
{/* components */}
</AnimateScreen>
)
}
export default App
Animation phases
To define the animation phases you can create a phases.js file and create an instance of the ScreenAnimationPhases
class.
/* phases.js */
import { ScreenAnimationPhases } from 'animate-screen'
const phases = new ScreenAnimationPhases()
phases.add('boxes-right', 0, 1, true)
phases.add('boxes-hidden', 0, 1, true)
export default phases
The add()
method is used to add a phase and it receives the following arguments:
- name: Name of the phase.
- delay: How many screens have to be scrolled to start the phase.
- duration: How many screens have to be scrolled to finish the phase.
- snap: If it has to snap at the end of the phase or not.
After that, you have to pass this instance to the phases
prop.
// ...
import phases from 'phases'
function App() {
return (
<AnimateScreen phases={phases} config={null}>
{/* components */}
</AnimateScreen>
)
}
// ...
Configuration
You also need to define the configuration of the animation, and you define it by passing an object with these properties to the config
props.
// ...
const config = {
scrub: 2, // Takes 2 seconds to "catch up" to the scrollbar
snap: {
delay: 0.2, // Wait 0.2 seconds before snapping
duration: {
min: 1, // Snap takes at least 1 second
max: 2, // Snap takes at most 2 seconds
},
ease: 'power1.inOut', // Snap uses the "power1.inOut" easing function
},
}
function App() {
return (
<AnimateScreen phases={phases} config={config}>
{/* components */}
</AnimateScreen>
)
}
// ...
Component animation
You are now ready to create the components that have to be animated. You can create a boxes folder with the boxes.jsx and boxes.module.css files.
/* boxes/boxes.jsx */
import styles from './boxes.module.css'
function Boxes() {
return (
<>
<div className={styles.box1} />
<div className={styles.box2} />
</>
)
}
export default Boxes
/* boxes/boxes.module.css */
.box1,
.box2 {
position: fixed;
width: 100px;
height: 100px;
top: calc(50% - 50px);
background: red;
}
.box1 {
left: calc(25% - 50px);
}
.box2 {
left: calc(75% - 50px);
}
// ...
import Boxes from './boxes/boxes'
// ...
function App() {
return (
<AnimateScreen phases={phases} config={config}>
<Boxes />
</AnimateScreen>
)
}
// ...
There is a small adjustment you have to do to the component. To animate it you have to use the AnimateComponent
component.
// ...
import { AnimateComponent } from 'animate-screen'
function Boxes() {
return (
<AnimateComponent
animationPhases={null}
render={() => (
<>
<div className={styles.box1} />
<div className={styles.box2} />
</>
)}
/>
)
}
// ...
Element tags
To animate the elements within the component, you need to assign tags to these elements. To accomplish this, use the ref()
function.
// ...
function Boxes() {
return (
<AnimateComponent
animationPhases={null}
render={(ref) => (
<>
<div ref={ref('box')} className={styles.box1} />
<div ref={ref('box')} className={styles.box2} />
</>
)}
/>
)
}
// ...
You can also pass multiple tags to the same element if you want.
// ...
function Boxes() {
return (
<AnimateComponent
animationPhases={null}
render={(ref) => (
<>
<div ref={ref('box', 'box-1')} className={styles.box1} />
<div ref={ref('box', 'box-2')} className={styles.box2} />
</>
)}
/>
)
}
// ...
Animation
You can now define the animation of the component in the different phases. To do it, you can create a boxes.phases.js file and use the ComponentAnimationPhases
class.
/* boxes/boxes.phases.js */
import { ComponentAnimationPhases } from 'animate-screen'
const phases = new ComponentAnimationPhases()
phases.set('boxes-right', null)
phases.set('boxes-hidden', null)
export default phases
The set()
method is used to set an animation for a phase and it receives the following arguments:
- name: Name of the phase.
- animation: Animation of the phase.
After that, you have to pass this instance to the animationPhases
prop.
// ...
import animationPhases from './boxes.phases'
function Boxes() {
return (
<AnimateComponent
animationPhases={animationPhases}
render={(ref) => (
<>
<div ref={ref('box', 'box-1')} className={styles.box1} />
<div ref={ref('box', 'box-2')} className={styles.box2} />
</>
)}
/>
)
}
// ...
To create the animations you can create a phases folder with the boxes-right.js and boxes-hidden.js files and use the ComponentAnimation
class.
/* boxes/phases/boxes-right.js */
import { ComponentAnimation } from 'animate-screen'
const animation = new ComponentAnimation()
animation.ref('box').to({ x: '100%' }).ease('power1.inOut').start(0).end(1)
animation
.ref('box-1')
.to({ background: 'orange' })
.ease('none')
.start(0)
.end(0.5)
animation
.ref('box-2')
.to({ background: 'yellow' })
.ease('none')
.start(0.5)
.end(1)
export default animation
/* boxes/phases/boxes-hidden.js */
import { ComponentAnimation } from 'animate-screen'
const animation = new ComponentAnimation()
animation.ref('box').to({ autoAlpha: 0 }).ease('power1.inOut').start(0).end(1)
export default animation
The ref()
method receives a tag as argument and returns an object that is used to define the animation of the elements with this tag. The object returned has the following methods:
to()
: It is used to define the properties to animate. The properties are the same you would use ingsap.to()
.ease()
: It is used to define the easing function. If you don't call this method the easing function will be "none" by default.start()
: It is used to define the start time of the animation with a number between 0 and 1. If you don't call this method the start time will be 0.end()
: It is used to define the end time of the animation with a number between 0 and 1. if you don't call this method the end time will be 1.
Finally, you have to pass these instances to the set()
methods.
/* boxes/boxes.phases.js */
import { ComponentAnimationPhases } from 'animate-screen'
import boxesRight from './phases/boxes-right'
import boxesHidden from './phases/boxes-hidden'
const phases = new ComponentAnimationPhases()
phases.set('boxes-right', boxesRight)
phases.set('boxes-hidden', boxesHidden)
export default phases
That's everything you need to know to create animations. After doing all of that, the component has all its animations set up to be triggered while you scroll.
Callbacks
In addition to defining scroll-triggered animations, you can also specify callbacks to execute while you scroll. To do it you have to use the setCallbacksPhases
prop.
// ...
import { useCallback } from 'react'
// ...
import animationPhases from './boxes.phases'
function Boxes() {
return (
<AnimateComponent
animationPhases={animationPhases}
setCallbacksPhases={useCallback((callbacks) => {
callbacks.add('boxes-hidden', 0.5, () => alert('Hello world!'))
}, [])}
render={(ref) => (
<>
<div ref={ref('box', 'box-1')} className={styles.box1} />
<div ref={ref('box', 'box-2')} className={styles.box2} />
</>
)}
/>
)
}
// ...
This prop receives a function you can use to add callbacks. To add them you have to use the add()
method of the callbacks parameter passing the following arguments:
- name: Name of the phase you want to add the callback to.
- time: Number between 0 and 1 that defines when the callback will be executed within the phase.
- callback: Callback to execute.