Astrology Data Sources and Calculation Methodology
What Zodiux runs on, where each dataset came from, how often it refreshes, and what goes wrong when a refresh does not happen.
Zodiux calls no astrology API. There is no chart service behind it, no licensed data feed, and no vendor whose output we reprint. The whole site runs on four datasets and two pieces of code: an open-source ephemeris, a city list with time-zone names, your browser's own copy of the time-zone rules, a precomputed sky almanac, a corpus of written interpretations, and a published scoring formula. This page names each one, says where it came from, gives its measured size, says how often it changes, and says what it gets wrong. It also states the update record plainly, including the five weeks a scheduled refresh job failed silently and froze the sky on every page it was supposed to keep current.
The six sources, in one table
Read this table first. Everything after it is one of these rows in detail.
Two of the six are code rather than data — the ephemeris computes positions instead of storing them, and the compatibility score is a formula with no dataset behind it at all. Both are listed anyway. A source-transparency page that quietly omits the parts that are not files is not being transparent.
| Source | What it drives | Where it came from | Refresh trigger | Known limitation |
|---|---|---|---|---|
| Astronomy Engine | Every planetary position on the site: birth charts, moon sign, the live sky, retrograde dates | Open-source library by Don Cross, MIT-licensed, copied into this repository as two files | Only when we deliberately update the vendored copy. Never at runtime | The rising-sign step holds the obliquity of the ecliptic at a fixed 23.4367 degrees instead of varying it |
| City list | The birth-city typeahead: latitude, longitude, and which time zone your birth time is read in | Filtered from the GeoNames cities5000 export by a script in this repository | Only when we re-run that script against a fresh GeoNames dump. Not on a schedule | 35,968 cities, so villages and small towns are missing. Coordinates are rounded to two decimals |
| Time-zone rules | Converting your wall-clock birth time into the UTC instant the astronomy needs | The IANA time-zone database, as shipped inside your own browser. Zodiux carries no copy | Whenever your browser or operating system updates. Nothing on our side controls it | We cannot pin its version, audit it, or fix it. Two visitors can hold different releases of it |
| Sky almanac | The Today's sky strip on the 12 sign pages and 32 learn pages | Precomputed at build time from the same ephemeris, one row per day | Rebuilt on every deploy; a scheduled job runs daily at 13:17 UTC | A 150-day horizon. Past it the strip stops claiming a date rather than printing a stale one |
| Interpretation corpus | The written reads on sign, compatibility, decan and learn pages, and inside paid reports | 487 reviewed units committed to this repository, 47 of them hand-authored, the rest machine-drafted against those and gated | Edited unit by unit. Nothing is generated at read time | It is prose about traditional meanings, not a measurement. It cannot be checked the way a longitude can |
| Compatibility model | The four dimension scores and the overall figure on the 78 sign-pair pages | A deterministic formula over element, modality and sign distance. No dataset at all | Changes only if we change the formula, and then every affected page is rewritten in the same edit | On those 78 pages it reads two sun signs and nothing else. See how compatibility scores work |
The last row needs one clarification, because the same word covers two different things. The 78 static pages, one per sign pair, are scored from sun signs alone. The two-chart compatibility calculator is a different model: it computes both full charts in your browser and scores the real aspects between them, so it is reading twenty placements rather than two. Only the first of those is a published formula.
The ephemeris, and what is actually inside it
Planetary positions come from Astronomy Engine, an MIT-licensed open-source library by Don Cross. Every position on Zodiux traces back to it — your birth chart, your moon sign, today's sky, and the Mercury retrograde tracker. There is no lookup table anywhere on the site and no second source that could disagree with the first. What the library is asked for, and what happens to the answer, is set out step by step in how Zodiux calculates a birth chart; this page is about the library itself.
"One library" is accurate but it hides something a source page ought to say: the ten bodies are not all computed the same way. Reading the vendored file, three different methods are in there.
Vendored twice, on purpose, and served from our own origin
The library is committed to this repository in two forms. A minified browser build of 116 KB is served to the calculator and the retrograde tracker. An ES module of 412 KB is imported by the static build that writes these pages. Both are files in this repository, pinned to the same version, and the browser copy is loaded from a path on zodiux.io.
Two files rather than one is a bundling decision, not a second source. The library ships no version string, so “the same version” is not something either of us can check — what is checkable is that both files are committed here, both are fingerprinted, and the positions they produce agree. Nothing in the build enforces that agreement, so it is a property to re-verify rather than a guarantee to lean on. The reason it is vendored at all is that a third party then cannot change what your chart says, and an outage elsewhere cannot take the calculator down.
It also makes the numbers checkable, which is the only claim on this page that you can test without our cooperation. Take a birth moment, convert it to UTC, ask any ephemeris you trust for the apparent geocentric ecliptic longitude of a body, and compare. If your answer differs from ours by more than rounding, one of us has a bug and we would like to know which: hello@zodiux.io. That offer means something only because the code on both sides of it is readable — a hosted chart API's approximations are not something you can inspect.
Three models under one interface
- Mercury through Neptune are evaluated from VSOP87, the analytical planetary theory — a long trigonometric series in time. Eight of the ten bodies take this path.
- Pluto does not. It is too poorly modelled by that kind of series, so the library carries a table of 51 precomputed state vectors and runs a small gravitational integrator between them. The table spans roughly the year 1 CE to the year 3999; outside that range the library extrapolates from the nearest end rather than refusing, which is worth knowing if you ever push a chart past those dates.
- The Moon has its own lunar series again, distinct from both — which is appropriate, because it is the fastest-moving body on the chart and the one an approximation would hurt most.
- Underneath all three sits a ΔT model — the Espenak and Meeus polynomial — which converts between the uniform timescale the theories are written in and the Earth-rotation time your birth certificate was written in. That correction is tens of seconds for a twentieth-century birth and grows the further back you go.
None of that changes an answer you would notice at the 30-degree resolution of a zodiac sign. It is here because "which ephemeris" is the question this page exists to answer, and "Astronomy Engine" on its own is only two-thirds of the answer.
The city and time-zone dataset
The birth-city box is a typeahead over a single file in this repository, built from the GeoNames cities5000 export by a script that lives beside it. The raw GeoNames dump is not committed; only the compact file the browser loads is.
The selection rule is a deliberate choice rather than a default, so it is worth stating exactly. The generator keeps every city in the world with a population of 20,000 or more, plus every place with a population of 5,000 or more in the United States, Canada, the United Kingdom, Australia, New Zealand and Ireland. That second clause exists because a flat 20,000 threshold drops a great many American and British towns that people actually name as a birthplace. The script also evaluates three rival thresholds on every run and prints their row counts and file sizes next to the chosen one, so the trade-off is visible rather than assumed.
What the shipped file contains, counted from the file itself
- 35,968 cities, each one row of six tab-separated fields: name, country code, region, latitude, longitude, and an index into a shared list of time-zone names.
- 326 distinct IANA time-zone names across 208 country codes.
- Rows sorted population-descending. That ordering is the typeahead's ranking — type Springfield and the most populous one comes first, because the file is already in that order and nothing re-sorts it at runtime.
- The region field is populated on 10,326 rows only — the US, Canada and Australia, where GeoNames supplies a clean short state code. Elsewhere it is deliberately blank rather than filled with an opaque administrative number.
- Coordinates rounded to two decimal places, about 1.1 km at the equator. What that rounding is worth against the other errors in a chart is measured in the rising-sign error budget on how a chart is calculated.
- 1.25 MB uncompressed, 511 KB gzipped, 373 KB with brotli. It is not requested until you first focus the city field, so it never sits on the critical path of any page.
The dataset carries no time-zone rules. It carries one zone name per city — America/Chicago, Asia/Kolkata — and the actual UTC offset for your birth date is resolved by your browser's own copy of the IANA time-zone database, through the standard date-formatting API. That split is the single most consequential architectural decision on this page, and it cuts both ways: Zodiux inherits every historical daylight-saving correction your operating system receives without us shipping an update, and Zodiux cannot pin a version, audit a rule, or fix a case the database gets wrong. Two people on different devices can in principle be running different releases of it. What that database does and does not know is covered on birth time, time zones and DST.
The daily sky almanac
The Today's sky strip that sits at the top of the 12 sign pages and 32 learn pages is baked into the HTML at build time. That is good for crawlers, which get real content instead of an empty container, and it used to be the site's most embarrassing accuracy problem. A baked strip is correct only on the day it was built, and only the homepage loaded the ephemeris needed to correct one. The homepage therefore showed the live sky while 44 other pages asserted a months-old one.
Shipping a 116 KB ephemeris to every page to refresh a decorative strip would have been a poor trade. So the build precomputes an almanac instead: one row per day for the next 150 days, written to a plain script file. Each row is seven values — moon phase index, moon sign index, phase fraction, a Mercury retrograde flag, Mercury's sign index, the Sun's sign index, and the date the current Sun season ends. Sign and phase names are stored once as separate arrays and referenced by index, which is why the whole file is 4.5 KB, about 1.1 KB gzipped.
What happens when you open one of those pages
- The page arrives with a baked strip and the ISO date it was baked on, held in a data attribute so nothing has to parse the human-readable stamp.
- A 3.4 KB script — 1.6 KB gzipped — compares that date with today. If the page was built today, it returns before touching the DOM and costs nothing at all.
- Otherwise it indexes into the almanac by your own calendar day — the rows are computed for midday UTC, but the lookup counts days in your local time zone — reads today's row, and rewrites the moon phase, moon sign, Mercury status and sign, Sun season and the visible stamp in place.
- If today falls outside the 150-day horizon, or the almanac file is missing, the strip drops its date claim entirely, relabels itself a snapshot, and links to today's sky instead.
That last step is the one worth noticing. The failure mode was chosen deliberately: stop asserting a date we cannot support, rather than print one that is wrong. A stale claim of freshness is worse than an admission of staleness.
Two things the almanac is not. It is not the ephemeris — it holds no positions, only the handful of derived facts the strip displays, which is why it fits in a kilobyte. And it does not cover every page: the decan pages, the compatibility pages and the live sky page carry no strip and no almanac, so nothing on them self-corrects between deploys.
Retrograde dates are computed, not stored
The Mercury retrograde tracker stores no dates. It has no table of periods, no annual list someone typed in, and no API call. It runs the vendored ephemeris in your browser and finds the stations itself, which means the page has no data source to name — only a method.
The method is short enough to describe completely. Starting 220 days before the moment you loaded the page, it takes 651 daily samples of Mercury's ecliptic longitude, ending about 430 days ahead. For each sample it subtracts that day's longitude from the next day's, wraps the difference into the range minus 180 to plus 180 degrees, and marks the day retrograde when the result is negative — Mercury losing ground against the zodiac. Consecutive retrograde days are paired into periods, the period containing the current moment becomes the yes-or-no answer at the top of the page, and the table lists every period whose end is no more than 45 days in the past. A typical 651-day scan finds about six retrograde periods of 20 to 24 days each; the table shows the four or five of them that have not already ended more than 45 days ago.
The same one-day differencing decides the retrograde marks on your birth chart and on the live sky page, for every body except the Sun and Moon, which are hard-coded as never retrograde because from Earth they never are. One detail differs and is easy to get wrong: the tracker differences forward, comparing a day with the next one, while the chart and the sky strip difference backward, comparing the birth instant with twenty-four hours earlier. Both answer "is it retrograde"; they just straddle the instant from opposite sides.
What day-resolution sampling costs, measured
Because the scan steps a whole day at a time, a station is located to within about a day rather than to the hour. That is easy to say and worth actually measuring, so we replayed the tracker's exact loop against the true stations, found by narrowing in on the instant Mercury's motion crosses zero.
Across the eleven stations in a scan run in August 2026, the reported date landed between 0.6 and 10.9 hours from the true station, averaging 5.5 hours. In every one of those eleven cases the reported calendar date was still the correct one. The sampling is coarse, but on this body at this cadence it is not usually wrong.
There is a second-order effect that is more interesting, because it is visible to two readers comparing notes. The scan is anchored to the moment you load the page, not to midnight, so the grid of sample instants shifts with your visit. Take the retrograde that begins 24 October 2026 at 07:15 UTC and ends 13 November at 15:52 UTC. Both stations fall inside a day rather than on its edge, so the sample either side of the turn can land on one date or its neighbour depending on where the grid happens to sit when you load — and the printed dates are then formatted in your own time zone, which can move a near-midnight station by another day on top of that. We are not going to publish a threshold hour for the flip, because there is not one: it depends on your load time and your offset together, so two readers can see different dates for the same station at the same instant. Same code, same sky, a one-day disagreement with two independent causes.
The interpretation corpus
Everything above is measurement. The written reads — what Venus in Aries means, what a Leo and Scorpio pairing tends to run into, what a decan is about — are not, and what Zodiux does not claim is the page that argues why that distinction matters. What belongs here is the narrower question: what the corpus physically is, how big it is, and where each part of it ends up.
It is 487 reviewed units across six surfaces, all of them JSON files committed to this repository: 120 planet-in-sign reads, 120 planet-in-house reads, 105 aspect reads, 78 sign-pair compatibility reads, 36 decan reads and 28 learn-topic reads. 47 of those are hand-authored exemplars. They are not extra — each one is a member of the 487 that a person wrote directly, and it does double duty as the voice reference for its surface and as the shipped text for that slot.
The 487 do not all travel the same road, and the split is a deliberate size decision rather than an editorial one.
| Surface | Units | Bundled into | Reaches you as |
|---|---|---|---|
| Planet in sign | 120 | The Worker module | A paid report, rendered server-side |
| Planet in house | 120 | The Worker module | A paid report, rendered server-side |
| Aspect | 105 | The Worker module | A paid report, rendered server-side |
| Sign-pair compatibility | 78 | Read at build time | Static HTML on the 78 compatibility pages |
| Decan | 36 | Read at build time | Static HTML on the 36 decan pages |
| Learn topic | 28 | Read at build time, then discarded | None — the editorial library owns all 32 /learn/ URLs, and the builder drops every corpus slug the library covers, which is all 28 |
The three report surfaces — 345 units — are bundled into a single ES module the Worker imports, because a paid report is assembled on request and needs them in memory. The other 142 are read by the page builder at build time and never enter the Worker bundle at all, which keeps the edge deployment small. The build is fail-closed on this: with the corpus files missing it emits no pages and no sitemap entries rather than shipping empty ones.
The part people most want stated plainly: 47 units were written by a person, and the remaining 440 were drafted by a language model at build time against those exemplars and a fixed brief, then mechanically linted, judged by a different and stricter model, checked for near-duplicates, and signed off by a person before entering the reviewed files. The lint and the judge are code you can read — the banned-phrase list rejects the stars, the universe, cosmic energy, manifest, divine and fixed-fate constructions like you will meet — and the judge scores voice, specificity, thinness and safety independently and defaults to failing. Editorial standards and corrections is where that brief, that pipeline and the human gate are set out in full, including what machine assistance does and does not extend to.
One thing is true of all 487 regardless of who drafted them: none of it runs at read time. There is no model call when you load a page and none when you run a chart. The text is static by the time it reaches you, which is what keeps the site free, fast, and able to work with the network gone.
What Zodiux does not use
The absences are part of the answer, so here they are.
Sources that are not in the stack
- No astrology API. No third-party chart service computes anything on this site.
- No licensed ephemeris data. The library is MIT-licensed and readable, and its output is not resold to you as proprietary.
- No third-party dependency for the maths. The engine, the city list and the almanac are all served from zodiux.io. Advertising and web fonts are loaded from other origins, as any reader can see in a network panel — but nothing the astronomy depends on is, so an ad blocker or a font outage cannot change a single degree in your chart.
- No house-system data, because the free chart draws no house cusps and takes no position on Placidus versus Whole Sign versus Koch.
- No user data in any dataset. The corpus is written against enumerated placements — ten planets, twelve signs, twelve houses — never against anything a visitor typed. Your birth details are not corpus input, not training data and not analytics fodder; where they do and do not travel is set out on data, privacy and saved chart links.
Update cadence, and what breaks when a refresh fails
The sources here change on very different clocks, and conflating them would hide the one that actually goes wrong.
The ephemeris and the city list are pinned files. They change when a person deliberately updates them and at no other time — no automatic upgrade, no background fetch, no version that can shift under you between two visits. The time-zone rules are the opposite: they live in your browser and update on your operating system's schedule, entirely outside our control. The sky data is the part on a timer, and it is the part that has failed.
| What | Trigger | Cadence | What you see if it fails |
|---|---|---|---|
| Ephemeris library | A deliberate version bump, committed | No schedule | Nothing. The pinned copy keeps computing |
| City and time-zone list | Re-running the generator against a new GeoNames dump | No schedule | A recently-grown town may be missing from the typeahead |
| Sky strip on the 44 baked pages | A scheduled rebuild and deploy, plus the client-side almanac | Daily at 13:17 UTC, with a 150-day client-side buffer | The strip self-corrects for up to 150 days, then relabels itself a snapshot |
| The live sky page | Recomputed in your browser on load; the baked copy is the fallback | Every visit | Falls back to the last deploy's positions, with a visible date showing how stale they are |
Here is the failure, stated plainly, because a transparency page that lists only successes is marketing. The scheduled refresh job failed on every run from 6 July 2026 onward, because the deploy credential it needed had never been set. It failed quietly. The live sky froze at 5 July and was still frozen six weeks later, on 17 August, with the credential still unset — while the homepage, which computes the sky in the browser, carried on showing the correct one. Anyone comparing the two pages would have caught it in seconds; nothing in the system was watching, which is the actual defect. The bug was never in the astronomy.
Three things changed as a result, in August 2026. The job now fails loudly with a named cause instead of an authentication stack trace. The cadence moved from weekly to daily, because the strip reports the Moon's phase and sign and those change every day, so a weekly rebuild was wrong six days in seven by construction. And the almanac described above now lets 44 baked pages self-correct in the browser, so a missed deploy degrades gracefully instead of freezing.
The live sky page used to be the exception, and this page said so for as long as it was true. It is now the opposite: /sky/ ships the full browser build of the ephemeris and a script that recomputes the ten-body table, the orrery, the retrograde list and the timestamp in your browser on load, so what you read there is current even when a deploy is not. The baked copy is the fallback rather than the product, and the page still prints a date so a failure of the live path is visible rather than silent. The last-reviewed date at the foot of this page is derived differently again, from a content hash rather than a build timestamp; editorial standards sets out that derivation.
Method. Every figure on this page was read out of the shipped source rather than estimated. City, zone, country and region counts come from evaluating the dataset file the browser downloads and counting its rows; the selection rule and the rival thresholds come from the generator script that wrote it. The three planetary models, the Pluto state table's span and the time-scale correction were read out of the vendored library. File sizes were measured on the shipped files, uncompressed and then gzipped and brotli-compressed. The almanac's horizon, row shape and fallback behaviour come from the build module and the client script that consumes it. The list of which pages carry the sky strip was produced by searching the built output, not assumed from the templates. The retrograde station errors and the load-time effect were measured by replaying the tracker's own loop against stations located by bisection. Corpus counts come from counting the arrays in the reviewed corpus files, and the bundling split from the build script that writes the Worker module. The refresh cadence, the failure window and its cause come from the scheduled job's own configuration.
Limits. This page says where the numbers come from, not what they mean. It cannot tell you whether an interpretation is true, because interpretations are not the kind of claim that has a source you can check — only the astronomy is. It describes the free tools; a paid report is rendered on the server and is covered by the privacy policy. And the counts here are true of the code as shipped on the date at the foot of this page. If a dataset is regenerated the figures move, and this page is meant to move with them. If you find a number here that no longer matches the site, that is a mistake and we want to hear about it at hello@zodiux.io.
Sources.
- Astronomy Engine — MIT-licensed open-source ephemeris by Don Cross. VSOP87 for Mercury through Neptune, a 51-state numerical integrator for Pluto covering roughly 1 CE to 3999 CE, a separate lunar series, and the Espenak–Meeus ΔT polynomial. Vendored twice — a 116 KB minified browser build and a 412 KB ES module — so the calculator and the static build compute from identical code.
- GeoNames — The cities5000 export is the upstream for the birth-city dataset. The raw dump is never committed; a script in the repository filters it to 35,968 places, packs them into 326 shared zone names, and writes the single file the browser lazy-loads.
- IANA Time Zone Database — Supplies the historical UTC offset for your birth date and place, reached through your browser's own standard date-formatting API. Zodiux ships no time-zone rules of its own, inherits every update your system receives, and cannot pin or audit the version you are running.
- The Zodiux interpretation corpus — 487 reviewed units across six surfaces, committed as JSON in this repository. 345 are bundled into the Worker module that renders paid reports; the other 142 are read at build time into static pages. Nothing is generated at read time.
- The scheduled sky refresh job — A daily rebuild-and-deploy at 13:17 UTC. Its configuration is the source for the cadence, for the failure window beginning 6 July 2026, and for the missing-credential cause stated above.
Written and reviewed by the Zodiux editorial team · Last reviewed · Editorial standards and corrections · Astrology is for reflection and entertainment, not advice.
See the sources produce something
A chart is the shortest way to check this page. It runs the vendored ephemeris in your browser, against the city list described above, and your birth details never leave the device — though pressing the button does send a one-line counter ping saying a chart was run.
Does Zodiux use a third-party astrology API?
No. There is no chart service, no ephemeris API and no licensed data feed anywhere in the stack. Positions are computed by an open-source library copied into the site's own repository and served from zodiux.io, both in your browser and in the static build. Nothing about your chart depends on another company staying online or keeping its numbers the same.
Where does the city list come from, and why is my town missing?
It is filtered from the GeoNames cities5000 export: every place in the world of 20,000 people or more, plus every place of 5,000 or more in the US, Canada, the UK, Australia, New Zealand and Ireland. That leaves 35,968 cities, so smaller towns and villages are genuinely absent. Pick the nearest listed city in the same time zone — the coordinates only affect your rising sign, and they affect it weakly, while the time zone affects how every hour you typed is read.
How often does the sky data update?
The site rebuilds and redeploys on a daily schedule at 13:17 UTC, which recomputes the sky baked into every page. On top of that, the 12 sign pages and 32 learn pages carry a 150-day almanac and correct their own Today's sky strip in the browser, so they stay right even if a deploy is missed. The live sky page is the exception: its ten-body table is baked with no client-side fallback, and it prints the date it was built so you can see how fresh it is.
Are the retrograde dates on the tracker exact?
They are accurate to about a day, not to the hour, because the scan samples Mercury's position once every twenty-four hours rather than solving for the exact station. Measured against true stations, the printed dates landed within eleven hours in every case we checked, and on the correct calendar date. The scan is anchored to the moment you load the page, so a station falling near the edge of your day can print one day earlier or later than a visit at a different hour would show.
Which parts of the writing were drafted by a machine?
Of the 487 interpretation units, 47 were written by a person and the remaining 440 were drafted by a language model at build time against those exemplars and a fixed brief, then linted, judged by a different and stricter model, de-duplicated and signed off by a person before publication. No model runs when you load a page, and no number on the site comes from one — positions come from the ephemeris and scores from a published formula. Editorial standards and corrections covers the full process.
Does my birth data go into any of these datasets?
No. The corpus is written against enumerated placements — ten planets across twelve signs and twelve houses — and never against anything a visitor typed. Nothing you enter is added to any file described on this page, used to train anything, or kept as a source. What does happen to your birth details, and what a shared chart link carries, is covered on data, privacy and saved chart links.
Can I check any of these numbers myself?
Yes, and that is the point of naming the sources. The ephemeris is open source, so any figure it produces can be reproduced in a different implementation of the same algorithms. The compatibility formula is published table by table. The counts on this page came from counting rows in the files the site actually ships. If you get a different answer from ours, email hello@zodiux.io — corrections get made and dated.