How this site is built

Moon Data is my own project: I design, build, check and deploy everything on it. This page is the engineering tour: what it runs on, how I make sure the numbers are right, and the choices behind accessibility and privacy.

Jump to: The stack · Getting the sky right · Accessibility · Privacy · Engineering details · Content rules

The stack

C# ASP.NET Core 8 MVC Razor Blazor WebAssembly Entity Framework Core SQLite ASP.NET Core Identity Azure App Service JavaScript SVG & CSS animation Bootstrap

  • Web app: ASP.NET Core 8 MVC with Razor views, a Bootstrap base and a custom space theme built on CSS variables, with self-hosted fonts.
  • Moon Journal: a separate Blazor WebAssembly app, hosted by the main site at /journal/. It installs like a native app, works offline and keeps entries on your device.
  • Data: Entity Framework Core with SQLite for Moon Pulse, sign-in accounts (ASP.NET Core Identity with roles, no public sign-up) and the Band Name Generator's list of names already taken. On Azure the database files live in App Service's persistent storage, so they survive redeploys.
  • Outside services: MusicBrainz for band names (cached, and identified as their rules ask) and Open-Meteo for the birth chart's city search. Public endpoints are rate-limited with ASP.NET Core's built-in limiter.
  • Astronomy: the Sun, Moon and planets come from Astronomy Engine (MIT-licensed). Chiron and four asteroids come from tables downloaded from NASA JPL's Horizons system (1799–2051), interpolated between stored days.

Getting the sky right

I check the calculations against NASA JPL's Horizons system, write the results down, and the pages quote them. The app has small command-line modes that print its own results (for example dotnet run -- list-ingresses 2026 2028), and PowerShell scripts fetch JPL's answers for the same moments and compare the two.

  • Sign changes and retrogrades: for 1960–61, 2023–24, 2026–27 and 2046–47, every sign change JPL lists was found and nothing extra. All are within an hour except one (3 hours), and all 54 retrograde ends are within 2 hours (JPL gives them to the nearest hour).
  • Birth chart: across 1800–2050 the Sun is within 0.53′ of JPL and the Moon within 0.87′ (a sign is 1,800′). The Ascendant is within 1.62′ and the Midheaven within 0.30′ of an independent calculation, since JPL doesn't compute those.
  • Chiron and the asteroids: identical to fresh JPL queries to 0.0001°.
  • Calendar: solstices and equinoxes within 0.1 minute; Western Easter for all 201 years from 1900 to 2100 matches the Royal Observatory of Belgium's table.

The checking has changed the code more than once. The site started with a simpler orbital model; comparing it with JPL showed Saturn up to 47 hours off and Mars's two-day dip into Gemini in February 1961 missed entirely, so I replaced it. The calendar's solstices were up to 10 minutes off with a shorter Sun formula; they're now within 0.1 minute.

Accessibility

  • Motion: animations (the stars, the seasonal tree, the floating decorations) have a prefers-reduced-motion fallback that keeps them still.
  • Pictures that carry information have a text version: the Wheel of the Sky is described for screen readers and has a full table of positions beside it, and the tree's season is announced in a live caption.
  • Keyboard: the calendar's months are tabs you can move through with the arrow keys.
  • Subtitles: silent films with German or Danish title cards have English subtitles (WebVTT), written from the original cards.
  • Colour: colours used for text are checked for contrast against the dark background.
  • Practice: I wrote a 24-exercise accessibility course, each exercise tied to WCAG 2.2 success criteria, for the site's members-only practice area.

Privacy

  • Moon Pulse stores only a date, a mood and an energy level: no IDs, notes, times or IP addresses. Its spam limit holds IP addresses in memory only and never writes them down.
  • Moon Journal entries stay on your device. Sharing a day's mood with Moon Pulse is opt-in, and only yesterday's last entry is shared, once.
  • Birth chart details are used only to draw the chart; they aren't saved anywhere.

Engineering details

A slider that feels instant

Dragging the Wheel of the Sky's year slider moves the Sun, Earth, the planets, the Moon's phase and the tree straight away. The first drag fetches a year of daily positions once (about 48 KB, which the browser keeps for a day), and the page moves everything from that. When you pause for 140 ms, the server's exact wheel for that date replaces the preview, and an AbortController cancels any request a newer one has overtaken.

Placing crowded planets

Planets bunch up in the sky. The wheel lays crowded bodies out in groups, each spread evenly around its average position and merged with the next group if they touch, and bodies at clearly different distances from the Sun are allowed to sit side by side. It replaced a simpler push-apart approach that could leave two bodies on the same spot.

Code exercises that run in the browser

The practice area runs learners' code without a server: Python in a Web Worker with Pyodide, TypeScript type-checked by the real compiler in a worker, and SVG and HTML in sandboxed iframes that can't run scripts. The REST and SOAP course talks to a pretend API server that lives inside the worker. A self-test page runs every exercise's solution (each must pass) and its starter code (each must fail).

Content rules

  • No AI-generated images. Every picture is either public domain (mostly from Wikimedia Commons and library collections, credited on the page) or drawn in code with SVG and CSS.
  • Films are public-domain copies, checked for added modern music and newer restorations, which can carry their own copyright.
  • Facts come from primary texts first, then academic sources; Wikipedia is only a pointer to its sources. Each section keeps a list of its claims and where they come from.

See the results on the Projects page, or get in touch.