solargod/js/lib.js
monsterrobotparty 26a5751394 🌞 genesis: scaffold — serve.py proxy+cache, importmap renderer, sky, sun, HUD, time bar, floating-origin bootstrap (opus)
Stage 0. Zero-dependency serve.py (static + allowlisted horizons/sbdb/cad proxy,
sha256 disk cache with past-span immutability). Three.js via pinned importmap,
logarithmic depth, procedural starfield sky (+ Milky Way panorama swap-in), Sun
with additive glow, OrbitControls, brass-and-void HUD, scrubbable time bar,
central bodyWorld position pass, focus/camera system, hash state. Boots clean,
no console errors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 00:04:41 +10:00

96 lines
3.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// SOLARGOD shared helpers — time (JD / centuries), math, the ecliptic→world
// frame map, and human formatters. Pure and dependency-free so verify.html can
// import it (and ephem.js) with zero Three.js in scope.
// ---- constants ----
export const AU_KM = 149597870.7; // 1 astronomical unit in km (IAU 2012)
export const C_KMS = 299792.458; // speed of light, km/s
export const MS_PER_DAY = 86400000;
export const J2000_JD = 2451545.0; // 2000-Jan-01 12:00 TT
export const UNIX_EPOCH_JD = 2440587.5; // JD of 1970-Jan-01 00:00 UTC
export const DEG = Math.PI / 180;
export const RAD = 180 / Math.PI;
// ---- time ----
// We treat the sim clock as UTC and ignore the TT/TDBUTC offset (~69 s in 2026).
// At interplanetary scale that is < 1e-5 AU even for Mars — noted, deliberately
// dropped (brief §2). JD from unix-ms: divide by ms/day, add the unix-epoch JD.
export function jdFromUnixMs(ms) { return ms / MS_PER_DAY + UNIX_EPOCH_JD; }
export function unixMsFromJd(jd) { return (jd - UNIX_EPOCH_JD) * MS_PER_DAY; }
// Julian centuries since J2000.0.
export function centuriesSinceJ2000(jd) { return (jd - J2000_JD) / 36525; }
// ---- scalar math ----
export const clamp = (x, lo, hi) => (x < lo ? lo : x > hi ? hi : x);
export const lerp = (a, b, t) => a + (b - a) * t;
export function smoothstep(t) { t = clamp(t, 0, 1); return t * t * (3 - 2 * t); }
// Normalize degrees to (180, +180]. Must run in float64 AFTER any large
// subtraction (Mercury's L rate is 149473°/Cy → M can be tens of thousands of
// degrees before reduction; brief §12).
export function normDegPM180(d) {
d = d % 360;
if (d <= -180) d += 360;
else if (d > 180) d -= 360;
return d;
}
export const normDeg360 = (d) => ((d % 360) + 360) % 360;
// ---- frame convention (fixed here once; nothing else maps by hand) ----
// Heliocentric J2000 ecliptic {x,y,z} [AU or view units] → Three.js world:
// ecliptic X → world x, ecliptic Z (north) → world y, ecliptic Y → world z.
// Keeps the frame right-handed with Y up. `out` is any {x,y,z} sink (Vector3 ok).
export function eclToWorld(ecl, out = {}) {
out.x = ecl.x;
out.y = ecl.z;
out.z = -ecl.y;
return out;
}
// Inverse, for round-trip checks and picking rays.
export function worldToEcl(w, out = {}) {
out.x = w.x;
out.y = -w.z;
out.z = w.y;
return out;
}
// ---- formatters ----
const pad = (n, w = 2) => String(n).padStart(w, '0');
// "2026-07-15 00:00:00 UTC" from unix-ms.
export function formatUTC(ms) {
const d = new Date(ms);
return `${d.getUTCFullYear()}-${pad(d.getUTCMonth() + 1)}-${pad(d.getUTCDate())} ` +
`${pad(d.getUTCHours())}:${pad(d.getUTCMinutes())}:${pad(d.getUTCSeconds())} UTC`;
}
export function formatUTCDate(ms) {
const d = new Date(ms);
return `${d.getUTCFullYear()}-${pad(d.getUTCMonth() + 1)}-${pad(d.getUTCDate())}`;
}
export function fmtAU(au) {
const a = Math.abs(au);
if (a < 0.001) return `${(au * AU_KM).toFixed(0)} km`;
if (a < 100) return `${au.toFixed(3)} AU`;
return `${au.toFixed(1)} AU`;
}
export function fmtKm(km) {
const a = Math.abs(km);
if (a >= 1e7) return `${(km / 1e6).toLocaleString('en-US', { maximumFractionDigits: 2 })} M km`;
return `${Math.round(km).toLocaleString('en-US')} km`;
}
// Light-time for a distance in AU → "43 min 12 s" / "1 h 08 m" / "8.3 s".
export function fmtLightTime(au) {
let s = (au * AU_KM) / C_KMS;
if (s < 90) return `${s.toFixed(1)} s`;
const h = Math.floor(s / 3600); s -= h * 3600;
const m = Math.floor(s / 60); s -= m * 60;
if (h > 0) return `${h} h ${pad(m)} m`;
return `${m} min ${pad(Math.floor(s))} s`;
}
// Duration in days → "27.3 d" / "1.88 yr".
export function fmtDuration(days) {
const a = Math.abs(days);
if (a < 2) return `${(a * 24).toFixed(1)} h`;
if (a < 900) return `${a.toFixed(1)} d`;
return `${(a / 365.25).toFixed(2)} yr`;
}
export function fmtSpeed(kms) { return `${kms.toFixed(2)} km/s`; }