Files
th-website/src/components/sections/HeroSection.vue
2026-03-10 18:49:57 +01:00

189 lines
3.6 KiB
Vue

<script setup lang="js">
import { onMounted, onUnmounted, ref } from "vue"
import gsap from "gsap"
import ScrollTrigger from "gsap/ScrollTrigger"
gsap.registerPlugin(ScrollTrigger)
const main = ref(null);
let tl;
let ctx;
function setBoxes() {
const wrapper = main.value.querySelector('.content-wrapper');
const rect = wrapper.getBoundingClientRect();
const boxes = gsap.utils.toArray(".box");
gsap.set(".title", { y: 200 });
boxes.forEach((box) => {
const randomX = gsap.utils.random(0, rect.width);
const randomY = gsap.utils.random(0, rect.height);
gsap.set(box, {
x: randomX,
y: randomY,
xPercent: -50,
yPercent: -50
});
});
}
function toggleTimeline() {
tl.reversed(!tl.reversed())
}
function startNextAnimation() {
const centerX = window.innerWidth / 2
const centerY = window.innerHeight / 2
const radius = 250
ctx = gsap.context(() => {
const boxes = gsap.utils.toArray(".box")
tl = gsap.timeline({
scrollTrigger: {
start: "top top",
end: "+=100%",
scrub: true,
pin: true,
}
})
tl.to(boxes, {
y: () => gsap.utils.random(-400, -150),
rotate: () => gsap.utils.random(-180, 180),
ease: "none",
stagger: 0.05
}).to(".title", {
y: window.innerHeight - 130,
ease: "power2.out",
duration: 1.0
}, 0)
}, main.value)
}
onMounted(() => {
setBoxes();
startNextAnimation();
});
onUnmounted(() => {
ctx?.revert()
// scrollTrigger.getAll().forEach(t => t.kill())
})
</script>
<template>
<section class="container" ref="main">
<div class="content-wrapper">
<h1 class="title">Welcome</h1>
<div class="box">l</div>
<div class="box">e</div>
<div class="box">e</div>
<div class="box">r</div>
<div class="box">p</div>
<div class="box"></div>
<div class="box">H</div>
<div class="box">e</div>
<div class="box">d</div>
<div class="box">n</div>
<div class="box">a</div>
<div class="box">e</div>
<div class="box">l</div>
<div class="box">A</div>
<div class="box">x</div>
<div class="box">m</div>
<div class="box">o</div>
<div class="box">T</div>
<div class="box">r</div>
<div class="box">l</div>
<div class="box">e</div>
<div class="box">e</div>
<div class="box">r</div>
<div class="box">p</div>
<div class="box"></div>
<div class="box">H</div>
<div class="box">e</div>
<div class="box">d</div>
<div class="box">n</div>
<div class="box">a</div>
<div class="box">e</div>
<div class="box">l</div>
<div class="box">A</div>
<div class="box">x</div>
<div class="box">m</div>
<div class="box">o</div>
<div class="box">T</div>
<div class="box">r</div>
</div>
</section>
</template>
<style scoped>
.container {
background: radial-gradient(
129% 99% at 20% 85%,
rgb(54, 54, 54) 20%,
rgb(0, 0, 0) 90%
);
background-blend-mode: color-dodge;
min-height: 100vh;
color: white;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.content-wrapper {
position: relative;
width: 100%;
height: 80vh;
}
.title {
position: relative;
z-index: 1;
text-align: center;
font-size: clamp(2rem, 12rem, 5vw);
margin: 0;
}
.box {
display: flex;
align-items: center;
justify-content: center;
text-align: center;
font-weight: 600;
color: var(--green);
line-height: 1.2;
will-change: transform;
position: absolute;
}
</style>