ascii-side-of-the-moon 1.0.8 → 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -0
- package/dist/cli.cjs +44 -18
- package/dist/index.cjs +9 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -4
- package/dist/index.d.ts +20 -4
- package/dist/index.mjs +9 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -71,7 +71,23 @@ Inside of repository for `ascii-side-of-the-moon`.
|
|
|
71
71
|
|
|
72
72
|
Render a single date:
|
|
73
73
|
```sh
|
|
74
|
+
# Show moon for current date
|
|
75
|
+
pnpm run render:demo
|
|
76
|
+
|
|
77
|
+
# Show moon for a specific date
|
|
74
78
|
pnpm run render:demo 2025-01-01
|
|
79
|
+
|
|
80
|
+
# Include a specific UTC time
|
|
81
|
+
pnpm run render:demo 2025-01-01 21:30
|
|
82
|
+
|
|
83
|
+
# Include observer location (enables parallactic rotation and horizon display)
|
|
84
|
+
pnpm run render:demo 2025-01-01 21:30 --lat 40.7128 --lon -74.0060
|
|
85
|
+
|
|
86
|
+
# With elevation (meters)
|
|
87
|
+
pnpm run render:demo 2025-01-01 21:30 --lat 37.7749 --lon -122.4194 --elevation 25
|
|
88
|
+
|
|
89
|
+
# Just observer location (uses current date/time)
|
|
90
|
+
pnpm run render:demo --lat 40.7128 --lon -74.0060
|
|
75
91
|
```
|
|
76
92
|
|
|
77
93
|
Render an animation:
|
package/dist/cli.cjs
CHANGED
|
@@ -46,6 +46,22 @@ function addDays(d, days) {
|
|
|
46
46
|
function normalizeDegrees(angle) {
|
|
47
47
|
return (angle % 360 + 360) % 360;
|
|
48
48
|
}
|
|
49
|
+
function calculateBrightLimbAngle(date) {
|
|
50
|
+
const sunVec = Astronomy.GeoVector(Astronomy.Body.Sun, date, true);
|
|
51
|
+
const moonVec = Astronomy.GeoVector(Astronomy.Body.Moon, date, true);
|
|
52
|
+
const sunEq = Astronomy.EquatorFromVector(sunVec);
|
|
53
|
+
const moonEq = Astronomy.EquatorFromVector(moonVec);
|
|
54
|
+
const dRA_hours = sunEq.ra - moonEq.ra;
|
|
55
|
+
const dRA_rad = dRA_hours * 15 * Astronomy.DEG2RAD;
|
|
56
|
+
const moonDecRad = moonEq.dec * Astronomy.DEG2RAD;
|
|
57
|
+
const sunDecRad = sunEq.dec * Astronomy.DEG2RAD;
|
|
58
|
+
const sinDRA = Math.sin(dRA_rad);
|
|
59
|
+
const cosDRA = Math.cos(dRA_rad);
|
|
60
|
+
const numerator = sinDRA;
|
|
61
|
+
const denominator = Math.cos(moonDecRad) * Math.tan(sunDecRad) - Math.sin(moonDecRad) * cosDRA;
|
|
62
|
+
const positionAngle = Math.atan2(numerator, denominator) * Astronomy.RAD2DEG;
|
|
63
|
+
return normalizeDegrees(positionAngle);
|
|
64
|
+
}
|
|
49
65
|
function normalizeHourAngle(hours) {
|
|
50
66
|
let h = (hours % 24 + 24) % 24;
|
|
51
67
|
if (h > 12) h -= 24;
|
|
@@ -85,7 +101,8 @@ function getMoonState(date, observerLocation) {
|
|
|
85
101
|
phase: {
|
|
86
102
|
phaseAngleDeg: illum.phase_angle,
|
|
87
103
|
illuminatedFraction: illum.phase_fraction,
|
|
88
|
-
isWaxing: isWaxingAt(date)
|
|
104
|
+
isWaxing: isWaxingAt(date),
|
|
105
|
+
brightLimbAngle: calculateBrightLimbAngle(date)
|
|
89
106
|
},
|
|
90
107
|
size: {
|
|
91
108
|
distanceKm: lib.dist_km,
|
|
@@ -444,7 +461,7 @@ var ascii_default = {
|
|
|
444
461
|
// src/render/renderer.ts
|
|
445
462
|
var FRAME_W = 60;
|
|
446
463
|
var FRAME_H = 29;
|
|
447
|
-
var
|
|
464
|
+
var TEXTURE_ORIENTATION_OFFSET = -45;
|
|
448
465
|
function asciiMoonDim(asciiArt) {
|
|
449
466
|
const lines = asciiArt.split("\n");
|
|
450
467
|
let minX = Infinity;
|
|
@@ -484,15 +501,22 @@ function clamp(v, lo, hi) {
|
|
|
484
501
|
function rad(d) {
|
|
485
502
|
return d * Math.PI / 180;
|
|
486
503
|
}
|
|
487
|
-
function phaseSunVector(phaseAngleDeg, isWaxing, elatDeg = 0) {
|
|
504
|
+
function phaseSunVector(phaseAngleDeg, brightLimbAngleDeg, isWaxing, elatDeg = 0) {
|
|
488
505
|
const a = rad(phaseAngleDeg);
|
|
489
506
|
const elat = rad(elatDeg);
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
507
|
+
let sunAngle;
|
|
508
|
+
if (brightLimbAngleDeg !== void 0) {
|
|
509
|
+
sunAngle = rad(brightLimbAngleDeg);
|
|
510
|
+
} else {
|
|
511
|
+
sunAngle = isWaxing ? rad(270) : rad(90);
|
|
512
|
+
}
|
|
513
|
+
const sunDirX = -Math.sin(sunAngle);
|
|
514
|
+
const sunDirY = -Math.cos(sunAngle);
|
|
515
|
+
const sx = sunDirX * Math.sin(a);
|
|
516
|
+
let sy = sunDirY * Math.sin(a);
|
|
493
517
|
let sz = Math.cos(a);
|
|
494
|
-
const sy1 = -sz * Math.sin(elat);
|
|
495
|
-
const sz1 = sz * Math.cos(elat);
|
|
518
|
+
const sy1 = sy * Math.cos(elat) - sz * Math.sin(elat);
|
|
519
|
+
const sz1 = sy * Math.sin(elat) + sz * Math.cos(elat);
|
|
496
520
|
sy = sy1;
|
|
497
521
|
sz = sz1;
|
|
498
522
|
const mag = Math.sqrt(sx * sx + sy * sy + sz * sz);
|
|
@@ -578,6 +602,7 @@ function renderMoon(state, _options = {}) {
|
|
|
578
602
|
const dim = asciiMoonDim(nearestMoon.ascii);
|
|
579
603
|
const { sx, sy, sz } = phaseSunVector(
|
|
580
604
|
state.phase.phaseAngleDeg,
|
|
605
|
+
state.phase.brightLimbAngle,
|
|
581
606
|
state.phase.isWaxing,
|
|
582
607
|
state.libration.elat
|
|
583
608
|
);
|
|
@@ -643,18 +668,19 @@ function renderMoon(state, _options = {}) {
|
|
|
643
668
|
}
|
|
644
669
|
out.push(row);
|
|
645
670
|
}
|
|
646
|
-
|
|
647
|
-
let finalArt = composed;
|
|
671
|
+
let composed = out.join("\n");
|
|
648
672
|
if (state.position?.parallacticAngle !== void 0) {
|
|
649
|
-
const
|
|
650
|
-
|
|
651
|
-
composed
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
673
|
+
const totalRotation = -state.position.parallacticAngle + TEXTURE_ORIENTATION_OFFSET;
|
|
674
|
+
if (Math.abs(totalRotation) > 0.1) {
|
|
675
|
+
composed = rotateCharacters(
|
|
676
|
+
composed,
|
|
677
|
+
totalRotation,
|
|
678
|
+
dim.centerX,
|
|
679
|
+
dim.centerY
|
|
680
|
+
);
|
|
681
|
+
}
|
|
656
682
|
}
|
|
657
|
-
return showHorizon ? overlayHorizon(
|
|
683
|
+
return showHorizon ? overlayHorizon(composed, state, dim) : composed;
|
|
658
684
|
}
|
|
659
685
|
function overlayHorizon(art, state, moonDim) {
|
|
660
686
|
const pos = state.position;
|
package/dist/index.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
'use strict';var T=require('astronomy-engine');function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var T__namespace=/*#__PURE__*/_interopNamespace(T);var
|
|
1
|
+
'use strict';var T=require('astronomy-engine');function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var T__namespace=/*#__PURE__*/_interopNamespace(T);var s=T__namespace.default??T__namespace;function p($,g){let n=new Date($.getTime());return n.setDate(n.getDate()+g),n}function z($){return ($%360+360)%360}function P($){let g=s.GeoVector(s.Body.Sun,$,true),n=s.GeoVector(s.Body.Moon,$,true),t=s.EquatorFromVector(g),_=s.EquatorFromVector(n),B=(t.ra-_.ra)*15*s.DEG2RAD,M=_.dec*s.DEG2RAD,a=t.dec*s.DEG2RAD,o=Math.sin(B),i=Math.cos(B),e=o,m=Math.cos(M)*Math.tan(a)-Math.sin(M)*i,A=Math.atan2(e,m)*s.RAD2DEG;return z(A)}function D($){let g=($%24+24)%24;return g>12&&(g-=24),g}function X($){let g=s.Illumination(s.Body.Moon,$).phase_fraction;return s.Illumination(s.Body.Moon,p($,1)).phase_fraction>g}function N($,g,n){let t=s.SiderealTime($),_=g.longitude/15,B=D(_+t-n.ra)*15*s.DEG2RAD,M=g.latitude*s.DEG2RAD,a=n.dec*s.DEG2RAD,o=Math.sin(B),i=Math.tan(M)*Math.cos(a)-Math.sin(a)*Math.cos(B);return Math.atan2(o,i)*s.RAD2DEG}function Y($,g){let n=new s.Observer(g.latitude,g.longitude,g.elevationMeters??0),t=s.Equator(s.Body.Moon,$,n,true,true),_=s.Horizon($,n,t.ra,t.dec,"normal");return {azimuth:z(_.azimuth),altitude:_.altitude,parallacticAngle:N($,g,t)}}function G($,g){let n=s.Illumination(s.Body.Moon,$),t=s.Libration($);return {date:$,phase:{phaseAngleDeg:n.phase_angle,illuminatedFraction:n.phase_fraction,isWaxing:X($),brightLimbAngle:P($)},size:{distanceKm:t.dist_km,angularDiameterDeg:t.diam_deg},libration:{elon:t.elon,elat:t.elat},position:g?Y($,g):void 0}}function H($){let{phaseAngleDeg:g,illuminatedFraction:n}=$.phase,t=$.phase.isWaxing??g>90,_=(g%360+360)%360,R=_>180?360-_:_,B=10,M=10,a=8,o=.98,i=.02,e=.02;return R<=B||n>=o?"Full Moon":R>=180-M||n<=i?"New Moon":Math.abs(R-90)<=a||Math.abs(n-.5)<=e?t?"First Quarter":"Last Quarter":R<90?t?"Waxing Gibbous":"Waning Gibbous":t?"Waxing Crescent":"Waning Crescent"}var K={moons:[{index:0,distance_km:405493.5,libration_elat:-0.888,libration_elon:-0.412,ascii:`
|
|
2
2
|
|
|
3
3
|
._ . - .
|
|
4
4
|
,_++> a, +. \`-.
|
|
@@ -894,12 +894,12 @@
|
|
|
894
894
|
'FFF'"Z"@MGR^^'\`
|
|
895
895
|
|
|
896
896
|
|
|
897
|
-
`}]};var
|
|
898
|
-
`),n=1/0,
|
|
899
|
-
`),B=
|
|
900
|
-
`)}function
|
|
901
|
-
`),B=V(
|
|
902
|
-
`)
|
|
903
|
-
`),
|
|
904
|
-
`)}function O($){let n=`--${$.trim().replace(/\s+/g,"-")}--`;if(n.length>
|
|
897
|
+
`}]};var c=60,d=29,J=-45;function V($){let g=$.split(`
|
|
898
|
+
`),n=1/0,t=-1/0,_=1/0,R=-1/0;if(g.forEach((a,o)=>{let i=a.search(/\S/);if(i!==-1){let e=a.search(/\s+$/);n=Math.min(n,i),t=Math.max(t,e===-1?a.length-1:e-1),_===1/0&&(_=o),R=o;}}),n===1/0)return {width:c,height:d,centerX:Math.floor(c/2),centerY:Math.floor(d/2)};let B=t-n+1,M=R-_+1;return {width:B,height:M,centerX:n+Math.floor(B/2),centerY:_+Math.floor(M/2)}}function L($,g,n){return Math.min(n,Math.max(g,$))}function x($){return $*Math.PI/180}function Q($,g,n,t=0){let _=x($),R=x(t),B;g!==void 0?B=x(g):B=x(n?270:90);let M=-Math.sin(B),a=-Math.cos(B),o=M*Math.sin(_),i=a*Math.sin(_),e=Math.cos(_),m=i*Math.cos(R)-e*Math.sin(R),A=i*Math.sin(R)+e*Math.cos(R);i=m,e=A;let W=Math.sqrt(o*o+i*i+e*e);return {sx:o/W,sy:i/W,sz:e/W}}function I($,g,n,t,_){let R=1/c,B=1/d,M=[-0.5,-0.25,0,.25,.5],a=0,o=0;for(let i of M)for(let e of M){let m=$+i*R,A=g+e*B,W=m*m+A*A;if(W>1)continue;let w=Math.sqrt(Math.max(0,1-W)),b=m*n+A*t+w*_;a+=Math.max(0,b),o++;}return o===0?0:a/o}function S($){let t=0,_=1/0;for(let R=0;R<K.moons.length;R++){let B=K.moons[R],M=Math.abs(B.distance_km-$.size.distanceKm)*1,a=Math.abs(B.libration_elat-$.libration.elat)*1e4,o=Math.abs(B.libration_elon-$.libration.elon)*1e4,i=M+a+o;i<_&&(_=i,t=R);}return K.moons[t]}var k=22/10;function q($,g,n,t){let _=(g%360+360)%360;if(Math.abs(_)<.1)return $;let R=$.split(`
|
|
899
|
+
`),B=R.length,M=R[0]?.length??0,a=n??(M-1)/2,o=t??(B-1)/2,i=_*Math.PI/180,e=Math.cos(i),m=Math.sin(i),A=Array.from({length:B},()=>Array(M).fill(" "));for(let W=0;W<B;W++)for(let w=0;w<M;w++){let b=w-a,F=(W-o)*k,r=b*e-F*m,E=b*m+F*e,u=Math.round(r+a),y=Math.round(E/k+o);if(u>=0&&u<M&&y>=0&&y<B){let l=R[y]?.[u]??" ";A[W][w]=l;}}return A.map(W=>W.join("")).join(`
|
|
900
|
+
`)}function C($,g={}){let t=(g??{}).showHorizon!==false,_=S($),R=_.ascii.split(`
|
|
901
|
+
`),B=V(_.ascii),{sx:M,sy:a,sz:o}=Q($.phase.phaseAngleDeg,$.phase.brightLimbAngle,$.phase.isWaxing,$.libration.elat),i=Array.from({length:d},()=>Array(c).fill(0)),e=Array.from({length:d},()=>Array(c).fill(-1)),m=Array.from({length:d},()=>Array(c).fill(false)),A=0,W=0;for(let r=0;r<d;r++)for(let E=0;E<c;E++){let u=E-B.centerX,y=r-B.centerY,l=u/(B.width/2),f=y/(B.height/2),h=l*l+f*f;if(h>1){i[r][E]=0,e[r][E]=-1;continue}m[r][E]=true,A++;let Z=I(l,f,M,a,o);i[r][E]=Z,Z>0&&W++;let j=Math.sqrt(Math.max(0,1-h));e[r][E]=l*M+f*a+j*o;}let w=Array.from({length:d},()=>Array(c).fill(false));if(W>0)for(let r=0;r<d;r++)for(let E=0;E<c;E++)w[r][E]=i[r][E]>0;else {let r=L($.phase.illuminatedFraction??0,0,1),E=Math.max(1,Math.round(r*A)),u=[];for(let y=0;y<d;y++)for(let l=0;l<c;l++)m[y][l]&&u.push({ix:l,iy:y,v:e[y][l]});u.sort((y,l)=>l.v-y.v);for(let y=0;y<Math.min(E,u.length);y++){let{ix:l,iy:f}=u[y];w[f][l]=true;}}let b=[];for(let r=0;r<d;r++){let E="",u=R[r]??"";for(let y=0;y<c;y++)w[r][y]?E+=u[y]??" ":E+=" ";b.push(E);}let F=b.join(`
|
|
902
|
+
`);if($.position?.parallacticAngle!==void 0){let r=-$.position.parallacticAngle+J;Math.abs(r)>.1&&(F=q(F,r,B.centerX,B.centerY));}return t?U(F,$,B):F}function U($,g,n){let t=g.position;if(!t||g.size.angularDiameterDeg<=0)return $;let _=t.altitude??0,R=g.size.angularDiameterDeg/2,B=_+R;if(_-R>=0)return $;let a=$.split(`
|
|
903
|
+
`),o=g.size.angularDiameterDeg/Math.max(1,n.height),i=n.centerY+_/o;i=Math.round(L(i,0,d-1));let e;return B<=0?e=`${Math.abs(_).toFixed(1).replace(/\.0$/,"")}-deg-below-horizon`:e="horizon",a[i]=O(e),a.join(`
|
|
904
|
+
`)}function O($){let n=`--${$.trim().replace(/\s+/g,"-")}--`;if(n.length>c&&(n=n.slice(0,c)),n.length===c)return n;let t=c-n.length,_=Math.floor(t/2),R=t-_;return "-".repeat(_)+n+"-".repeat(R)}exports.getMoonPhase=H;exports.getMoonState=G;exports.renderMoon=C;//# sourceMappingURL=index.cjs.map
|
|
905
905
|
//# sourceMappingURL=index.cjs.map
|