/
Dgunamel
/
META_SCAN
Обзор
Документация
Войти
/
Dgunamel
/
META_SCAN
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
dev
src/lib/moon.ts
81 строка
3 KB
studio-agent
Squash 'studio-workflow-seed-71c2daea-aa89-42dd-b80e-3340378b7f39' into dev
29 июл 2026, 23:47
29 июл 2026, 23:47
2d16536
Код
Авторство
О чём код?
// Локальный расчёт фазы Луны. // Источник: классический алгоритм на основе синодического месяца 29.530588853 дней. export interface MoonInfo { ageDays: number; illumination: number; // 0..1 phaseName: string; phaseEmoji: string; phaseKey: MoonPhaseKey; riseTime: string; // локальное время (приблизительно) setTime: string; distance: number; // км } export type MoonPhaseKey = | "new" | "waxing-crescent" | "first-quarter" | "waxing-gibbous" | "full" | "waning-gibbous" | "last-quarter" | "waning-crescent"; const SYNODIC = 29.530588853; const KNOWN_NEW_MOON = 2451550.1; // JDN 2000-01-06 18:14 UT function julianDate(date: Date): number { // Юлианская дата (JD) return date.getTime() / 86400000 + 2440587.5; } function normalize(n: number): number { const v = n - Math.floor(n / SYNODIC) * SYNODIC; return v < 0 ? v + SYNODIC : v; } export function moonPhase(date: Date): MoonInfo { const jd = julianDate(date); const days = normalize(jd - KNOWN_NEW_MOON); const age = days; // Освещённость (0..1) const phase = (1 - Math.cos((days / SYNODIC) * 2 * Math.PI)) / 2; let key: MoonPhaseKey; let name: string; let emoji: string; if (age < 1.84566) { key = "new"; name = "Новолуние"; emoji = "🌑"; } else if (age < 5.53699) { key = "waxing-crescent"; name = "Растущий серп"; emoji = "🌒"; } else if (age < 9.22831) { key = "first-quarter"; name = "Первая четверть"; emoji = "🌓"; } else if (age < 12.91963) { key = "waxing-gibbous"; name = "Растущая Луна"; emoji = "🌔"; } else if (age < 16.61096) { key = "full"; name = "Полнолуние"; emoji = "🌕"; } else if (age < 20.30228) { key = "waning-gibbous"; name = "Убывающая Луна"; emoji = "🌖"; } else if (age < 23.99361) { key = "last-quarter"; name = "Последняя четверть"; emoji = "🌗"; } else if (age < 27.68493) { key = "waning-crescent"; name = "Убывающий серп"; emoji = "🌘"; } else { key = "new"; name = "Новолуние"; emoji = "🌑"; } // Восход и заход — упрощённый расчёт (зависит от фазы и дня года) // Базис: в новолуние восход совпадает с рассветом, в полнолуние — с закатом. const phaseOffsetHours = (age / SYNODIC) * 24; // смещение восхода относительно 6 утра const rise = (6 + phaseOffsetHours) % 24; const set = (rise + 12) % 24; const fmt = (h: number) => { const hh = Math.floor(h); const mm = Math.floor((h - hh) * 60); return `${String(hh).padStart(2, "0")}:${String(mm).padStart(2, "0")}`; }; // Расстояние до Луны (приблизительно, синодический месяц ~ синодическому для простоты) const distance = 384400 + Math.sin((age / SYNODIC) * 2 * Math.PI) * 21000; return { ageDays: age, illumination: phase, phaseName: name, phaseEmoji: emoji, phaseKey: key, riseTime: fmt(rise), setTime: fmt(set), distance: Math.round(distance), }; }