JSFiddle - React, Tailwind, and code Playground
by soulwire
HTML
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&display=swap" rel="stylesheet">
<div class="container">
<div class="text"/>
</div>
CSS
:root {
--color-1: #3b4c55;
--color-2: #b5d5bc;
--color-3: #f3f3f3;
--color-4: #ef6486;
}
html, body {
font-family: "IBM Plex Mono", monospace;
font-weight: 400;
font-style: normal;
background: #111;
color: #fff;
}
.container {
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.text {
max-width: 400px;
text-align: left;
}
JavaScript
const container = document.querySelector('.container');
const text = document.querySelector('.text');
const gridSize = 24;
"Keep your face always toward sunshine, and shadows will fall behind you.".split('').map(char => {
const el = document.createElement('span');
el.classList.add('char')
el.innerText = char;
text.appendChild(el);
})
const chars = [];
document.querySelectorAll('.char').forEach(el => {
const bounds = el.getBoundingClientRect();
chars.push({
el: el,
value: el.innerText,
target: bounds,
path: createWanderPath(),
index: 0,
done: false,
});
});
function createWanderPath_() {
const path = [{ x: 0, y: 0 }];
let x = 0;
let y = 0;
let a = Math.random() * Math.PI;
let steps = 100 + Math.random() * 400;
for (let i = 0; i < steps; i++) {
const d = Math.random() * 3;
a += (Math.random() - 0.5) * Math.PI * 0.2;
x += Math.cos(a) * d;
y += Math.sin(a) * d;
path.push({
x: clamp(x, gridSize),
y: clamp(y, gridSize),
char: getRandomChar(),
// x,
// y,
})
}
return path.reverse();
}
function createWanderPath() {
const path = [{ x: 0, y: 0 }];
let x = 0;
let y = 0;
let char;
let steps = 20 + Math.random() * 300;
for (let i = 0; i < steps; i++) {
if (Math.random() < Math.random() * 2) {
path.push({ x, y, char })
continue;
}
const mx = Math.floor(Math.random() * 3) - 1;
const my = Math.floor(Math.random() * 3) - 1;
char = getRandomChar(),
path.push({
x: x += mx * gridSize * Math.random(),
y: y += my * gridSize * Math.random(),
char,
// x,
// y,
})
}
return path.reverse();
}
function clamp(n, g) {
return Math.floor(n / g) * g;
}
chars.forEach(({ el, target }) => {
el.style.position = 'absolute';
el.style.left = target.left + 'px';
el.style.top = target.top + 'px';
})
function update()...