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.
4.5 KiB
Architecture
See CLAUDE.md for build commands and the sharp edges to
know before changing the engine. This document is the visual overview.
Components
res/holds the source assets: the 22 Rider-Waite-Smith Major Arcana card images and A. E. Waite's Pictorial Key to the Tarot PDF (public domain), whichtarot_data.c's card and position text is condensed from.engine/third_party/astronomy/is a vendored, unmodified copy of cosinekitty/astronomy (MIT), pinned to a specific commit — see itsVENDORED.md.engine/src/is the core engine. Everything exceptmain.c,reading.c'sreading_print_text/reading_print_htmlfunctions, andi18n.c's file-loading half is free ofstdio/CLI assumptions, specifically so it can be linked into the Pebble watchapp later without rework.rng.c— deterministic string-seeded PRNG (FNV-1a + splitmix64).tarot.c/tarot_data.c— the Celtic Cross draw and its content.astro.c— natal chart + daily transits, built on the vendored Astronomy Engine.i18n.c— loads akey=valuetranslation file into a small fixed-size catalog; every display-text lookup elsewhere falls back to the built-in English string if no catalog is loaded or a key is missing from it.reading.c— orchestrates the above into oneDailyReadingand (desktop-only) renders it as text or HTML.main.c— CLI argument parsing, the only consumer ofreading_print_*.
engine/i18n/holds the translation source files (en.lang,de.lang, ...), onekey=valuefile per language — seeCLAUDE.mdfor the key-naming convention.dist/is generated bymake: thedeck-enginebinary, a copy of the card art underimg/, a copy of the translation files underi18n/,run.sh, and auser.propertiestemplate that's seeded once and never overwritten by later builds.- The Pebble watchapp does not exist yet. When it's built, it will
call
reading_generate()directly and walk the returned struct to lay out its own screens — it has no reason to touchreading_print_*.
Dataflow
A single reading is produced by one call: reading_generate(seed, birth, utc_moment, &out) in reading.c. It fans out to three independent
computations and combines their results:
astro_compute_natal_chart(birth)→NatalChart— geocentric ecliptic sign/degree for the Sun through Pluto, the Ascendant, and whole-sign houses, all from the birth date/time/location.astro_compute_daily_transits(utc_moment, natal_chart)→DailyTransits— today's planetary positions, the Moon phase, and every transiting-to-natal aspect within orb. Depends on the natal chart (read-only) to compute aspects against it.tarot_draw_celtic_cross(seed)→CelticCrossSpread— ten cards with position and upright/reversed orientation, fully determined by the seed string alone.
These three results are combined into one DailyReading struct, which is
either rendered by reading_print_text/reading_print_html (used by the
CLI) or, in the future, walked directly by watchapp UI code. See
input-output-format.md for the exact fields
and output formats.
Every display string produced along the way (tarot_data.c's card and
position text, astro.c's body/sign/moon-phase/aspect names, and
reading.c's section headers) is looked up in i18n.c's translation
catalog, with the built-in English text as the fallback. main.c loads
the catalog from --lang/--i18n-dir (or run.sh's lang= property)
before calling reading_generate, so this is orthogonal to the three
computations above — it only affects how their results are rendered as
text, not the underlying TarotCard/ZodiacSign/etc. enum values.
Both entry points (direct CLI flags, or run.sh pulling the seed/date
from the OS clock and birth data from user.properties) converge on the
same main.c argument parsing before calling reading_generate — there
is exactly one code path from parsed input to a reading.
Regenerating the diagrams
The diagrams are Graphviz sources in docs/diagrams/, rendered to PNG:
cd docs
dot -Tpng -Gdpi=150 diagrams/architecture.dot -o images/architecture.png
dot -Tpng -Gdpi=150 diagrams/dataflow.dot -o images/dataflow.png

