// Minimal CoBiE analog clock logic wrapped in its own scope to // avoid clashes with variables from other scripts on the page. (function () { const { COBIE_EPOCH, COBIE_UNITS, floorDiv, getTAIOffsetAt, toCobiets } = window.Cobie; // CoBiE helpers pulled from cobie.js function placeMarkers() { const clock = document.getElementById('clock'); let markers = clock.querySelectorAll('.marker'); let ticks = clock.querySelectorAll('.tick'); // Create markers if they don't exist yet if (markers.length === 0) { for (let i = 0; i < 16; i++) { const m = document.createElement('div'); m.className = 'marker'; m.textContent = i.toString(16).toUpperCase(); clock.appendChild(m); } markers = clock.querySelectorAll('.marker'); } // Create tick marks once if (ticks.length === 0) { for (let i = 0; i < 256; i++) { const t = document.createElement('div'); t.classList.add('tick'); if (i % 16 === 0) t.classList.add('big'); else if (i % 8 === 0) t.classList.add('mid'); // insert before markers so digits sit on top clock.insertBefore(t, clock.firstChild); } ticks = clock.querySelectorAll('.tick'); } // Position markers based on the current clock size const markerRadius = clock.offsetWidth / 2 - 20; markers.forEach((m, i) => { const angle = (i / 16) * 2 * Math.PI; const x = markerRadius * Math.sin(angle); const y = -markerRadius * Math.cos(angle); m.style.left = `${clock.offsetWidth / 2 + x}px`; m.style.top = `${clock.offsetHeight / 2 + y}px`; }); // Tick lengths based on the marker radius const lenBig = markerRadius * 0.12; const lenMid = markerRadius * 0.08; const lenSmall = markerRadius * 0.05; ticks.forEach((t, i) => { let len = lenSmall; if (t.classList.contains('big')) len = lenBig; else if (t.classList.contains('mid')) len = lenMid; const outerR = clock.offsetWidth / 2 - 2; const innerR = outerR - len; const angle = (i / 256) * 2 * Math.PI; const x = innerR * Math.sin(angle); const y = -innerR * Math.cos(angle); t.style.height = `${len}px`; t.style.left = `${clock.offsetWidth / 2 + x}px`; t.style.top = `${clock.offsetHeight / 2 + y}px`; t.style.transform = `rotate(${angle}rad)`; }); } const lastAngles = { handXeno: 0, handQuantic: 0, handChronon: 0, handEonstrip: 0, handMegasequence: 0 }; function rotateHand(id, angle) { const el = document.getElementById(id); if (!el) return; const prev = lastAngles[id]; if (angle < prev) { // When wrapping around (e.g. 15 → 0), animate to one full turn // and then snap back to the new angle to avoid a jump. const target = angle + 360; const handle = () => { el.removeEventListener('transitionend', handle); // Snap back without animation el.style.transition = 'none'; el.style.transform = `rotate(${angle}deg)`; void el.offsetWidth; el.style.transition = ''; }; el.addEventListener('transitionend', handle, { once: true }); el.style.transform = `rotate(${target}deg)`; } else { el.style.transform = `rotate(${angle}deg)`; } lastAngles[id] = angle; } function renderClock(cob) { // Use fractional progress within each unit so angles stay small const xf = (cob % COBIE_UNITS.quantic) / COBIE_UNITS.quantic; const qf = (cob % COBIE_UNITS.chronon) / COBIE_UNITS.chronon; const cf = (cob % COBIE_UNITS.eonstrip) / COBIE_UNITS.eonstrip; const ef = (cob % COBIE_UNITS.megasequence) / COBIE_UNITS.megasequence; const mf = (cob % COBIE_UNITS.cosmocycle) / COBIE_UNITS.cosmocycle; rotateHand('handXeno', xf * 360); rotateHand('handQuantic', qf * 360); rotateHand('handChronon', cf * 360); rotateHand('handEonstrip', ef * 360); rotateHand('handMegasequence', mf * 360); } function updateClock() { renderClock(toCobiets(new Date())); } let intervalId = null; function startClock() { clearInterval(intervalId); updateClock(); intervalId = setInterval(updateClock, 1000); } function showTime(cob) { clearInterval(intervalId); renderClock(cob); } function initClock() { placeMarkers(); startClock(); const clk = document.getElementById('clock'); if (clk) { clk.addEventListener('click', () => { document.body.classList.toggle('fullscreen-clock'); // Re-position markers after toggling fullscreen requestAnimationFrame(placeMarkers); }); } window.addEventListener('resize', placeMarkers); window.CobieClock = { start: startClock, showTime }; } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initClock); } else { initClock(); } })();