A Pen by Stan Williams on CodePen.
Created
May 20, 2025 23:26
-
-
Save stanwmusic/8223a3bc21e972c4536df9e808d9a3e9 to your computer and use it in GitHub Desktop.
Looping words with GSAP - Osmo
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<li class="looping-words__list"> | |
<p class="looping-words__p">Looping</p> | |
</li><!--------- Osmo [https://osmo.supply/] ---------> | |
<section class="cloneable"> | |
<div class="looping-words"> | |
<div class="looping-words__containers"> | |
<ul data-looping-words-list="" class="looping-words__list"> | |
<li class="looping-words__list"> | |
<a href="https://www.stanwilliams.org/blog/" target="_blank"><p class="looping-words__p">stanwilliams.org</p></a> | |
</li> | |
<li class="looping-words__list"> | |
<p class="looping-words__p">Looping</p> | |
</li> | |
<li class="looping-words__list"> | |
<p class="looping-words__p">Words</p> | |
</li> | |
<li class="looping-words__list"> | |
<p class="looping-words__p">Selector</p> | |
</li> | |
<li class="looping-words__list"> | |
<p class="looping-words__p">Made with</p> | |
<li class="looping-words__list"> | |
<p class="looping-words__p">a Keyboard</p> | |
</li> | |
<li class="looping-words__list"> | |
<p class="looping-words__p">Aint It</p> | |
</li> | |
</li> | |
</ul> | |
</div> | |
<div class="looping-words__fade"></div> | |
<div data-looping-words-selector="" class="looping-words__selector"> | |
<div class="looping-words__edge"></div> | |
<div class="looping-words__edge is--2"></div> | |
<div class="looping-words__edge is--3"></div> | |
<div class="looping-words__edge is--4"></div> | |
</div> | |
</div> | |
</section> | |
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/gsap.min.js"></script> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ------- Osmo [https://osmo.supply/] ------- // | |
document.addEventListener('DOMContentLoaded', function() { | |
const wordList = document.querySelector('[data-looping-words-list]'); | |
const words = Array.from(wordList.children); | |
const totalWords = words.length; | |
const wordHeight = 100 / totalWords; // Offset as a percentage | |
const edgeElement = document.querySelector('[data-looping-words-selector]'); | |
let currentIndex = 0; | |
function updateEdgeWidth() { | |
const centerIndex = (currentIndex + 1) % totalWords; | |
const centerWord = words[centerIndex]; | |
const centerWordWidth = centerWord.getBoundingClientRect().width; | |
const listWidth = wordList.getBoundingClientRect().width; | |
const percentageWidth = (centerWordWidth / listWidth) * 100; | |
gsap.to(edgeElement, { | |
width: `${percentageWidth}%`, | |
duration: 0.5, | |
ease: 'Expo.easeOut', | |
}); | |
} | |
function moveWords() { | |
currentIndex++; | |
gsap.to(wordList, { | |
yPercent: -wordHeight * currentIndex, | |
duration: 1.2, | |
ease: 'elastic.out(1, 0.85)', | |
onStart: updateEdgeWidth, | |
onComplete: function() { | |
if (currentIndex >= totalWords - 3) { | |
wordList.appendChild(wordList.children[0]); | |
currentIndex--; | |
gsap.set(wordList, { yPercent: -wordHeight * currentIndex }); | |
words.push(words.shift()); | |
} | |
} | |
}); | |
} | |
updateEdgeWidth(); | |
gsap.timeline({ repeat: -1, delay: 1 }) | |
.call(moveWords) | |
.to({}, { duration: 2 }) | |
.repeat(-1); | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* ------- Osmo [https://osmo.supply/] ------- */ | |
/* Osmo UI: https://slater.app/10324/23333.css */ | |
body { | |
background-color: var(--color-neutral-300); | |
color: var(--color-dark); | |
font-size: var(--size-font); | |
} | |
.cloneable { | |
padding: var(--container-padding); | |
justify-content: center; | |
align-items: center; | |
min-height: 100vh; | |
display: flex; | |
position: relative; | |
} | |
.looping-words { | |
height: 2.7em; | |
padding-left: .1em; | |
padding-right: .1em; | |
font-size: 11vw; | |
line-height: .9; | |
position: relative; | |
} | |
.looping-words__list { | |
text-align: center; | |
text-transform: uppercase; | |
white-space: nowrap; | |
flex-flow: column; | |
align-items: center; | |
margin: 0; | |
padding: 0; | |
font-family: PP Neue Corp, sans-serif; | |
font-weight: 700; | |
list-style: none; | |
display: flex; | |
position: relative; | |
} | |
.looping-words__list.is--primary { | |
color: var(--color-primary); | |
} | |
.looping-words__list.is--gray { | |
color: var(--color-neutral-500); | |
} | |
.looping-words__fade { | |
background-image: linear-gradient(180deg, var(--color-neutral-300) 5%, transparent 40%, transparent 60%, var(--color-neutral-300) 95%); | |
pointer-events: none; | |
width: 100%; | |
height: 100%; | |
position: absolute; | |
top: 0; | |
left: 0; | |
} | |
.looping-words__fade.is--radial { | |
background-image: radial-gradient(circle closest-side at 50% 50%, transparent 64%, var(--color-neutral-400) 93%); | |
width: 140%; | |
display: block; | |
left: -20%; | |
} | |
.looping-words__selector { | |
pointer-events: none; | |
width: 100%; | |
height: .9em; | |
position: absolute; | |
top: 50%; | |
left: 50%; | |
transform: translate(-50%, -50%); | |
} | |
.looping-words__edge { | |
border-top: .035em solid var(--color-primary); | |
border-left: .035em solid var(--color-primary); | |
width: .125em; | |
height: .125em; | |
position: absolute; | |
top: 0; | |
left: 0; | |
} | |
.looping-words__edge.is--2 { | |
left: auto; | |
right: 0; | |
transform: rotate(90deg); | |
} | |
.looping-words__edge.is--3 { | |
inset: auto 0 0 auto; | |
transform: rotate(180deg); | |
} | |
.looping-words__edge.is--4 { | |
top: auto; | |
bottom: 0; | |
transform: rotate(270deg); | |
} | |
.looping-words__containers { | |
width: 100%; | |
height: 100%; | |
position: relative; | |
overflow: hidden; | |
} | |
.looping-words__p { | |
margin: 0; | |
} | |
@font-face { | |
font-family: 'PP Neue Corp'; | |
src: url('https://cdn.prod.website-files.com/6717aac16c9ea22eeef1e79e/6717de2d56e40b921572d2d9_PPNeueCorp-TightUltrabold.woff2') format('woff2'); | |
font-weight: 700; | |
font-style: normal; | |
font-display: swap; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<link href="https://slater.app/10324/23333.css" rel="stylesheet" /> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment