(()=>{ // the initial seed var seed = 6; // in order to work 'seed' must NOT be undefined, // so in any case, you HAVE to provide a seed var seededRandom = (max, min)=> { max = max || 1; min = min || 0; seed = (seed * 9301 + 49297) % 233280; var rnd = seed / 233280; return min + rnd * (max - min); }; window.stopSimulatingGestures && window.stopSimulatingGestures(); window.simulatingGestures = false; let gestureTimeoutID; let periodicGesturesTimeoutID; let choose = (array)=> array[~~(seededRandom() * array.length)]; let isAnyMenuOpen = ()=> $(".menu-button.active").length > 0; let cursor_image = new Image(); cursor_image.src = "images/cursors/default.png"; var $cursor = $(cursor_image).addClass("user-cursor"); $cursor.css({ position: "absolute", left: 0, top: 0, opacity: 0, zIndex: 500, // arbitrary; maybe too high pointerEvents: "none", transition: "opacity 0.5s", }); window.simulateRandomGesture = (callback, {shift, shiftToggleChance=0.01, secondary, secondaryToggleChance, target=canvas}) => { let startWithinRect = target.getBoundingClientRect(); let canvasAreaRect = $canvas_area[0].getBoundingClientRect(); let startMinX = Math.max(startWithinRect.left, canvasAreaRect.left); let startMaxX = Math.min(startWithinRect.right, canvasAreaRect.right); let startMinY = Math.max(startWithinRect.top, canvasAreaRect.top); let startMaxY = Math.min(startWithinRect.bottom, canvasAreaRect.bottom); let startPointX = startMinX + seededRandom() * (startMaxX - startMinX); let startPointY = startMinY + seededRandom() * (startMaxY - startMinY); $cursor.appendTo($app); let triggerMouseEvent = (type, point) => { if (isAnyMenuOpen()) { return; } var clientX = point.x; var clientY = point.y; var el_over = document.elementFromPoint(clientX, clientY); var do_nothing = !type.match(/move/) && (!el_over || !el_over.closest(".canvas-area")); $cursor.css({ display: "block", position: "absolute", left: clientX, top: clientY, opacity: do_nothing ? 0.5 : 1, }); if (do_nothing) { return; } let event = new $.Event(type, { view: window, bubbles: true, cancelable: true, clientX: clientX, clientY: clientY, screenX: clientX, screenY: clientY, offsetX: point.x, offsetY: point.y, button: secondary ? 2 : 0, buttons: secondary ? 2 : 1, shiftKey: shift, }); $(target).trigger(event); }; let t = 0; let gestureComponents = []; let numberOfComponents = 5; for (let i = 0; i < numberOfComponents; i += 1) { gestureComponents.push({ rx: (seededRandom() * Math.min(canvasAreaRect.width, canvasAreaRect.height)) / 2 / numberOfComponents, ry: (seededRandom() * Math.min(canvasAreaRect.width, canvasAreaRect.height)) / 2 / numberOfComponents, angularFactor: seededRandom() * 5 - seededRandom(), angularOffset: seededRandom() * 5 - seededRandom(), }); } const stepsInGesture = 50; let pointForTimeWithArbitraryStart = (t) => { let point = { x: 0, y: 0 }; for (let i = 0; i < gestureComponents.length; i += 1) { let { rx, ry, angularFactor, angularOffset } = gestureComponents[i]; point.x += Math.sin(Math.PI * 2 * ((t / 2) * angularFactor + angularOffset)) * rx; point.y += Math.cos(Math.PI * 2 * ((t / 2) * angularFactor + angularOffset)) * ry; } return point; }; let pointForTime = (t) => { let point = pointForTimeWithArbitraryStart(t); let zeroPoint = pointForTimeWithArbitraryStart(0); point.x -= zeroPoint.x; point.y -= zeroPoint.y; point.x += startPointX; point.y += startPointY; return point; }; triggerMouseEvent("pointerenter", pointForTime(t)); // so dynamic cursors follow the simulation cursor triggerMouseEvent("pointerdown", pointForTime(t)); let move = () => { t += 1 / stepsInGesture; if (seededRandom() < shiftToggleChance) { shift = !shift; } if (seededRandom() < secondaryToggleChance) { secondary = !secondary; } if (t > 1) { triggerMouseEvent("pointerup", pointForTime(t)); $cursor.remove(); if (callback) { callback(); } } else { triggerMouseEvent("pointermove", pointForTime(t)); gestureTimeoutID = setTimeout(move, 10); } }; triggerMouseEvent("pointerleave", pointForTime(t)); move(); }; window.simulateRandomGesturesPeriodically = () => { window.simulatingGestures = true; if (window.drawRandomlySeed != null) { seed = window.drawRandomlySeed; } else { seed = ~~(Math.random() * 5000000); } console.log("Using seed:", seed); console.log("Note: Seeds are not guaranteed to work with different versions of the app, but within the same version it should produce the same results given the same starting document & other state & NO interference... except for airbrush randomness"); console.log(`To use this seed: window.drawRandomlySeed = ${seed}; document.body.style.width = "${getComputedStyle(document.body).width}"; document.body.style.height = "${getComputedStyle(document.body).height}"; simulateRandomGesturesPeriodically(); delete window.drawRandomlySeed; `); let delayBetweenGestures = 500; let shiftStart = false; let shiftStartToggleChance = 0.1; let shiftToggleChance = 0.001; let secondaryStart = false; let secondaryStartToggleChance = 0.1; let secondaryToggleChance = 0.001; let switchToolsChance = 0.5; let multiToolsChance = 0.8; let pickColorChance = 0.5; let pickToolOptionsChance = 0.8; let scrollChance = 0.2; let dragSelectionChance = 0.8; // scroll randomly absolutely initially so the starting scroll doesn't play into whether a seed reproduces $canvas_area.scrollTop($canvas_area.width() * seededRandom()); $canvas_area.scrollLeft($canvas_area.height() * seededRandom()); let _simulateRandomGesture = (callback)=> { window.simulateRandomGesture(callback, { shift: shiftStart, shiftToggleChance, secondary: secondaryStart, secondaryToggleChance }); }; let waitThenGo = () => { // TODO: a button to stop it as well (maybe make "stop drawing randomly" a link button?) $status_text.text("Press Esc to stop drawing randomly."); if (isAnyMenuOpen()) { setTimeout(waitThenGo, 50); return; } if (seededRandom() < shiftStartToggleChance) { shiftStart = !shiftStart; } if (seededRandom() < secondaryStartToggleChance) { secondaryStart = !secondaryStart; } if (seededRandom() < switchToolsChance) { let multiToolsPlz = seededRandom() < multiToolsChance; $(choose($(".tool, tool-button"))).trigger($.Event("click", {shiftKey: multiToolsPlz})); } if (seededRandom() < pickToolOptionsChance) { $(choose($(".tool-options *"))).trigger("click"); } if (seededRandom() < pickColorChance) { // TODO: maybe these should respond to a normal click? let secondary = seededRandom() < 0.5; var colorButton = choose($(".swatch, .color-button")); $(colorButton) .trigger($.Event("pointerdown", {button: secondary ? 2 : 0})) .trigger($.Event("click", {button: secondary ? 2 : 0})) .trigger($.Event("pointerup", {button: secondary ? 2 : 0})); } if (seededRandom() < scrollChance) { let scrollAmount = (seededRandom() * 2 - 1) * 700; if (seededRandom() < 0.5) { $canvas_area.scrollTop($canvas_area.scrollTop() + scrollAmount); } else { $canvas_area.scrollLeft($canvas_area.scrollLeft() + scrollAmount); } } periodicGesturesTimeoutID = setTimeout(() => { _simulateRandomGesture(()=> { if (selection && seededRandom() < dragSelectionChance) { window.simulateRandomGesture(waitThenGo, { shift: shiftStart, shiftToggleChance, secondary: secondaryStart, secondaryToggleChance, target: selection.canvas }); } else { waitThenGo(); } }); }, delayBetweenGestures); }; _simulateRandomGesture(waitThenGo); }; window.stopSimulatingGestures = () => { if (window.simulatingGestures) { clearTimeout(gestureTimeoutID); clearTimeout(periodicGesturesTimeoutID); window.simulatingGestures = false; $status_text.default(); } document.body.style.width = ""; document.body.style.height = ""; }; })();