Cursed Analog Clock
HTML
<input type="range" id="slider" min="0" max="1" step="0.001" value="0" style="width:400px">
<br>
<span id="digital">00:00:00</span>
<br>
<canvas id="clock" width="400" height="400"></canvas>
JavaScript
// scaffoling prompted: https://chatgpt.com/share/690b05d9-2fac-800c-b014-386b2450573c
// Feel free to change the order of the numbers.
// Here are some presets you can try :-)
const PRESET_ROMAN_NUMERAL = ["I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII"];
const PRESET_DECIMAL = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"];
// ASC / DESC ?
const ASCENDING = true;
const hour_numbers = [...PRESET_ROMAN_NUMERAL];
if (hour_numbers.length !== 12) throw new Error("hour_numbers must have length 12");
const hours = hour_numbers.map((key, i) => ({ key, value: (i + 1) % 12 }));
// Text sort
hours.sort((a, b) => ((a.key > b.key) - (a.key < b.key)) * (ASCENDING ? 1 : -1));
// Extract separate arrays
const clock_face = hours.map(h => h.key);
const clock_value = hours.map(h => h.value);
const f12_angles = [];
for (let n = 0; n < 12; n++) {
const idx = clock_value.indexOf(n);
if (idx === -1) throw new Error(`Number ${n} not found in array`);
f12_angles.push(idx / 12);
}
const canvas = document.getElementById('clock');
const slider = document.getElementById('slider');
const digital = document.getElementById('digital');
const ctx = canvas.getContext('2d');
const hour_hand_thickness = 8;
const hour_hand_length = 0.4;
const minute_hand_thinkness = 5;
const minute_hand_length = 0.7;
const second_hand_thinkness = 2;
const second_hand_length = 0.8;
// global constants
const tau = 2 * Math.PI;
const center = { x: canvas.width / 2, y: canvas.height / 2 };
const radius = 150;
// draw helper: single number at given angle (in tau)
function draw_number(angle, number) {
if (number === 0) {
number = 12;
}
const r = radius - 25;
const x = center.x + r * Math.sin(angle * tau);
const y = center.y - r * Math.cos(angle * tau);
ctx.font = "20px sans-serif";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(number.toString(), x,...