This is the fourteenth post in the LocalPapa Notes dev-log series.
The previous post on Zi Wei Dou Shu spent a lot of space explaining how to build a divination service architecture from the ground up. This one is about the opposite: when an architecture has been validated, the right move for the next service is to copy it wholesale.
What is Da Mo Yi Zhang Jing?
Da Mo Yi Zhang Jing (also known as the Palm Classic) is a folk divination system — you input your birth year, month, day and hour, and each unit maps to one of twelve "Palm Stars" (fixed to the twelve Earth Branches). The four pillars each carry a Palm Star: the year pillar shows root nature, the month pillar shows personality and middle years, the day pillar covers adulthood, and the hour pillar covers later life.
Compared to Zi Wei Dou Shu, the calculation is much simpler: no stem derivation, no flying star four-transformations, just Earth Branch → Palm Star mapping plus a mod12 placement rule. But its "fun factor" is just as high — the twelve stars have vivid names (Heavenly Noble, Heavenly Loner, Heavenly Blade, Heavenly Calamity…), and the year pillar's "past-life root nature" is something many users go back to read multiple times.
The first decision: copy, don't redesign
Before writing a line of code, the decision was made: deliberately copy Zi Wei Dou Shu's three-layer architecture wholesale, without redesigning it.
`` build_yizhang_okf.py → static knowledge layer (OKF Markdown) → yizhang-interpret.js (browser interpretation data) yizhang-engine.js → dynamic computation layer (chart calculation) yizhang.html → presentation layer (rendering and i18n) ``
A few reasons for this:
- A validated architecture doesn't need revalidating. Zi Wei's "generator holds knowledge, dual-output (OKF + interpret.js), engine is pure computation, page only looks up and assembles text" had already been built, debugged, and proven.
- Consistency makes maintenance easier. When two divination services look the same, a future maintainer (including an AI) who sees the second one already knows how it works.
- Maximum reuse, minimum new code. Not copying the architecture means rewriting it — and the only good reason to rewrite is "this problem is different." It wasn't.
The single most important DRY decision: no second lunar table
yizhang-engine.js needs to convert a Gregorian birth date to the lunar calendar to know the year, month and day Earth Branches. That requires a 1900–2100 lunarInfo compressed table — which already exists in the Zi Wei engine.
Decision: don't copy that table into yizhang-engine.js. Instead, load ziwei-engine.js first on the page, then call window.ZiweiEngine.solarToLunar.
This saves only a few kilobytes, but the principle behind it matters: duplicate data is two places to go wrong. If there's a boundary-date bug in the lunar table, you'd have to fix it in two places. Worse, the two copies can silently drift apart — you fix one and forget the other, and suddenly the same birthday gives different lunar dates in two different services. Users think it's a bug; it's actually version skew between two identical tables maintained separately. DRY here isn't a style preference; it's a guard against silent errors.
The chart algorithm: four pillars, mod12
The Yi Zhang Jing placement rule is elegant precisely because it's simple — core is just mod12:
``` Twelve Palm Stars fixed to Earth Branches: 子=Heavenly Noble 丑=Heavenly Calamity 寅=Heavenly Authority 卯=Heavenly Breaker 辰=Heavenly Cunning 巳=Heavenly Arts 午=Heavenly Blessing 未=Heavenly Wanderer 申=Heavenly Loner 酉=Heavenly Blade 戌=Heavenly Craft 亥=Heavenly Longevity
Four-pillar placement: Year palace = birth year Earth Branch (direct) Month palace = (year EB index + birth month - 1) mod 12 Day palace = (month EB index + birth day - 1) mod 12 Hour palace = (day EB index + birth hour EB index) mod 12 ```
Four mod12 operations, four stars. Compared to Zi Wei's flying-star transformations, this is almost arithmetic.
Verification is equally simple: find a few reference charts (family members, public figures) and compare the engine output to hand calculation. Unlike Zi Wei, there are virtually no "different schools disagree on this part" issues in the core computation — the twelve stars map to twelve branches, and that mapping is fixed.
The interpretation layer: year pillar as root, Six Paths as past lives
Laying out the chart is just placing the four stars. The interpretation layer is what makes users actually engage.
The central emphasis in Yi Zhang Jing is the year pillar — it represents your "past-life root nature," the baseline you bring into this life. The other three pillars cover personality and experiences in youth/middle age/adulthood/later years.
A richer layer is the "Six Paths" (六道) classification: the twelve Palm Stars are grouped into six paths (Heavenly Path, Human Path, Asura, Animal, Hungry Ghost, Hell Realm), and your year-pillar star's group is said to indicate your previous life's trajectory. This layering makes the interpretation richer — twelve stars, six groups, the year pillar now carries both a star-level meaning and a group-level meaning.
But honest labelling is required here: Six Paths groupings are "one school's view," and different traditions vary. The page carries a note: "this Six Paths classification follows one traditional reading; schools differ." The OKF star pages note this too. We're not presenting it as the one authoritative answer.
Five-element interaction: do the verifiable things first
The second dimension of the interpretation layer is Five-Element analysis across the four pillars — which pillar's element is dominant, which is absent, whether adjacent pillars are in a generative or controlling relationship.
This was built after the Six Paths layer, for a reason worth stating: do the verifiable things first. Earth Branch → Five Element mapping (寅卯木, 巳午火, 申酉金, 亥子水, 辰戌丑未土) is fixed, undisputed. The generative/controlling cycle (Wood→Fire→Earth→Metal→Water→Wood) is equally fixed.
The calculation uses modular arithmetic: Five-Element sequence [Wood Fire Earth Metal Water], and for adjacent pillars a and b, d = (idx_b - idx_a + 5) % 5 gives: 0 = same, 1 = a generates b, 2 = a controls b, 3 = b controls a, 4 = b generates a. Pure arithmetic, cross-verifiable, no school settings needed — which is why this was built before annual fortune (annual fortune has too many competing school variants to be verifiable).
School settings: turn disclaimers into options
There are two variant points in Yi Zhang Jing that actually change the chart result:
- Night-Zi hour rollover: The hour from 11pm to midnight is "Zi hour" — some schools attribute it to the current calendar day, others to the next.
- Leap-month assignment: An intercalary lunar month — does it count as the month before or the month after?
Rather than a footnote saying "different schools vary slightly, for reference only," we turned both into user-selectable options. Pick your school, and you know exactly which set of rules produced your chart — that's more honest and more useful than a vague caveat.
The school option labels live in build_yizhang_okf.py's output (yizhang-interpret.js), and the page builds the <select> dynamically from YizhangInterpret.schools via initSchools(). Language switching preserves the selection and rebuilds the option text. No option text is hardcoded in the HTML — the same principle as Zi Wei's "star names fixed in Chinese, other labels follow the language."
Annual fortune: label the method, then build it
Annual fortune is a high-demand feature and also the most school-dependent one. Yi Zhang Jing's various traditions disagree on how annual luck should be calculated, and picking any one version without documenting it risks looking like "we invented our own algorithm."
Solution: pick a verifiable method, then document it explicitly. We chose "annual Earth Branch Palm Star method" — each year's Earth Branch directly maps to a Palm Star (the star↔branch table already exists), and the year's relationship to your birth-year pillar branch (conflicting / combining / triple-combining / same) determines good/neutral/challenging. Pure computation, traceable tradition, cross-verifiable with known years.
The page labels which method is being used; the OKF annual.md documents the calculation. Users know exactly what rules produced their reading — not a black box that outputs "2026 will be good for you."
What this service really teaches
Zi Wei Dou Shu taught how to build a divination service architecture. Yi Zhang Jing taught something different: a validated architecture should be copied, not affectionately redesigned.
"Design flair" is a liability here. Building the second service with a slightly different three-layer architecture — because the first one felt too plain, or because it's tempting to do something new — creates two slightly different three-layer architectures to maintain in parallel. The cost of that drift compounds indefinitely. It outweighs the momentary satisfaction of "not copying."
What we learned
- Copy validated architecture. Resist the engineer's impulse to redesign each time. Consistency compounds in your favour.
- DRY prevents silent errors, not just redundancy. Two copies of the lunar table means two divergence points — one day they drift and nobody notices until users get conflicting results.
- Do the verifiable things first. Five-element mapping before annual fortune because the former is verifiable and the latter has school variance.
- Upgrade disclaimers to options. "Schools differ on night-Zi hour" → give a selector, not a footnote. More honest and more useful.
- Label the method before you build it. "Annual Earth Branch Palm Star method" is traceable; "traditional calculation" isn't.
The same question, applied to architecture
This series usually asks "can this be done in the browser." This post asks a different question: are you redesigning because the problem is different, or because you're tired of looking at the same thing?
If it's the second reason, copy the architecture. Consistent structure, predictable behaviour, low maintenance cost — that combination is more valuable than creative variety in your service implementations.
Next in the series, the divination arc continues — how tarot uses "22 major arcana individually, 56 minor arcana as combinations" to cover all 78 cards with the same three-layer architecture, instead of hardcoding 78 × 2 (upright/reversed) = 156 entries. Want to follow the series? Bookmark LocalPapa Notes.