Spaces:
Running
Running
| export class SensoryDiceRoller { | |
| constructor(onRoll) { | |
| this.onRoll = onRoll; | |
| this.samples = []; | |
| this.isSampling = false; | |
| this.timer = null; | |
| this.init(); | |
| } | |
| mulberry32(a) { | |
| return function() { | |
| let t = a += 0x6D2B79F5; | |
| t = Math.imul(t ^ t >>> 15, t | 1); | |
| t ^= t + Math.imul(t ^ t >>> 7, t | 61); | |
| return ((t ^ t >>> 14) >>> 0) / 4294967296; | |
| }; | |
| } | |
| init() { | |
| if (window.DeviceMotionEvent) { | |
| window.addEventListener('devicemotion', (e) => this.handleMotion(e)); | |
| } | |
| window.addEventListener('mousemove', (e) => this.handleMouse(e)); | |
| } | |
| startSequence() { | |
| this.samples = []; | |
| this.isSampling = true; | |
| this.timer = setTimeout(() => { | |
| if (this.isSampling) { | |
| this.triggerRoll(Math.floor(Math.random() * 0xFFFFFFFF)); | |
| } | |
| }, 5000); | |
| } | |
| handleMotion(e) { | |
| if (!this.isSampling) return; | |
| const { x, y, z } = e.accelerationIncludingGravity || {}; | |
| if (x && y && z) { | |
| this.samples.push(Math.sqrt(x*x + y*y + z*z)); | |
| this.check(); | |
| } | |
| } | |
| handleMouse(e) { | |
| if (!this.isSampling) return; | |
| const v = Math.sqrt(e.movementX**2 + e.movementY**2); | |
| this.samples.push(v); | |
| this.check(); | |
| } | |
| check() { | |
| if (this.samples.length >= 30) { | |
| clearTimeout(this.timer); | |
| const seed = this.samples.reduce((a, b) => a + Math.floor(b * 1000), 0); | |
| this.triggerRoll(seed); | |
| } | |
| } | |
| triggerRoll(seed) { | |
| this.isSampling = false; | |
| const rng = this.mulberry32(seed); | |
| const result = Math.floor(rng() * 20) + 1; | |
| this.onRoll(result); | |
| } | |
| } |