VIDEO 7
Code:
JavaScript
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.13.0/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.13.0/CustomEase.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.13.0/SplitText.min.js"></script>
<script src="https://unpkg.com/@studio-freight/lenis@1.0.42/dist/lenis.min.js"></script>
<script>
document.addEventListener("DOMContentLoaded", () => {
gsap.registerPlugin(CustomEase, SplitText);
CustomEase.create("hop", ".87,0,.13,1");
const lenis = new Lenis();
function raf(time) {
lenis.raf(time);
requestAnimationFrame(raf);
}
requestAnimationFrame(raf);
const textContainers = document.querySelectorAll(".menu-col");
let splitTextByContainer = [];
textContainers.forEach((container) => {
const textElements = container.querySelectorAll("a");
let containerSplits = [];
textElements.forEach((element) => {
const split = SplitText.create(element, {
type: "lines",
mask: "lines",
linesClass: "line",
});
containerSplits.push(split);
gsap.set(split.lines, { y: "-250%" });
});
splitTextByContainer.push(containerSplits);
});
const container = document.querySelector(".container");
const menuToggleBtn = document.querySelector(".menu-toggle-btn");
const menuOverlay = document.querySelector(".menu-overlay");
const menuOverlayContainer = document.querySelector(".menu-overlay-content");
const menuMediaWrapper = document.querySelector(".menu-media-wrapper");
const copyContainers = document.querySelectorAll(".menu-col");
const menuToggleLabel = document.querySelector(".menu-toggle-label p");
const hamburgerIcon = document.querySelector(".menu-hamburger-icon");
let isMenuOpen = false;
let isAnimating = false;
menuToggleBtn.addEventListener("click", () => {
if (isAnimating) return;
if (!isMenuOpen) {
isAnimating = true;
lenis.stop();
const tl = gsap.timeline();
tl.to(
menuToggleLabel,
{
y: "-250%",
duration: 1,
ease: "hop",
},
"<"
)
.to(
container,
{
y: "100vh",
duration: 1,
ease: "hop",
},
"<"
)
.to(
menuOverlay,
{
clipPath: "polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%)",
duration: 1,
ease: "hop",
},
"<"
)
.to(
menuOverlayContainer,
{
yPercent: 0,
duration: 1,
ease: "hop",
},
"<"
)
.to(
menuMediaWrapper,
{
opacity: 1,
duration: 0.75,
ease: "power2.out",
delay: 0.5,
},
"<"
);
splitTextByContainer.forEach((containerSplits) => {
const copyLines = containerSplits.flatMap((split) => split.lines);
tl.to(
copyLines,
{
y: "0%",
duration: 2,
ease: "hop",
stagger: -0.075,
},
-0.15
);
});
hamburgerIcon.classList.add("active");
tl.call(() => {
isAnimating = false;
});
isMenuOpen = true;
} else {
isAnimating = true;
hamburgerIcon.classList.remove("active");
const tl = gsap.timeline();
tl.to(container, {
y: "0vh",
duration: 1,
ease: "hop",
})
.to(
menuOverlay,
{
clipPath: "polygon(0% 0%, 100% 0%, 100% 0%, 0% 0%)",
duration: 1,
ease: "hop",
},
"<"
)
.to(
menuOverlayContainer,
{
yPercent: -50,
duration: 1,
ease: "hop",
},
"<"
)
.to(
menuToggleLabel,
{
y: "0%",
duration: 1,
ease: "hop",
},
"<"
)
.to(
copyContainers,
{
opacity: 0.25,
duration: 1,
ease: "hop",
},
"<"
);
tl.call(() => {
splitTextByContainer.forEach((containerSplits) => {
const copyLines = containerSplits.flatMap((split) => split.lines);
gsap.set(copyLines, { y: "-250%" });
});
gsap.set(copyContainers, { opacity: 1 });
gsap.set(menuMediaWrapper, { opacity: 0 });
isAnimating = false;
lenis.start();
});
isMenuOpen = false;
}
});
});
</script>
CSS
nav {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
overflow: hidden;
z-index: 2;
}
.menu-bar {
position: fixed;
top: 0;
left: 0;
width: 100vw;
padding: 2rem;
display: flex;
justify-content: space-between;
align-items: center;
pointer-events: all;
z-index: 2;
}
.menu-toggle-btn {
display: flex;
align-items: center;
gap: 1rem;
cursor: pointer;
}
.menu-toggle-label {
overflow: hidden;
}
.menu-toggle-label p {
position: relative;
transform: translateY(0%);
will-change: transform;
}
.menu-hamburger-icon {
position: relative;
width: 3rem;
height: 3rem;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 0.3rem;
border: 1px solid grey;
border-radius: 100%;
}
.menu-hamburger-icon span {
position: absolute;
width: 15px;
height: 1.25px;
background-color: grey;
transition: all 0.75s cubic-bezier(0.87, 0, 0.13, 1);
transform-origin: center;
will-change: transform;
}
.menu-hamburger-icon span:nth-child(1) {
transform: translateY(-3px);
}
.menu-hamburger-icon span:nth-child(2) {
transform: translateY(3px);
}
.menu-hamburger-icon.active span:nth-child(1) {
transform: translateY(0) rotate(45deg) scaleX(1.05);
}
.menu-hamburger-icon.active span:nth-child(2) {
transform: translateY(0) rotate(-45deg) scaleX(1.05);
}
.menu-overlay,
.menu-overlay-content {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
color: black;
overflow: hidden;
z-index: 1;
}
.menu-overlay {
background-color: black;
clip-path: polygon(0% 0%, 100% 0%, 100% 0%, 0% 0%);
will-change: clip-path;
}
.menu-overlay-content {
display: flex;
transform: translateY(-50%);
will-change: transform;
pointer-events: all;
}
.menu-media-wrapper {
flex: 2;
opacity: 0;
will-change: opacity;
}
.menu-media-wrapper img {
opacity: 0.65;
}
.menu-content-main {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}