Skip to content

Instantly share code, notes, and snippets.

@adiog
Created November 3, 2017 22:06
Show Gist options
  • Save adiog/cc3f642a3d7d4e39c5b3762972cee3d7 to your computer and use it in GitHub Desktop.
Save adiog/cc3f642a3d7d4e39c5b3762972cee3d7 to your computer and use it in GitHub Desktop.
neo-text-scramble.html
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script>
// ——————————————————————————————————————————————————
// TextScramble
// ——————————————————————————————————————————————————
class TextScramble {
constructor(el) {
this.el = el;
this.chars = '!<>-_\\/[]{}—=+*^?#________';
this.update = this.update.bind(this)
}
setText(newText) {
const oldText = this.el.innerText;
const length = Math.max(oldText.length, newText.length);
const promise = new Promise((resolve) => this.resolve = resolve);
this.queue = [];
for (let i = 0; i < length; i++) {
const from = oldText[i] || '';
const to = newText[i] || '';
const start = Math.floor(Math.random() * 40);
const end = start + Math.floor(Math.random() * 40);
this.queue.push({from, to, start, end});
}
cancelAnimationFrame(this.frameRequest);
this.frame = 0;
this.update();
return promise;
}
update() {
let output = '';
let complete = 0;
for (let i = 0, n = this.queue.length; i < n; i++) {
let {from, to, start, end, char} = this.queue[i];
if (this.frame >= end) {
complete++;
output += to;
} else if (this.frame >= start) {
if (!char || Math.random() < 0.28) {
char = this.randomChar();
this.queue[i].char = char;
}
output += `<span class="dud">${char}</span>`;
} else {
output += from;
}
}
this.el.innerHTML = output;
if (complete === this.queue.length) {
this.resolve();
} else {
this.frameRequest = requestAnimationFrame(this.update);
this.frame++;
}
}
randomChar() {
return this.chars[Math.floor(Math.random() * this.chars.length)];
}
}
// ——————————————————————————————————————————————————
// Example
// ——————————————————————————————————————————————————
const bootstrap = function() {
const phrases = [
'Neo,',
'sooner or later',
'you\'re going to realize',
'just as I did',
'that there\'s a difference',
'between knowing the path',
'and walking the path'
];
const el = document.querySelector('.text');
const fx = new TextScramble(el);
let counter = 0;
const next = function () {
fx.setText(phrases[counter]).then(() => {
setTimeout(next, 800)
});
counter = (counter + 1) % phrases.length;
};
next();
}
</script>
</head>
<body onload="bootstrap();">
<div class="container">
<div class="text"></div>
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment