Plain-C, dependency-free engine that produces a personalized daily Celtic Cross tarot spread and natal-chart/transit astrology reading, plus a standalone CLI (dist/deck-engine) and run.sh wrapper. Includes English/German output via a simple key=value translation format, and docs/diagrams describing the architecture and I/O.
6.6 KiB
Input & output formats
See architecture.md for how these fit together.
There are two ways to provide input (direct CLI flags, or run.sh +
user.properties) and two output formats (text, html); the
DailyReading struct is the programmatic form both outputs are rendered
from, and the one the future watchapp will consume directly.
Input
Direct CLI flags (dist/deck-engine)
deck-engine --seed <string> --birth-date YYYY-MM-DD --birth-time HH:MM
--birth-utc-offset <hours> --birth-lat <deg> --birth-lon <deg>
[--date YYYY-MM-DDTHH:MM] [--format text|html]
| Flag | Required | Format | Meaning |
|---|---|---|---|
--seed |
yes | any string | Tarot seed. The same seed always produces the same 10-card spread, positions, and orientations (see rng.c/tarot.c). |
--birth-date |
yes | YYYY-MM-DD |
Birth date, local calendar. |
--birth-time |
yes | HH:MM (24h) |
Birth time, local clock. |
--birth-utc-offset |
yes | decimal hours, e.g. 2 or -5.5 |
Hours to subtract from local birth time to get UTC (e.g. 2 for CEST). |
--birth-lat |
yes | decimal degrees | Birth latitude, north positive. |
--birth-lon |
yes | decimal degrees | Birth longitude, east positive. |
--date |
no | YYYY-MM-DDTHH:MM[:SS] |
UTC moment used for today's transits and as the moment the tarot seed is drawn against. Defaults to the current system time. |
--format |
no | text | html |
Output format, defaults to text. |
--lang |
no | language code, e.g. en, de |
Reading language, defaults to en. Matches a file named <code>.lang in --i18n-dir (see "Translations" below). Unknown codes or missing files fall back to English with a warning on stderr. |
--i18n-dir |
no | path | Directory to look for <lang>.lang in. Defaults to an i18n/ directory next to the binary itself (resolved from argv[0], so dist/deck-engine finds dist/i18n/ regardless of the caller's working directory). |
Birth latitude/longitude only affect the Ascendant/houses — planet signs are geocentric and location-independent.
run.sh + user.properties
dist/run.sh [text|html] [lang] wraps the binary for daily use:
-
Seed and
--datecome from the OS clock:date +%Y-%m-%d(stable all day) anddate -u +%Y-%m-%dT%H:%M. -
Birth data and language are read from
dist/user.properties, akey=valueproperties file next to the script (#-prefixed lines and blank lines are comments; whitespace around=is trimmed):birth_date=1990-05-14 birth_time=14:32 birth_utc_offset=2 birth_lat=52.5200 birth_lon=13.4050 lang=enThe file is seeded once from
engine/scripts/user.properties.templatewith placeholder values (YOUR_BIRTH_DATE_HERE, etc.) and is never overwritten by later builds.run.shchecks every birth field for an empty value or a leftoverYOUR_placeholder and refuses to run with a clear error until the file is filled in;langhas no such check since it always has a usable default (en). -
The optional second argument overrides
lang=for a single run without editing the file, e.g.dist/run.sh html de.
Translations (--lang, dist/i18n/)
Every piece of display text — planet/sign/moon-phase/aspect names, tarot
card names and meanings, Celtic Cross position names, and the section
headers in the text/html output — is looked up in a translation
catalog with the built-in English text as the fallback for any key the
catalog doesn't have. See CLAUDE.md's "Translations" section for the
key-naming convention and how to add a new language.
engine/i18n/en.lang and de.lang are the shipped translation files;
make copies engine/i18n/*.lang to dist/i18n/ (refreshed on every
build, like dist/img/). Adding a language is just dropping another
<code>.lang file into engine/i18n/ — no code changes needed.
Output
DailyReading (the real output — reading.h)
reading_generate() is the actual API; text/html below are just two
ways of rendering the struct it fills in. This is what the watchapp will
read directly once it exists.
typedef struct {
NatalChart natal;
DailyTransits transits;
CelticCrossSpread spread;
} DailyReading;
NatalChart(astro.h):bodies[10](Sun..Pluto, each a sign + degree-in-sign + raw ecliptic longitude),ascendant_longitude,houses[12](whole-sign:houses[0]is the Ascendant's sign).DailyTransits(astro.h):bodies[10](today's positions, same shape as above),moon_phase(one of 8 named phases),aspects[]+aspect_count(each aspect names a transiting planet, a natal planet, anAspectType— conjunction/sextile/square/trine/opposition — and the orb in degrees).CelticCrossSpread(tarot.h):positions[10], indexed byCelticCrossPosition(Present, Challenge, Crown, Foundation, Recent Past, Near Future, Attitude, Environment, Hopes and Fears, Outcome — Waite's own drawing order), each holding aTarotCardand areversedbool.
--format text
Four =====-delimited sections, in order: natal chart (each body's sign
- degree, then the Ascendant), today's sky (Moon phase, then each body's
transiting position), today's aspects to the natal chart (one line per
aspect, with orb), and the Celtic Cross (one block per position: name,
card,
(Reversed)if applicable, the position's meaning, then the card's meaning).
===== Natal Chart =====
Sun 23.5° Taurus
Moon 15.2° Capricorn
...
Ascendant 18.4° Pisces
===== Today's Sky =====
Moon phase: Waning Gibbous
Sun 11.5° Cancer
...
===== Today's Aspects to Natal Chart =====
Transiting Sun Opposition natal Moon (orb 3.7°)
...
===== Celtic Cross =====
The Present The High Priestess (Reversed)
This covers him: the general influence affecting the matter.
Passion, moral or physical ardour, conceit, surface knowledge.
...
--format html
A single self-contained HTML page (inline <style>, no JS, no external
requests) with the same four sections, plus each of the 10 Celtic Cross
cards rendered as an image:
<img class="reversed" src="img/RWS_Tarot_02_High_Priestess.jpeg" alt="The High Priestess">
src="img/<file>"is relative to the HTML file's own location — it expects to sit next to animg/directory, exactly likedist/reading.htmlnext todist/img/(whichmake imagespopulates fromres/img/). Saving the HTML output anywhere else breaks the image links.- Reversed cards get
class="reversed", styled withtransform: rotate(180deg)in the page's inline CSS.