Onboarding Screen
A phone frame that pops in, then fills with list rows.
Why it is timed this way
The reasoning
Two sequences rather than one: the frame establishes itself, and only then does content arrive inside it. Running both at once makes the rows look like they are falling through the phone rather than into it.
10 elements move, the first at 0ms and the last starting at 645ms — the whole scene settles by 1545ms. Every bar below is one element's animation window.
The code
Everything the scene needs, in whichever format you ship. Entrances compile to@keyframesand hover states totransition, with a reduced-motion guard on both.
.onboarding {
transform: translate3d(0px, 0px, 0);
width: 960px;
height: 480px;
transform-origin: 480px 120px;
}
.phone {
transform: translate3d(0px, 0px, 0);
box-shadow: 0px 20px 50px 0px #00000073;
width: 200px;
height: 192px;
background: #171a24;
border-radius: 30px;
transform-origin: 120px 116px;
}
.rows {
transform: translate3d(0px, 0px, 0);
height: 116px;
transform-origin: 16px 58px;
}
.row-1 {
transform: translate3d(0px, 0px, 0);
height: 20px;
background: #1f2331;
border-radius: 14px;
transform-origin: 30px 24px;
}
.row-2 {
transform: translate3d(0px, 0px, 0);
height: 20px;
background: #1f2331;
border-radius: 14px;
transform-origin: 30px 24px;
}
.row-3 {
transform: translate3d(0px, 0px, 0);
height: 20px;
background: #1f2331;
border-radius: 14px;
transform-origin: 30px 24px;
}
.row-4 {
transform: translate3d(0px, 0px, 0);
height: 20px;
background: #1f2331;
border-radius: 14px;
transform-origin: 30px 24px;
}
.notch {
transform: translate3d(0px, 0px, 0);
width: 64px;
height: 10px;
background: #0e1016;
border-radius: 999px;
animation: notch-anim 1545ms linear 0ms infinite both;
will-change: transform, opacity;
}
@keyframes notch-anim {
0% {
transform: translate3d(0px, 0px, 0) scale(0, 0);
opacity: 0;
animation-timing-function: ease-out;
}
12.94% {
transform: translate3d(0px, 0px, 0) scale(1.029, 1.029);
opacity: 1;
}
32.36% {
transform: translate3d(0px, 0px, 0);
opacity: 1;
}
100% {
transform: translate3d(0px, 0px, 0);
opacity: 1;
}
}
.screen-title {
transform: translate3d(0px, 0px, 0);
height: 30px;
background: #00000000;
color: #eceef4;
font-size: 22px;
font-weight: 700;
animation: screen-title-anim 1545ms linear 0ms infinite both;
will-change: transform, opacity;
}
@keyframes screen-title-anim {
0% {
transform: translate3d(0px, 0px, 0) scale(0, 0);
opacity: 0;
}
3.88% {
transform: translate3d(0px, 0px, 0) scale(0, 0);
opacity: 0;
animation-timing-function: ease-out;
}
16.83% {
transform: translate3d(0px, 0px, 0) scale(1.029, 1.029);
opacity: 1;
}
36.25% {
transform: translate3d(0px, 0px, 0);
opacity: 1;
}
100% {
transform: translate3d(0px, 0px, 0);
opacity: 1;
}
}
.row-1-dot {
transform: translate3d(0px, 0px, 0);
width: 20px;
height: 20px;
background: #6366f1;
border-radius: 999px;
animation: row-1-dot-anim 1545ms linear 0ms infinite both;
will-change: transform, opacity;
}
@keyframes row-1-dot-anim {
0% {
transform: translate3d(-64px, 0px, 0);
opacity: 0;
}
16.83% {
transform: translate3d(-64px, 0px, 0);
opacity: 0;
animation-timing-function: ease-out;
}
62.14% {
transform: translate3d(0px, 0px, 0);
opacity: 1;
}
100% {
transform: translate3d(0px, 0px, 0);
opacity: 1;
}
}
.row-1-bar {
transform: translate3d(0px, 0px, 0);
height: 10px;
background: #272c3a;
border-radius: 999px;
animation: row-1-bar-anim 1545ms linear 0ms infinite both;
will-change: transform, opacity;
}
@keyframes row-1-bar-anim {
0% {
transform: translate3d(-64px, 0px, 0);
opacity: 0;
}
20.39% {
transform: translate3d(-64px, 0px, 0);
opacity: 0;
animation-timing-function: ease-out;
}
65.7% {
transform: translate3d(0px, 0px, 0);
opacity: 1;
}
100% {
transform: translate3d(0px, 0px, 0);
opacity: 1;
}
}
.row-2-dot {
transform: translate3d(0px, 0px, 0);
width: 20px;
height: 20px;
background: #22d3ee;
border-radius: 999px;
animation: row-2-dot-anim 1545ms linear 0ms infinite both;
will-change: transform, opacity;
}
@keyframes row-2-dot-anim {
0% {
transform: translate3d(-64px, 0px, 0);
opacity: 0;
}
23.95% {
transform: translate3d(-64px, 0px, 0);
opacity: 0;
animation-timing-function: ease-out;
}
69.26% {
transform: translate3d(0px, 0px, 0);
opacity: 1;
}
100% {
transform: translate3d(0px, 0px, 0);
opacity: 1;
}
}
.row-2-bar {
transform: translate3d(0px, 0px, 0);
height: 10px;
background: #272c3a;
border-radius: 999px;
animation: row-2-bar-anim 1545ms linear 0ms infinite both;
will-change: transform, opacity;
}
@keyframes row-2-bar-anim {
0% {
transform: translate3d(-64px, 0px, 0);
opacity: 0;
}
27.51% {
transform: translate3d(-64px, 0px, 0);
opacity: 0;
animation-timing-function: ease-out;
}
72.82% {
transform: translate3d(0px, 0px, 0);
opacity: 1;
}
100% {
transform: translate3d(0px, 0px, 0);
opacity: 1;
}
}
.row-3-dot {
transform: translate3d(0px, 0px, 0);
width: 20px;
height: 20px;
background: #6366f1;
border-radius: 999px;
animation: row-3-dot-anim 1545ms linear 0ms infinite both;
will-change: transform, opacity;
}
@keyframes row-3-dot-anim {
0% {
transform: translate3d(-64px, 0px, 0);
opacity: 0;
}
31.07% {
transform: translate3d(-64px, 0px, 0);
opacity: 0;
animation-timing-function: ease-out;
}
76.38% {
transform: translate3d(0px, 0px, 0);
opacity: 1;
}
100% {
transform: translate3d(0px, 0px, 0);
opacity: 1;
}
}
.row-3-bar {
transform: translate3d(0px, 0px, 0);
height: 10px;
background: #272c3a;
border-radius: 999px;
animation: row-3-bar-anim 1545ms linear 0ms infinite both;
will-change: transform, opacity;
}
@keyframes row-3-bar-anim {
0% {
transform: translate3d(-64px, 0px, 0);
opacity: 0;
}
34.63% {
transform: translate3d(-64px, 0px, 0);
opacity: 0;
animation-timing-function: ease-out;
}
79.94% {
transform: translate3d(0px, 0px, 0);
opacity: 1;
}
100% {
transform: translate3d(0px, 0px, 0);
opacity: 1;
}
}
.row-4-dot {
transform: translate3d(0px, 0px, 0);
width: 20px;
height: 20px;
background: #22d3ee;
border-radius: 999px;
animation: row-4-dot-anim 1545ms linear 0ms infinite both;
will-change: transform, opacity;
}
@keyframes row-4-dot-anim {
0% {
transform: translate3d(-64px, 0px, 0);
opacity: 0;
}
38.19% {
transform: translate3d(-64px, 0px, 0);
opacity: 0;
animation-timing-function: ease-out;
}
83.5% {
transform: translate3d(0px, 0px, 0);
opacity: 1;
}
100% {
transform: translate3d(0px, 0px, 0);
opacity: 1;
}
}
.row-4-bar {
transform: translate3d(0px, 0px, 0);
height: 10px;
background: #272c3a;
border-radius: 999px;
animation: row-4-bar-anim 1545ms linear 0ms infinite both;
will-change: transform, opacity;
}
@keyframes row-4-bar-anim {
0% {
transform: translate3d(-64px, 0px, 0);
opacity: 0;
}
41.75% {
transform: translate3d(-64px, 0px, 0);
opacity: 0;
animation-timing-function: ease-out;
}
87.06% {
transform: translate3d(0px, 0px, 0);
opacity: 1;
}
100% {
transform: translate3d(0px, 0px, 0);
opacity: 1;
}
}
@media (prefers-reduced-motion: reduce) {
.notch,
.screen-title,
.row-1-dot,
.row-1-bar,
.row-2-dot,
.row-2-bar,
.row-3-dot,
.row-3-bar,
.row-4-dot,
.row-4-bar {
animation: none;
transition: none;
}
}More scenes
Sign-In Card
A sign-in card that assembles downward, with fields that answer to focus.
Launch Hero
A product hero whose copy, buttons and panel arrive in sequence.
Three-Plan Pricing
Three plans that pop in, with the featured column raised and hover lifts on every card.