JSFiddle - React, Tailwind, and code Playground
by Airweb
HTML
<section>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce posuere orci sed est maximus semper. Pellentesque tincidunt, lectus a finibus consectetur, turpis augue facilisis neque, ac venenatis elit tellus vel urna. In hac habitasse platea dictumst. Integer pharetra elit nisl, vitae dapibus leo blandit vitae. Aenean sodales tincidunt lacinia. Ut sagittis molestie tellus nec blandit. Nam id mauris at libero porta dignissim eget ut nibh. Quisque pulvinar tortor non lacinia pellentesque. Donec ultrices lacus iaculis libero placerat varius sed nec nunc. Interdum et malesuada fames ac ante ipsum primis in faucibus. Fusce egestas nisl cursus risus venenatis elementum. Phasellus ut diam sed tortor egestas auctor in eu leo. Vestibulum pharetra eget ante eu vehicula.</p>
</section>
CSS
* body {
margin: 0;
padding: 0;
background: black;
font-family: sans-serif;
color: white;
overflow: hidden;
cursor: pointer;
font-size: 25px;
}
section {
width: 100%;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
span {
font-size: 25px;
}
p {
display: block;
position: relative;
width: 75vw;
}
JavaScript
const p = document.querySelector('p')
p.innerHTML = p.innerText.replace(/(.)/g, '<span>$1</span>')
const spans = document.querySelectorAll('span')
let base = p.getBoundingClientRect()
let mouse = {
"x": null,
"y": null,
radius: 75
}
for (let span of spans) {
span.dataset.x = (span.getBoundingClientRect().x - base.left)
span.dataset.y = (span.getBoundingClientRect().y - base.height / 2 - base.top)
span.dataset.vx = 0;
span.dataset.vy = 0;
span.dataset.accX = 0;
span.dataset.accY = 0;
span.dataset.friction = Math.random() * 0.1 + 0.65;
span.dataset.dest = '{"x" : ' + (span.getBoundingClientRect().x - base.left) + ',"y": ' + (span.getBoundingClientRect().y - base.height / 2 - base.top) + '}'
}
window.addEventListener("mousemove", (e) => {
mouse.x = e.clientX - base.left;
mouse.y = e.clientY - base.height / 2 - base.top;
})
function render() {
requestAnimationFrame(render);
if (mouse.x == null) {
return
}
for (let span of spans) {
span.style.position = 'absolute'
span.dataset.accX = (Number(JSON.parse(span.dataset.dest).x) - Number(span.dataset.x)) / 10;
span.dataset.accY = (Number(JSON.parse(span.dataset.dest).y) - Number(span.dataset.y)) / 10;
span.dataset.vx = Number(span.dataset.vx) + Number(span.dataset.accX);
span.dataset.vy = Number(span.dataset.vy) + Number(span.dataset.accY);
span.dataset.vx = Number(span.dataset.vx) * Number(span.dataset.friction);
span.dataset.vy = Number(span.dataset.vy) * Number(span.dataset.friction);
span.dataset.x = Number(span.dataset.x) + Number(span.dataset.vx);
span.dataset.y = Number(span.dataset.y) + Number(span.dataset.vy);
span.style.transform = 'translate(' + Number(span.dataset.x).toFixed(2) + 'px, ' + Number(span.dataset.y).toFixed(2) + 'px)'
span.style.opacity = 0.5
var a = Number(span.dataset.x) - mouse.x;
var b = Number(span.dataset.y) - mouse.y;
var distance = Math.sqrt(a * a + b * b);
if (distance < mouse.radius *...