/* * Mountain background animation. * * Cycles the 60 ASCII frames from window.TP_MOUNTAIN_FRAMES at 12 fps. * Mounts a single
in the body that gets its textContent swapped
* on each frame. Uses requestAnimationFrame to stay smooth and yields
* cleanly to the browser's frame budget. Pauses on prefers-reduced-motion
* and on document.hidden.
*/
(function () {
"use strict";
function init() {
if (typeof window.TP_MOUNTAIN_FRAMES === "undefined") return;
var pre = document.querySelector("#tp-mountain-bg");
if (!pre) return;
pre.setAttribute("data-tp-mountain", "");
pre.setAttribute("aria-hidden", "true");
pre.textContent = window.TP_MOUNTAIN_FRAMES[0];
var n = window.TP_MOUNTAIN_N_FRAMES;
var fps = window.TP_MOUNTAIN_FPS;
var i = 0;
var last = 0;
var acc = 0;
var interval = 1000 / fps;
var reduceMotion =
window.matchMedia &&
window.matchMedia("(prefers-reduced-motion: reduce)").matches;
if (reduceMotion) {
// Show a single representative frame; no animation.
pre.textContent = window.TP_MOUNTAIN_FRAMES[Math.floor(n / 2)];
return;
}
function step(ts) {
if (!last) last = ts;
acc += ts - last;
last = ts;
while (acc >= interval) {
i = (i + 1) % n;
pre.textContent = window.TP_MOUNTAIN_FRAMES[i];
acc -= interval;
}
if (!document.hidden) {
requestAnimationFrame(step);
} else {
// Resume on next visibility change.
document.addEventListener(
"visibilitychange",
function onVisible() {
if (!document.hidden) {
last = 0;
acc = 0;
document.removeEventListener("visibilitychange", onVisible);
requestAnimationFrame(step);
}
}
);
}
}
requestAnimationFrame(step);
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", init);
} else {
init();
}
})();