Velocity
Elder Project
by Grzegorz Matyszewski
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/ScrollTrigger.min.js"></script>
<div class="bars">
<div class="bar-wrap">Scroll Velocity:
<div class="bar" id="scroll-velocity">0</div>
</div>
<div class="bar-wrap">Mouse Velocity:
<div class="bar" id="mouse-velocity">0</div>
</div>
</div>
<div id="content">
<h1>
Shining
<span>Shining</span>
<span>Shining</span>
<span>Shining</span>
<span>Shining</span>
<span>Shining</span>
</h1>
</div>
CSS
body {
background: #F8F7F7;
pointer-events: none;
}
.bars {
position: fixed;
top: 0;
}
.bar-wrap {
display: flex;
gap: 10px;
}
.bar {
height: 20px;
background: red;
width: 0;
}
#content {
height: 400vh;
}
h1 {
font-family: "Arial Narrow", sans-serif;
text-transform: uppercase;
position: relative;
margin-top: 392px;
font-size: 18vw;
letter-spacing: -0.02em;
color: #1B1B1B;
font-style: italic;
}
h1 span {
position: absolute;
left: 0;
z-index: -1;
}
h1 span:nth-of-type(1) { color: #1B7DB6; }
h1 span:nth-of-type(2) { color: #548068; }
h1 span:nth-of-type(3) { color: #BDD5E3; }
h1 span:nth-of-type(4) { color: #EDB548; }
h1 span:nth-of-type(5) { color: #D54335; }
JavaScript
const maxVelocity = 10;
const velocityFactor = 800;
const shift = 4;
var velocity = 0;
const tl = gsap.timeline({
paused: true
});
tl.fromTo('h1 span', {
xPercent: (index, target, targets) => -shift * (targets.length - index),
}, {
xPercent: (index, target, targets) => shift * (targets.length - index),
ease: 'none',
});
tl.progress(0.5);
ScrollTrigger.create({
onUpdate: self => {
velocity = Math.max(-maxVelocity, Math.min(maxVelocity, self.getVelocity() / velocityFactor));
gsap.killTweensOf(window, "velocity");
gsap.to(window, {
velocity: 0,
duration: 2,
ease: 'power3',
overwrite: true,
});
},
});
let lastMouseX = 0;
let lastMouseY = 0;
let lastTime = Date.now();
var mouseVelocity = 0;
document.addEventListener('mousemove', (event) => {
const currentTime = Date.now();
const elapsed = currentTime - lastTime;
lastTime = currentTime;
const velocityX = (event.clientX - lastMouseX) / elapsed;
const velocityY = (event.clientY - lastMouseY) / elapsed;
gsap.killTweensOf(window, "mouseVelocity");
gsap.to(window, {
duration: 1,
ease: 'power3',
mouseVelocity: Math.sqrt(velocityX * velocityX + velocityY * velocityY) / 10,
});
lastMouseX = event.clientX;
lastMouseY = event.clientY;
});
function update() {
document.getElementById('mouse-velocity').innerHTML = mouseVelocity;
gsap.set('#mouse-velocity', {
width: 10 * mouseVelocity
});
document.getElementById('scroll-velocity').innerHTML = velocity;
gsap.set('#scroll-velocity', {
width: 10 * velocity
});
tl.progress(Math.min(1, Math.max(-1, 0.5 + (velocity / maxVelocity) / 2 + mouseVelocity / 2)));
}
function loop() {
if (mouseVelocity > 0) {
mouseVelocity *= 0.95;
}
update();
requestAnimationFrame(() => loop());
}
requestAnimationFrame(() => loop());