Skip to content

Instantly share code, notes, and snippets.

@lunetics
Created December 5, 2025 18:38
Show Gist options
  • Select an option

  • Save lunetics/cd050881ef78567aac8d62f2cbe66c75 to your computer and use it in GitHub Desktop.

Select an option

Save lunetics/cd050881ef78567aac8d62f2cbe66c75 to your computer and use it in GitHub Desktop.
function boing(times = 1, pause = 1000) {
const canvas = document.getElementById('canvas');
if (!canvas) { console.error('No canvas!'); return; }
const rect = canvas.getBoundingClientRect();
const cx = rect.width / 2;
const cy = rect.height / 2;
function fire(type, x, y) {
const common = {
bubbles: true, cancelable: true, view: window,
clientX: rect.left + x, clientY: rect.top + y,
offsetX: x, offsetY: y,
button: 0, buttons: type.includes('up') ? 0 : 1
};
canvas.dispatchEvent(new PointerEvent('pointer' + type, { ...common, pointerId: 1, pointerType: 'mouse', isPrimary: true }));
canvas.dispatchEvent(new MouseEvent('mouse' + type, common));
}
function doPull(callback) {
const endX = cx + rect.width * 0.35;
const randomY = (Math.random() - 0.5) * rect.height * 0.6;
const endY = cy + randomY;
fire('down', cx, cy);
let x = cx, y = cy, step = 0;
const dx = (endX - cx) / 12;
const dy = (endY - cy) / 12;
const id = setInterval(() => {
x += dx; y += dy; step++;
fire('move', x, y);
if (step >= 12) {
clearInterval(id);
setTimeout(() => {
fire('up', endX, endY);
if (callback) callback();
}, 30);
}
}, 20);
}
let count = 0;
function next() {
if (count >= times) return;
count++;
console.log(`Boing ${count}/${times}`);
doPull(() => {
if (count < times) {
setTimeout(next, pause);
}
});
}
next();
}
// Usage examples:
// boing() - pull once
// boing(5) - pull 5 times with 1 second pause
// boing(10, 500) - pull 10 times with 500ms pause
// boing(3, 2000) - pull 3 times with 2 second pause
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment