<div class="marquee">
	<span>What's on</span>
	<span aria-hidden="true">What's on</span>
	<span aria-hidden="true">What's on</span>
	<span aria-hidden="true">What's on</span>
	<span aria-hidden="true">What's on</span>
</div>
body {
	height: 1000vh;
	background: #b98987;
background-image: linear-gradient(0deg, #67001f, #ab202e, #d55f50, #f0a285, #fcd8c4, #faf4f0, #dfdfdf, #b8b8b8, #868686, #4e4e4e, #4e4e4e);
}

.marquee {
	position: fixed;
	top: 0;
	bottom: 0;
	left: 0;
	display: flex;
	padding: 0 15px 0 20px;
	font: 400 2.25rem/1 "Bagel Fat One", sans-serif;
	writing-mode: vertical-lr;
	transform-orign: 50% 50%;
	transform: rotate(-180deg);
	white-space: nowrap;
	text-transform: uppercase;
	background: #333;
	color: #FAFAFA;
	text-align: center;
	
	span {
		display: block;
		padding: 10px 0;
	}
}
View Compiled
gsap.registerPlugin(ScrollTrigger);

let direction = 1;
let duration = 2;

let tl = gsap.timeline({});

tl.to(".marquee > span", {
	repeat: -1,
	yoyo: false,
	yPercent: -100,
	ease: "linear",
	duration: duration
});

let scroll = ScrollTrigger.create({
	onUpdate(self) {
		if (self.direction !== direction) {
			direction *= -1;
			gsap.to(tl, {timeScale: direction});
		}
		
		tl.timeScale(duration * self.getVelocity() / 350);
		gsap.to(tl, {timeScale: direction, overwrite: true});
	}
});
View Compiled

External CSS

  1. https://fonts.googleapis.com/css2?family=Bagel+Fat+One&amp;display=swap

External JavaScript

  1. https://unpkg.co/gsap@3/dist/gsap.min.js
  2. https://unpkg.com/gsap@3/dist/ScrollTrigger.min.js