Skip to content

Instantly share code, notes, and snippets.

@keegan-sabo
Last active September 15, 2022 20:50
Show Gist options
  • Save keegan-sabo/7efc5d215f684e3d490a88fcddcb5644 to your computer and use it in GitHub Desktop.
Save keegan-sabo/7efc5d215f684e3d490a88fcddcb5644 to your computer and use it in GitHub Desktop.
A script to make text appear word-by-word.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
body { margin: 0 50px; }
p { padding: 25px 0; }
.invisible { opacity: 0; }
.visible { opacity: 1; }
</style>
</head>
<body>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam consectetur venenatis blandit. Praesent
vehicula,
libero non pretium vulputate, lacus arcu facilisis lectus, sed feugiat tellus nulla eu dolor. Nulla porta
bibendum
lectus quis euismod. Aliquam volutpat ultricies porttitor. Cras risus nisi, accumsan vel cursus ut, sollicitudin
vitae dolor. Fusce scelerisque eleifend lectus in bibendum. Suspendisse lacinia egestas felis a volutpat.
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam consectetur venenatis blandit. Praesent
vehicula,
libero non pretium vulputate, lacus arcu facilisis lectus, sed feugiat tellus nulla eu dolor. Nulla porta
bibendum
lectus quis euismod. Aliquam volutpat ultricies porttitor. Cras risus nisi, accumsan vel cursus ut, sollicitudin
vitae dolor. Fusce scelerisque eleifend lectus in bibendum. Suspendisse lacinia egestas felis a volutpat.
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam consectetur venenatis blandit. Praesent
vehicula,
libero non pretium vulputate, lacus arcu facilisis lectus, sed feugiat tellus nulla eu dolor. Nulla porta
bibendum
lectus quis euismod. Aliquam volutpat ultricies porttitor. Cras risus nisi, accumsan vel cursus ut, sollicitudin
vitae dolor. Fusce scelerisque eleifend lectus in bibendum. Suspendisse lacinia egestas felis a volutpat.
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam consectetur venenatis blandit. Praesent
vehicula,
libero non pretium vulputate, lacus arcu facilisis lectus, sed feugiat tellus nulla eu dolor. Nulla porta
bibendum
lectus quis euismod. Aliquam volutpat ultricies porttitor. Cras risus nisi, accumsan vel cursus ut, sollicitudin
vitae dolor. Fusce scelerisque eleifend lectus in bibendum. Suspendisse lacinia egestas felis a volutpat.
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam consectetur venenatis blandit. Praesent
vehicula,
libero non pretium vulputate, lacus arcu facilisis lectus, sed feugiat tellus nulla eu dolor. Nulla porta
bibendum
lectus quis euismod. Aliquam volutpat ultricies porttitor. Cras risus nisi, accumsan vel cursus ut, sollicitudin
vitae dolor. Fusce scelerisque eleifend lectus in bibendum. Suspendisse lacinia egestas felis a volutpat.
</p>
<p id="emerge">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam consectetur venenatis blandit. Praesent
vehicula,
libero non pretium vulputate, lacus arcu facilisis lectus, sed feugiat tellus nulla eu dolor. Nulla porta
bibendum
lectus quis euismod. Aliquam volutpat ultricies porttitor. Cras risus nisi, accumsan vel cursus ut, sollicitudin
vitae dolor. Fusce scelerisque eleifend lectus in bibendum. Suspendisse lacinia egestas felis a volutpat.
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam consectetur venenatis blandit. Praesent
vehicula,
libero non pretium vulputate, lacus arcu facilisis lectus, sed feugiat tellus nulla eu dolor. Nulla porta
bibendum
lectus quis euismod. Aliquam volutpat ultricies porttitor. Cras risus nisi, accumsan vel cursus ut, sollicitudin
vitae dolor. Fusce scelerisque eleifend lectus in bibendum. Suspendisse lacinia egestas felis a volutpat.
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam consectetur venenatis blandit. Praesent
vehicula,
libero non pretium vulputate, lacus arcu facilisis lectus, sed feugiat tellus nulla eu dolor. Nulla porta
bibendum
lectus quis euismod. Aliquam volutpat ultricies porttitor. Cras risus nisi, accumsan vel cursus ut, sollicitudin
vitae dolor. Fusce scelerisque eleifend lectus in bibendum. Suspendisse lacinia egestas felis a volutpat.
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam consectetur venenatis blandit. Praesent
vehicula,
libero non pretium vulputate, lacus arcu facilisis lectus, sed feugiat tellus nulla eu dolor. Nulla porta
bibendum
lectus quis euismod. Aliquam volutpat ultricies porttitor. Cras risus nisi, accumsan vel cursus ut, sollicitudin
vitae dolor. Fusce scelerisque eleifend lectus in bibendum. Suspendisse lacinia egestas felis a volutpat.
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam consectetur venenatis blandit. Praesent
vehicula,
libero non pretium vulputate, lacus arcu facilisis lectus, sed feugiat tellus nulla eu dolor. Nulla porta
bibendum
lectus quis euismod. Aliquam volutpat ultricies porttitor. Cras risus nisi, accumsan vel cursus ut, sollicitudin
vitae dolor. Fusce scelerisque eleifend lectus in bibendum. Suspendisse lacinia egestas felis a volutpat.
</p>
<script>
/**
* Fade in one HTML element
* @param word
*/
function fadeIn(word) {
word.style.opacity = 0;
let last = +new Date();
let increment = function () {
word.style.opacity = +word.style.opacity + (new Date() - last) / 400;
last = +new Date();
if (+word.style.opacity < 1) {
(window.requestAnimationFrame && requestAnimationFrame(increment)) || setTimeout(increment, 16);
}
};
increment();
}
/**
* Wrap words of a paragraph in <span> tags
* @param para the <p> elemement
*/
function splitLines(para) {
para.innerHTML = para.innerText.split(/\s/).map(function (word) {
return '<span class="invisible">' + word + '</span>'
}).join(' ');
}
/**
* Collect spans into the list of visible lines
* @param para the <p> elemement
*/
function getLines(para) {
let lines = [];
let line;
let words = para.getElementsByTagName('span');
let lastTop;
for (let i = 0; i < words.length; i++) {
let word = words[i];
if (word.offsetTop != lastTop) {
lastTop = word.offsetTop;
line = [];
lines.push(line);
}
line.push(word);
}
return lines;
}
/**
* Fade-in text word by word and line by line
* @param para the <p> elemement
*/
function showLines(para) {
let lines = getLines(para);
const l = lines.map(function (line) {
return line.map(function (span) {
return span.innerText;
}).join(' ')
});
let fadeInterval = 150;
lines.forEach(function (value, index) {
value.forEach(function (v, i) {
setTimeout(fadeIn, (2 * index + i) * fadeInterval, v);
});
});
}
/**
* Add scroll event listener
* @param para the <p> elemement
* @param {number} [pageOffset] where to start
*/
(function (para, pageOffset = 0.5) {
splitLines(para);
let screenHeight = window.innerHeight || window.clientHeight;
let position = para.getBoundingClientRect().top;
let activationPoint = position - (screenHeight * pageOffset);
let shown = false;
document.addEventListener('scroll', (e) => {
let yPos = window.scrollY;
let inView = yPos > activationPoint;
if (inView && shown === false) {
splitLines(para);
showLines(para);
shown = true;
}
});
})(document.getElementById('emerge'));
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment