Created
April 21, 2024 01:49
-
-
Save mikeybob/ba3509fe3ebe340d9ca66b82321a260d to your computer and use it in GitHub Desktop.
Revolving Text
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
<div class="bg-lighting"></div> |
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
const animationDuration = 24000; | |
const updateInterval = 400; | |
let startTimeMap = new Map(); | |
let intervalMap = new Map(); | |
function createLetters(text, rad, offset, frontColor, direction, id) { | |
const radius = rad; | |
let letters = text.split(''); | |
if(direction != 'backwards') { letters = letters.reverse(); } | |
let dir = ( direction == 'backwards') ? -1 : 1; | |
const container = document.createElement('div'); | |
container.classList.add('text-container'); | |
container.classList.add(id); | |
document.body.appendChild(container); | |
startTimeMap.set(id, Date.now()); | |
letters.forEach((letter, index) => { | |
const angle = (360 / letters.length) * (dir) * index - 8; | |
const radian = angle * (Math.PI / 180); | |
const x = radius * Math.cos(radian); | |
const y = radius * Math.sin(radian); | |
const letterElement = document.createElement('div'); | |
letterElement.classList.add('letter'); | |
letterElement.classList.add(id); | |
letterElement.textContent = letter; | |
letterElement.setAttribute("data-text", letter); | |
letterElement.style.transform = `translate(-50%, -50%) translate(${x}px, ${y}px) rotateX(90deg) rotateY(${angle + 90}deg) rotateZ(180deg) translateY(${offset}px)`; | |
container.appendChild(letterElement); | |
}); | |
if (!intervalMap.has(id)) { | |
const intervalId = setInterval(() => { | |
updateLetters(container, letters.length, 0.54, 1, frontColor, dir, id); | |
}, updateInterval); | |
intervalMap.set(id, intervalId); | |
} | |
} | |
function updateLetters(container, totalLetters, op1, op2, colorFront, dir, id) { | |
const startTime = startTimeMap.get(id); | |
const elapsedTime = Date.now() - startTime; | |
const rotation = (elapsedTime % animationDuration) / animationDuration * 360; | |
const activeAngleRange = 180; | |
const letters = container.querySelectorAll(`.${id}`); | |
letters.forEach((letter, index) => { | |
const letterAngle = 270 + (360 / totalLetters * index); | |
const angleDifference = Math.abs(rotation - letterAngle) % 360; | |
let isActive = angleDifference < activeAngleRange / 2 || angleDifference > 360 - activeAngleRange / 2; | |
let activeDirection = dir === 1 ? !isActive : isActive; | |
letter.style.opacity = activeDirection ? op1 : op2; | |
letter.style.color = activeDirection ? '' : colorFront; | |
}); | |
} | |
function isMobileDevice() { | |
return (typeof window.orientation !== "undefined") || (navigator.userAgent.indexOf('IEMobile') !== -1); | |
} | |
if (isMobileDevice()) { | |
createLetters(" ⟩ Revolving Text ⟩ Revolving Text", 124, 0, 'white' , 'forwards', 'set1'); | |
} else { | |
createLetters(" ⟩ Revolving Text ⟩ Revolving Text", 124, 0, 'white' , 'forwards','set1'); | |
createLetters(" ⟨ Revolving Text ⟨ Revolving Text ⟨ Revolving Text", 200, 0, 'white', 'backwards','set2'); | |
} | |
function updateText(newText) { | |
document.querySelectorAll('.text-container').forEach(container => { | |
container.remove(); | |
}); | |
startTimeMap.clear(); | |
intervalMap.forEach(intervalId => clearInterval(intervalId)); | |
intervalMap.clear(); | |
if (isMobileDevice()) { | |
createLetters(` ⟩ ${newText} ⟩ ${newText}`, 124, 0, 'white' , 'forwards', 'set1'); | |
} else { | |
createLetters(` ⟩ ${newText} ⟩ ${newText}`, 124, 0, 'white' , 'forwards','set1'); | |
createLetters(` ⟨ ${newText} ⟨ ${newText} ⟨ ${newText}`, 200, 0, 'white', 'backwards','set2'); | |
} | |
} | |
/* GUI */ | |
import { GUI } from 'https://cdn.skypack.dev/dat.gui' | |
const CONFIG = { shadowHeight: 24, fontSize: 26, refOpacity: 0.7, refBlur: 2, newText: 'Revolving Text'} | |
const CTRL = new GUI() | |
const UPDATE = () => { | |
for (const key of Object.keys(CONFIG)) { | |
document.documentElement.style.setProperty(`--${key}`, CONFIG[key]) | |
} | |
} | |
CTRL.add(CONFIG, 'fontSize', 14, 42, 1).name("Font Size").onChange(UPDATE) | |
CTRL.add(CONFIG, 'shadowHeight', 0, 264, 1).name("Height").onChange(UPDATE) | |
CTRL.add(CONFIG, 'refOpacity', 0, 1, 0.01).name("Reflection Opacity").onChange(UPDATE) | |
CTRL.add(CONFIG, 'refBlur', 0, 12, 1).name("Reflection Blur").onChange(UPDATE) | |
CTRL.add(CONFIG, 'newText').name("Text").onChange(updateText); | |
UPDATE() |
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
@import url('https://fonts.googleapis.com/css2?family=Poppins&display=swap'); | |
*{ | |
box-sizing: border-box; | |
} | |
html, body { | |
height: 100%; | |
overflow: hidden; | |
} | |
body { | |
display: flex; | |
flex-direction: row; | |
flex-wrap: wrap; | |
justify-content: center; | |
align-items: center; | |
margin: 0; | |
font-family: Poppins; | |
background: #161616; | |
--speed: 24s; | |
} | |
.bg-lighting { | |
position: absolute; | |
pointer-events: none; | |
width: 100%; | |
height: 100%; | |
top: 0;bottom: 0; margin: auto; | |
background: radial-gradient( | |
circle at 50% -100%, | |
rgba(0, 0, 0, 1), | |
rgba(0, 0, 0, 0) | |
), | |
url("data:image/svg+xml,%3Csvg viewBox='0 0 600 600' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)'/%3E%3C/svg%3E" | |
); | |
filter: contrast(100%) brightness(200%) invert(100%) grayscale(1) opacity(0.1); | |
mix-blend-mode: screen; | |
z-index: -1; | |
} | |
.bg-lighting::after { | |
display: block; content: ''; | |
width: 100%; height: 100%; | |
position: absolute; | |
background: linear-gradient( #000 20%, #0003 80%, transparent 100%); | |
animation: var(--speed) f-grad linear infinite; | |
} | |
@keyframes f-grad { | |
0% { height: 100%; } | |
50% { height: 50%; } | |
100% { height: 100%; } | |
} | |
.text-container { | |
position: absolute; | |
width: 300px; | |
height: 300px; | |
transform-style: preserve-3d; | |
animation: var(--speed) f-rotate linear infinite; | |
} | |
.text-container.set1 { | |
animation: var(--speed) f-rotate linear infinite reverse; | |
} | |
@keyframes f-rotate { | |
0% { transform: rotateX(80deg) rotateY(0deg) rotateZ(0deg); } | |
50% { transform: rotateX(42deg) rotateY(0deg) rotateZ(180deg); } | |
100% { transform: rotateX(80deg) rotateY(0deg) rotateZ(360deg); } | |
} | |
.letter { | |
position: absolute; | |
top: 50%; | |
left: 50%; | |
transform-origin: center; | |
font-size: calc(var(--fontSize)*1px); | |
color: #fff; | |
filter: drop-shadow(0 3px 3px #ffffff9a); | |
} | |
.letter::after { | |
content: attr(data-text); | |
position: absolute; | |
transform-origin: top; | |
top: 100%; | |
left: 0; | |
transform: scaleY(-1) translateY(calc((var(--shadowHeight)*-1px) + -82%)); | |
z-index: -1; | |
color: #fff; | |
filter: blur(calc(var(--refBlur) * 1px)); | |
opacity: var(--refOpacity); | |
} | |
.text-container.set2 .letter { | |
transform: rotateX(180deg); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment