<p class='target'></p>
<input type="text">
xxxxxxxxxx
html {
cursor: text;
}
body {
background: #c0c0c0;
overflow: hidden;
}
.target {
position: relative;
max-width: 750px;
margin: 0 auto;
transform: translatey(30vh);
font-size: 1.2rem;
line-height: 1.75rem;
}
input {
position: absolute;
bottom: 0;
display: none;
}
.demo-cursor {}
@keyframes move {
100% {
transform: translate(0, 0);
}
}
@keyframes remove {
100% {
color: red;
transform: rotate(20deg) scale(0.1) translate(0, -200px);
opacity: 0;
}
}
xxxxxxxxxx
const input = document.querySelector('input');
const target = document.querySelector('.target');
const sampleText = 'Few young people: half-dead to give a start. Dead through spite, he will cause the others to shine, And in an exalted place some great evils to occur, Sad concepts will come to harm each one, Temporal dignified, the Mass to succeed.Fathers and mothers dead of infinite sorrows, Women in mourning, the pestilent she−monster: The Great One to be no more, all the world to end. After great trouble for humanity, a greater one is prepared, The Great Mover renews the ages: Rain, blood, milk, famine, steel, and plague, Is the heavens fire seen, a long spark running - Nostradamus';
let letterIndex = 0;
function floatText(letter, sourcePos) {
const span = document.createElement('span');
span.innerText = letter;
target.appendChild(span);
const posDiff = span.getBoundingClientRect();
const pos = {
x: sourcePos.x - posDiff.x,
y: sourcePos.y - posDiff.y
};
const styles = `
display: inline-block;
white-space: pre;
transition: all 0.5s;
transform: translate(${pos.x}px, ${~~(pos.y)}px) rotate(${~~(Math.random() * 360)}deg);
animation: move 3s forwards,
remove 1.5s ease-out ${12000-Math.random()*3000}ms forwards;`
span.style = styles;
}
let isDemo = true;
let endTimer = null;
let sampleTimer = null;
const pointer = {
tx: 0,
ty: 0
}
function writeSample() {
if (isDemo) {
demoMode();
}
floatText(sampleText[letterIndex], mousePos);
letterIndex++;
if (letterIndex < sampleText.length) {
sampleTimer = setTimeout(() => {
writeSample();
}, 25);
} else {
// reset the demo.
endTimer = setTimeout(() => {
target.innerHTML = '';
letterIndex = 0;
writeSample();
}, 13000);
}
}
function demoMode() {
const dx = pointer.tx - mousePos.x;
const dy = pointer.ty - mousePos.y;
const dist = Math.sqrt(dx * dx + dy * dy);
const rad = Math.atan2(dy, dx);
const angle = rad / Math.PI * 180;
const velX = (dx / dist) * 10;
const velY = (dy / dist) * 10;
if (dist > 20) {
mousePos.x += velX;
mousePos.y += velY;
} else {
pointer.tx = Math.random() * window.innerWidth;
pointer.ty = Math.random() * window.innerHeight;
}
}
let mousePos = {
x: 0,
y: 0
};
window.addEventListener('mouseover', () => {
isDemo = false;
});
window.addEventListener('mouseout', () => {
isDemo = true;
});
// Clear when clicked
window.addEventListener('click', () => {
target.innerHTML = '';
letterIndex = 0;
clearTimeout(endTimer);
clearTimeout(sampleTimer);
writeSample();
});
window.addEventListener('mousemove', (e) => {
const x = e.clientX;
const y = e.clientY;
mousePos = {
x,
y
};
});
// Unhide input to use it, works the same way floats to where it's supposed to be.
input.addEventListener('keydown', (e) => {
floatText(e.target.value, e.target.getBoundingClientRect());
e.target.value = '';
});
window.addEventListener('DOMContentLoaded', () => {
writeSample();
});
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.