Custom Code Experiment •
Domination
Source Code View HTML / CSS / JavaScript
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>Perspective · Creative Loop</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
display: grid;
place-items: center;
min-height: 100vh;
background: black;
font-family: system-ui, 'Segoe UI', 'Roboto', 'Helvetica Neue', sans-serif;
overflow-x: hidden;
}
.container {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 1fr;
width: 100%;
max-width: 1200px;
padding: 1rem;
perspective: 800px;
}
h1 {
grid-row: 1;
grid-column: 1;
font-size: clamp(2.8rem, 12vw, 6rem);
font-weight: 800;
letter-spacing: -0.02em;
color: hsl(0 0% 98% / 0.2);
text-shadow: 0 0 1px rgba(255,255,255,0.3);
position: relative;
text-align: center;
margin: 0;
line-height: 1.2;
backface-visibility: hidden;
will-change: transform, opacity;
}
h1:after {
content: attr(data-word);
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 100%;
text-align: center;
background: linear-gradient(135deg, #fff 0%, #e0e0e0 100%);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
font-weight: 800;
letter-spacing: -0.02em;
clip-path: inset(var(--t, 0%) 0 0 var(--l, 100%));
pointer-events: none;
}
@supports not (background-clip: text) {
h1:after { background: none; color: hsl(0 0% 98%); }
}
#domination .glitch-clone {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 100%;
text-align: center;
font-size: inherit;
font-weight: 800;
letter-spacing: -0.02em;
opacity: 0;
pointer-events: none;
white-space: nowrap;
}
#domination .glitch-clone.red { color: #ff003c; mix-blend-mode: screen; }
#domination .glitch-clone.blue { color: #00e5ff; mix-blend-mode: screen; }
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js"></script>
</head>
<body>
<div class="container">
<h1 data-word="Madness">Madness</h1>
<h1 data-word="Power">Power</h1>
<h1 data-word="Domination" id="domination">Domination</h1>
</div>
<script>
(function () {
const words = Array.from(document.querySelectorAll('.container h1'));
const total = words.length;
let current = 0;
const domEl = document.getElementById('domination');
domEl.insertAdjacentHTML('beforeend',
`<span class="glitch-clone red" aria-hidden="true">Domination</span>` +
`<span class="glitch-clone blue" aria-hidden="true">Domination</span>`
);
const redClone = domEl.querySelector('.glitch-clone.red');
const blueClone = domEl.querySelector('.glitch-clone.blue');
gsap.set(words, {
xPercent: 100,
transformOrigin: '120% 100%',
opacity: 0,
rotate: 0,
'--t': '0%',
'--l': '100%'
});
gsap.set([redClone, blueClone], { opacity: 0 });
function glitchEffect() {
const tl = gsap.timeline();
const hits = 10;
for (let i = 0; i < hits; i++) {
const t = (i / hits) * 1.6;
const rx = (Math.random() - 0.5) * 18;
const bx = (Math.random() - 0.5) * 18;
const ry = (Math.random() - 0.5) * 6;
const by = (Math.random() - 0.5) * 6;
const dur = 0.04 + Math.random() * 0.06;
tl.to(redClone, { x: rx, y: ry, opacity: 0.85, duration: dur, ease: 'none' }, t)
.to(redClone, { x: 0, y: 0, opacity: 0, duration: dur, ease: 'none' }, t + dur);
tl.to(blueClone, { x: -rx, y: -by, opacity: 0.85, duration: dur, ease: 'none' }, t + 0.01)
.to(blueClone, { x: 0, y: 0, opacity: 0, duration: dur, ease: 'none' }, t + dur + 0.01);
tl.to(domEl, { skewX: (Math.random() - 0.5) * 8, duration: dur, ease: 'none' }, t)
.to(domEl, { skewX: 0, duration: dur * 0.5, ease: 'none' }, t + dur);
}
tl.set([redClone, blueClone], { x: 0, y: 0, opacity: 0 });
tl.set(domEl, { skewX: 0 });
tl.to({}, { duration: 0.4 });
return tl;
}
function animateNext() {
const incoming = words[current % total];
const outgoing = words[(current - 1 + total) % total];
const isDomination = incoming === domEl;
const tl = gsap.timeline({ onComplete: animateNext });
tl.set(incoming, {
xPercent: 100,
rotate: 0,
opacity: 0,
'--t': '100%',
'--l': '0%'
});
if (isDomination) {
tl.set([redClone, blueClone], { x: 0, y: 0, opacity: 0 });
tl.set(domEl, { skewX: 0 });
}
tl.to(incoming, {
xPercent: 0,
opacity: 1,
duration: 1,
ease: 'back.out(0.6)'
}, '+=0.1');
tl.to(outgoing, {
xPercent: -100,
rotate: 75,
duration: 1,
ease: 'power2.in'
}, '<');
tl.to(incoming, {
'--t': '0%',
duration: 1,
ease: 'sine.inOut'
}, '<+0.1');
tl.to(outgoing, {
'--l': '100%',
duration: 1,
ease: 'sine.inOut'
}, '<');
tl.to(outgoing, {
opacity: 0,
duration: 0.9,
ease: 'power2.in'
}, '<+0.1');
tl.set(outgoing, {
xPercent: 100,
rotate: 0,
opacity: 0,
'--t': '0%',
'--l': '100%'
});
if (isDomination) {
tl.add(glitchEffect());
} else {
tl.to({}, { duration: 1.0 });
}
current++;
}
animateNext();
window.addEventListener('resize', () => {
gsap.set(words, { transformOrigin: '120% 100%' });
});
})();
</script>
</body>
</html>