ascii-side-of-the-moon 1.0.8 → 1.0.10
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 +54 -19
- 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);
|
|
@@ -574,10 +598,20 @@ function renderMoon(state, _options = {}) {
|
|
|
574
598
|
const options = _options ?? {};
|
|
575
599
|
const showHorizon = options.showHorizon !== false;
|
|
576
600
|
const nearestMoon = findNearestMoonState(state);
|
|
577
|
-
const asciiLines = nearestMoon.ascii.split("\n");
|
|
578
601
|
const dim = asciiMoonDim(nearestMoon.ascii);
|
|
602
|
+
let textureAscii = nearestMoon.ascii;
|
|
603
|
+
if (Math.abs(TEXTURE_ORIENTATION_OFFSET) > 0.1) {
|
|
604
|
+
textureAscii = rotateCharacters(
|
|
605
|
+
textureAscii,
|
|
606
|
+
TEXTURE_ORIENTATION_OFFSET,
|
|
607
|
+
dim.centerX,
|
|
608
|
+
dim.centerY
|
|
609
|
+
);
|
|
610
|
+
}
|
|
611
|
+
const asciiLines = textureAscii.split("\n");
|
|
579
612
|
const { sx, sy, sz } = phaseSunVector(
|
|
580
613
|
state.phase.phaseAngleDeg,
|
|
614
|
+
state.phase.brightLimbAngle,
|
|
581
615
|
state.phase.isWaxing,
|
|
582
616
|
state.libration.elat
|
|
583
617
|
);
|
|
@@ -643,18 +677,19 @@ function renderMoon(state, _options = {}) {
|
|
|
643
677
|
}
|
|
644
678
|
out.push(row);
|
|
645
679
|
}
|
|
646
|
-
|
|
647
|
-
let finalArt = composed;
|
|
680
|
+
let composed = out.join("\n");
|
|
648
681
|
if (state.position?.parallacticAngle !== void 0) {
|
|
649
|
-
const
|
|
650
|
-
|
|
651
|
-
composed
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
682
|
+
const rotation = -state.position.parallacticAngle;
|
|
683
|
+
if (Math.abs(rotation) > 0.1) {
|
|
684
|
+
composed = rotateCharacters(
|
|
685
|
+
composed,
|
|
686
|
+
rotation,
|
|
687
|
+
dim.centerX,
|
|
688
|
+
dim.centerY
|
|
689
|
+
);
|
|
690
|
+
}
|
|
656
691
|
}
|
|
657
|
-
return showHorizon ? overlayHorizon(
|
|
692
|
+
return showHorizon ? overlayHorizon(composed, state, dim) : composed;
|
|
658
693
|
}
|
|
659
694
|
function overlayHorizon(art, state, moonDim) {
|
|
660
695
|
const pos = state.position;
|
package/dist/index.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
'use strict';var
|
|
1
|
+
'use strict';var h=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 h__namespace=/*#__PURE__*/_interopNamespace(h);var s=h__namespace.default??h__namespace;function X($,g){let n=new Date($.getTime());return n.setDate(n.getDate()+g),n}function k($){return ($%360+360)%360}function N($){let g=s.GeoVector(s.Body.Sun,$,true),n=s.GeoVector(s.Body.Moon,$,true),B=s.EquatorFromVector(g),t=s.EquatorFromVector(n),R=(B.ra-t.ra)*15*s.DEG2RAD,r=t.dec*s.DEG2RAD,a=B.dec*s.DEG2RAD,o=Math.sin(R),i=Math.cos(R),e=o,l=Math.cos(r)*Math.tan(a)-Math.sin(r)*i,A=Math.atan2(e,l)*s.RAD2DEG;return k(A)}function Y($){let g=($%24+24)%24;return g>12&&(g-=24),g}function G($){let g=s.Illumination(s.Body.Moon,$).phase_fraction;return s.Illumination(s.Body.Moon,X($,1)).phase_fraction>g}function H($,g,n){let B=s.SiderealTime($),t=g.longitude/15,R=Y(t+B-n.ra)*15*s.DEG2RAD,r=g.latitude*s.DEG2RAD,a=n.dec*s.DEG2RAD,o=Math.sin(R),i=Math.tan(r)*Math.cos(a)-Math.sin(a)*Math.cos(R);return Math.atan2(o,i)*s.RAD2DEG}function v($,g){let n=new s.Observer(g.latitude,g.longitude,g.elevationMeters??0),B=s.Equator(s.Body.Moon,$,n,true,true),t=s.Horizon($,n,B.ra,B.dec,"normal");return {azimuth:k(t.azimuth),altitude:t.altitude,parallacticAngle:H($,g,B)}}function J($,g){let n=s.Illumination(s.Body.Moon,$),B=s.Libration($);return {date:$,phase:{phaseAngleDeg:n.phase_angle,illuminatedFraction:n.phase_fraction,isWaxing:G($),brightLimbAngle:N($)},size:{distanceKm:B.dist_km,angularDiameterDeg:B.diam_deg},libration:{elon:B.elon,elat:B.elat},position:g?v($,g):void 0}}function V($){let{phaseAngleDeg:g,illuminatedFraction:n}=$.phase,B=$.phase.isWaxing??g>90,t=(g%360+360)%360,_=t>180?360-t:t,R=10,r=10,a=8,o=.98,i=.02,e=.02;return _<=R||n>=o?"Full Moon":_>=180-r||n<=i?"New Moon":Math.abs(_-90)<=a||Math.abs(n-.5)<=e?B?"First Quarter":"Last Quarter":_<90?B?"Waxing Gibbous":"Waning Gibbous":B?"Waxing Crescent":"Waning Crescent"}var T={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
|
-
`),
|
|
900
|
-
`)}function
|
|
901
|
-
`),
|
|
902
|
-
`)
|
|
903
|
-
`),
|
|
904
|
-
`)}function
|
|
897
|
+
`}]};var c=60,d=29,L=-45;function I($){let g=$.split(`
|
|
898
|
+
`),n=1/0,B=-1/0,t=1/0,_=-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),B=Math.max(B,e===-1?a.length-1:e-1),t===1/0&&(t=o),_=o;}}),n===1/0)return {width:c,height:d,centerX:Math.floor(c/2),centerY:Math.floor(d/2)};let R=B-n+1,r=_-t+1;return {width:R,height:r,centerX:n+Math.floor(R/2),centerY:t+Math.floor(r/2)}}function P($,g,n){return Math.min(n,Math.max(g,$))}function K($){return $*Math.PI/180}function S($,g,n,B=0){let t=K($),_=K(B),R;g!==void 0?R=K(g):R=K(n?270:90);let r=-Math.sin(R),a=-Math.cos(R),o=r*Math.sin(t),i=a*Math.sin(t),e=Math.cos(t),l=i*Math.cos(_)-e*Math.sin(_),A=i*Math.sin(_)+e*Math.cos(_);i=l,e=A;let W=Math.sqrt(o*o+i*i+e*e);return {sx:o/W,sy:i/W,sz:e/W}}function q($,g,n,B,t){let _=1/c,R=1/d,r=[-0.5,-0.25,0,.25,.5],a=0,o=0;for(let i of r)for(let e of r){let l=$+i*_,A=g+e*R,W=l*l+A*A;if(W>1)continue;let w=Math.sqrt(Math.max(0,1-W)),b=l*n+A*B+w*t;a+=Math.max(0,b),o++;}return o===0?0:a/o}function C($){let B=0,t=1/0;for(let _=0;_<T.moons.length;_++){let R=T.moons[_],r=Math.abs(R.distance_km-$.size.distanceKm)*1,a=Math.abs(R.libration_elat-$.libration.elat)*1e4,o=Math.abs(R.libration_elon-$.libration.elon)*1e4,i=r+a+o;i<t&&(t=i,B=_);}return T.moons[B]}var j=22/10;function p($,g,n,B){let t=(g%360+360)%360;if(Math.abs(t)<.1)return $;let _=$.split(`
|
|
899
|
+
`),R=_.length,r=_[0]?.length??0,a=n??(r-1)/2,o=B??(R-1)/2,i=t*Math.PI/180,e=Math.cos(i),l=Math.sin(i),A=Array.from({length:R},()=>Array(r).fill(" "));for(let W=0;W<R;W++)for(let w=0;w<r;w++){let b=w-a,x=(W-o)*j,f=b*e-x*l,M=b*l+x*e,y=Math.round(f+a),u=Math.round(M/j+o);if(y>=0&&y<r&&u>=0&&u<R){let E=_[u]?.[y]??" ";A[W][w]=E;}}return A.map(W=>W.join("")).join(`
|
|
900
|
+
`)}function U($,g={}){let B=(g??{}).showHorizon!==false,t=C($),_=I(t.ascii),R=t.ascii;Math.abs(L)>.1&&(R=p(R,L,_.centerX,_.centerY));let r=R.split(`
|
|
901
|
+
`),{sx:a,sy:o,sz:i}=S($.phase.phaseAngleDeg,$.phase.brightLimbAngle,$.phase.isWaxing,$.libration.elat),e=Array.from({length:d},()=>Array(c).fill(0)),l=Array.from({length:d},()=>Array(c).fill(-1)),A=Array.from({length:d},()=>Array(c).fill(false)),W=0,w=0;for(let M=0;M<d;M++)for(let y=0;y<c;y++){let u=y-_.centerX,E=M-_.centerY,m=u/(_.width/2),F=E/(_.height/2),Z=m*m+F*F;if(Z>1){e[M][y]=0,l[M][y]=-1;continue}A[M][y]=true,W++;let z=q(m,F,a,o,i);e[M][y]=z,z>0&&w++;let D=Math.sqrt(Math.max(0,1-Z));l[M][y]=m*a+F*o+D*i;}let b=Array.from({length:d},()=>Array(c).fill(false));if(w>0)for(let M=0;M<d;M++)for(let y=0;y<c;y++)b[M][y]=e[M][y]>0;else {let M=P($.phase.illuminatedFraction??0,0,1),y=Math.max(1,Math.round(M*W)),u=[];for(let E=0;E<d;E++)for(let m=0;m<c;m++)A[E][m]&&u.push({ix:m,iy:E,v:l[E][m]});u.sort((E,m)=>m.v-E.v);for(let E=0;E<Math.min(y,u.length);E++){let{ix:m,iy:F}=u[E];b[F][m]=true;}}let x=[];for(let M=0;M<d;M++){let y="",u=r[M]??"";for(let E=0;E<c;E++)b[M][E]?y+=u[E]??" ":y+=" ";x.push(y);}let f=x.join(`
|
|
902
|
+
`);if($.position?.parallacticAngle!==void 0){let M=-$.position.parallacticAngle;Math.abs(M)>.1&&(f=p(f,M,_.centerX,_.centerY));}return B?O(f,$,_):f}function O($,g,n){let B=g.position;if(!B||g.size.angularDiameterDeg<=0)return $;let t=B.altitude??0,_=g.size.angularDiameterDeg/2,R=t+_;if(t-_>=0)return $;let a=$.split(`
|
|
903
|
+
`),o=g.size.angularDiameterDeg/Math.max(1,n.height),i=n.centerY+t/o;i=Math.round(P(i,0,d-1));let e;return R<=0?e=`${Math.abs(t).toFixed(1).replace(/\.0$/,"")}-deg-below-horizon`:e="horizon",a[i]=$$(e),a.join(`
|
|
904
|
+
`)}function $$($){let n=`--${$.trim().replace(/\s+/g,"-")}--`;if(n.length>c&&(n=n.slice(0,c)),n.length===c)return n;let B=c-n.length,t=Math.floor(B/2),_=B-t;return "-".repeat(t)+n+"-".repeat(_)}exports.getMoonPhase=V;exports.getMoonState=J;exports.renderMoon=U;//# sourceMappingURL=index.cjs.map
|
|
905
905
|
//# sourceMappingURL=index.cjs.map
|