<p id="offscreen-text" class="offscreen-text"></p>
<p id="text" class="text"></p>
<svg id="svg">
</svg>
<input type="text" class="input", id="input" />
html, body {
width: 100%;
height: 100%;
overflow: hidden;
font-family: 'Rubik Mono One', sans-serif;
background: #22292C;
}
svg {
width: 100%;
height: 100%;
position: absolute;
top: 0px;
left: 0px;
z-index: 0;
}
.input {
position: absolute;
z-index: 1;
bottom: 0px;
font-size: 20px;
text-align: center;
left: 50%;
transform: translateX(-50%);
font-family: helvetica, sans-serif;
bottom: 20px;
background: none;
border: 1px solid #ddd;
color: #eee;
}
.text, .offscreen-text {
width: 100%;
top: 50%;
transform: translateY(-50%);
display: block;
position: absolute;
margin: 0;
}
.offscreen-text {
text-align: center;
top: -9999px;
}
.text span {
position: absolute;
}
const selectSVG = id => {
const el = document.getElementById(id);
return new SVGElement(el);
};
const createSVG = type => {
const el = document.createElementNS('http://www.w3.org/2000/svg', type);
return new SVGElement(el);
};
class SVGElement {
constructor(element) {
this.element = element;
}
set(attributeName, value) {
this.element.setAttribute(attributeName, value);
}
style(property, value) {
this.element.style[property] = value;
}
}
const colors = [
{ main: '#FBDB4A', shades: ['#FAE073', '#FCE790', '#FADD65', '#E4C650'] },
{ main: '#F3934A', shades: ['#F7B989', '#F9CDAA', '#DD8644', '#F39C59'] },
{ main: '#EB547D', shades: ['#EE7293', '#F191AB', '#D64D72', '#C04567'] },
{ main: '#9F6AA7', shades: ['#B084B6', '#C19FC7', '#916198', '#82588A'] },
{ main: '#5476B3', shades: ['#6382B9', '#829BC7', '#4D6CA3', '#3E5782'] },
{ main: '#2BB19B', shades: ['#4DBFAD', '#73CDBF', '#27A18D', '#1F8171'] },
{ main: '#70B984', shades: ['#7FBE90', '#98CBA6', '#68A87A', '#5E976E'] }
];
const svg = selectSVG('svg');
const text = document.getElementById('text');
const offscreenText = document.getElementById('offscreen-text');
const input = document.getElementById('input');
let width = window.innerWidth;
let height = window.innerHeight;
let textSize = 0;
let textCenter = 0;
const letters = [];
const prompt = ['s', 't', 'a', 'r', 't', ' ', 't', 'y', 'p', 'i', 'n', 'g'];
let runPrompt = true;
const resizePage = () => {
width = window.innerWidth;
height = window.innerHeight;
svg.set('height', height);
svg.set('width', width);
svg.set('viewBox', `0 0 ${width} ${height}`);
resizeLetters();
}
const resizeLetters = () => {
textSize = width / (letters.length+2);
if (textSize > 100) textSize = 100;
text.style.fontSize = `${textSize}px`;
text.style.height = `${textSize}px`;
text.style.lineHeight = `${textSize}px`;
offscreenText.style.fontSize = `${textSize}px`;
const textRect = text.getBoundingClientRect();
textCenter = textRect.top + textRect.height/2;
positionLetters();
};
const positionLetters = () => {
letters.forEach(letter => {
const timing = letter.shift ? 0.1 : 0;
TweenLite.to(letter.onScreen, timing, {x:letter.offScreen.offsetLeft+'px', ease: Power3.easeInOut});
letter.shift = true;
});
}
const animateLetterIn = letter => {
const yOffset = (0.5+Math.random()*0.5) * textSize;
TweenLite.fromTo(letter, 0.4, {scale:0}, {scale:1, ease: Back.easeOut});
TweenLite.fromTo(letter, 0.4, {opacity:0}, {opacity: 1, ease: Power3.easeOut});
TweenLite.to(letter, 0.2, {y:-yOffset, ease: Power3.easeInOut});
TweenLite.to(letter, 0.2, {y:0, ease: Power3.easeInOut, delay: 0.2});
const rotation = -50 + Math.random()*100;
TweenLite.to(letter, 0.2, {rotation: rotation, ease: Power3.easeInOut});
TweenLite.to(letter, 0.2, {rotation: 0, ease: Power3.easeInOut, delay: 0.2});
}
const addDecor = (letter, color) => {
setTimeout(() => {
var rect = letter.getBoundingClientRect();
const x0 = letter.offsetLeft + letter.offsetWidth/2;
const y0 = textCenter - textSize*0.5;
const shade = color.shades[Math.floor(Math.random()*4)];
for (var i = 0; i < 8; i++) addTri(x0, y0, shade);
for (var i = 0; i < 8; i++) addCirc(x0, y0);
}, 150);
};
const addTri = (x0, y0, shade) => {
const tri = createSVG('polygon');
const a = Math.random();
const a2 = a + (-0.2 + Math.random()*0.4);
const r = textSize*0.52;
const r2 = r + textSize*Math.random()*0.2;
const x = x0 + r * Math.cos(2 * Math.PI * a);
const y = y0 + r * Math.sin(2 * Math.PI * a);
const x2 = x0 + r2 * Math.cos(2 * Math.PI * a2);
const y2 = y0 + r2 * Math.sin(2 * Math.PI * a2);
const triSize = textSize * 0.1;
const scale = 0.3 + Math.random()*0.7;
const offset = triSize*scale;
tri.set('points', `0,0 ${triSize*2},0 ${triSize},${triSize*2}`);
tri.style('fill', shade);
svg.element.appendChild(tri.element);
TweenLite.fromTo(tri.element, 0.6, {rotation: Math.random()*360, scale: scale, x: x-offset, y: y-offset, opacity: 1}, {x: x2-offset, y: y2-offset, opacity: 0, ease: Power1.easeInOut, onComplete: () => {
svg.element.removeChild(tri.element);
}});
}
const addCirc = (x0, y0) => {
const circ = createSVG('circle');
const a = Math.random();
const r = textSize*0.52;
const r2 = r + textSize;
const x = x0 + r * Math.cos(2 * Math.PI * a);
const y = y0 + r * Math.sin(2 * Math.PI * a);
const x2 = x0 + r2 * Math.cos(2 * Math.PI * a);
const y2 = y0 + r2 * Math.sin(2 * Math.PI * a);
const circSize = textSize * 0.05 * Math.random();
circ.set('r', circSize);
circ.style('fill', '#eee');
svg.element.appendChild(circ.element);
TweenLite.fromTo(circ.element, 0.6, {x: x-circSize, y: y-circSize, opacity: 1}, {x: x2-circSize, y: y2-circSize, opacity: 0, ease: Power1.easeInOut, onComplete: () => {
svg.element.removeChild(circ.element);
}});
}
const addLetter = (char, i) => {
const letter = document.createElement('span');
const oLetter = document.createElement('span');
letter.innerHTML = char;
oLetter.innerHTML = char;
text.appendChild(letter);
const color = colors[i%colors.length];
letter.style.color = color.main;
offscreenText.appendChild(oLetter);
letters[i] = {offScreen: oLetter, onScreen: letter, char: char};
animateLetterIn(letter);
addDecor(oLetter, color);
}
const addLetters = value => {
value.forEach((char, i) => {
if (letters[i] && letters[i].char !== char) {
letters[i].onScreen.innerHTML = char;
letters[i].offScreen.innerHTML = char;
letters[i].char = char;
}
if (letters[i] === undefined) {
addLetter(char, i);
}
});
};
const animateLetterOut = (letter, i) => {
TweenLite.to(letter.onScreen, 0.1, {scale: 0, opacity: 0, ease: Power2.easeIn, onComplete: () => {
console.log('removing');
console.log(letter);
offscreenText.removeChild(letter.offScreen);
text.removeChild(letter.onScreen);
positionLetters();
}});
letters.splice(i, 1);
}
const removeLetters = value => {
for (let i = letters.length-1; i >= 0; i--) {
const letter = letters[i];
if (value[i] === undefined) {
animateLetterOut(letter, i)
}
}
}
const onInputChange = () => {
const value = input.value === '' ? [] : input.value.toLowerCase().split('');
addLetters(value);
removeLetters(value);
resizeLetters();
};
const keyup = (e) => {
if (runPrompt) {
input.value = '';
runPrompt = false;
};
onInputChange();
}
const addPrompt = (i) => {
setTimeout(() => {
if (runPrompt && prompt[i]) {
input.value = input.value + prompt[i];
onInputChange();
addPrompt(i+1);
}
}, 300);
}
resizePage();
window.addEventListener('resize', resizePage);
input.addEventListener('keyup', keyup);
input.focus();
addPrompt(0);
View Compiled
This Pen doesn't use any external CSS resources.