<section class="demo" id="stage">
<div class="demo__float" id="float"></div>
<ul class="demo__list">
<li class="demo__row" data-tone="a"><span>Aurora Studio</span><em>2024</em></li>
<li class="demo__row" data-tone="b"><span>Basalt Type</span><em>2024</em></li>
<li class="demo__row" data-tone="c"><span>Cobalt Works</span><em>2025</em></li>
<li class="demo__row" data-tone="d"><span>Dune Archive</span><em>2025</em></li>
<li class="demo__row" data-tone="e"><span>Ember Press</span><em>2026</em></li>
</ul>
</section>.demo {
position: relative;
min-height: 100dvh;
display: grid;
place-items: center;
padding: 32px 24px;
background: #08080a;
color: #f4f4f2;
font-family: "Helvetica Neue", Inter, system-ui, sans-serif;
overflow: hidden;
}
.demo__list {
list-style: none;
margin: 0;
padding: 0;
width: min(460px, 100%);
}
.demo__row {
display: flex;
align-items: baseline;
justify-content: space-between;
padding: 16px 4px;
border-bottom: 1px solid #17171c;
font-size: clamp(18px, 4.4vw, 26px);
letter-spacing: -0.025em;
color: #6e6e76;
cursor: pointer;
transition: color 0.4s ease;
}
.demo__row:hover { color: #f4f4f2; }
.demo__row em {
font-style: normal;
font-size: 11px;
letter-spacing: 0.18em;
color: #3f3f46;
}
.demo__float {
position: fixed;
top: 0;
left: 0;
width: 150px;
height: 190px;
border-radius: 12px;
margin: -95px 0 0 -75px;
pointer-events: none;
opacity: 0;
will-change: transform;
background: linear-gradient(150deg, #2b2f4a, #14161f);
}const stage = document.querySelector("#stage");
const float = document.querySelector("#float");
const rows = gsap.utils.toArray(".demo__row");
const tones = {
a: "linear-gradient(150deg, #6f7bd8, #2b2f4a)",
b: "linear-gradient(150deg, #b9bcc2, #23262a)",
c: "linear-gradient(150deg, #4f9bd8, #0c1420)",
d: "linear-gradient(150deg, #d8b26f, #17130d)",
e: "linear-gradient(150deg, #e0705f, #1d0f0e)",
};
// 지연 추적: duration이 곧 "무게"입니다.
const xTo = gsap.quickTo(float, "x", { duration: 0.55, ease: "power3" });
const yTo = gsap.quickTo(float, "y", { duration: 0.55, ease: "power3" });
const rotTo = gsap.quickTo(float, "rotation", { duration: 0.9, ease: "power3" });
let lastX = 0;
stage.addEventListener("pointermove", (event) => {
xTo(event.clientX);
yTo(event.clientY);
rotTo(gsap.utils.clamp(-14, 14, (event.clientX - lastX) * 0.9));
lastX = event.clientX;
});
rows.forEach((row) => {
row.addEventListener("pointerenter", () => {
float.style.backgroundImage = tones[row.dataset.tone];
gsap.to(float, { opacity: 1, scale: 1, duration: 0.45, ease: "expo.out" });
});
row.addEventListener("pointerleave", () => {
gsap.to(float, { opacity: 0, scale: 0.85, duration: 0.35, ease: "power2.out" });
});
});
gsap.set(float, { scale: 0.85 });