// scrubber.js export class SubtickScrubber { constructor(elementId, frame, diorama) { this.frame = frame; this.diorama = diorama; this.container = diorama.element; this.playMode = 'paused'; // 'paused' | 'realtime' | 'subtick' this.speed = 1.0; // Ticks per second scaling this.lastFrameTime = performance.now(); this.playbackAccumulator = 0; // Hook into the Diorama tap event we just created this.diorama.onTap = () => { if (this.playMode !== 'paused') this.playMode = 'paused'; else this.playMode = 'realtime'; this.syncUI(); }; this.buildUI(); this.frame.subscribe(() => this.syncUI()); // Start playback loop this._loop = this.loop.bind(this); requestAnimationFrame(this._loop); } buildUI() { this.container.style.cssText = ` font-family: monospace; background: #333; padding: 10px; border-radius: 4px; display: flex; flex-direction: column; gap: 8px; `; // Secondary Row (Subticks) this.subRow = document.createElement('div'); this.subRow.style.cssText = `display: flex; gap: 10px; align-items: center;`; this.subRow.innerHTML = `