SUNDIAL solar dial v0.3: round screen, NOAA solar math, day/night arc
- 466px round layout, designWidth 466 (S4 41mm 466x466) - solar position + dayProgress in src/common/solar.js (pure, TDD'd) - sunrise/sunset sweep, night moon, countdown, 30s refresh - tests: solar math, page logic, circle geometry/contrast
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
// TDD: solar position math — RFC-accurate NOAA algorithm, pure functions.
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const src = fs.readFileSync('src/common/solar.js', 'utf8');
|
||||
const mod = {};
|
||||
new Function('module', 'exports', src)(mod, mod.exports || (mod.exports = {}));
|
||||
const { solarPosition, dayProgress, formatCountdown } = mod.exports;
|
||||
|
||||
// Reference: NOAA solar calculator, 2026-09-09, Paris (48.8566, 2.3522), 12:00 UTC ≈ solar noon-ish
|
||||
const p = solarPosition(new Date('2026-09-09T12:00:00Z'), 48.8566, 2.3522);
|
||||
assert.ok(Number.isFinite(p.altitude) && Number.isFinite(p.azimuth), 'finite angles');
|
||||
assert.ok(p.altitude > 35 && p.altitude < 60, `Paris noon September altitude ~45°, got ${p.altitude}`);
|
||||
|
||||
// Night: same place, 00:30 UTC → sun below horizon
|
||||
const n = solarPosition(new Date('2026-09-09T00:30:00Z'), 48.8566, 2.3522);
|
||||
assert.ok(n.altitude < -20, `midnight Paris altitude strongly negative, got ${n.altitude}`);
|
||||
|
||||
// Southern hemisphere summer: Sydney January noon → high sun
|
||||
const syd = solarPosition(new Date('2026-01-15T03:00:00Z'), -33.8688, 151.2093);
|
||||
assert.ok(syd.altitude > 55, `Sydney Jan noon altitude high, got ${syd.altitude}`);
|
||||
|
||||
// dayProgress: 0 at sunrise, 1 at sunset, 0.5 ≈ solar noon
|
||||
const dp = dayProgress(new Date('2026-09-09T12:00:00Z'), 48.8566, 2.3522);
|
||||
assert.ok(dp > 0.4 && dp < 0.6, `midday progress ≈ 0.5, got ${dp}`);
|
||||
assert.equal(dayProgress(new Date('2026-09-09T00:30:00Z'), 48.8566, 2.3522), 0, 'before sunrise → 0');
|
||||
assert.equal(dayProgress(new Date('2026-09-09T22:00:00Z'), 48.8566, 2.3522), 1, 'after sunset → 1');
|
||||
|
||||
// Polar night / midnight sun don't crash
|
||||
solarPosition(new Date('2026-06-21T12:00:00Z'), 78.22, 15.63); // Svalbard
|
||||
solarPosition(new Date('2026-12-21T12:00:00Z'), 78.22, 15.63);
|
||||
const polar = dayProgress(new Date('2026-12-21T12:00:00Z'), 78.22, 15.63);
|
||||
assert.ok(polar === 0 || polar === 1, 'polar night returns boundary');
|
||||
|
||||
// countdown formatting
|
||||
assert.equal(formatCountdown(3725), '1h 2m');
|
||||
assert.equal(formatCountdown(600), '10m');
|
||||
assert.equal(formatCountdown(45), '<1m');
|
||||
assert.equal(formatCountdown(0), '0m');
|
||||
|
||||
console.log('ALL SOLAR MATH PASS');
|
||||
Reference in New Issue
Block a user