import { Smc } from "./smc/lib.js" main(); async function fetchShader(uri, delegate) { const res = await fetch(uri); if (res.ok) return await res.text(); this.raiseError( SmcErr.FETCH_SHADER, `Failed to load shader source ${url}: ${res.status} ${res.json()}`); return "" } function animDelta(anim) { const timing = anim.effect.getComputedTiming(); return (timing.delay ?? 0) + (timing.duration ?? 0) + (timing.endDelay ?? 0); } function main() { const cps = 12; // chars per second const promptDelay = 0.5; const commandDelay = 5; const outputDelay = 5; const blinkTime = 600; // x2 then x1000 // WARNING: delay does not account for runtime // WARNING: it assumes all computations are down instantaneously var delay = 0; const boot = document.querySelector("#boot-ppty"); // WARNING: ensure boot != null boot .querySelectorAll(".ppty-block") .forEach((block, index, blocks) => { const prompt = block.querySelector(".ppty-prompt"); const command = block.querySelector(".ppty-command"); const output = block.querySelector(".ppty-output"); // WARNING: ensure prompt|command|output != null const promptAnim = prompt.animate( [{ visibility: "visible" }], { delay: delay + promptDelay * 1000, fill: "forwards", }, ); delay = animDelta(promptAnim); const showCursor = () => { command.style.borderRightColor = cursorColor; return true; }; const hideCursor = () => { command.style.borderRightColor = "transparent"; return false; }; const startCursorBlink = () => setInterval(() => { cursorVisible = cursorVisible ? hideCursor() : showCursor(); }, blinkTime); const cursorColor = command.style.borderRightColor; var cursorVisible = true; var blinkId = null; setTimeout(() => { command.style.visibility = "visible"; blinkId = startCursorBlink(); }, delay); // WARNING: ensure command.textContent != null const commandLen = command.textContent.trim().length const commandAnim = command.animate( [ { width: "0ch", visibility: "visible", }, { width: `${commandLen}ch`, visibility: "visible", } ], { duration: commandLen / cps * 1000, delay: delay + commandDelay * 1000, easing: `steps(${commandLen}, end)`, fill: "forwards", } ); // pause the cursor while typing setTimeout(() => { clearInterval(blinkId); showCursor(); cursorVisible = true; }, delay + commandDelay * 1000); delay = animDelta(commandAnim); setTimeout(() => { blinkId = startCursorBlink(); }, delay); setTimeout(() => { clearInterval(blinkId); hideCursor(); }, delay + outputDelay * 1000); // unhide output output.animate( [{ visibility: "visible" }], { delay: delay + outputDelay * 1000, fill: "forwards", } ); delay += outputDelay * 1000; // hide the cursor after output displays setTimeout(() => command.style.borderRightColor = "transparent", delay); }); const canvas = document.querySelector("#bg-canvas"); canvas.setAttribute('width', window.innerWidth); canvas.setAttribute('height', window.innerHeight); fetchShader("../shaders/segfault.glsl") .then(frag => new Smc(canvas) .setMaxFps(30) .setProgram(builder => builder .addFragmentShader(frag)) .run() ); }