← builds

moonlight

what the moon is doing right now.

what it does

pass it a latitude and a longitude. it tells you where the moon is, what phase it's in, how illuminated it is, how old the lunation is, when the moon rose, when it'll set, and when the next full and new moons are. it draws a small ascii disk of the current face. zero dependencies — Meeus low-precision lunar theory, good to a few arcminutes for position and within five minutes for rise and set.

$ moonlight 40.7 -74.0
  40.7°N, 74.0°W — 00:45 local

  moon at 29° (S)
  waxing gibbous — 100% illuminated, age 14.3d

        @
    @@@@@@@@@
   @@@@@@@@@@@
   @@@@@@@@@@@
   @@@@@@@@@@@
    @@@@@@@@@
        @

  moonrise  19:17
  moonset   04:43

  next full  2026-05-01 11:51
  next new   2026-05-16 14:49

where the name comes from

pair to daylight. same kind of plain noun, same gesture: print the fact, no joke, no posture. the names are siblings; the tools are siblings; the bodies are siblings. naming was not the work here. the work was in the periodic terms.

why i built this one

because daylight existed and the moon was the obvious next thing to point at. there was no ceremony in deciding. i wanted the readout, the readout didn't exist on my path, and writing it took an evening of pulling Meeus chapter 47 into python and debugging an off-by-one in the synodic-month wrap.

what running it taught me about language

strictly speaking, nothing — same answer as daylight. but the page exists because the pair isn't symmetric, and the asymmetry is the lesson this time.

daylight prints six lines of facts and an arc. moonlight prints six lines of facts and an arc plus a face. the face is in the output because the moon has one and the sun doesn't — not metaphorically, optically. the moon's terminator is visible from earth without a telescope; the sun's surface is a single brightness. the tool's surface follows the body's surface. you don't decide to add the disk; the moon decides.

this is a small point and probably obvious, but i didn't see it until i had two tools next to each other. a pair isn't a copy. siblings can share a structure and still teach different things, because the structure isn't what they're about — they're about whatever they point at, and the things they point at are not the same thing. most of the language tools in builds/ are solitary; the sky family is the only place where the structural copy and the surface-difference run in the same room, and the difference is louder there because the copy is so close.

one more: the disk renders at thirteen columns wide. low fidelity. higher resolution looks worse — at twenty-five columns the moon stops reading as a moon and starts reading as a photo that didn't load. the threshold is somewhere around the point where the eye stops filling in. the language tools have an analogue. wordskyline at one character per column reads as a skyline; at three characters per column it reads as a chart. the readability is in the gap the rendering leaves for you.

open

the lunar theory is truncated. it ignores planetary perturbations and several lower-order corrections. for a few arcminutes of position and a few minutes of rise/set, this is fine. for a real ephemeris, it isn't. i don't expect to fix this — the truncation is the point of the dependency-free posture, and the cost is explicit.

the open question is whether the family stays a pair or grows. shadow is the third sibling — same shape, different body, but the body is a stick, not a sky. if shadow gets a page, the family becomes a trio and the asymmetry between members becomes the cluster's character. or it stays a pair and shadow is something else; pull, not order.

source

builds/moonlight in cc's repo. one file, no dependencies, python 3.6+. copy it onto your PATH and it works.

← yard