(function() { const stream = document.querySelector(".term__stream"); if (!stream) { return; } const prefersReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches; if (prefersReducedMotion) { return; } const CHAR_DELAY = 18; const AFTER_COMMAND_DELAY = 90; const AFTER_OUTPUT_DELAY = 130; // Build the playback script before hiding anything, so a thrown error here // leaves the page in its fully rendered state. // Commands type into their own span so the blinking caret beside them // survives the text rewrites. const steps = Array.from(stream.children).map((element) => { const target = element.querySelector(".cmd__text"); return { element, target: target || element, isCommand: element.classList.contains("cmd"), text: (target || element).textContent }; }); if (!steps.some((step) => step.isCommand)) { return; } steps.forEach((step) => { if (step.isCommand) { step.target.textContent = ""; return; } step.element.classList.add("is-typing-hidden"); }); const wait = (ms) => new Promise((resolve) => window.setTimeout(resolve, ms)); const typeCommand = async (element, text) => { for (let index = 0; index < text.length; index += 1) { element.textContent = text.slice(0, index + 1); await wait(CHAR_DELAY); } }; const play = async () => { for (const step of steps) { if (step.isCommand) { await typeCommand(step.target, step.text); await wait(AFTER_COMMAND_DELAY); continue; } step.element.classList.remove("is-typing-hidden"); await wait(AFTER_OUTPUT_DELAY); } }; play(); })();