const m = 76667 * 78887; const nextRandom = x => x ** 2 % m const generateRandomArray = (initialSeed, count) => ( count <= 0 ? [] : [initialSeed].concat(generateRandomArray(nextRandom(initialSeed), count - 1))) const zip = (f, ...lists) => ( lists.some(l => l.length == 0) ? [] : [f(...lists.map(l => l[0]))].concat(zip(f, ...lists.map(l => l.slice(1))))) const goopZoneElem = document.getElementById("goop-zone"); const goopHeader = document.getElementById("header-box"); const nextState = (state, width, height) => document.hidden ? state : state.map(orig => { const projectedNewX = orig.x + orig.vx; const projectedNewY = orig.y + orig.vy; const [newX, newVX] = projectedNewX < 0 || projectedNewX > width ? [orig.x - orig.vx, -orig.vx] : [projectedNewX, orig.vx]; const [newY, newVY] = projectedNewY < -50 || projectedNewY > height - 20 ? [orig.y - orig.vy, -orig.vy] : [projectedNewY, orig.vy]; return ({ elem: orig.elem, x: newX, y: newY, vx: newVX, vy: newVY }) }); const mkInitialState = (drifters, width, height) => zip( (elem, random1, random2, random3) => (direction => ({ elem: elem , x: random1 % width , y: random2 % height , vx: 20 * Math.cos(direction) , vy: 20 * Math.sin(direction) }) )(random3 % 2000 / 1000 * Math.PI), drifters, generateRandomArray(5737051, drifters.length), generateRandomArray(5457297, drifters.length), generateRandomArray(3631413, drifters.length)) const applyState = states => states.map(s => { s.elem.setAttribute('style', `transform: translate(${s.x}px, ${s.y}px)`) }); loop = (state) => { setInterval(() => { const goopZoneWidth = goopZoneElem.width.baseVal.value/2; const goopZoneHeight = goopZoneElem.height.baseVal.value/2; goopHeader.setAttribute("x", (goopZoneWidth - 300)/2); state = nextState(state, goopZoneWidth, goopZoneHeight); applyState(state) }, 500) } const drifters = Array.from(document.getElementsByClassName("glob")); loop(mkInitialState(drifters, goopZoneElem.width.baseVal.value/2, goopZoneElem.height.baseVal.value/2));